editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlay_hint_cache;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use proposed_changes_editor::{
   72    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   73};
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79};
   80use aho_corasick::AhoCorasick;
   81use anyhow::{Context as _, Result, anyhow};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::{AGENT_REPLICA_ID, ReplicaId};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  110    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  111    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  112    div, point, prelude::*, pulsating_between, px, relative, size,
  113};
  114use highlight_matching_bracket::refresh_matching_bracket_highlights;
  115use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  116use hover_popover::{HoverState, hide_hover};
  117use indent_guides::ActiveIndentGuidesState;
  118use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  119use itertools::{Either, Itertools};
  120use language::{
  121    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  122    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  123    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  124    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  125    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  126    language_settings::{
  127        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  128        all_language_settings, language_settings,
  129    },
  130    point_from_lsp, point_to_lsp, text_diff_with_options,
  131};
  132use linked_editing_ranges::refresh_linked_ranges;
  133use lsp::{
  134    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  135    LanguageServerId,
  136};
  137use lsp_colors::LspColorData;
  138use markdown::Markdown;
  139use mouse_context_menu::MouseContextMenu;
  140use movement::TextLayoutDetails;
  141use multi_buffer::{
  142    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  143    ToOffsetUtf16,
  144};
  145use parking_lot::Mutex;
  146use persistence::DB;
  147use project::{
  148    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  149    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  150    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  151    ProjectTransaction, TaskSourceKind,
  152    debugger::{
  153        breakpoint_store::{
  154            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  155            BreakpointStore, BreakpointStoreEvent,
  156        },
  157        session::{Session, SessionEvent},
  158    },
  159    git_store::{GitStoreEvent, RepositoryEvent},
  160    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  161    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  162};
  163use rand::seq::SliceRandom;
  164use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  165use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  166use selections_collection::{
  167    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  168};
  169use serde::{Deserialize, Serialize};
  170use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  213};
  214
  215pub const FILE_HEADER_HEIGHT: u32 = 2;
  216pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  217const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  218const MAX_LINE_LEN: usize = 1024;
  219const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  220const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  221pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  222#[doc(hidden)]
  223pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  224pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  225
  226pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  227pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  229pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  230
  231pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  232pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  233pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  234
  235pub type RenderDiffHunkControlsFn = Arc<
  236    dyn Fn(
  237        u32,
  238        &DiffHunkStatus,
  239        Range<Anchor>,
  240        bool,
  241        Pixels,
  242        &Entity<Editor>,
  243        &mut Window,
  244        &mut App,
  245    ) -> AnyElement,
  246>;
  247
  248enum ReportEditorEvent {
  249    Saved { auto_saved: bool },
  250    EditorOpened,
  251    Closed,
  252}
  253
  254impl ReportEditorEvent {
  255    pub fn event_type(&self) -> &'static str {
  256        match self {
  257            Self::Saved { .. } => "Editor Saved",
  258            Self::EditorOpened => "Editor Opened",
  259            Self::Closed => "Editor Closed",
  260        }
  261    }
  262}
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    EditPrediction(u32),
  283    DebuggerValue(u32),
  284    // LSP
  285    Hint(u32),
  286    Color(u32),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> u32 {
  291        match self {
  292            Self::EditPrediction(id) => *id,
  293            Self::DebuggerValue(id) => *id,
  294            Self::Hint(id) => *id,
  295            Self::Color(id) => *id,
  296        }
  297    }
  298}
  299
  300pub enum ActiveDebugLine {}
  301pub enum DebugStackFrameLine {}
  302enum DocumentHighlightRead {}
  303enum DocumentHighlightWrite {}
  304enum InputComposition {}
  305pub enum PendingInput {}
  306enum SelectedTextHighlight {}
  307
  308pub enum ConflictsOuter {}
  309pub enum ConflictsOurs {}
  310pub enum ConflictsTheirs {}
  311pub enum ConflictsOursMarker {}
  312pub enum ConflictsTheirsMarker {}
  313
  314#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  315pub enum Navigated {
  316    Yes,
  317    No,
  318}
  319
  320impl Navigated {
  321    pub fn from_bool(yes: bool) -> Navigated {
  322        if yes { Navigated::Yes } else { Navigated::No }
  323    }
  324}
  325
  326#[derive(Debug, Clone, PartialEq, Eq)]
  327enum DisplayDiffHunk {
  328    Folded {
  329        display_row: DisplayRow,
  330    },
  331    Unfolded {
  332        is_created_file: bool,
  333        diff_base_byte_range: Range<usize>,
  334        display_row_range: Range<DisplayRow>,
  335        multi_buffer_range: Range<Anchor>,
  336        status: DiffHunkStatus,
  337    },
  338}
  339
  340pub enum HideMouseCursorOrigin {
  341    TypingAction,
  342    MovementAction,
  343}
  344
  345pub fn init_settings(cx: &mut App) {
  346    EditorSettings::register(cx);
  347}
  348
  349pub fn init(cx: &mut App) {
  350    init_settings(cx);
  351
  352    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  353
  354    workspace::register_project_item::<Editor>(cx);
  355    workspace::FollowableViewRegistry::register::<Editor>(cx);
  356    workspace::register_serializable_item::<Editor>(cx);
  357
  358    cx.observe_new(
  359        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  360            workspace.register_action(Editor::new_file);
  361            workspace.register_action(Editor::new_file_vertical);
  362            workspace.register_action(Editor::new_file_horizontal);
  363            workspace.register_action(Editor::cancel_language_server_work);
  364            workspace.register_action(Editor::toggle_focus);
  365        },
  366    )
  367    .detach();
  368
  369    cx.on_action(move |_: &workspace::NewFile, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    Editor::new_file(workspace, &Default::default(), window, cx)
  378                },
  379            )
  380            .detach();
  381        }
  382    });
  383    cx.on_action(move |_: &workspace::NewWindow, cx| {
  384        let app_state = workspace::AppState::global(cx);
  385        if let Some(app_state) = app_state.upgrade() {
  386            workspace::open_new(
  387                Default::default(),
  388                app_state,
  389                cx,
  390                |workspace, window, cx| {
  391                    cx.activate(true);
  392                    Editor::new_file(workspace, &Default::default(), window, cx)
  393                },
  394            )
  395            .detach();
  396        }
  397    });
  398}
  399
  400pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  401    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  402}
  403
  404pub trait DiagnosticRenderer {
  405    fn render_group(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  408        buffer_id: BufferId,
  409        snapshot: EditorSnapshot,
  410        editor: WeakEntity<Editor>,
  411        cx: &mut App,
  412    ) -> Vec<BlockProperties<Anchor>>;
  413
  414    fn render_hover(
  415        &self,
  416        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  417        range: Range<Point>,
  418        buffer_id: BufferId,
  419        cx: &mut App,
  420    ) -> Option<Entity<markdown::Markdown>>;
  421
  422    fn open_link(
  423        &self,
  424        editor: &mut Editor,
  425        link: SharedString,
  426        window: &mut Window,
  427        cx: &mut Context<Editor>,
  428    );
  429}
  430
  431pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  432
  433impl GlobalDiagnosticRenderer {
  434    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  435        cx.try_global::<Self>().map(|g| g.0.clone())
  436    }
  437}
  438
  439impl gpui::Global for GlobalDiagnosticRenderer {}
  440pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  441    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  442}
  443
  444pub struct SearchWithinRange;
  445
  446trait InvalidationRegion {
  447    fn ranges(&self) -> &[Range<Anchor>];
  448}
  449
  450#[derive(Clone, Debug, PartialEq)]
  451pub enum SelectPhase {
  452    Begin {
  453        position: DisplayPoint,
  454        add: bool,
  455        click_count: usize,
  456    },
  457    BeginColumnar {
  458        position: DisplayPoint,
  459        reset: bool,
  460        mode: ColumnarMode,
  461        goal_column: u32,
  462    },
  463    Extend {
  464        position: DisplayPoint,
  465        click_count: usize,
  466    },
  467    Update {
  468        position: DisplayPoint,
  469        goal_column: u32,
  470        scroll_delta: gpui::Point<f32>,
  471    },
  472    End,
  473}
  474
  475#[derive(Clone, Debug, PartialEq)]
  476pub enum ColumnarMode {
  477    FromMouse,
  478    FromSelection,
  479}
  480
  481#[derive(Clone, Debug)]
  482pub enum SelectMode {
  483    Character,
  484    Word(Range<Anchor>),
  485    Line(Range<Anchor>),
  486    All,
  487}
  488
  489#[derive(Clone, PartialEq, Eq, Debug)]
  490pub enum EditorMode {
  491    SingleLine,
  492    AutoHeight {
  493        min_lines: usize,
  494        max_lines: Option<usize>,
  495    },
  496    Full {
  497        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  498        scale_ui_elements_with_buffer_font_size: bool,
  499        /// When set to `true`, the editor will render a background for the active line.
  500        show_active_line_background: bool,
  501        /// When set to `true`, the editor's height will be determined by its content.
  502        sized_by_content: bool,
  503    },
  504    Minimap {
  505        parent: WeakEntity<Editor>,
  506    },
  507}
  508
  509impl EditorMode {
  510    pub fn full() -> Self {
  511        Self::Full {
  512            scale_ui_elements_with_buffer_font_size: true,
  513            show_active_line_background: true,
  514            sized_by_content: false,
  515        }
  516    }
  517
  518    #[inline]
  519    pub fn is_full(&self) -> bool {
  520        matches!(self, Self::Full { .. })
  521    }
  522
  523    #[inline]
  524    pub fn is_single_line(&self) -> bool {
  525        matches!(self, Self::SingleLine { .. })
  526    }
  527
  528    #[inline]
  529    fn is_minimap(&self) -> bool {
  530        matches!(self, Self::Minimap { .. })
  531    }
  532}
  533
  534#[derive(Copy, Clone, Debug)]
  535pub enum SoftWrap {
  536    /// Prefer not to wrap at all.
  537    ///
  538    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  539    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  540    GitDiff,
  541    /// Prefer a single line generally, unless an overly long line is encountered.
  542    None,
  543    /// Soft wrap lines that exceed the editor width.
  544    EditorWidth,
  545    /// Soft wrap lines at the preferred line length.
  546    Column(u32),
  547    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  548    Bounded(u32),
  549}
  550
  551#[derive(Clone)]
  552pub struct EditorStyle {
  553    pub background: Hsla,
  554    pub border: Hsla,
  555    pub local_player: PlayerColor,
  556    pub text: TextStyle,
  557    pub scrollbar_width: Pixels,
  558    pub syntax: Arc<SyntaxTheme>,
  559    pub status: StatusColors,
  560    pub inlay_hints_style: HighlightStyle,
  561    pub edit_prediction_styles: EditPredictionStyles,
  562    pub unnecessary_code_fade: f32,
  563    pub show_underlines: bool,
  564}
  565
  566impl Default for EditorStyle {
  567    fn default() -> Self {
  568        Self {
  569            background: Hsla::default(),
  570            border: Hsla::default(),
  571            local_player: PlayerColor::default(),
  572            text: TextStyle::default(),
  573            scrollbar_width: Pixels::default(),
  574            syntax: Default::default(),
  575            // HACK: Status colors don't have a real default.
  576            // We should look into removing the status colors from the editor
  577            // style and retrieve them directly from the theme.
  578            status: StatusColors::dark(),
  579            inlay_hints_style: HighlightStyle::default(),
  580            edit_prediction_styles: EditPredictionStyles {
  581                insertion: HighlightStyle::default(),
  582                whitespace: HighlightStyle::default(),
  583            },
  584            unnecessary_code_fade: Default::default(),
  585            show_underlines: true,
  586        }
  587    }
  588}
  589
  590pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  591    let show_background = language_settings::language_settings(None, None, cx)
  592        .inlay_hints
  593        .show_background;
  594
  595    let mut style = cx.theme().syntax().get("hint");
  596
  597    if style.color.is_none() {
  598        style.color = Some(cx.theme().status().hint);
  599    }
  600
  601    if !show_background {
  602        style.background_color = None;
  603        return style;
  604    }
  605
  606    if style.background_color.is_none() {
  607        style.background_color = Some(cx.theme().status().hint_background);
  608    }
  609
  610    style
  611}
  612
  613pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  614    EditPredictionStyles {
  615        insertion: HighlightStyle {
  616            color: Some(cx.theme().status().predictive),
  617            ..HighlightStyle::default()
  618        },
  619        whitespace: HighlightStyle {
  620            background_color: Some(cx.theme().status().created_background),
  621            ..HighlightStyle::default()
  622        },
  623    }
  624}
  625
  626type CompletionId = usize;
  627
  628pub(crate) enum EditDisplayMode {
  629    TabAccept,
  630    DiffPopover,
  631    Inline,
  632}
  633
  634enum EditPrediction {
  635    Edit {
  636        edits: Vec<(Range<Anchor>, String)>,
  637        edit_preview: Option<EditPreview>,
  638        display_mode: EditDisplayMode,
  639        snapshot: BufferSnapshot,
  640    },
  641    /// Move to a specific location in the active editor
  642    MoveWithin {
  643        target: Anchor,
  644        snapshot: BufferSnapshot,
  645    },
  646    /// Move to a specific location in a different editor (not the active one)
  647    MoveOutside {
  648        target: language::Anchor,
  649        snapshot: BufferSnapshot,
  650    },
  651}
  652
  653struct EditPredictionState {
  654    inlay_ids: Vec<InlayId>,
  655    completion: EditPrediction,
  656    completion_id: Option<SharedString>,
  657    invalidation_range: Option<Range<Anchor>>,
  658}
  659
  660enum EditPredictionSettings {
  661    Disabled,
  662    Enabled {
  663        show_in_menu: bool,
  664        preview_requires_modifier: bool,
  665    },
  666}
  667
  668enum EditPredictionHighlight {}
  669
  670#[derive(Debug, Clone)]
  671struct InlineDiagnostic {
  672    message: SharedString,
  673    group_id: usize,
  674    is_primary: bool,
  675    start: Point,
  676    severity: lsp::DiagnosticSeverity,
  677}
  678
  679pub enum MenuEditPredictionsPolicy {
  680    Never,
  681    ByProvider,
  682}
  683
  684pub enum EditPredictionPreview {
  685    /// Modifier is not pressed
  686    Inactive { released_too_fast: bool },
  687    /// Modifier pressed
  688    Active {
  689        since: Instant,
  690        previous_scroll_position: Option<ScrollAnchor>,
  691    },
  692}
  693
  694impl EditPredictionPreview {
  695    pub fn released_too_fast(&self) -> bool {
  696        match self {
  697            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  698            EditPredictionPreview::Active { .. } => false,
  699        }
  700    }
  701
  702    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  703        if let EditPredictionPreview::Active {
  704            previous_scroll_position,
  705            ..
  706        } = self
  707        {
  708            *previous_scroll_position = scroll_position;
  709        }
  710    }
  711}
  712
  713pub struct ContextMenuOptions {
  714    pub min_entries_visible: usize,
  715    pub max_entries_visible: usize,
  716    pub placement: Option<ContextMenuPlacement>,
  717}
  718
  719#[derive(Debug, Clone, PartialEq, Eq)]
  720pub enum ContextMenuPlacement {
  721    Above,
  722    Below,
  723}
  724
  725#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  726struct EditorActionId(usize);
  727
  728impl EditorActionId {
  729    pub fn post_inc(&mut self) -> Self {
  730        let answer = self.0;
  731
  732        *self = Self(answer + 1);
  733
  734        Self(answer)
  735    }
  736}
  737
  738// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  739// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  740
  741type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  742type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  743
  744#[derive(Default)]
  745struct ScrollbarMarkerState {
  746    scrollbar_size: Size<Pixels>,
  747    dirty: bool,
  748    markers: Arc<[PaintQuad]>,
  749    pending_refresh: Option<Task<Result<()>>>,
  750}
  751
  752impl ScrollbarMarkerState {
  753    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  754        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  755    }
  756}
  757
  758#[derive(Clone, Copy, PartialEq, Eq)]
  759pub enum MinimapVisibility {
  760    Disabled,
  761    Enabled {
  762        /// The configuration currently present in the users settings.
  763        setting_configuration: bool,
  764        /// Whether to override the currently set visibility from the users setting.
  765        toggle_override: bool,
  766    },
  767}
  768
  769impl MinimapVisibility {
  770    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  771        if mode.is_full() {
  772            Self::Enabled {
  773                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  774                toggle_override: false,
  775            }
  776        } else {
  777            Self::Disabled
  778        }
  779    }
  780
  781    fn hidden(&self) -> Self {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => Self::Enabled {
  787                setting_configuration,
  788                toggle_override: setting_configuration,
  789            },
  790            Self::Disabled => Self::Disabled,
  791        }
  792    }
  793
  794    fn disabled(&self) -> bool {
  795        matches!(*self, Self::Disabled)
  796    }
  797
  798    fn settings_visibility(&self) -> bool {
  799        match *self {
  800            Self::Enabled {
  801                setting_configuration,
  802                ..
  803            } => setting_configuration,
  804            _ => false,
  805        }
  806    }
  807
  808    fn visible(&self) -> bool {
  809        match *self {
  810            Self::Enabled {
  811                setting_configuration,
  812                toggle_override,
  813            } => setting_configuration ^ toggle_override,
  814            _ => false,
  815        }
  816    }
  817
  818    fn toggle_visibility(&self) -> Self {
  819        match *self {
  820            Self::Enabled {
  821                toggle_override,
  822                setting_configuration,
  823            } => Self::Enabled {
  824                setting_configuration,
  825                toggle_override: !toggle_override,
  826            },
  827            Self::Disabled => Self::Disabled,
  828        }
  829    }
  830}
  831
  832#[derive(Clone, Debug)]
  833struct RunnableTasks {
  834    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  835    offset: multi_buffer::Anchor,
  836    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  837    column: u32,
  838    // Values of all named captures, including those starting with '_'
  839    extra_variables: HashMap<String, String>,
  840    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  841    context_range: Range<BufferOffset>,
  842}
  843
  844impl RunnableTasks {
  845    fn resolve<'a>(
  846        &'a self,
  847        cx: &'a task::TaskContext,
  848    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  849        self.templates.iter().filter_map(|(kind, template)| {
  850            template
  851                .resolve_task(&kind.to_id_base(), cx)
  852                .map(|task| (kind.clone(), task))
  853        })
  854    }
  855}
  856
  857#[derive(Clone)]
  858pub struct ResolvedTasks {
  859    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  860    position: Anchor,
  861}
  862
  863#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  864struct BufferOffset(usize);
  865
  866/// Addons allow storing per-editor state in other crates (e.g. Vim)
  867pub trait Addon: 'static {
  868    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  869
  870    fn render_buffer_header_controls(
  871        &self,
  872        _: &ExcerptInfo,
  873        _: &Window,
  874        _: &App,
  875    ) -> Option<AnyElement> {
  876        None
  877    }
  878
  879    fn to_any(&self) -> &dyn std::any::Any;
  880
  881    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  882        None
  883    }
  884}
  885
  886struct ChangeLocation {
  887    current: Option<Vec<Anchor>>,
  888    original: Vec<Anchor>,
  889}
  890impl ChangeLocation {
  891    fn locations(&self) -> &[Anchor] {
  892        self.current.as_ref().unwrap_or(&self.original)
  893    }
  894}
  895
  896/// A set of caret positions, registered when the editor was edited.
  897pub struct ChangeList {
  898    changes: Vec<ChangeLocation>,
  899    /// Currently "selected" change.
  900    position: Option<usize>,
  901}
  902
  903impl ChangeList {
  904    pub fn new() -> Self {
  905        Self {
  906            changes: Vec::new(),
  907            position: None,
  908        }
  909    }
  910
  911    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  912    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  913    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  914        if self.changes.is_empty() {
  915            return None;
  916        }
  917
  918        let prev = self.position.unwrap_or(self.changes.len());
  919        let next = if direction == Direction::Prev {
  920            prev.saturating_sub(count)
  921        } else {
  922            (prev + count).min(self.changes.len() - 1)
  923        };
  924        self.position = Some(next);
  925        self.changes.get(next).map(|change| change.locations())
  926    }
  927
  928    /// Adds a new change to the list, resetting the change list position.
  929    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  930        self.position.take();
  931        if let Some(last) = self.changes.last_mut()
  932            && group
  933        {
  934            last.current = Some(new_positions)
  935        } else {
  936            self.changes.push(ChangeLocation {
  937                original: new_positions,
  938                current: None,
  939            });
  940        }
  941    }
  942
  943    pub fn last(&self) -> Option<&[Anchor]> {
  944        self.changes.last().map(|change| change.locations())
  945    }
  946
  947    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  948        self.changes.last().map(|change| change.original.as_slice())
  949    }
  950
  951    pub fn invert_last_group(&mut self) {
  952        if let Some(last) = self.changes.last_mut()
  953            && let Some(current) = last.current.as_mut()
  954        {
  955            mem::swap(&mut last.original, current);
  956        }
  957    }
  958}
  959
  960#[derive(Clone)]
  961struct InlineBlamePopoverState {
  962    scroll_handle: ScrollHandle,
  963    commit_message: Option<ParsedCommitMessage>,
  964    markdown: Entity<Markdown>,
  965}
  966
  967struct InlineBlamePopover {
  968    position: gpui::Point<Pixels>,
  969    hide_task: Option<Task<()>>,
  970    popover_bounds: Option<Bounds<Pixels>>,
  971    popover_state: InlineBlamePopoverState,
  972    keyboard_grace: bool,
  973}
  974
  975enum SelectionDragState {
  976    /// State when no drag related activity is detected.
  977    None,
  978    /// State when the mouse is down on a selection that is about to be dragged.
  979    ReadyToDrag {
  980        selection: Selection<Anchor>,
  981        click_position: gpui::Point<Pixels>,
  982        mouse_down_time: Instant,
  983    },
  984    /// State when the mouse is dragging the selection in the editor.
  985    Dragging {
  986        selection: Selection<Anchor>,
  987        drop_cursor: Selection<Anchor>,
  988        hide_drop_cursor: bool,
  989    },
  990}
  991
  992enum ColumnarSelectionState {
  993    FromMouse {
  994        selection_tail: Anchor,
  995        display_point: Option<DisplayPoint>,
  996    },
  997    FromSelection {
  998        selection_tail: Anchor,
  999    },
 1000}
 1001
 1002/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1003/// a breakpoint on them.
 1004#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1005struct PhantomBreakpointIndicator {
 1006    display_row: DisplayRow,
 1007    /// There's a small debounce between hovering over the line and showing the indicator.
 1008    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1009    is_active: bool,
 1010    collides_with_existing_breakpoint: bool,
 1011}
 1012
 1013/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1014///
 1015/// See the [module level documentation](self) for more information.
 1016pub struct Editor {
 1017    focus_handle: FocusHandle,
 1018    last_focused_descendant: Option<WeakFocusHandle>,
 1019    /// The text buffer being edited
 1020    buffer: Entity<MultiBuffer>,
 1021    /// Map of how text in the buffer should be displayed.
 1022    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1023    pub display_map: Entity<DisplayMap>,
 1024    placeholder_display_map: Option<Entity<DisplayMap>>,
 1025    pub selections: SelectionsCollection,
 1026    pub scroll_manager: ScrollManager,
 1027    /// When inline assist editors are linked, they all render cursors because
 1028    /// typing enters text into each of them, even the ones that aren't focused.
 1029    pub(crate) show_cursor_when_unfocused: bool,
 1030    columnar_selection_state: Option<ColumnarSelectionState>,
 1031    add_selections_state: Option<AddSelectionsState>,
 1032    select_next_state: Option<SelectNextState>,
 1033    select_prev_state: Option<SelectNextState>,
 1034    selection_history: SelectionHistory,
 1035    defer_selection_effects: bool,
 1036    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1037    autoclose_regions: Vec<AutocloseRegion>,
 1038    snippet_stack: InvalidationStack<SnippetState>,
 1039    select_syntax_node_history: SelectSyntaxNodeHistory,
 1040    ime_transaction: Option<TransactionId>,
 1041    pub diagnostics_max_severity: DiagnosticSeverity,
 1042    active_diagnostics: ActiveDiagnostic,
 1043    show_inline_diagnostics: bool,
 1044    inline_diagnostics_update: Task<()>,
 1045    inline_diagnostics_enabled: bool,
 1046    diagnostics_enabled: bool,
 1047    word_completions_enabled: bool,
 1048    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1049    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1050    hard_wrap: Option<usize>,
 1051    project: Option<Entity<Project>>,
 1052    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1053    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1054    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1055    blink_manager: Entity<BlinkManager>,
 1056    show_cursor_names: bool,
 1057    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1058    pub show_local_selections: bool,
 1059    mode: EditorMode,
 1060    show_breadcrumbs: bool,
 1061    show_gutter: bool,
 1062    show_scrollbars: ScrollbarAxes,
 1063    minimap_visibility: MinimapVisibility,
 1064    offset_content: bool,
 1065    disable_expand_excerpt_buttons: bool,
 1066    show_line_numbers: Option<bool>,
 1067    use_relative_line_numbers: Option<bool>,
 1068    show_git_diff_gutter: Option<bool>,
 1069    show_code_actions: Option<bool>,
 1070    show_runnables: Option<bool>,
 1071    show_breakpoints: Option<bool>,
 1072    show_wrap_guides: Option<bool>,
 1073    show_indent_guides: Option<bool>,
 1074    highlight_order: usize,
 1075    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1076    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1077    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1078    scrollbar_marker_state: ScrollbarMarkerState,
 1079    active_indent_guides_state: ActiveIndentGuidesState,
 1080    nav_history: Option<ItemNavHistory>,
 1081    context_menu: RefCell<Option<CodeContextMenu>>,
 1082    context_menu_options: Option<ContextMenuOptions>,
 1083    mouse_context_menu: Option<MouseContextMenu>,
 1084    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1085    inline_blame_popover: Option<InlineBlamePopover>,
 1086    inline_blame_popover_show_task: Option<Task<()>>,
 1087    signature_help_state: SignatureHelpState,
 1088    auto_signature_help: Option<bool>,
 1089    find_all_references_task_sources: Vec<Anchor>,
 1090    next_completion_id: CompletionId,
 1091    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1092    code_actions_task: Option<Task<Result<()>>>,
 1093    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1095    document_highlights_task: Option<Task<()>>,
 1096    linked_editing_range_task: Option<Task<Option<()>>>,
 1097    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1098    pending_rename: Option<RenameState>,
 1099    searchable: bool,
 1100    cursor_shape: CursorShape,
 1101    current_line_highlight: Option<CurrentLineHighlight>,
 1102    collapse_matches: bool,
 1103    autoindent_mode: Option<AutoindentMode>,
 1104    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1105    input_enabled: bool,
 1106    use_modal_editing: bool,
 1107    read_only: bool,
 1108    leader_id: Option<CollaboratorId>,
 1109    remote_id: Option<ViewId>,
 1110    pub hover_state: HoverState,
 1111    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1112    gutter_hovered: bool,
 1113    hovered_link_state: Option<HoveredLinkState>,
 1114    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1115    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1116    active_edit_prediction: Option<EditPredictionState>,
 1117    /// Used to prevent flickering as the user types while the menu is open
 1118    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1119    edit_prediction_settings: EditPredictionSettings,
 1120    edit_predictions_hidden_for_vim_mode: bool,
 1121    show_edit_predictions_override: Option<bool>,
 1122    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1123    edit_prediction_preview: EditPredictionPreview,
 1124    edit_prediction_indent_conflict: bool,
 1125    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1126    inlay_hint_cache: InlayHintCache,
 1127    next_inlay_id: u32,
 1128    next_color_inlay_id: u32,
 1129    _subscriptions: Vec<Subscription>,
 1130    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1131    gutter_dimensions: GutterDimensions,
 1132    style: Option<EditorStyle>,
 1133    text_style_refinement: Option<TextStyleRefinement>,
 1134    next_editor_action_id: EditorActionId,
 1135    editor_actions: Rc<
 1136        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1137    >,
 1138    use_autoclose: bool,
 1139    use_auto_surround: bool,
 1140    auto_replace_emoji_shortcode: bool,
 1141    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1142    show_git_blame_gutter: bool,
 1143    show_git_blame_inline: bool,
 1144    show_git_blame_inline_delay_task: Option<Task<()>>,
 1145    git_blame_inline_enabled: bool,
 1146    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1147    serialize_dirty_buffers: bool,
 1148    show_selection_menu: Option<bool>,
 1149    blame: Option<Entity<GitBlame>>,
 1150    blame_subscription: Option<Subscription>,
 1151    custom_context_menu: Option<
 1152        Box<
 1153            dyn 'static
 1154                + Fn(
 1155                    &mut Self,
 1156                    DisplayPoint,
 1157                    &mut Window,
 1158                    &mut Context<Self>,
 1159                ) -> Option<Entity<ui::ContextMenu>>,
 1160        >,
 1161    >,
 1162    last_bounds: Option<Bounds<Pixels>>,
 1163    last_position_map: Option<Rc<PositionMap>>,
 1164    expect_bounds_change: Option<Bounds<Pixels>>,
 1165    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1166    tasks_update_task: Option<Task<()>>,
 1167    breakpoint_store: Option<Entity<BreakpointStore>>,
 1168    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1169    hovered_diff_hunk_row: Option<DisplayRow>,
 1170    pull_diagnostics_task: Task<()>,
 1171    in_project_search: bool,
 1172    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1173    breadcrumb_header: Option<String>,
 1174    focused_block: Option<FocusedBlock>,
 1175    next_scroll_position: NextScrollCursorCenterTopBottom,
 1176    addons: HashMap<TypeId, Box<dyn Addon>>,
 1177    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1178    load_diff_task: Option<Shared<Task<()>>>,
 1179    /// Whether we are temporarily displaying a diff other than git's
 1180    temporary_diff_override: bool,
 1181    selection_mark_mode: bool,
 1182    toggle_fold_multiple_buffers: Task<()>,
 1183    _scroll_cursor_center_top_bottom_task: Task<()>,
 1184    serialize_selections: Task<()>,
 1185    serialize_folds: Task<()>,
 1186    mouse_cursor_hidden: bool,
 1187    minimap: Option<Entity<Self>>,
 1188    hide_mouse_mode: HideMouseMode,
 1189    pub change_list: ChangeList,
 1190    inline_value_cache: InlineValueCache,
 1191    selection_drag_state: SelectionDragState,
 1192    colors: Option<LspColorData>,
 1193    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        self.begin_selection(position, false, click_count, window, cx);
 3518
 3519        let position = position.to_offset(&display_map, Bias::Left);
 3520        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3521
 3522        let mut pending_selection = self
 3523            .selections
 3524            .pending_anchor()
 3525            .cloned()
 3526            .expect("extend_selection not called with pending selection");
 3527        if position >= tail {
 3528            pending_selection.start = tail_anchor;
 3529        } else {
 3530            pending_selection.end = tail_anchor;
 3531            pending_selection.reversed = true;
 3532        }
 3533
 3534        let mut pending_mode = self.selections.pending_mode().unwrap();
 3535        match &mut pending_mode {
 3536            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3537            _ => {}
 3538        }
 3539
 3540        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3541            SelectionEffects::scroll(Autoscroll::fit())
 3542        } else {
 3543            SelectionEffects::no_scroll()
 3544        };
 3545
 3546        self.change_selections(effects, window, cx, |s| {
 3547            s.set_pending(pending_selection.clone(), pending_mode)
 3548        });
 3549    }
 3550
 3551    fn begin_selection(
 3552        &mut self,
 3553        position: DisplayPoint,
 3554        add: bool,
 3555        click_count: usize,
 3556        window: &mut Window,
 3557        cx: &mut Context<Self>,
 3558    ) {
 3559        if !self.focus_handle.is_focused(window) {
 3560            self.last_focused_descendant = None;
 3561            window.focus(&self.focus_handle);
 3562        }
 3563
 3564        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3565        let buffer = display_map.buffer_snapshot();
 3566        let position = display_map.clip_point(position, Bias::Left);
 3567
 3568        let start;
 3569        let end;
 3570        let mode;
 3571        let mut auto_scroll;
 3572        match click_count {
 3573            1 => {
 3574                start = buffer.anchor_before(position.to_point(&display_map));
 3575                end = start;
 3576                mode = SelectMode::Character;
 3577                auto_scroll = true;
 3578            }
 3579            2 => {
 3580                let position = display_map
 3581                    .clip_point(position, Bias::Left)
 3582                    .to_offset(&display_map, Bias::Left);
 3583                let (range, _) = buffer.surrounding_word(position, None);
 3584                start = buffer.anchor_before(range.start);
 3585                end = buffer.anchor_before(range.end);
 3586                mode = SelectMode::Word(start..end);
 3587                auto_scroll = true;
 3588            }
 3589            3 => {
 3590                let position = display_map
 3591                    .clip_point(position, Bias::Left)
 3592                    .to_point(&display_map);
 3593                let line_start = display_map.prev_line_boundary(position).0;
 3594                let next_line_start = buffer.clip_point(
 3595                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3596                    Bias::Left,
 3597                );
 3598                start = buffer.anchor_before(line_start);
 3599                end = buffer.anchor_before(next_line_start);
 3600                mode = SelectMode::Line(start..end);
 3601                auto_scroll = true;
 3602            }
 3603            _ => {
 3604                start = buffer.anchor_before(0);
 3605                end = buffer.anchor_before(buffer.len());
 3606                mode = SelectMode::All;
 3607                auto_scroll = false;
 3608            }
 3609        }
 3610        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3611
 3612        let point_to_delete: Option<usize> = {
 3613            let selected_points: Vec<Selection<Point>> =
 3614                self.selections.disjoint_in_range(start..end, cx);
 3615
 3616            if !add || click_count > 1 {
 3617                None
 3618            } else if !selected_points.is_empty() {
 3619                Some(selected_points[0].id)
 3620            } else {
 3621                let clicked_point_already_selected =
 3622                    self.selections.disjoint_anchors().iter().find(|selection| {
 3623                        selection.start.to_point(buffer) == start.to_point(buffer)
 3624                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3625                    });
 3626
 3627                clicked_point_already_selected.map(|selection| selection.id)
 3628            }
 3629        };
 3630
 3631        let selections_count = self.selections.count();
 3632        let effects = if auto_scroll {
 3633            SelectionEffects::default()
 3634        } else {
 3635            SelectionEffects::no_scroll()
 3636        };
 3637
 3638        self.change_selections(effects, window, cx, |s| {
 3639            if let Some(point_to_delete) = point_to_delete {
 3640                s.delete(point_to_delete);
 3641
 3642                if selections_count == 1 {
 3643                    s.set_pending_anchor_range(start..end, mode);
 3644                }
 3645            } else {
 3646                if !add {
 3647                    s.clear_disjoint();
 3648                }
 3649
 3650                s.set_pending_anchor_range(start..end, mode);
 3651            }
 3652        });
 3653    }
 3654
 3655    fn begin_columnar_selection(
 3656        &mut self,
 3657        position: DisplayPoint,
 3658        goal_column: u32,
 3659        reset: bool,
 3660        mode: ColumnarMode,
 3661        window: &mut Window,
 3662        cx: &mut Context<Self>,
 3663    ) {
 3664        if !self.focus_handle.is_focused(window) {
 3665            self.last_focused_descendant = None;
 3666            window.focus(&self.focus_handle);
 3667        }
 3668
 3669        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3670
 3671        if reset {
 3672            let pointer_position = display_map
 3673                .buffer_snapshot()
 3674                .anchor_before(position.to_point(&display_map));
 3675
 3676            self.change_selections(
 3677                SelectionEffects::scroll(Autoscroll::newest()),
 3678                window,
 3679                cx,
 3680                |s| {
 3681                    s.clear_disjoint();
 3682                    s.set_pending_anchor_range(
 3683                        pointer_position..pointer_position,
 3684                        SelectMode::Character,
 3685                    );
 3686                },
 3687            );
 3688        };
 3689
 3690        let tail = self.selections.newest::<Point>(cx).tail();
 3691        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3692        self.columnar_selection_state = match mode {
 3693            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3694                selection_tail: selection_anchor,
 3695                display_point: if reset {
 3696                    if position.column() != goal_column {
 3697                        Some(DisplayPoint::new(position.row(), goal_column))
 3698                    } else {
 3699                        None
 3700                    }
 3701                } else {
 3702                    None
 3703                },
 3704            }),
 3705            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3706                selection_tail: selection_anchor,
 3707            }),
 3708        };
 3709
 3710        if !reset {
 3711            self.select_columns(position, goal_column, &display_map, window, cx);
 3712        }
 3713    }
 3714
 3715    fn update_selection(
 3716        &mut self,
 3717        position: DisplayPoint,
 3718        goal_column: u32,
 3719        scroll_delta: gpui::Point<f32>,
 3720        window: &mut Window,
 3721        cx: &mut Context<Self>,
 3722    ) {
 3723        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3724
 3725        if self.columnar_selection_state.is_some() {
 3726            self.select_columns(position, goal_column, &display_map, window, cx);
 3727        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3728            let buffer = display_map.buffer_snapshot();
 3729            let head;
 3730            let tail;
 3731            let mode = self.selections.pending_mode().unwrap();
 3732            match &mode {
 3733                SelectMode::Character => {
 3734                    head = position.to_point(&display_map);
 3735                    tail = pending.tail().to_point(buffer);
 3736                }
 3737                SelectMode::Word(original_range) => {
 3738                    let offset = display_map
 3739                        .clip_point(position, Bias::Left)
 3740                        .to_offset(&display_map, Bias::Left);
 3741                    let original_range = original_range.to_offset(buffer);
 3742
 3743                    let head_offset = if buffer.is_inside_word(offset, None)
 3744                        || original_range.contains(&offset)
 3745                    {
 3746                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3747                        if word_range.start < original_range.start {
 3748                            word_range.start
 3749                        } else {
 3750                            word_range.end
 3751                        }
 3752                    } else {
 3753                        offset
 3754                    };
 3755
 3756                    head = head_offset.to_point(buffer);
 3757                    if head_offset <= original_range.start {
 3758                        tail = original_range.end.to_point(buffer);
 3759                    } else {
 3760                        tail = original_range.start.to_point(buffer);
 3761                    }
 3762                }
 3763                SelectMode::Line(original_range) => {
 3764                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3765
 3766                    let position = display_map
 3767                        .clip_point(position, Bias::Left)
 3768                        .to_point(&display_map);
 3769                    let line_start = display_map.prev_line_boundary(position).0;
 3770                    let next_line_start = buffer.clip_point(
 3771                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3772                        Bias::Left,
 3773                    );
 3774
 3775                    if line_start < original_range.start {
 3776                        head = line_start
 3777                    } else {
 3778                        head = next_line_start
 3779                    }
 3780
 3781                    if head <= original_range.start {
 3782                        tail = original_range.end;
 3783                    } else {
 3784                        tail = original_range.start;
 3785                    }
 3786                }
 3787                SelectMode::All => {
 3788                    return;
 3789                }
 3790            };
 3791
 3792            if head < tail {
 3793                pending.start = buffer.anchor_before(head);
 3794                pending.end = buffer.anchor_before(tail);
 3795                pending.reversed = true;
 3796            } else {
 3797                pending.start = buffer.anchor_before(tail);
 3798                pending.end = buffer.anchor_before(head);
 3799                pending.reversed = false;
 3800            }
 3801
 3802            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3803                s.set_pending(pending.clone(), mode);
 3804            });
 3805        } else {
 3806            log::error!("update_selection dispatched with no pending selection");
 3807            return;
 3808        }
 3809
 3810        self.apply_scroll_delta(scroll_delta, window, cx);
 3811        cx.notify();
 3812    }
 3813
 3814    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3815        self.columnar_selection_state.take();
 3816        if self.selections.pending_anchor().is_some() {
 3817            let selections = self.selections.all::<usize>(cx);
 3818            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3819                s.select(selections);
 3820                s.clear_pending();
 3821            });
 3822        }
 3823    }
 3824
 3825    fn select_columns(
 3826        &mut self,
 3827        head: DisplayPoint,
 3828        goal_column: u32,
 3829        display_map: &DisplaySnapshot,
 3830        window: &mut Window,
 3831        cx: &mut Context<Self>,
 3832    ) {
 3833        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3834            return;
 3835        };
 3836
 3837        let tail = match columnar_state {
 3838            ColumnarSelectionState::FromMouse {
 3839                selection_tail,
 3840                display_point,
 3841            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3842            ColumnarSelectionState::FromSelection { selection_tail } => {
 3843                selection_tail.to_display_point(display_map)
 3844            }
 3845        };
 3846
 3847        let start_row = cmp::min(tail.row(), head.row());
 3848        let end_row = cmp::max(tail.row(), head.row());
 3849        let start_column = cmp::min(tail.column(), goal_column);
 3850        let end_column = cmp::max(tail.column(), goal_column);
 3851        let reversed = start_column < tail.column();
 3852
 3853        let selection_ranges = (start_row.0..=end_row.0)
 3854            .map(DisplayRow)
 3855            .filter_map(|row| {
 3856                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3857                    || start_column <= display_map.line_len(row))
 3858                    && !display_map.is_block_line(row)
 3859                {
 3860                    let start = display_map
 3861                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3862                        .to_point(display_map);
 3863                    let end = display_map
 3864                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3865                        .to_point(display_map);
 3866                    if reversed {
 3867                        Some(end..start)
 3868                    } else {
 3869                        Some(start..end)
 3870                    }
 3871                } else {
 3872                    None
 3873                }
 3874            })
 3875            .collect::<Vec<_>>();
 3876
 3877        let ranges = match columnar_state {
 3878            ColumnarSelectionState::FromMouse { .. } => {
 3879                let mut non_empty_ranges = selection_ranges
 3880                    .iter()
 3881                    .filter(|selection_range| selection_range.start != selection_range.end)
 3882                    .peekable();
 3883                if non_empty_ranges.peek().is_some() {
 3884                    non_empty_ranges.cloned().collect()
 3885                } else {
 3886                    selection_ranges
 3887                }
 3888            }
 3889            _ => selection_ranges,
 3890        };
 3891
 3892        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3893            s.select_ranges(ranges);
 3894        });
 3895        cx.notify();
 3896    }
 3897
 3898    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3899        self.selections
 3900            .all_adjusted(cx)
 3901            .iter()
 3902            .any(|selection| !selection.is_empty())
 3903    }
 3904
 3905    pub fn has_pending_nonempty_selection(&self) -> bool {
 3906        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3907            Some(Selection { start, end, .. }) => start != end,
 3908            None => false,
 3909        };
 3910
 3911        pending_nonempty_selection
 3912            || (self.columnar_selection_state.is_some()
 3913                && self.selections.disjoint_anchors().len() > 1)
 3914    }
 3915
 3916    pub fn has_pending_selection(&self) -> bool {
 3917        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3918    }
 3919
 3920    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3921        self.selection_mark_mode = false;
 3922        self.selection_drag_state = SelectionDragState::None;
 3923
 3924        if self.clear_expanded_diff_hunks(cx) {
 3925            cx.notify();
 3926            return;
 3927        }
 3928        if self.dismiss_menus_and_popups(true, window, cx) {
 3929            return;
 3930        }
 3931
 3932        if self.mode.is_full()
 3933            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3934        {
 3935            return;
 3936        }
 3937
 3938        cx.propagate();
 3939    }
 3940
 3941    pub fn dismiss_menus_and_popups(
 3942        &mut self,
 3943        is_user_requested: bool,
 3944        window: &mut Window,
 3945        cx: &mut Context<Self>,
 3946    ) -> bool {
 3947        if self.take_rename(false, window, cx).is_some() {
 3948            return true;
 3949        }
 3950
 3951        if hide_hover(self, cx) {
 3952            return true;
 3953        }
 3954
 3955        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3956            return true;
 3957        }
 3958
 3959        if self.hide_context_menu(window, cx).is_some() {
 3960            return true;
 3961        }
 3962
 3963        if self.mouse_context_menu.take().is_some() {
 3964            return true;
 3965        }
 3966
 3967        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3968            return true;
 3969        }
 3970
 3971        if self.snippet_stack.pop().is_some() {
 3972            return true;
 3973        }
 3974
 3975        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3976            self.dismiss_diagnostics(cx);
 3977            return true;
 3978        }
 3979
 3980        false
 3981    }
 3982
 3983    fn linked_editing_ranges_for(
 3984        &self,
 3985        selection: Range<text::Anchor>,
 3986        cx: &App,
 3987    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3988        if self.linked_edit_ranges.is_empty() {
 3989            return None;
 3990        }
 3991        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3992            selection.end.buffer_id.and_then(|end_buffer_id| {
 3993                if selection.start.buffer_id != Some(end_buffer_id) {
 3994                    return None;
 3995                }
 3996                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3997                let snapshot = buffer.read(cx).snapshot();
 3998                self.linked_edit_ranges
 3999                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4000                    .map(|ranges| (ranges, snapshot, buffer))
 4001            })?;
 4002        use text::ToOffset as TO;
 4003        // find offset from the start of current range to current cursor position
 4004        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4005
 4006        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4007        let start_difference = start_offset - start_byte_offset;
 4008        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4009        let end_difference = end_offset - start_byte_offset;
 4010        // Current range has associated linked ranges.
 4011        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4012        for range in linked_ranges.iter() {
 4013            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4014            let end_offset = start_offset + end_difference;
 4015            let start_offset = start_offset + start_difference;
 4016            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4017                continue;
 4018            }
 4019            if self.selections.disjoint_anchor_ranges().any(|s| {
 4020                if s.start.buffer_id != selection.start.buffer_id
 4021                    || s.end.buffer_id != selection.end.buffer_id
 4022                {
 4023                    return false;
 4024                }
 4025                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4026                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4027            }) {
 4028                continue;
 4029            }
 4030            let start = buffer_snapshot.anchor_after(start_offset);
 4031            let end = buffer_snapshot.anchor_after(end_offset);
 4032            linked_edits
 4033                .entry(buffer.clone())
 4034                .or_default()
 4035                .push(start..end);
 4036        }
 4037        Some(linked_edits)
 4038    }
 4039
 4040    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4041        let text: Arc<str> = text.into();
 4042
 4043        if self.read_only(cx) {
 4044            return;
 4045        }
 4046
 4047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4048
 4049        let selections = self.selections.all_adjusted(cx);
 4050        let mut bracket_inserted = false;
 4051        let mut edits = Vec::new();
 4052        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4053        let mut new_selections = Vec::with_capacity(selections.len());
 4054        let mut new_autoclose_regions = Vec::new();
 4055        let snapshot = self.buffer.read(cx).read(cx);
 4056        let mut clear_linked_edit_ranges = false;
 4057
 4058        for (selection, autoclose_region) in
 4059            self.selections_with_autoclose_regions(selections, &snapshot)
 4060        {
 4061            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4062                // Determine if the inserted text matches the opening or closing
 4063                // bracket of any of this language's bracket pairs.
 4064                let mut bracket_pair = None;
 4065                let mut is_bracket_pair_start = false;
 4066                let mut is_bracket_pair_end = false;
 4067                if !text.is_empty() {
 4068                    let mut bracket_pair_matching_end = None;
 4069                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4070                    //  and they are removing the character that triggered IME popup.
 4071                    for (pair, enabled) in scope.brackets() {
 4072                        if !pair.close && !pair.surround {
 4073                            continue;
 4074                        }
 4075
 4076                        if enabled && pair.start.ends_with(text.as_ref()) {
 4077                            let prefix_len = pair.start.len() - text.len();
 4078                            let preceding_text_matches_prefix = prefix_len == 0
 4079                                || (selection.start.column >= (prefix_len as u32)
 4080                                    && snapshot.contains_str_at(
 4081                                        Point::new(
 4082                                            selection.start.row,
 4083                                            selection.start.column - (prefix_len as u32),
 4084                                        ),
 4085                                        &pair.start[..prefix_len],
 4086                                    ));
 4087                            if preceding_text_matches_prefix {
 4088                                bracket_pair = Some(pair.clone());
 4089                                is_bracket_pair_start = true;
 4090                                break;
 4091                            }
 4092                        }
 4093                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4094                        {
 4095                            // take first bracket pair matching end, but don't break in case a later bracket
 4096                            // pair matches start
 4097                            bracket_pair_matching_end = Some(pair.clone());
 4098                        }
 4099                    }
 4100                    if let Some(end) = bracket_pair_matching_end
 4101                        && bracket_pair.is_none()
 4102                    {
 4103                        bracket_pair = Some(end);
 4104                        is_bracket_pair_end = true;
 4105                    }
 4106                }
 4107
 4108                if let Some(bracket_pair) = bracket_pair {
 4109                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4110                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4111                    let auto_surround =
 4112                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4113                    if selection.is_empty() {
 4114                        if is_bracket_pair_start {
 4115                            // If the inserted text is a suffix of an opening bracket and the
 4116                            // selection is preceded by the rest of the opening bracket, then
 4117                            // insert the closing bracket.
 4118                            let following_text_allows_autoclose = snapshot
 4119                                .chars_at(selection.start)
 4120                                .next()
 4121                                .is_none_or(|c| scope.should_autoclose_before(c));
 4122
 4123                            let preceding_text_allows_autoclose = selection.start.column == 0
 4124                                || snapshot
 4125                                    .reversed_chars_at(selection.start)
 4126                                    .next()
 4127                                    .is_none_or(|c| {
 4128                                        bracket_pair.start != bracket_pair.end
 4129                                            || !snapshot
 4130                                                .char_classifier_at(selection.start)
 4131                                                .is_word(c)
 4132                                    });
 4133
 4134                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4135                                && bracket_pair.start.len() == 1
 4136                            {
 4137                                let target = bracket_pair.start.chars().next().unwrap();
 4138                                let current_line_count = snapshot
 4139                                    .reversed_chars_at(selection.start)
 4140                                    .take_while(|&c| c != '\n')
 4141                                    .filter(|&c| c == target)
 4142                                    .count();
 4143                                current_line_count % 2 == 1
 4144                            } else {
 4145                                false
 4146                            };
 4147
 4148                            if autoclose
 4149                                && bracket_pair.close
 4150                                && following_text_allows_autoclose
 4151                                && preceding_text_allows_autoclose
 4152                                && !is_closing_quote
 4153                            {
 4154                                let anchor = snapshot.anchor_before(selection.end);
 4155                                new_selections.push((selection.map(|_| anchor), text.len()));
 4156                                new_autoclose_regions.push((
 4157                                    anchor,
 4158                                    text.len(),
 4159                                    selection.id,
 4160                                    bracket_pair.clone(),
 4161                                ));
 4162                                edits.push((
 4163                                    selection.range(),
 4164                                    format!("{}{}", text, bracket_pair.end).into(),
 4165                                ));
 4166                                bracket_inserted = true;
 4167                                continue;
 4168                            }
 4169                        }
 4170
 4171                        if let Some(region) = autoclose_region {
 4172                            // If the selection is followed by an auto-inserted closing bracket,
 4173                            // then don't insert that closing bracket again; just move the selection
 4174                            // past the closing bracket.
 4175                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4176                                && text.as_ref() == region.pair.end.as_str()
 4177                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4178                            if should_skip {
 4179                                let anchor = snapshot.anchor_after(selection.end);
 4180                                new_selections
 4181                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4182                                continue;
 4183                            }
 4184                        }
 4185
 4186                        let always_treat_brackets_as_autoclosed = snapshot
 4187                            .language_settings_at(selection.start, cx)
 4188                            .always_treat_brackets_as_autoclosed;
 4189                        if always_treat_brackets_as_autoclosed
 4190                            && is_bracket_pair_end
 4191                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4192                        {
 4193                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4194                            // and the inserted text is a closing bracket and the selection is followed
 4195                            // by the closing bracket then move the selection past the closing bracket.
 4196                            let anchor = snapshot.anchor_after(selection.end);
 4197                            new_selections.push((selection.map(|_| anchor), text.len()));
 4198                            continue;
 4199                        }
 4200                    }
 4201                    // If an opening bracket is 1 character long and is typed while
 4202                    // text is selected, then surround that text with the bracket pair.
 4203                    else if auto_surround
 4204                        && bracket_pair.surround
 4205                        && is_bracket_pair_start
 4206                        && bracket_pair.start.chars().count() == 1
 4207                    {
 4208                        edits.push((selection.start..selection.start, text.clone()));
 4209                        edits.push((
 4210                            selection.end..selection.end,
 4211                            bracket_pair.end.as_str().into(),
 4212                        ));
 4213                        bracket_inserted = true;
 4214                        new_selections.push((
 4215                            Selection {
 4216                                id: selection.id,
 4217                                start: snapshot.anchor_after(selection.start),
 4218                                end: snapshot.anchor_before(selection.end),
 4219                                reversed: selection.reversed,
 4220                                goal: selection.goal,
 4221                            },
 4222                            0,
 4223                        ));
 4224                        continue;
 4225                    }
 4226                }
 4227            }
 4228
 4229            if self.auto_replace_emoji_shortcode
 4230                && selection.is_empty()
 4231                && text.as_ref().ends_with(':')
 4232                && let Some(possible_emoji_short_code) =
 4233                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4234                && !possible_emoji_short_code.is_empty()
 4235                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4236            {
 4237                let emoji_shortcode_start = Point::new(
 4238                    selection.start.row,
 4239                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4240                );
 4241
 4242                // Remove shortcode from buffer
 4243                edits.push((
 4244                    emoji_shortcode_start..selection.start,
 4245                    "".to_string().into(),
 4246                ));
 4247                new_selections.push((
 4248                    Selection {
 4249                        id: selection.id,
 4250                        start: snapshot.anchor_after(emoji_shortcode_start),
 4251                        end: snapshot.anchor_before(selection.start),
 4252                        reversed: selection.reversed,
 4253                        goal: selection.goal,
 4254                    },
 4255                    0,
 4256                ));
 4257
 4258                // Insert emoji
 4259                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4260                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4261                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4262
 4263                continue;
 4264            }
 4265
 4266            // If not handling any auto-close operation, then just replace the selected
 4267            // text with the given input and move the selection to the end of the
 4268            // newly inserted text.
 4269            let anchor = snapshot.anchor_after(selection.end);
 4270            if !self.linked_edit_ranges.is_empty() {
 4271                let start_anchor = snapshot.anchor_before(selection.start);
 4272
 4273                let is_word_char = text.chars().next().is_none_or(|char| {
 4274                    let classifier = snapshot
 4275                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4276                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4277                    classifier.is_word(char)
 4278                });
 4279
 4280                if is_word_char {
 4281                    if let Some(ranges) = self
 4282                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4283                    {
 4284                        for (buffer, edits) in ranges {
 4285                            linked_edits
 4286                                .entry(buffer.clone())
 4287                                .or_default()
 4288                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4289                        }
 4290                    }
 4291                } else {
 4292                    clear_linked_edit_ranges = true;
 4293                }
 4294            }
 4295
 4296            new_selections.push((selection.map(|_| anchor), 0));
 4297            edits.push((selection.start..selection.end, text.clone()));
 4298        }
 4299
 4300        drop(snapshot);
 4301
 4302        self.transact(window, cx, |this, window, cx| {
 4303            if clear_linked_edit_ranges {
 4304                this.linked_edit_ranges.clear();
 4305            }
 4306            let initial_buffer_versions =
 4307                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4308
 4309            this.buffer.update(cx, |buffer, cx| {
 4310                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4311            });
 4312            for (buffer, edits) in linked_edits {
 4313                buffer.update(cx, |buffer, cx| {
 4314                    let snapshot = buffer.snapshot();
 4315                    let edits = edits
 4316                        .into_iter()
 4317                        .map(|(range, text)| {
 4318                            use text::ToPoint as TP;
 4319                            let end_point = TP::to_point(&range.end, &snapshot);
 4320                            let start_point = TP::to_point(&range.start, &snapshot);
 4321                            (start_point..end_point, text)
 4322                        })
 4323                        .sorted_by_key(|(range, _)| range.start);
 4324                    buffer.edit(edits, None, cx);
 4325                })
 4326            }
 4327            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4328            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4329            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4330            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4331                .zip(new_selection_deltas)
 4332                .map(|(selection, delta)| Selection {
 4333                    id: selection.id,
 4334                    start: selection.start + delta,
 4335                    end: selection.end + delta,
 4336                    reversed: selection.reversed,
 4337                    goal: SelectionGoal::None,
 4338                })
 4339                .collect::<Vec<_>>();
 4340
 4341            let mut i = 0;
 4342            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4343                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4344                let start = map.buffer_snapshot().anchor_before(position);
 4345                let end = map.buffer_snapshot().anchor_after(position);
 4346                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4347                    match existing_state
 4348                        .range
 4349                        .start
 4350                        .cmp(&start, map.buffer_snapshot())
 4351                    {
 4352                        Ordering::Less => i += 1,
 4353                        Ordering::Greater => break,
 4354                        Ordering::Equal => {
 4355                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4356                                Ordering::Less => i += 1,
 4357                                Ordering::Equal => break,
 4358                                Ordering::Greater => break,
 4359                            }
 4360                        }
 4361                    }
 4362                }
 4363                this.autoclose_regions.insert(
 4364                    i,
 4365                    AutocloseRegion {
 4366                        selection_id,
 4367                        range: start..end,
 4368                        pair,
 4369                    },
 4370                );
 4371            }
 4372
 4373            let had_active_edit_prediction = this.has_active_edit_prediction();
 4374            this.change_selections(
 4375                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4376                window,
 4377                cx,
 4378                |s| s.select(new_selections),
 4379            );
 4380
 4381            if !bracket_inserted
 4382                && let Some(on_type_format_task) =
 4383                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4384            {
 4385                on_type_format_task.detach_and_log_err(cx);
 4386            }
 4387
 4388            let editor_settings = EditorSettings::get_global(cx);
 4389            if bracket_inserted
 4390                && (editor_settings.auto_signature_help
 4391                    || editor_settings.show_signature_help_after_edits)
 4392            {
 4393                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4394            }
 4395
 4396            let trigger_in_words =
 4397                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4398            if this.hard_wrap.is_some() {
 4399                let latest: Range<Point> = this.selections.newest(cx).range();
 4400                if latest.is_empty()
 4401                    && this
 4402                        .buffer()
 4403                        .read(cx)
 4404                        .snapshot(cx)
 4405                        .line_len(MultiBufferRow(latest.start.row))
 4406                        == latest.start.column
 4407                {
 4408                    this.rewrap_impl(
 4409                        RewrapOptions {
 4410                            override_language_settings: true,
 4411                            preserve_existing_whitespace: true,
 4412                        },
 4413                        cx,
 4414                    )
 4415                }
 4416            }
 4417            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4418            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4419            this.refresh_edit_prediction(true, false, window, cx);
 4420            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4421        });
 4422    }
 4423
 4424    fn find_possible_emoji_shortcode_at_position(
 4425        snapshot: &MultiBufferSnapshot,
 4426        position: Point,
 4427    ) -> Option<String> {
 4428        let mut chars = Vec::new();
 4429        let mut found_colon = false;
 4430        for char in snapshot.reversed_chars_at(position).take(100) {
 4431            // Found a possible emoji shortcode in the middle of the buffer
 4432            if found_colon {
 4433                if char.is_whitespace() {
 4434                    chars.reverse();
 4435                    return Some(chars.iter().collect());
 4436                }
 4437                // If the previous character is not a whitespace, we are in the middle of a word
 4438                // and we only want to complete the shortcode if the word is made up of other emojis
 4439                let mut containing_word = String::new();
 4440                for ch in snapshot
 4441                    .reversed_chars_at(position)
 4442                    .skip(chars.len() + 1)
 4443                    .take(100)
 4444                {
 4445                    if ch.is_whitespace() {
 4446                        break;
 4447                    }
 4448                    containing_word.push(ch);
 4449                }
 4450                let containing_word = containing_word.chars().rev().collect::<String>();
 4451                if util::word_consists_of_emojis(containing_word.as_str()) {
 4452                    chars.reverse();
 4453                    return Some(chars.iter().collect());
 4454                }
 4455            }
 4456
 4457            if char.is_whitespace() || !char.is_ascii() {
 4458                return None;
 4459            }
 4460            if char == ':' {
 4461                found_colon = true;
 4462            } else {
 4463                chars.push(char);
 4464            }
 4465        }
 4466        // Found a possible emoji shortcode at the beginning of the buffer
 4467        chars.reverse();
 4468        Some(chars.iter().collect())
 4469    }
 4470
 4471    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4472        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4473        self.transact(window, cx, |this, window, cx| {
 4474            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4475                let selections = this.selections.all::<usize>(cx);
 4476                let multi_buffer = this.buffer.read(cx);
 4477                let buffer = multi_buffer.snapshot(cx);
 4478                selections
 4479                    .iter()
 4480                    .map(|selection| {
 4481                        let start_point = selection.start.to_point(&buffer);
 4482                        let mut existing_indent =
 4483                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4484                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4485                        let start = selection.start;
 4486                        let end = selection.end;
 4487                        let selection_is_empty = start == end;
 4488                        let language_scope = buffer.language_scope_at(start);
 4489                        let (
 4490                            comment_delimiter,
 4491                            doc_delimiter,
 4492                            insert_extra_newline,
 4493                            indent_on_newline,
 4494                            indent_on_extra_newline,
 4495                        ) = if let Some(language) = &language_scope {
 4496                            let mut insert_extra_newline =
 4497                                insert_extra_newline_brackets(&buffer, start..end, language)
 4498                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4499
 4500                            // Comment extension on newline is allowed only for cursor selections
 4501                            let comment_delimiter = maybe!({
 4502                                if !selection_is_empty {
 4503                                    return None;
 4504                                }
 4505
 4506                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4507                                    return None;
 4508                                }
 4509
 4510                                let delimiters = language.line_comment_prefixes();
 4511                                let max_len_of_delimiter =
 4512                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4513                                let (snapshot, range) =
 4514                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4515
 4516                                let num_of_whitespaces = snapshot
 4517                                    .chars_for_range(range.clone())
 4518                                    .take_while(|c| c.is_whitespace())
 4519                                    .count();
 4520                                let comment_candidate = snapshot
 4521                                    .chars_for_range(range.clone())
 4522                                    .skip(num_of_whitespaces)
 4523                                    .take(max_len_of_delimiter)
 4524                                    .collect::<String>();
 4525                                let (delimiter, trimmed_len) = delimiters
 4526                                    .iter()
 4527                                    .filter_map(|delimiter| {
 4528                                        let prefix = delimiter.trim_end();
 4529                                        if comment_candidate.starts_with(prefix) {
 4530                                            Some((delimiter, prefix.len()))
 4531                                        } else {
 4532                                            None
 4533                                        }
 4534                                    })
 4535                                    .max_by_key(|(_, len)| *len)?;
 4536
 4537                                if let Some(BlockCommentConfig {
 4538                                    start: block_start, ..
 4539                                }) = language.block_comment()
 4540                                {
 4541                                    let block_start_trimmed = block_start.trim_end();
 4542                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4543                                        let line_content = snapshot
 4544                                            .chars_for_range(range)
 4545                                            .skip(num_of_whitespaces)
 4546                                            .take(block_start_trimmed.len())
 4547                                            .collect::<String>();
 4548
 4549                                        if line_content.starts_with(block_start_trimmed) {
 4550                                            return None;
 4551                                        }
 4552                                    }
 4553                                }
 4554
 4555                                let cursor_is_placed_after_comment_marker =
 4556                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4557                                if cursor_is_placed_after_comment_marker {
 4558                                    Some(delimiter.clone())
 4559                                } else {
 4560                                    None
 4561                                }
 4562                            });
 4563
 4564                            let mut indent_on_newline = IndentSize::spaces(0);
 4565                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4566
 4567                            let doc_delimiter = maybe!({
 4568                                if !selection_is_empty {
 4569                                    return None;
 4570                                }
 4571
 4572                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4573                                    return None;
 4574                                }
 4575
 4576                                let BlockCommentConfig {
 4577                                    start: start_tag,
 4578                                    end: end_tag,
 4579                                    prefix: delimiter,
 4580                                    tab_size: len,
 4581                                } = language.documentation_comment()?;
 4582                                let is_within_block_comment = buffer
 4583                                    .language_scope_at(start_point)
 4584                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4585                                if !is_within_block_comment {
 4586                                    return None;
 4587                                }
 4588
 4589                                let (snapshot, range) =
 4590                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4591
 4592                                let num_of_whitespaces = snapshot
 4593                                    .chars_for_range(range.clone())
 4594                                    .take_while(|c| c.is_whitespace())
 4595                                    .count();
 4596
 4597                                // 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.
 4598                                let column = start_point.column;
 4599                                let cursor_is_after_start_tag = {
 4600                                    let start_tag_len = start_tag.len();
 4601                                    let start_tag_line = snapshot
 4602                                        .chars_for_range(range.clone())
 4603                                        .skip(num_of_whitespaces)
 4604                                        .take(start_tag_len)
 4605                                        .collect::<String>();
 4606                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4607                                        num_of_whitespaces + start_tag_len <= column as usize
 4608                                    } else {
 4609                                        false
 4610                                    }
 4611                                };
 4612
 4613                                let cursor_is_after_delimiter = {
 4614                                    let delimiter_trim = delimiter.trim_end();
 4615                                    let delimiter_line = snapshot
 4616                                        .chars_for_range(range.clone())
 4617                                        .skip(num_of_whitespaces)
 4618                                        .take(delimiter_trim.len())
 4619                                        .collect::<String>();
 4620                                    if delimiter_line.starts_with(delimiter_trim) {
 4621                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4622                                    } else {
 4623                                        false
 4624                                    }
 4625                                };
 4626
 4627                                let cursor_is_before_end_tag_if_exists = {
 4628                                    let mut char_position = 0u32;
 4629                                    let mut end_tag_offset = None;
 4630
 4631                                    'outer: for chunk in snapshot.text_for_range(range) {
 4632                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4633                                            let chars_before_match =
 4634                                                chunk[..byte_pos].chars().count() as u32;
 4635                                            end_tag_offset =
 4636                                                Some(char_position + chars_before_match);
 4637                                            break 'outer;
 4638                                        }
 4639                                        char_position += chunk.chars().count() as u32;
 4640                                    }
 4641
 4642                                    if let Some(end_tag_offset) = end_tag_offset {
 4643                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4644                                        if cursor_is_after_start_tag {
 4645                                            if cursor_is_before_end_tag {
 4646                                                insert_extra_newline = true;
 4647                                            }
 4648                                            let cursor_is_at_start_of_end_tag =
 4649                                                column == end_tag_offset;
 4650                                            if cursor_is_at_start_of_end_tag {
 4651                                                indent_on_extra_newline.len = *len;
 4652                                            }
 4653                                        }
 4654                                        cursor_is_before_end_tag
 4655                                    } else {
 4656                                        true
 4657                                    }
 4658                                };
 4659
 4660                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4661                                    && cursor_is_before_end_tag_if_exists
 4662                                {
 4663                                    if cursor_is_after_start_tag {
 4664                                        indent_on_newline.len = *len;
 4665                                    }
 4666                                    Some(delimiter.clone())
 4667                                } else {
 4668                                    None
 4669                                }
 4670                            });
 4671
 4672                            (
 4673                                comment_delimiter,
 4674                                doc_delimiter,
 4675                                insert_extra_newline,
 4676                                indent_on_newline,
 4677                                indent_on_extra_newline,
 4678                            )
 4679                        } else {
 4680                            (
 4681                                None,
 4682                                None,
 4683                                false,
 4684                                IndentSize::default(),
 4685                                IndentSize::default(),
 4686                            )
 4687                        };
 4688
 4689                        let prevent_auto_indent = doc_delimiter.is_some();
 4690                        let delimiter = comment_delimiter.or(doc_delimiter);
 4691
 4692                        let capacity_for_delimiter =
 4693                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4694                        let mut new_text = String::with_capacity(
 4695                            1 + capacity_for_delimiter
 4696                                + existing_indent.len as usize
 4697                                + indent_on_newline.len as usize
 4698                                + indent_on_extra_newline.len as usize,
 4699                        );
 4700                        new_text.push('\n');
 4701                        new_text.extend(existing_indent.chars());
 4702                        new_text.extend(indent_on_newline.chars());
 4703
 4704                        if let Some(delimiter) = &delimiter {
 4705                            new_text.push_str(delimiter);
 4706                        }
 4707
 4708                        if insert_extra_newline {
 4709                            new_text.push('\n');
 4710                            new_text.extend(existing_indent.chars());
 4711                            new_text.extend(indent_on_extra_newline.chars());
 4712                        }
 4713
 4714                        let anchor = buffer.anchor_after(end);
 4715                        let new_selection = selection.map(|_| anchor);
 4716                        (
 4717                            ((start..end, new_text), prevent_auto_indent),
 4718                            (insert_extra_newline, new_selection),
 4719                        )
 4720                    })
 4721                    .unzip()
 4722            };
 4723
 4724            let mut auto_indent_edits = Vec::new();
 4725            let mut edits = Vec::new();
 4726            for (edit, prevent_auto_indent) in edits_with_flags {
 4727                if prevent_auto_indent {
 4728                    edits.push(edit);
 4729                } else {
 4730                    auto_indent_edits.push(edit);
 4731                }
 4732            }
 4733            if !edits.is_empty() {
 4734                this.edit(edits, cx);
 4735            }
 4736            if !auto_indent_edits.is_empty() {
 4737                this.edit_with_autoindent(auto_indent_edits, cx);
 4738            }
 4739
 4740            let buffer = this.buffer.read(cx).snapshot(cx);
 4741            let new_selections = selection_info
 4742                .into_iter()
 4743                .map(|(extra_newline_inserted, new_selection)| {
 4744                    let mut cursor = new_selection.end.to_point(&buffer);
 4745                    if extra_newline_inserted {
 4746                        cursor.row -= 1;
 4747                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4748                    }
 4749                    new_selection.map(|_| cursor)
 4750                })
 4751                .collect();
 4752
 4753            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4754            this.refresh_edit_prediction(true, false, window, cx);
 4755        });
 4756    }
 4757
 4758    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4760
 4761        let buffer = self.buffer.read(cx);
 4762        let snapshot = buffer.snapshot(cx);
 4763
 4764        let mut edits = Vec::new();
 4765        let mut rows = Vec::new();
 4766
 4767        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4768            let cursor = selection.head();
 4769            let row = cursor.row;
 4770
 4771            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4772
 4773            let newline = "\n".to_string();
 4774            edits.push((start_of_line..start_of_line, newline));
 4775
 4776            rows.push(row + rows_inserted as u32);
 4777        }
 4778
 4779        self.transact(window, cx, |editor, window, cx| {
 4780            editor.edit(edits, cx);
 4781
 4782            editor.change_selections(Default::default(), window, cx, |s| {
 4783                let mut index = 0;
 4784                s.move_cursors_with(|map, _, _| {
 4785                    let row = rows[index];
 4786                    index += 1;
 4787
 4788                    let point = Point::new(row, 0);
 4789                    let boundary = map.next_line_boundary(point).1;
 4790                    let clipped = map.clip_point(boundary, Bias::Left);
 4791
 4792                    (clipped, SelectionGoal::None)
 4793                });
 4794            });
 4795
 4796            let mut indent_edits = Vec::new();
 4797            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4798            for row in rows {
 4799                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4800                for (row, indent) in indents {
 4801                    if indent.len == 0 {
 4802                        continue;
 4803                    }
 4804
 4805                    let text = match indent.kind {
 4806                        IndentKind::Space => " ".repeat(indent.len as usize),
 4807                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4808                    };
 4809                    let point = Point::new(row.0, 0);
 4810                    indent_edits.push((point..point, text));
 4811                }
 4812            }
 4813            editor.edit(indent_edits, cx);
 4814        });
 4815    }
 4816
 4817    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4818        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4819
 4820        let buffer = self.buffer.read(cx);
 4821        let snapshot = buffer.snapshot(cx);
 4822
 4823        let mut edits = Vec::new();
 4824        let mut rows = Vec::new();
 4825        let mut rows_inserted = 0;
 4826
 4827        for selection in self.selections.all_adjusted(cx) {
 4828            let cursor = selection.head();
 4829            let row = cursor.row;
 4830
 4831            let point = Point::new(row + 1, 0);
 4832            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4833
 4834            let newline = "\n".to_string();
 4835            edits.push((start_of_line..start_of_line, newline));
 4836
 4837            rows_inserted += 1;
 4838            rows.push(row + rows_inserted);
 4839        }
 4840
 4841        self.transact(window, cx, |editor, window, cx| {
 4842            editor.edit(edits, cx);
 4843
 4844            editor.change_selections(Default::default(), window, cx, |s| {
 4845                let mut index = 0;
 4846                s.move_cursors_with(|map, _, _| {
 4847                    let row = rows[index];
 4848                    index += 1;
 4849
 4850                    let point = Point::new(row, 0);
 4851                    let boundary = map.next_line_boundary(point).1;
 4852                    let clipped = map.clip_point(boundary, Bias::Left);
 4853
 4854                    (clipped, SelectionGoal::None)
 4855                });
 4856            });
 4857
 4858            let mut indent_edits = Vec::new();
 4859            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4860            for row in rows {
 4861                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4862                for (row, indent) in indents {
 4863                    if indent.len == 0 {
 4864                        continue;
 4865                    }
 4866
 4867                    let text = match indent.kind {
 4868                        IndentKind::Space => " ".repeat(indent.len as usize),
 4869                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4870                    };
 4871                    let point = Point::new(row.0, 0);
 4872                    indent_edits.push((point..point, text));
 4873                }
 4874            }
 4875            editor.edit(indent_edits, cx);
 4876        });
 4877    }
 4878
 4879    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4880        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4881            original_indent_columns: Vec::new(),
 4882        });
 4883        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4884    }
 4885
 4886    fn insert_with_autoindent_mode(
 4887        &mut self,
 4888        text: &str,
 4889        autoindent_mode: Option<AutoindentMode>,
 4890        window: &mut Window,
 4891        cx: &mut Context<Self>,
 4892    ) {
 4893        if self.read_only(cx) {
 4894            return;
 4895        }
 4896
 4897        let text: Arc<str> = text.into();
 4898        self.transact(window, cx, |this, window, cx| {
 4899            let old_selections = this.selections.all_adjusted(cx);
 4900            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4901                let anchors = {
 4902                    let snapshot = buffer.read(cx);
 4903                    old_selections
 4904                        .iter()
 4905                        .map(|s| {
 4906                            let anchor = snapshot.anchor_after(s.head());
 4907                            s.map(|_| anchor)
 4908                        })
 4909                        .collect::<Vec<_>>()
 4910                };
 4911                buffer.edit(
 4912                    old_selections
 4913                        .iter()
 4914                        .map(|s| (s.start..s.end, text.clone())),
 4915                    autoindent_mode,
 4916                    cx,
 4917                );
 4918                anchors
 4919            });
 4920
 4921            this.change_selections(Default::default(), window, cx, |s| {
 4922                s.select_anchors(selection_anchors);
 4923            });
 4924
 4925            cx.notify();
 4926        });
 4927    }
 4928
 4929    fn trigger_completion_on_input(
 4930        &mut self,
 4931        text: &str,
 4932        trigger_in_words: bool,
 4933        window: &mut Window,
 4934        cx: &mut Context<Self>,
 4935    ) {
 4936        let completions_source = self
 4937            .context_menu
 4938            .borrow()
 4939            .as_ref()
 4940            .and_then(|menu| match menu {
 4941                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4942                CodeContextMenu::CodeActions(_) => None,
 4943            });
 4944
 4945        match completions_source {
 4946            Some(CompletionsMenuSource::Words { .. }) => {
 4947                self.open_or_update_completions_menu(
 4948                    Some(CompletionsMenuSource::Words {
 4949                        ignore_threshold: false,
 4950                    }),
 4951                    None,
 4952                    window,
 4953                    cx,
 4954                );
 4955            }
 4956            Some(CompletionsMenuSource::Normal)
 4957            | Some(CompletionsMenuSource::SnippetChoices)
 4958            | None
 4959                if self.is_completion_trigger(
 4960                    text,
 4961                    trigger_in_words,
 4962                    completions_source.is_some(),
 4963                    cx,
 4964                ) =>
 4965            {
 4966                self.show_completions(
 4967                    &ShowCompletions {
 4968                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4969                    },
 4970                    window,
 4971                    cx,
 4972                )
 4973            }
 4974            _ => {
 4975                self.hide_context_menu(window, cx);
 4976            }
 4977        }
 4978    }
 4979
 4980    fn is_completion_trigger(
 4981        &self,
 4982        text: &str,
 4983        trigger_in_words: bool,
 4984        menu_is_open: bool,
 4985        cx: &mut Context<Self>,
 4986    ) -> bool {
 4987        let position = self.selections.newest_anchor().head();
 4988        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4989            return false;
 4990        };
 4991
 4992        if let Some(completion_provider) = &self.completion_provider {
 4993            completion_provider.is_completion_trigger(
 4994                &buffer,
 4995                position.text_anchor,
 4996                text,
 4997                trigger_in_words,
 4998                menu_is_open,
 4999                cx,
 5000            )
 5001        } else {
 5002            false
 5003        }
 5004    }
 5005
 5006    /// If any empty selections is touching the start of its innermost containing autoclose
 5007    /// region, expand it to select the brackets.
 5008    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5009        let selections = self.selections.all::<usize>(cx);
 5010        let buffer = self.buffer.read(cx).read(cx);
 5011        let new_selections = self
 5012            .selections_with_autoclose_regions(selections, &buffer)
 5013            .map(|(mut selection, region)| {
 5014                if !selection.is_empty() {
 5015                    return selection;
 5016                }
 5017
 5018                if let Some(region) = region {
 5019                    let mut range = region.range.to_offset(&buffer);
 5020                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5021                        range.start -= region.pair.start.len();
 5022                        if buffer.contains_str_at(range.start, &region.pair.start)
 5023                            && buffer.contains_str_at(range.end, &region.pair.end)
 5024                        {
 5025                            range.end += region.pair.end.len();
 5026                            selection.start = range.start;
 5027                            selection.end = range.end;
 5028
 5029                            return selection;
 5030                        }
 5031                    }
 5032                }
 5033
 5034                let always_treat_brackets_as_autoclosed = buffer
 5035                    .language_settings_at(selection.start, cx)
 5036                    .always_treat_brackets_as_autoclosed;
 5037
 5038                if !always_treat_brackets_as_autoclosed {
 5039                    return selection;
 5040                }
 5041
 5042                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5043                    for (pair, enabled) in scope.brackets() {
 5044                        if !enabled || !pair.close {
 5045                            continue;
 5046                        }
 5047
 5048                        if buffer.contains_str_at(selection.start, &pair.end) {
 5049                            let pair_start_len = pair.start.len();
 5050                            if buffer.contains_str_at(
 5051                                selection.start.saturating_sub(pair_start_len),
 5052                                &pair.start,
 5053                            ) {
 5054                                selection.start -= pair_start_len;
 5055                                selection.end += pair.end.len();
 5056
 5057                                return selection;
 5058                            }
 5059                        }
 5060                    }
 5061                }
 5062
 5063                selection
 5064            })
 5065            .collect();
 5066
 5067        drop(buffer);
 5068        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5069            selections.select(new_selections)
 5070        });
 5071    }
 5072
 5073    /// Iterate the given selections, and for each one, find the smallest surrounding
 5074    /// autoclose region. This uses the ordering of the selections and the autoclose
 5075    /// regions to avoid repeated comparisons.
 5076    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5077        &'a self,
 5078        selections: impl IntoIterator<Item = Selection<D>>,
 5079        buffer: &'a MultiBufferSnapshot,
 5080    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5081        let mut i = 0;
 5082        let mut regions = self.autoclose_regions.as_slice();
 5083        selections.into_iter().map(move |selection| {
 5084            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5085
 5086            let mut enclosing = None;
 5087            while let Some(pair_state) = regions.get(i) {
 5088                if pair_state.range.end.to_offset(buffer) < range.start {
 5089                    regions = &regions[i + 1..];
 5090                    i = 0;
 5091                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5092                    break;
 5093                } else {
 5094                    if pair_state.selection_id == selection.id {
 5095                        enclosing = Some(pair_state);
 5096                    }
 5097                    i += 1;
 5098                }
 5099            }
 5100
 5101            (selection, enclosing)
 5102        })
 5103    }
 5104
 5105    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5106    fn invalidate_autoclose_regions(
 5107        &mut self,
 5108        mut selections: &[Selection<Anchor>],
 5109        buffer: &MultiBufferSnapshot,
 5110    ) {
 5111        self.autoclose_regions.retain(|state| {
 5112            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5113                return false;
 5114            }
 5115
 5116            let mut i = 0;
 5117            while let Some(selection) = selections.get(i) {
 5118                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5119                    selections = &selections[1..];
 5120                    continue;
 5121                }
 5122                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5123                    break;
 5124                }
 5125                if selection.id == state.selection_id {
 5126                    return true;
 5127                } else {
 5128                    i += 1;
 5129                }
 5130            }
 5131            false
 5132        });
 5133    }
 5134
 5135    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5136        let offset = position.to_offset(buffer);
 5137        let (word_range, kind) =
 5138            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5139        if offset > word_range.start && kind == Some(CharKind::Word) {
 5140            Some(
 5141                buffer
 5142                    .text_for_range(word_range.start..offset)
 5143                    .collect::<String>(),
 5144            )
 5145        } else {
 5146            None
 5147        }
 5148    }
 5149
 5150    pub fn toggle_inline_values(
 5151        &mut self,
 5152        _: &ToggleInlineValues,
 5153        _: &mut Window,
 5154        cx: &mut Context<Self>,
 5155    ) {
 5156        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5157
 5158        self.refresh_inline_values(cx);
 5159    }
 5160
 5161    pub fn toggle_inlay_hints(
 5162        &mut self,
 5163        _: &ToggleInlayHints,
 5164        _: &mut Window,
 5165        cx: &mut Context<Self>,
 5166    ) {
 5167        self.refresh_inlay_hints(
 5168            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5169            cx,
 5170        );
 5171    }
 5172
 5173    pub fn inlay_hints_enabled(&self) -> bool {
 5174        self.inlay_hint_cache.enabled
 5175    }
 5176
 5177    pub fn inline_values_enabled(&self) -> bool {
 5178        self.inline_value_cache.enabled
 5179    }
 5180
 5181    #[cfg(any(test, feature = "test-support"))]
 5182    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5183        self.display_map
 5184            .read(cx)
 5185            .current_inlays()
 5186            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5187            .cloned()
 5188            .collect()
 5189    }
 5190
 5191    #[cfg(any(test, feature = "test-support"))]
 5192    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5193        self.display_map
 5194            .read(cx)
 5195            .current_inlays()
 5196            .cloned()
 5197            .collect()
 5198    }
 5199
 5200    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5201        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5202            return;
 5203        }
 5204
 5205        let reason_description = reason.description();
 5206        let ignore_debounce = matches!(
 5207            reason,
 5208            InlayHintRefreshReason::SettingsChange(_)
 5209                | InlayHintRefreshReason::Toggle(_)
 5210                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5211                | InlayHintRefreshReason::ModifiersChanged(_)
 5212        );
 5213        let (invalidate_cache, required_languages) = match reason {
 5214            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5215                match self.inlay_hint_cache.modifiers_override(enabled) {
 5216                    Some(enabled) => {
 5217                        if enabled {
 5218                            (InvalidationStrategy::RefreshRequested, None)
 5219                        } else {
 5220                            self.splice_inlays(
 5221                                &self
 5222                                    .visible_inlay_hints(cx)
 5223                                    .iter()
 5224                                    .map(|inlay| inlay.id)
 5225                                    .collect::<Vec<InlayId>>(),
 5226                                Vec::new(),
 5227                                cx,
 5228                            );
 5229                            return;
 5230                        }
 5231                    }
 5232                    None => return,
 5233                }
 5234            }
 5235            InlayHintRefreshReason::Toggle(enabled) => {
 5236                if self.inlay_hint_cache.toggle(enabled) {
 5237                    if enabled {
 5238                        (InvalidationStrategy::RefreshRequested, None)
 5239                    } else {
 5240                        self.splice_inlays(
 5241                            &self
 5242                                .visible_inlay_hints(cx)
 5243                                .iter()
 5244                                .map(|inlay| inlay.id)
 5245                                .collect::<Vec<InlayId>>(),
 5246                            Vec::new(),
 5247                            cx,
 5248                        );
 5249                        return;
 5250                    }
 5251                } else {
 5252                    return;
 5253                }
 5254            }
 5255            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5256                match self.inlay_hint_cache.update_settings(
 5257                    &self.buffer,
 5258                    new_settings,
 5259                    self.visible_inlay_hints(cx),
 5260                    cx,
 5261                ) {
 5262                    ControlFlow::Break(Some(InlaySplice {
 5263                        to_remove,
 5264                        to_insert,
 5265                    })) => {
 5266                        self.splice_inlays(&to_remove, to_insert, cx);
 5267                        return;
 5268                    }
 5269                    ControlFlow::Break(None) => return,
 5270                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5271                }
 5272            }
 5273            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5274                if let Some(InlaySplice {
 5275                    to_remove,
 5276                    to_insert,
 5277                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5278                {
 5279                    self.splice_inlays(&to_remove, to_insert, cx);
 5280                }
 5281                self.display_map.update(cx, |display_map, _| {
 5282                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5283                });
 5284                return;
 5285            }
 5286            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5287            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5288                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5289            }
 5290            InlayHintRefreshReason::RefreshRequested => {
 5291                (InvalidationStrategy::RefreshRequested, None)
 5292            }
 5293        };
 5294
 5295        if let Some(InlaySplice {
 5296            to_remove,
 5297            to_insert,
 5298        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5299            reason_description,
 5300            self.visible_excerpts(required_languages.as_ref(), cx),
 5301            invalidate_cache,
 5302            ignore_debounce,
 5303            cx,
 5304        ) {
 5305            self.splice_inlays(&to_remove, to_insert, cx);
 5306        }
 5307    }
 5308
 5309    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5310        self.display_map
 5311            .read(cx)
 5312            .current_inlays()
 5313            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5314            .cloned()
 5315            .collect()
 5316    }
 5317
 5318    pub fn visible_excerpts(
 5319        &self,
 5320        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5321        cx: &mut Context<Editor>,
 5322    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5323        let Some(project) = self.project() else {
 5324            return HashMap::default();
 5325        };
 5326        let project = project.read(cx);
 5327        let multi_buffer = self.buffer().read(cx);
 5328        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5329        let multi_buffer_visible_start = self
 5330            .scroll_manager
 5331            .anchor()
 5332            .anchor
 5333            .to_point(&multi_buffer_snapshot);
 5334        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5335            multi_buffer_visible_start
 5336                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5337            Bias::Left,
 5338        );
 5339        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5340        multi_buffer_snapshot
 5341            .range_to_buffer_ranges(multi_buffer_visible_range)
 5342            .into_iter()
 5343            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5344            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5345                let buffer_file = project::File::from_dyn(buffer.file())?;
 5346                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5347                let worktree_entry = buffer_worktree
 5348                    .read(cx)
 5349                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5350                if worktree_entry.is_ignored {
 5351                    return None;
 5352                }
 5353
 5354                let language = buffer.language()?;
 5355                if let Some(restrict_to_languages) = restrict_to_languages
 5356                    && !restrict_to_languages.contains(language)
 5357                {
 5358                    return None;
 5359                }
 5360                Some((
 5361                    excerpt_id,
 5362                    (
 5363                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5364                        buffer.version().clone(),
 5365                        excerpt_visible_range,
 5366                    ),
 5367                ))
 5368            })
 5369            .collect()
 5370    }
 5371
 5372    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5373        TextLayoutDetails {
 5374            text_system: window.text_system().clone(),
 5375            editor_style: self.style.clone().unwrap(),
 5376            rem_size: window.rem_size(),
 5377            scroll_anchor: self.scroll_manager.anchor(),
 5378            visible_rows: self.visible_line_count(),
 5379            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5380        }
 5381    }
 5382
 5383    pub fn splice_inlays(
 5384        &self,
 5385        to_remove: &[InlayId],
 5386        to_insert: Vec<Inlay>,
 5387        cx: &mut Context<Self>,
 5388    ) {
 5389        self.display_map.update(cx, |display_map, cx| {
 5390            display_map.splice_inlays(to_remove, to_insert, cx)
 5391        });
 5392        cx.notify();
 5393    }
 5394
 5395    fn trigger_on_type_formatting(
 5396        &self,
 5397        input: String,
 5398        window: &mut Window,
 5399        cx: &mut Context<Self>,
 5400    ) -> Option<Task<Result<()>>> {
 5401        if input.len() != 1 {
 5402            return None;
 5403        }
 5404
 5405        let project = self.project()?;
 5406        let position = self.selections.newest_anchor().head();
 5407        let (buffer, buffer_position) = self
 5408            .buffer
 5409            .read(cx)
 5410            .text_anchor_for_position(position, cx)?;
 5411
 5412        let settings = language_settings::language_settings(
 5413            buffer
 5414                .read(cx)
 5415                .language_at(buffer_position)
 5416                .map(|l| l.name()),
 5417            buffer.read(cx).file(),
 5418            cx,
 5419        );
 5420        if !settings.use_on_type_format {
 5421            return None;
 5422        }
 5423
 5424        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5425        // hence we do LSP request & edit on host side only — add formats to host's history.
 5426        let push_to_lsp_host_history = true;
 5427        // If this is not the host, append its history with new edits.
 5428        let push_to_client_history = project.read(cx).is_via_collab();
 5429
 5430        let on_type_formatting = project.update(cx, |project, cx| {
 5431            project.on_type_format(
 5432                buffer.clone(),
 5433                buffer_position,
 5434                input,
 5435                push_to_lsp_host_history,
 5436                cx,
 5437            )
 5438        });
 5439        Some(cx.spawn_in(window, async move |editor, cx| {
 5440            if let Some(transaction) = on_type_formatting.await? {
 5441                if push_to_client_history {
 5442                    buffer
 5443                        .update(cx, |buffer, _| {
 5444                            buffer.push_transaction(transaction, Instant::now());
 5445                            buffer.finalize_last_transaction();
 5446                        })
 5447                        .ok();
 5448                }
 5449                editor.update(cx, |editor, cx| {
 5450                    editor.refresh_document_highlights(cx);
 5451                })?;
 5452            }
 5453            Ok(())
 5454        }))
 5455    }
 5456
 5457    pub fn show_word_completions(
 5458        &mut self,
 5459        _: &ShowWordCompletions,
 5460        window: &mut Window,
 5461        cx: &mut Context<Self>,
 5462    ) {
 5463        self.open_or_update_completions_menu(
 5464            Some(CompletionsMenuSource::Words {
 5465                ignore_threshold: true,
 5466            }),
 5467            None,
 5468            window,
 5469            cx,
 5470        );
 5471    }
 5472
 5473    pub fn show_completions(
 5474        &mut self,
 5475        options: &ShowCompletions,
 5476        window: &mut Window,
 5477        cx: &mut Context<Self>,
 5478    ) {
 5479        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5480    }
 5481
 5482    fn open_or_update_completions_menu(
 5483        &mut self,
 5484        requested_source: Option<CompletionsMenuSource>,
 5485        trigger: Option<&str>,
 5486        window: &mut Window,
 5487        cx: &mut Context<Self>,
 5488    ) {
 5489        if self.pending_rename.is_some() {
 5490            return;
 5491        }
 5492
 5493        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5494
 5495        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5496        // inserted and selected. To handle that case, the start of the selection is used so that
 5497        // the menu starts with all choices.
 5498        let position = self
 5499            .selections
 5500            .newest_anchor()
 5501            .start
 5502            .bias_right(&multibuffer_snapshot);
 5503        if position.diff_base_anchor.is_some() {
 5504            return;
 5505        }
 5506        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5507        let Some(buffer) = buffer_position
 5508            .buffer_id
 5509            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5510        else {
 5511            return;
 5512        };
 5513        let buffer_snapshot = buffer.read(cx).snapshot();
 5514
 5515        let query: Option<Arc<String>> =
 5516            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5517                .map(|query| query.into());
 5518
 5519        drop(multibuffer_snapshot);
 5520
 5521        // Hide the current completions menu when query is empty. Without this, cached
 5522        // completions from before the trigger char may be reused (#32774).
 5523        if query.is_none() {
 5524            let menu_is_open = matches!(
 5525                self.context_menu.borrow().as_ref(),
 5526                Some(CodeContextMenu::Completions(_))
 5527            );
 5528            if menu_is_open {
 5529                self.hide_context_menu(window, cx);
 5530            }
 5531        }
 5532
 5533        let mut ignore_word_threshold = false;
 5534        let provider = match requested_source {
 5535            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5536            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5537                ignore_word_threshold = ignore_threshold;
 5538                None
 5539            }
 5540            Some(CompletionsMenuSource::SnippetChoices) => {
 5541                log::error!("bug: SnippetChoices requested_source is not handled");
 5542                None
 5543            }
 5544        };
 5545
 5546        let sort_completions = provider
 5547            .as_ref()
 5548            .is_some_and(|provider| provider.sort_completions());
 5549
 5550        let filter_completions = provider
 5551            .as_ref()
 5552            .is_none_or(|provider| provider.filter_completions());
 5553
 5554        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5555            if filter_completions {
 5556                menu.filter(query.clone(), provider.clone(), window, cx);
 5557            }
 5558            // When `is_incomplete` is false, no need to re-query completions when the current query
 5559            // is a suffix of the initial query.
 5560            if !menu.is_incomplete {
 5561                // If the new query is a suffix of the old query (typing more characters) and
 5562                // the previous result was complete, the existing completions can be filtered.
 5563                //
 5564                // Note that this is always true for snippet completions.
 5565                let query_matches = match (&menu.initial_query, &query) {
 5566                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5567                    (None, _) => true,
 5568                    _ => false,
 5569                };
 5570                if query_matches {
 5571                    let position_matches = if menu.initial_position == position {
 5572                        true
 5573                    } else {
 5574                        let snapshot = self.buffer.read(cx).read(cx);
 5575                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5576                    };
 5577                    if position_matches {
 5578                        return;
 5579                    }
 5580                }
 5581            }
 5582        };
 5583
 5584        let trigger_kind = match trigger {
 5585            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5586                CompletionTriggerKind::TRIGGER_CHARACTER
 5587            }
 5588            _ => CompletionTriggerKind::INVOKED,
 5589        };
 5590        let completion_context = CompletionContext {
 5591            trigger_character: trigger.and_then(|trigger| {
 5592                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5593                    Some(String::from(trigger))
 5594                } else {
 5595                    None
 5596                }
 5597            }),
 5598            trigger_kind,
 5599        };
 5600
 5601        let Anchor {
 5602            excerpt_id: buffer_excerpt_id,
 5603            text_anchor: buffer_position,
 5604            ..
 5605        } = buffer_position;
 5606
 5607        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5608            buffer_snapshot.surrounding_word(buffer_position, None)
 5609        {
 5610            let word_to_exclude = buffer_snapshot
 5611                .text_for_range(word_range.clone())
 5612                .collect::<String>();
 5613            (
 5614                buffer_snapshot.anchor_before(word_range.start)
 5615                    ..buffer_snapshot.anchor_after(buffer_position),
 5616                Some(word_to_exclude),
 5617            )
 5618        } else {
 5619            (buffer_position..buffer_position, None)
 5620        };
 5621
 5622        let language = buffer_snapshot
 5623            .language_at(buffer_position)
 5624            .map(|language| language.name());
 5625
 5626        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5627            .completions
 5628            .clone();
 5629
 5630        let show_completion_documentation = buffer_snapshot
 5631            .settings_at(buffer_position, cx)
 5632            .show_completion_documentation;
 5633
 5634        // The document can be large, so stay in reasonable bounds when searching for words,
 5635        // otherwise completion pop-up might be slow to appear.
 5636        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5637        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5638        let min_word_search = buffer_snapshot.clip_point(
 5639            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5640            Bias::Left,
 5641        );
 5642        let max_word_search = buffer_snapshot.clip_point(
 5643            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5644            Bias::Right,
 5645        );
 5646        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5647            ..buffer_snapshot.point_to_offset(max_word_search);
 5648
 5649        let skip_digits = query
 5650            .as_ref()
 5651            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5652
 5653        let omit_word_completions = !self.word_completions_enabled
 5654            || (!ignore_word_threshold
 5655                && match &query {
 5656                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5657                    None => completion_settings.words_min_length != 0,
 5658                });
 5659
 5660        let (mut words, provider_responses) = match &provider {
 5661            Some(provider) => {
 5662                let provider_responses = provider.completions(
 5663                    buffer_excerpt_id,
 5664                    &buffer,
 5665                    buffer_position,
 5666                    completion_context,
 5667                    window,
 5668                    cx,
 5669                );
 5670
 5671                let words = match (omit_word_completions, completion_settings.words) {
 5672                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5673                        Task::ready(BTreeMap::default())
 5674                    }
 5675                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5676                        .background_spawn(async move {
 5677                            buffer_snapshot.words_in_range(WordsQuery {
 5678                                fuzzy_contents: None,
 5679                                range: word_search_range,
 5680                                skip_digits,
 5681                            })
 5682                        }),
 5683                };
 5684
 5685                (words, provider_responses)
 5686            }
 5687            None => {
 5688                let words = if omit_word_completions {
 5689                    Task::ready(BTreeMap::default())
 5690                } else {
 5691                    cx.background_spawn(async move {
 5692                        buffer_snapshot.words_in_range(WordsQuery {
 5693                            fuzzy_contents: None,
 5694                            range: word_search_range,
 5695                            skip_digits,
 5696                        })
 5697                    })
 5698                };
 5699                (words, Task::ready(Ok(Vec::new())))
 5700            }
 5701        };
 5702
 5703        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5704
 5705        let id = post_inc(&mut self.next_completion_id);
 5706        let task = cx.spawn_in(window, async move |editor, cx| {
 5707            let Ok(()) = editor.update(cx, |this, _| {
 5708                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5709            }) else {
 5710                return;
 5711            };
 5712
 5713            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5714            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5715            let mut completions = Vec::new();
 5716            let mut is_incomplete = false;
 5717            let mut display_options: Option<CompletionDisplayOptions> = None;
 5718            if let Some(provider_responses) = provider_responses.await.log_err()
 5719                && !provider_responses.is_empty()
 5720            {
 5721                for response in provider_responses {
 5722                    completions.extend(response.completions);
 5723                    is_incomplete = is_incomplete || response.is_incomplete;
 5724                    match display_options.as_mut() {
 5725                        None => {
 5726                            display_options = Some(response.display_options);
 5727                        }
 5728                        Some(options) => options.merge(&response.display_options),
 5729                    }
 5730                }
 5731                if completion_settings.words == WordsCompletionMode::Fallback {
 5732                    words = Task::ready(BTreeMap::default());
 5733                }
 5734            }
 5735            let display_options = display_options.unwrap_or_default();
 5736
 5737            let mut words = words.await;
 5738            if let Some(word_to_exclude) = &word_to_exclude {
 5739                words.remove(word_to_exclude);
 5740            }
 5741            for lsp_completion in &completions {
 5742                words.remove(&lsp_completion.new_text);
 5743            }
 5744            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5745                replace_range: word_replace_range.clone(),
 5746                new_text: word.clone(),
 5747                label: CodeLabel::plain(word, None),
 5748                icon_path: None,
 5749                documentation: None,
 5750                source: CompletionSource::BufferWord {
 5751                    word_range,
 5752                    resolved: false,
 5753                },
 5754                insert_text_mode: Some(InsertTextMode::AS_IS),
 5755                confirm: None,
 5756            }));
 5757
 5758            let menu = if completions.is_empty() {
 5759                None
 5760            } else {
 5761                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5762                    let languages = editor
 5763                        .workspace
 5764                        .as_ref()
 5765                        .and_then(|(workspace, _)| workspace.upgrade())
 5766                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5767                    let menu = CompletionsMenu::new(
 5768                        id,
 5769                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5770                        sort_completions,
 5771                        show_completion_documentation,
 5772                        position,
 5773                        query.clone(),
 5774                        is_incomplete,
 5775                        buffer.clone(),
 5776                        completions.into(),
 5777                        display_options,
 5778                        snippet_sort_order,
 5779                        languages,
 5780                        language,
 5781                        cx,
 5782                    );
 5783
 5784                    let query = if filter_completions { query } else { None };
 5785                    let matches_task = if let Some(query) = query {
 5786                        menu.do_async_filtering(query, cx)
 5787                    } else {
 5788                        Task::ready(menu.unfiltered_matches())
 5789                    };
 5790                    (menu, matches_task)
 5791                }) else {
 5792                    return;
 5793                };
 5794
 5795                let matches = matches_task.await;
 5796
 5797                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5798                    // Newer menu already set, so exit.
 5799                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5800                        editor.context_menu.borrow().as_ref()
 5801                        && prev_menu.id > id
 5802                    {
 5803                        return;
 5804                    };
 5805
 5806                    // Only valid to take prev_menu because it the new menu is immediately set
 5807                    // below, or the menu is hidden.
 5808                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5809                        editor.context_menu.borrow_mut().take()
 5810                    {
 5811                        let position_matches =
 5812                            if prev_menu.initial_position == menu.initial_position {
 5813                                true
 5814                            } else {
 5815                                let snapshot = editor.buffer.read(cx).read(cx);
 5816                                prev_menu.initial_position.to_offset(&snapshot)
 5817                                    == menu.initial_position.to_offset(&snapshot)
 5818                            };
 5819                        if position_matches {
 5820                            // Preserve markdown cache before `set_filter_results` because it will
 5821                            // try to populate the documentation cache.
 5822                            menu.preserve_markdown_cache(prev_menu);
 5823                        }
 5824                    };
 5825
 5826                    menu.set_filter_results(matches, provider, window, cx);
 5827                }) else {
 5828                    return;
 5829                };
 5830
 5831                menu.visible().then_some(menu)
 5832            };
 5833
 5834            editor
 5835                .update_in(cx, |editor, window, cx| {
 5836                    if editor.focus_handle.is_focused(window)
 5837                        && let Some(menu) = menu
 5838                    {
 5839                        *editor.context_menu.borrow_mut() =
 5840                            Some(CodeContextMenu::Completions(menu));
 5841
 5842                        crate::hover_popover::hide_hover(editor, cx);
 5843                        if editor.show_edit_predictions_in_menu() {
 5844                            editor.update_visible_edit_prediction(window, cx);
 5845                        } else {
 5846                            editor.discard_edit_prediction(false, cx);
 5847                        }
 5848
 5849                        cx.notify();
 5850                        return;
 5851                    }
 5852
 5853                    if editor.completion_tasks.len() <= 1 {
 5854                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5855                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5856                        // If it was already hidden and we don't show edit predictions in the menu,
 5857                        // we should also show the edit prediction when available.
 5858                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5859                            editor.update_visible_edit_prediction(window, cx);
 5860                        }
 5861                    }
 5862                })
 5863                .ok();
 5864        });
 5865
 5866        self.completion_tasks.push((id, task));
 5867    }
 5868
 5869    #[cfg(feature = "test-support")]
 5870    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5871        let menu = self.context_menu.borrow();
 5872        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5873            let completions = menu.completions.borrow();
 5874            Some(completions.to_vec())
 5875        } else {
 5876            None
 5877        }
 5878    }
 5879
 5880    pub fn with_completions_menu_matching_id<R>(
 5881        &self,
 5882        id: CompletionId,
 5883        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5884    ) -> R {
 5885        let mut context_menu = self.context_menu.borrow_mut();
 5886        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5887            return f(None);
 5888        };
 5889        if completions_menu.id != id {
 5890            return f(None);
 5891        }
 5892        f(Some(completions_menu))
 5893    }
 5894
 5895    pub fn confirm_completion(
 5896        &mut self,
 5897        action: &ConfirmCompletion,
 5898        window: &mut Window,
 5899        cx: &mut Context<Self>,
 5900    ) -> Option<Task<Result<()>>> {
 5901        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5902        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5903    }
 5904
 5905    pub fn confirm_completion_insert(
 5906        &mut self,
 5907        _: &ConfirmCompletionInsert,
 5908        window: &mut Window,
 5909        cx: &mut Context<Self>,
 5910    ) -> Option<Task<Result<()>>> {
 5911        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5912        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5913    }
 5914
 5915    pub fn confirm_completion_replace(
 5916        &mut self,
 5917        _: &ConfirmCompletionReplace,
 5918        window: &mut Window,
 5919        cx: &mut Context<Self>,
 5920    ) -> Option<Task<Result<()>>> {
 5921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5922        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5923    }
 5924
 5925    pub fn compose_completion(
 5926        &mut self,
 5927        action: &ComposeCompletion,
 5928        window: &mut Window,
 5929        cx: &mut Context<Self>,
 5930    ) -> Option<Task<Result<()>>> {
 5931        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5932        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5933    }
 5934
 5935    fn do_completion(
 5936        &mut self,
 5937        item_ix: Option<usize>,
 5938        intent: CompletionIntent,
 5939        window: &mut Window,
 5940        cx: &mut Context<Editor>,
 5941    ) -> Option<Task<Result<()>>> {
 5942        use language::ToOffset as _;
 5943
 5944        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5945        else {
 5946            return None;
 5947        };
 5948
 5949        let candidate_id = {
 5950            let entries = completions_menu.entries.borrow();
 5951            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5952            if self.show_edit_predictions_in_menu() {
 5953                self.discard_edit_prediction(true, cx);
 5954            }
 5955            mat.candidate_id
 5956        };
 5957
 5958        let completion = completions_menu
 5959            .completions
 5960            .borrow()
 5961            .get(candidate_id)?
 5962            .clone();
 5963        cx.stop_propagation();
 5964
 5965        let buffer_handle = completions_menu.buffer.clone();
 5966
 5967        let CompletionEdit {
 5968            new_text,
 5969            snippet,
 5970            replace_range,
 5971        } = process_completion_for_edit(
 5972            &completion,
 5973            intent,
 5974            &buffer_handle,
 5975            &completions_menu.initial_position.text_anchor,
 5976            cx,
 5977        );
 5978
 5979        let buffer = buffer_handle.read(cx);
 5980        let snapshot = self.buffer.read(cx).snapshot(cx);
 5981        let newest_anchor = self.selections.newest_anchor();
 5982        let replace_range_multibuffer = {
 5983            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5984            let multibuffer_anchor = snapshot
 5985                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5986                .unwrap()
 5987                ..snapshot
 5988                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5989                    .unwrap();
 5990            multibuffer_anchor.start.to_offset(&snapshot)
 5991                ..multibuffer_anchor.end.to_offset(&snapshot)
 5992        };
 5993        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5994            return None;
 5995        }
 5996
 5997        let old_text = buffer
 5998            .text_for_range(replace_range.clone())
 5999            .collect::<String>();
 6000        let lookbehind = newest_anchor
 6001            .start
 6002            .text_anchor
 6003            .to_offset(buffer)
 6004            .saturating_sub(replace_range.start);
 6005        let lookahead = replace_range
 6006            .end
 6007            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6008        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6009        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6010
 6011        let selections = self.selections.all::<usize>(cx);
 6012        let mut ranges = Vec::new();
 6013        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6014
 6015        for selection in &selections {
 6016            let range = if selection.id == newest_anchor.id {
 6017                replace_range_multibuffer.clone()
 6018            } else {
 6019                let mut range = selection.range();
 6020
 6021                // if prefix is present, don't duplicate it
 6022                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6023                    range.start = range.start.saturating_sub(lookbehind);
 6024
 6025                    // if suffix is also present, mimic the newest cursor and replace it
 6026                    if selection.id != newest_anchor.id
 6027                        && snapshot.contains_str_at(range.end, suffix)
 6028                    {
 6029                        range.end += lookahead;
 6030                    }
 6031                }
 6032                range
 6033            };
 6034
 6035            ranges.push(range.clone());
 6036
 6037            if !self.linked_edit_ranges.is_empty() {
 6038                let start_anchor = snapshot.anchor_before(range.start);
 6039                let end_anchor = snapshot.anchor_after(range.end);
 6040                if let Some(ranges) = self
 6041                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6042                {
 6043                    for (buffer, edits) in ranges {
 6044                        linked_edits
 6045                            .entry(buffer.clone())
 6046                            .or_default()
 6047                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6048                    }
 6049                }
 6050            }
 6051        }
 6052
 6053        let common_prefix_len = old_text
 6054            .chars()
 6055            .zip(new_text.chars())
 6056            .take_while(|(a, b)| a == b)
 6057            .map(|(a, _)| a.len_utf8())
 6058            .sum::<usize>();
 6059
 6060        cx.emit(EditorEvent::InputHandled {
 6061            utf16_range_to_replace: None,
 6062            text: new_text[common_prefix_len..].into(),
 6063        });
 6064
 6065        self.transact(window, cx, |editor, window, cx| {
 6066            if let Some(mut snippet) = snippet {
 6067                snippet.text = new_text.to_string();
 6068                editor
 6069                    .insert_snippet(&ranges, snippet, window, cx)
 6070                    .log_err();
 6071            } else {
 6072                editor.buffer.update(cx, |multi_buffer, cx| {
 6073                    let auto_indent = match completion.insert_text_mode {
 6074                        Some(InsertTextMode::AS_IS) => None,
 6075                        _ => editor.autoindent_mode.clone(),
 6076                    };
 6077                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6078                    multi_buffer.edit(edits, auto_indent, cx);
 6079                });
 6080            }
 6081            for (buffer, edits) in linked_edits {
 6082                buffer.update(cx, |buffer, cx| {
 6083                    let snapshot = buffer.snapshot();
 6084                    let edits = edits
 6085                        .into_iter()
 6086                        .map(|(range, text)| {
 6087                            use text::ToPoint as TP;
 6088                            let end_point = TP::to_point(&range.end, &snapshot);
 6089                            let start_point = TP::to_point(&range.start, &snapshot);
 6090                            (start_point..end_point, text)
 6091                        })
 6092                        .sorted_by_key(|(range, _)| range.start);
 6093                    buffer.edit(edits, None, cx);
 6094                })
 6095            }
 6096
 6097            editor.refresh_edit_prediction(true, false, window, cx);
 6098        });
 6099        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6100
 6101        let show_new_completions_on_confirm = completion
 6102            .confirm
 6103            .as_ref()
 6104            .is_some_and(|confirm| confirm(intent, window, cx));
 6105        if show_new_completions_on_confirm {
 6106            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6107        }
 6108
 6109        let provider = self.completion_provider.as_ref()?;
 6110        drop(completion);
 6111        let apply_edits = provider.apply_additional_edits_for_completion(
 6112            buffer_handle,
 6113            completions_menu.completions.clone(),
 6114            candidate_id,
 6115            true,
 6116            cx,
 6117        );
 6118
 6119        let editor_settings = EditorSettings::get_global(cx);
 6120        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6121            // After the code completion is finished, users often want to know what signatures are needed.
 6122            // so we should automatically call signature_help
 6123            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6124        }
 6125
 6126        Some(cx.foreground_executor().spawn(async move {
 6127            apply_edits.await?;
 6128            Ok(())
 6129        }))
 6130    }
 6131
 6132    pub fn toggle_code_actions(
 6133        &mut self,
 6134        action: &ToggleCodeActions,
 6135        window: &mut Window,
 6136        cx: &mut Context<Self>,
 6137    ) {
 6138        let quick_launch = action.quick_launch;
 6139        let mut context_menu = self.context_menu.borrow_mut();
 6140        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6141            if code_actions.deployed_from == action.deployed_from {
 6142                // Toggle if we're selecting the same one
 6143                *context_menu = None;
 6144                cx.notify();
 6145                return;
 6146            } else {
 6147                // Otherwise, clear it and start a new one
 6148                *context_menu = None;
 6149                cx.notify();
 6150            }
 6151        }
 6152        drop(context_menu);
 6153        let snapshot = self.snapshot(window, cx);
 6154        let deployed_from = action.deployed_from.clone();
 6155        let action = action.clone();
 6156        self.completion_tasks.clear();
 6157        self.discard_edit_prediction(false, cx);
 6158
 6159        let multibuffer_point = match &action.deployed_from {
 6160            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6161                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6162            }
 6163            _ => self.selections.newest::<Point>(cx).head(),
 6164        };
 6165        let Some((buffer, buffer_row)) = snapshot
 6166            .buffer_snapshot()
 6167            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6168            .and_then(|(buffer_snapshot, range)| {
 6169                self.buffer()
 6170                    .read(cx)
 6171                    .buffer(buffer_snapshot.remote_id())
 6172                    .map(|buffer| (buffer, range.start.row))
 6173            })
 6174        else {
 6175            return;
 6176        };
 6177        let buffer_id = buffer.read(cx).remote_id();
 6178        let tasks = self
 6179            .tasks
 6180            .get(&(buffer_id, buffer_row))
 6181            .map(|t| Arc::new(t.to_owned()));
 6182
 6183        if !self.focus_handle.is_focused(window) {
 6184            return;
 6185        }
 6186        let project = self.project.clone();
 6187
 6188        let code_actions_task = match deployed_from {
 6189            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6190            _ => self.code_actions(buffer_row, window, cx),
 6191        };
 6192
 6193        let runnable_task = match deployed_from {
 6194            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6195            _ => {
 6196                let mut task_context_task = Task::ready(None);
 6197                if let Some(tasks) = &tasks
 6198                    && let Some(project) = project
 6199                {
 6200                    task_context_task =
 6201                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6202                }
 6203
 6204                cx.spawn_in(window, {
 6205                    let buffer = buffer.clone();
 6206                    async move |editor, cx| {
 6207                        let task_context = task_context_task.await;
 6208
 6209                        let resolved_tasks =
 6210                            tasks
 6211                                .zip(task_context.clone())
 6212                                .map(|(tasks, task_context)| ResolvedTasks {
 6213                                    templates: tasks.resolve(&task_context).collect(),
 6214                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6215                                        multibuffer_point.row,
 6216                                        tasks.column,
 6217                                    )),
 6218                                });
 6219                        let debug_scenarios = editor
 6220                            .update(cx, |editor, cx| {
 6221                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6222                            })?
 6223                            .await;
 6224                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6225                    }
 6226                })
 6227            }
 6228        };
 6229
 6230        cx.spawn_in(window, async move |editor, cx| {
 6231            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6232            let code_actions = code_actions_task.await;
 6233            let spawn_straight_away = quick_launch
 6234                && resolved_tasks
 6235                    .as_ref()
 6236                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6237                && code_actions
 6238                    .as_ref()
 6239                    .is_none_or(|actions| actions.is_empty())
 6240                && debug_scenarios.is_empty();
 6241
 6242            editor.update_in(cx, |editor, window, cx| {
 6243                crate::hover_popover::hide_hover(editor, cx);
 6244                let actions = CodeActionContents::new(
 6245                    resolved_tasks,
 6246                    code_actions,
 6247                    debug_scenarios,
 6248                    task_context.unwrap_or_default(),
 6249                );
 6250
 6251                // Don't show the menu if there are no actions available
 6252                if actions.is_empty() {
 6253                    cx.notify();
 6254                    return Task::ready(Ok(()));
 6255                }
 6256
 6257                *editor.context_menu.borrow_mut() =
 6258                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6259                        buffer,
 6260                        actions,
 6261                        selected_item: Default::default(),
 6262                        scroll_handle: UniformListScrollHandle::default(),
 6263                        deployed_from,
 6264                    }));
 6265                cx.notify();
 6266                if spawn_straight_away
 6267                    && let Some(task) = editor.confirm_code_action(
 6268                        &ConfirmCodeAction { item_ix: Some(0) },
 6269                        window,
 6270                        cx,
 6271                    )
 6272                {
 6273                    return task;
 6274                }
 6275
 6276                Task::ready(Ok(()))
 6277            })
 6278        })
 6279        .detach_and_log_err(cx);
 6280    }
 6281
 6282    fn debug_scenarios(
 6283        &mut self,
 6284        resolved_tasks: &Option<ResolvedTasks>,
 6285        buffer: &Entity<Buffer>,
 6286        cx: &mut App,
 6287    ) -> Task<Vec<task::DebugScenario>> {
 6288        maybe!({
 6289            let project = self.project()?;
 6290            let dap_store = project.read(cx).dap_store();
 6291            let mut scenarios = vec![];
 6292            let resolved_tasks = resolved_tasks.as_ref()?;
 6293            let buffer = buffer.read(cx);
 6294            let language = buffer.language()?;
 6295            let file = buffer.file();
 6296            let debug_adapter = language_settings(language.name().into(), file, cx)
 6297                .debuggers
 6298                .first()
 6299                .map(SharedString::from)
 6300                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6301
 6302            dap_store.update(cx, |dap_store, cx| {
 6303                for (_, task) in &resolved_tasks.templates {
 6304                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6305                        task.original_task().clone(),
 6306                        debug_adapter.clone().into(),
 6307                        task.display_label().to_owned().into(),
 6308                        cx,
 6309                    );
 6310                    scenarios.push(maybe_scenario);
 6311                }
 6312            });
 6313            Some(cx.background_spawn(async move {
 6314                futures::future::join_all(scenarios)
 6315                    .await
 6316                    .into_iter()
 6317                    .flatten()
 6318                    .collect::<Vec<_>>()
 6319            }))
 6320        })
 6321        .unwrap_or_else(|| Task::ready(vec![]))
 6322    }
 6323
 6324    fn code_actions(
 6325        &mut self,
 6326        buffer_row: u32,
 6327        window: &mut Window,
 6328        cx: &mut Context<Self>,
 6329    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6330        let mut task = self.code_actions_task.take();
 6331        cx.spawn_in(window, async move |editor, cx| {
 6332            while let Some(prev_task) = task {
 6333                prev_task.await.log_err();
 6334                task = editor
 6335                    .update(cx, |this, _| this.code_actions_task.take())
 6336                    .ok()?;
 6337            }
 6338
 6339            editor
 6340                .update(cx, |editor, cx| {
 6341                    editor
 6342                        .available_code_actions
 6343                        .clone()
 6344                        .and_then(|(location, code_actions)| {
 6345                            let snapshot = location.buffer.read(cx).snapshot();
 6346                            let point_range = location.range.to_point(&snapshot);
 6347                            let point_range = point_range.start.row..=point_range.end.row;
 6348                            if point_range.contains(&buffer_row) {
 6349                                Some(code_actions)
 6350                            } else {
 6351                                None
 6352                            }
 6353                        })
 6354                })
 6355                .ok()
 6356                .flatten()
 6357        })
 6358    }
 6359
 6360    pub fn confirm_code_action(
 6361        &mut self,
 6362        action: &ConfirmCodeAction,
 6363        window: &mut Window,
 6364        cx: &mut Context<Self>,
 6365    ) -> Option<Task<Result<()>>> {
 6366        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6367
 6368        let actions_menu =
 6369            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6370                menu
 6371            } else {
 6372                return None;
 6373            };
 6374
 6375        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6376        let action = actions_menu.actions.get(action_ix)?;
 6377        let title = action.label();
 6378        let buffer = actions_menu.buffer;
 6379        let workspace = self.workspace()?;
 6380
 6381        match action {
 6382            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6383                workspace.update(cx, |workspace, cx| {
 6384                    workspace.schedule_resolved_task(
 6385                        task_source_kind,
 6386                        resolved_task,
 6387                        false,
 6388                        window,
 6389                        cx,
 6390                    );
 6391
 6392                    Some(Task::ready(Ok(())))
 6393                })
 6394            }
 6395            CodeActionsItem::CodeAction {
 6396                excerpt_id,
 6397                action,
 6398                provider,
 6399            } => {
 6400                let apply_code_action =
 6401                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6402                let workspace = workspace.downgrade();
 6403                Some(cx.spawn_in(window, async move |editor, cx| {
 6404                    let project_transaction = apply_code_action.await?;
 6405                    Self::open_project_transaction(
 6406                        &editor,
 6407                        workspace,
 6408                        project_transaction,
 6409                        title,
 6410                        cx,
 6411                    )
 6412                    .await
 6413                }))
 6414            }
 6415            CodeActionsItem::DebugScenario(scenario) => {
 6416                let context = actions_menu.actions.context;
 6417
 6418                workspace.update(cx, |workspace, cx| {
 6419                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6420                    workspace.start_debug_session(
 6421                        scenario,
 6422                        context,
 6423                        Some(buffer),
 6424                        None,
 6425                        window,
 6426                        cx,
 6427                    );
 6428                });
 6429                Some(Task::ready(Ok(())))
 6430            }
 6431        }
 6432    }
 6433
 6434    pub async fn open_project_transaction(
 6435        editor: &WeakEntity<Editor>,
 6436        workspace: WeakEntity<Workspace>,
 6437        transaction: ProjectTransaction,
 6438        title: String,
 6439        cx: &mut AsyncWindowContext,
 6440    ) -> Result<()> {
 6441        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6442        cx.update(|_, cx| {
 6443            entries.sort_unstable_by_key(|(buffer, _)| {
 6444                buffer.read(cx).file().map(|f| f.path().clone())
 6445            });
 6446        })?;
 6447        if entries.is_empty() {
 6448            return Ok(());
 6449        }
 6450
 6451        // If the project transaction's edits are all contained within this editor, then
 6452        // avoid opening a new editor to display them.
 6453
 6454        if let [(buffer, transaction)] = &*entries {
 6455            let excerpt = editor.update(cx, |editor, cx| {
 6456                editor
 6457                    .buffer()
 6458                    .read(cx)
 6459                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6460            })?;
 6461            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6462                && excerpted_buffer == *buffer
 6463            {
 6464                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6465                    let excerpt_range = excerpt_range.to_offset(buffer);
 6466                    buffer
 6467                        .edited_ranges_for_transaction::<usize>(transaction)
 6468                        .all(|range| {
 6469                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6470                        })
 6471                })?;
 6472
 6473                if all_edits_within_excerpt {
 6474                    return Ok(());
 6475                }
 6476            }
 6477        }
 6478
 6479        let mut ranges_to_highlight = Vec::new();
 6480        let excerpt_buffer = cx.new(|cx| {
 6481            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6482            for (buffer_handle, transaction) in &entries {
 6483                let edited_ranges = buffer_handle
 6484                    .read(cx)
 6485                    .edited_ranges_for_transaction::<Point>(transaction)
 6486                    .collect::<Vec<_>>();
 6487                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6488                    PathKey::for_buffer(buffer_handle, cx),
 6489                    buffer_handle.clone(),
 6490                    edited_ranges,
 6491                    multibuffer_context_lines(cx),
 6492                    cx,
 6493                );
 6494
 6495                ranges_to_highlight.extend(ranges);
 6496            }
 6497            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6498            multibuffer
 6499        })?;
 6500
 6501        workspace.update_in(cx, |workspace, window, cx| {
 6502            let project = workspace.project().clone();
 6503            let editor =
 6504                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6505            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6506            editor.update(cx, |editor, cx| {
 6507                editor.highlight_background::<Self>(
 6508                    &ranges_to_highlight,
 6509                    |theme| theme.colors().editor_highlighted_line_background,
 6510                    cx,
 6511                );
 6512            });
 6513        })?;
 6514
 6515        Ok(())
 6516    }
 6517
 6518    pub fn clear_code_action_providers(&mut self) {
 6519        self.code_action_providers.clear();
 6520        self.available_code_actions.take();
 6521    }
 6522
 6523    pub fn add_code_action_provider(
 6524        &mut self,
 6525        provider: Rc<dyn CodeActionProvider>,
 6526        window: &mut Window,
 6527        cx: &mut Context<Self>,
 6528    ) {
 6529        if self
 6530            .code_action_providers
 6531            .iter()
 6532            .any(|existing_provider| existing_provider.id() == provider.id())
 6533        {
 6534            return;
 6535        }
 6536
 6537        self.code_action_providers.push(provider);
 6538        self.refresh_code_actions(window, cx);
 6539    }
 6540
 6541    pub fn remove_code_action_provider(
 6542        &mut self,
 6543        id: Arc<str>,
 6544        window: &mut Window,
 6545        cx: &mut Context<Self>,
 6546    ) {
 6547        self.code_action_providers
 6548            .retain(|provider| provider.id() != id);
 6549        self.refresh_code_actions(window, cx);
 6550    }
 6551
 6552    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6553        !self.code_action_providers.is_empty()
 6554            && EditorSettings::get_global(cx).toolbar.code_actions
 6555    }
 6556
 6557    pub fn has_available_code_actions(&self) -> bool {
 6558        self.available_code_actions
 6559            .as_ref()
 6560            .is_some_and(|(_, actions)| !actions.is_empty())
 6561    }
 6562
 6563    fn render_inline_code_actions(
 6564        &self,
 6565        icon_size: ui::IconSize,
 6566        display_row: DisplayRow,
 6567        is_active: bool,
 6568        cx: &mut Context<Self>,
 6569    ) -> AnyElement {
 6570        let show_tooltip = !self.context_menu_visible();
 6571        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6572            .icon_size(icon_size)
 6573            .shape(ui::IconButtonShape::Square)
 6574            .icon_color(ui::Color::Hidden)
 6575            .toggle_state(is_active)
 6576            .when(show_tooltip, |this| {
 6577                this.tooltip({
 6578                    let focus_handle = self.focus_handle.clone();
 6579                    move |window, cx| {
 6580                        Tooltip::for_action_in(
 6581                            "Toggle Code Actions",
 6582                            &ToggleCodeActions {
 6583                                deployed_from: None,
 6584                                quick_launch: false,
 6585                            },
 6586                            &focus_handle,
 6587                            window,
 6588                            cx,
 6589                        )
 6590                    }
 6591                })
 6592            })
 6593            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6594                window.focus(&editor.focus_handle(cx));
 6595                editor.toggle_code_actions(
 6596                    &crate::actions::ToggleCodeActions {
 6597                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6598                            display_row,
 6599                        )),
 6600                        quick_launch: false,
 6601                    },
 6602                    window,
 6603                    cx,
 6604                );
 6605            }))
 6606            .into_any_element()
 6607    }
 6608
 6609    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6610        &self.context_menu
 6611    }
 6612
 6613    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6614        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6615            cx.background_executor()
 6616                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6617                .await;
 6618
 6619            let (start_buffer, start, _, end, newest_selection) = this
 6620                .update(cx, |this, cx| {
 6621                    let newest_selection = this.selections.newest_anchor().clone();
 6622                    if newest_selection.head().diff_base_anchor.is_some() {
 6623                        return None;
 6624                    }
 6625                    let newest_selection_adjusted = this.selections.newest_adjusted(cx);
 6626                    let buffer = this.buffer.read(cx);
 6627
 6628                    let (start_buffer, start) =
 6629                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6630                    let (end_buffer, end) =
 6631                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6632
 6633                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6634                })?
 6635                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6636                .context(
 6637                    "Expected selection to lie in a single buffer when refreshing code actions",
 6638                )?;
 6639            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6640                let providers = this.code_action_providers.clone();
 6641                let tasks = this
 6642                    .code_action_providers
 6643                    .iter()
 6644                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6645                    .collect::<Vec<_>>();
 6646                (providers, tasks)
 6647            })?;
 6648
 6649            let mut actions = Vec::new();
 6650            for (provider, provider_actions) in
 6651                providers.into_iter().zip(future::join_all(tasks).await)
 6652            {
 6653                if let Some(provider_actions) = provider_actions.log_err() {
 6654                    actions.extend(provider_actions.into_iter().map(|action| {
 6655                        AvailableCodeAction {
 6656                            excerpt_id: newest_selection.start.excerpt_id,
 6657                            action,
 6658                            provider: provider.clone(),
 6659                        }
 6660                    }));
 6661                }
 6662            }
 6663
 6664            this.update(cx, |this, cx| {
 6665                this.available_code_actions = if actions.is_empty() {
 6666                    None
 6667                } else {
 6668                    Some((
 6669                        Location {
 6670                            buffer: start_buffer,
 6671                            range: start..end,
 6672                        },
 6673                        actions.into(),
 6674                    ))
 6675                };
 6676                cx.notify();
 6677            })
 6678        }));
 6679    }
 6680
 6681    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6682        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6683            self.show_git_blame_inline = false;
 6684
 6685            self.show_git_blame_inline_delay_task =
 6686                Some(cx.spawn_in(window, async move |this, cx| {
 6687                    cx.background_executor().timer(delay).await;
 6688
 6689                    this.update(cx, |this, cx| {
 6690                        this.show_git_blame_inline = true;
 6691                        cx.notify();
 6692                    })
 6693                    .log_err();
 6694                }));
 6695        }
 6696    }
 6697
 6698    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6699        let snapshot = self.snapshot(window, cx);
 6700        let cursor = self.selections.newest::<Point>(cx).head();
 6701        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6702        else {
 6703            return;
 6704        };
 6705
 6706        let Some(blame) = self.blame.as_ref() else {
 6707            return;
 6708        };
 6709
 6710        let row_info = RowInfo {
 6711            buffer_id: Some(buffer.remote_id()),
 6712            buffer_row: Some(point.row),
 6713            ..Default::default()
 6714        };
 6715        let Some((buffer, blame_entry)) = blame
 6716            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6717            .flatten()
 6718        else {
 6719            return;
 6720        };
 6721
 6722        let anchor = self.selections.newest_anchor().head();
 6723        let position = self.to_pixel_point(anchor, &snapshot, window);
 6724        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6725            self.show_blame_popover(
 6726                buffer,
 6727                &blame_entry,
 6728                position + last_bounds.origin,
 6729                true,
 6730                cx,
 6731            );
 6732        };
 6733    }
 6734
 6735    fn show_blame_popover(
 6736        &mut self,
 6737        buffer: BufferId,
 6738        blame_entry: &BlameEntry,
 6739        position: gpui::Point<Pixels>,
 6740        ignore_timeout: bool,
 6741        cx: &mut Context<Self>,
 6742    ) {
 6743        if let Some(state) = &mut self.inline_blame_popover {
 6744            state.hide_task.take();
 6745        } else {
 6746            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6747            let blame_entry = blame_entry.clone();
 6748            let show_task = cx.spawn(async move |editor, cx| {
 6749                if !ignore_timeout {
 6750                    cx.background_executor()
 6751                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6752                        .await;
 6753                }
 6754                editor
 6755                    .update(cx, |editor, cx| {
 6756                        editor.inline_blame_popover_show_task.take();
 6757                        let Some(blame) = editor.blame.as_ref() else {
 6758                            return;
 6759                        };
 6760                        let blame = blame.read(cx);
 6761                        let details = blame.details_for_entry(buffer, &blame_entry);
 6762                        let markdown = cx.new(|cx| {
 6763                            Markdown::new(
 6764                                details
 6765                                    .as_ref()
 6766                                    .map(|message| message.message.clone())
 6767                                    .unwrap_or_default(),
 6768                                None,
 6769                                None,
 6770                                cx,
 6771                            )
 6772                        });
 6773                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6774                            position,
 6775                            hide_task: None,
 6776                            popover_bounds: None,
 6777                            popover_state: InlineBlamePopoverState {
 6778                                scroll_handle: ScrollHandle::new(),
 6779                                commit_message: details,
 6780                                markdown,
 6781                            },
 6782                            keyboard_grace: ignore_timeout,
 6783                        });
 6784                        cx.notify();
 6785                    })
 6786                    .ok();
 6787            });
 6788            self.inline_blame_popover_show_task = Some(show_task);
 6789        }
 6790    }
 6791
 6792    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6793        self.inline_blame_popover_show_task.take();
 6794        if let Some(state) = &mut self.inline_blame_popover {
 6795            let hide_task = cx.spawn(async move |editor, cx| {
 6796                cx.background_executor()
 6797                    .timer(std::time::Duration::from_millis(100))
 6798                    .await;
 6799                editor
 6800                    .update(cx, |editor, cx| {
 6801                        editor.inline_blame_popover.take();
 6802                        cx.notify();
 6803                    })
 6804                    .ok();
 6805            });
 6806            state.hide_task = Some(hide_task);
 6807        }
 6808    }
 6809
 6810    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6811        if self.pending_rename.is_some() {
 6812            return None;
 6813        }
 6814
 6815        let provider = self.semantics_provider.clone()?;
 6816        let buffer = self.buffer.read(cx);
 6817        let newest_selection = self.selections.newest_anchor().clone();
 6818        let cursor_position = newest_selection.head();
 6819        let (cursor_buffer, cursor_buffer_position) =
 6820            buffer.text_anchor_for_position(cursor_position, cx)?;
 6821        let (tail_buffer, tail_buffer_position) =
 6822            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6823        if cursor_buffer != tail_buffer {
 6824            return None;
 6825        }
 6826
 6827        let snapshot = cursor_buffer.read(cx).snapshot();
 6828        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6829        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6830        if start_word_range != end_word_range {
 6831            self.document_highlights_task.take();
 6832            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6833            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6834            return None;
 6835        }
 6836
 6837        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6838        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6839            cx.background_executor()
 6840                .timer(Duration::from_millis(debounce))
 6841                .await;
 6842
 6843            let highlights = if let Some(highlights) = cx
 6844                .update(|cx| {
 6845                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6846                })
 6847                .ok()
 6848                .flatten()
 6849            {
 6850                highlights.await.log_err()
 6851            } else {
 6852                None
 6853            };
 6854
 6855            if let Some(highlights) = highlights {
 6856                this.update(cx, |this, cx| {
 6857                    if this.pending_rename.is_some() {
 6858                        return;
 6859                    }
 6860
 6861                    let buffer = this.buffer.read(cx);
 6862                    if buffer
 6863                        .text_anchor_for_position(cursor_position, cx)
 6864                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6865                    {
 6866                        return;
 6867                    }
 6868
 6869                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6870                    let mut write_ranges = Vec::new();
 6871                    let mut read_ranges = Vec::new();
 6872                    for highlight in highlights {
 6873                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6874                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6875                        {
 6876                            let start = highlight
 6877                                .range
 6878                                .start
 6879                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6880                            let end = highlight
 6881                                .range
 6882                                .end
 6883                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6884                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6885                                continue;
 6886                            }
 6887
 6888                            let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
 6889                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6890                                write_ranges.push(range);
 6891                            } else {
 6892                                read_ranges.push(range);
 6893                            }
 6894                        }
 6895                    }
 6896
 6897                    this.highlight_background::<DocumentHighlightRead>(
 6898                        &read_ranges,
 6899                        |theme| theme.colors().editor_document_highlight_read_background,
 6900                        cx,
 6901                    );
 6902                    this.highlight_background::<DocumentHighlightWrite>(
 6903                        &write_ranges,
 6904                        |theme| theme.colors().editor_document_highlight_write_background,
 6905                        cx,
 6906                    );
 6907                    cx.notify();
 6908                })
 6909                .log_err();
 6910            }
 6911        }));
 6912        None
 6913    }
 6914
 6915    fn prepare_highlight_query_from_selection(
 6916        &mut self,
 6917        cx: &mut Context<Editor>,
 6918    ) -> Option<(String, Range<Anchor>)> {
 6919        if matches!(self.mode, EditorMode::SingleLine) {
 6920            return None;
 6921        }
 6922        if !EditorSettings::get_global(cx).selection_highlight {
 6923            return None;
 6924        }
 6925        if self.selections.count() != 1 || self.selections.line_mode() {
 6926            return None;
 6927        }
 6928        let selection = self.selections.newest_anchor();
 6929        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6930        let selection_point_range = selection.start.to_point(&multi_buffer_snapshot)
 6931            ..selection.end.to_point(&multi_buffer_snapshot);
 6932        // If the selection spans multiple rows OR it is empty
 6933        if selection_point_range.start.row != selection_point_range.end.row
 6934            || selection_point_range.start.column == selection_point_range.end.column
 6935        {
 6936            return None;
 6937        }
 6938
 6939        let query = multi_buffer_snapshot
 6940            .text_for_range(selection.range())
 6941            .collect::<String>();
 6942        if query.trim().is_empty() {
 6943            return None;
 6944        }
 6945        Some((query, selection.range()))
 6946    }
 6947
 6948    fn update_selection_occurrence_highlights(
 6949        &mut self,
 6950        query_text: String,
 6951        query_range: Range<Anchor>,
 6952        multi_buffer_range_to_query: Range<Point>,
 6953        use_debounce: bool,
 6954        window: &mut Window,
 6955        cx: &mut Context<Editor>,
 6956    ) -> Task<()> {
 6957        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6958        cx.spawn_in(window, async move |editor, cx| {
 6959            if use_debounce {
 6960                cx.background_executor()
 6961                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6962                    .await;
 6963            }
 6964            let match_task = cx.background_spawn(async move {
 6965                let buffer_ranges = multi_buffer_snapshot
 6966                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6967                    .into_iter()
 6968                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6969                let mut match_ranges = Vec::new();
 6970                let Ok(regex) = project::search::SearchQuery::text(
 6971                    query_text.clone(),
 6972                    false,
 6973                    false,
 6974                    false,
 6975                    Default::default(),
 6976                    Default::default(),
 6977                    false,
 6978                    None,
 6979                ) else {
 6980                    return Vec::default();
 6981                };
 6982                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6983                    match_ranges.extend(
 6984                        regex
 6985                            .search(buffer_snapshot, Some(search_range.clone()))
 6986                            .await
 6987                            .into_iter()
 6988                            .filter_map(|match_range| {
 6989                                let match_start = buffer_snapshot
 6990                                    .anchor_after(search_range.start + match_range.start);
 6991                                let match_end = buffer_snapshot
 6992                                    .anchor_before(search_range.start + match_range.end);
 6993                                let match_anchor_range = Anchor::range_in_buffer(
 6994                                    excerpt_id,
 6995                                    buffer_snapshot.remote_id(),
 6996                                    match_start..match_end,
 6997                                );
 6998                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6999                            }),
 7000                    );
 7001                }
 7002                match_ranges
 7003            });
 7004            let match_ranges = match_task.await;
 7005            editor
 7006                .update_in(cx, |editor, _, cx| {
 7007                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7008                    if !match_ranges.is_empty() {
 7009                        editor.highlight_background::<SelectedTextHighlight>(
 7010                            &match_ranges,
 7011                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7012                            cx,
 7013                        )
 7014                    }
 7015                })
 7016                .log_err();
 7017        })
 7018    }
 7019
 7020    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7021        struct NewlineFold;
 7022        let type_id = std::any::TypeId::of::<NewlineFold>();
 7023        if !self.mode.is_single_line() {
 7024            return;
 7025        }
 7026        let snapshot = self.snapshot(window, cx);
 7027        if snapshot.buffer_snapshot().max_point().row == 0 {
 7028            return;
 7029        }
 7030        let task = cx.background_spawn(async move {
 7031            let new_newlines = snapshot
 7032                .buffer_chars_at(0)
 7033                .filter_map(|(c, i)| {
 7034                    if c == '\n' {
 7035                        Some(
 7036                            snapshot.buffer_snapshot().anchor_after(i)
 7037                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7038                        )
 7039                    } else {
 7040                        None
 7041                    }
 7042                })
 7043                .collect::<Vec<_>>();
 7044            let existing_newlines = snapshot
 7045                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7046                .filter_map(|fold| {
 7047                    if fold.placeholder.type_tag == Some(type_id) {
 7048                        Some(fold.range.start..fold.range.end)
 7049                    } else {
 7050                        None
 7051                    }
 7052                })
 7053                .collect::<Vec<_>>();
 7054
 7055            (new_newlines, existing_newlines)
 7056        });
 7057        self.folding_newlines = cx.spawn(async move |this, cx| {
 7058            let (new_newlines, existing_newlines) = task.await;
 7059            if new_newlines == existing_newlines {
 7060                return;
 7061            }
 7062            let placeholder = FoldPlaceholder {
 7063                render: Arc::new(move |_, _, cx| {
 7064                    div()
 7065                        .bg(cx.theme().status().hint_background)
 7066                        .border_b_1()
 7067                        .size_full()
 7068                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7069                        .border_color(cx.theme().status().hint)
 7070                        .child("\\n")
 7071                        .into_any()
 7072                }),
 7073                constrain_width: false,
 7074                merge_adjacent: false,
 7075                type_tag: Some(type_id),
 7076            };
 7077            let creases = new_newlines
 7078                .into_iter()
 7079                .map(|range| Crease::simple(range, placeholder.clone()))
 7080                .collect();
 7081            this.update(cx, |this, cx| {
 7082                this.display_map.update(cx, |display_map, cx| {
 7083                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7084                    display_map.fold(creases, cx);
 7085                });
 7086            })
 7087            .ok();
 7088        });
 7089    }
 7090
 7091    fn refresh_selected_text_highlights(
 7092        &mut self,
 7093        on_buffer_edit: bool,
 7094        window: &mut Window,
 7095        cx: &mut Context<Editor>,
 7096    ) {
 7097        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7098        else {
 7099            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7100            self.quick_selection_highlight_task.take();
 7101            self.debounced_selection_highlight_task.take();
 7102            return;
 7103        };
 7104        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7105        if on_buffer_edit
 7106            || self
 7107                .quick_selection_highlight_task
 7108                .as_ref()
 7109                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7110        {
 7111            let multi_buffer_visible_start = self
 7112                .scroll_manager
 7113                .anchor()
 7114                .anchor
 7115                .to_point(&multi_buffer_snapshot);
 7116            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7117                multi_buffer_visible_start
 7118                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7119                Bias::Left,
 7120            );
 7121            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7122            self.quick_selection_highlight_task = Some((
 7123                query_range.clone(),
 7124                self.update_selection_occurrence_highlights(
 7125                    query_text.clone(),
 7126                    query_range.clone(),
 7127                    multi_buffer_visible_range,
 7128                    false,
 7129                    window,
 7130                    cx,
 7131                ),
 7132            ));
 7133        }
 7134        if on_buffer_edit
 7135            || self
 7136                .debounced_selection_highlight_task
 7137                .as_ref()
 7138                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7139        {
 7140            let multi_buffer_start = multi_buffer_snapshot
 7141                .anchor_before(0)
 7142                .to_point(&multi_buffer_snapshot);
 7143            let multi_buffer_end = multi_buffer_snapshot
 7144                .anchor_after(multi_buffer_snapshot.len())
 7145                .to_point(&multi_buffer_snapshot);
 7146            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7147            self.debounced_selection_highlight_task = Some((
 7148                query_range.clone(),
 7149                self.update_selection_occurrence_highlights(
 7150                    query_text,
 7151                    query_range,
 7152                    multi_buffer_full_range,
 7153                    true,
 7154                    window,
 7155                    cx,
 7156                ),
 7157            ));
 7158        }
 7159    }
 7160
 7161    pub fn refresh_edit_prediction(
 7162        &mut self,
 7163        debounce: bool,
 7164        user_requested: bool,
 7165        window: &mut Window,
 7166        cx: &mut Context<Self>,
 7167    ) -> Option<()> {
 7168        if DisableAiSettings::get_global(cx).disable_ai {
 7169            return None;
 7170        }
 7171
 7172        let provider = self.edit_prediction_provider()?;
 7173        let cursor = self.selections.newest_anchor().head();
 7174        let (buffer, cursor_buffer_position) =
 7175            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7176
 7177        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7178            self.discard_edit_prediction(false, cx);
 7179            return None;
 7180        }
 7181
 7182        self.update_visible_edit_prediction(window, cx);
 7183
 7184        if !user_requested
 7185            && (!self.should_show_edit_predictions()
 7186                || !self.is_focused(window)
 7187                || buffer.read(cx).is_empty())
 7188        {
 7189            self.discard_edit_prediction(false, cx);
 7190            return None;
 7191        }
 7192
 7193        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7194        Some(())
 7195    }
 7196
 7197    fn show_edit_predictions_in_menu(&self) -> bool {
 7198        match self.edit_prediction_settings {
 7199            EditPredictionSettings::Disabled => false,
 7200            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7201        }
 7202    }
 7203
 7204    pub fn edit_predictions_enabled(&self) -> bool {
 7205        match self.edit_prediction_settings {
 7206            EditPredictionSettings::Disabled => false,
 7207            EditPredictionSettings::Enabled { .. } => true,
 7208        }
 7209    }
 7210
 7211    fn edit_prediction_requires_modifier(&self) -> bool {
 7212        match self.edit_prediction_settings {
 7213            EditPredictionSettings::Disabled => false,
 7214            EditPredictionSettings::Enabled {
 7215                preview_requires_modifier,
 7216                ..
 7217            } => preview_requires_modifier,
 7218        }
 7219    }
 7220
 7221    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7222        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7223            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7224            self.discard_edit_prediction(false, cx);
 7225        } else {
 7226            let selection = self.selections.newest_anchor();
 7227            let cursor = selection.head();
 7228
 7229            if let Some((buffer, cursor_buffer_position)) =
 7230                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7231            {
 7232                self.edit_prediction_settings =
 7233                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7234            }
 7235        }
 7236    }
 7237
 7238    fn edit_prediction_settings_at_position(
 7239        &self,
 7240        buffer: &Entity<Buffer>,
 7241        buffer_position: language::Anchor,
 7242        cx: &App,
 7243    ) -> EditPredictionSettings {
 7244        if !self.mode.is_full()
 7245            || !self.show_edit_predictions_override.unwrap_or(true)
 7246            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7247        {
 7248            return EditPredictionSettings::Disabled;
 7249        }
 7250
 7251        let buffer = buffer.read(cx);
 7252
 7253        let file = buffer.file();
 7254
 7255        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7256            return EditPredictionSettings::Disabled;
 7257        };
 7258
 7259        let by_provider = matches!(
 7260            self.menu_edit_predictions_policy,
 7261            MenuEditPredictionsPolicy::ByProvider
 7262        );
 7263
 7264        let show_in_menu = by_provider
 7265            && self
 7266                .edit_prediction_provider
 7267                .as_ref()
 7268                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7269
 7270        let preview_requires_modifier =
 7271            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7272
 7273        EditPredictionSettings::Enabled {
 7274            show_in_menu,
 7275            preview_requires_modifier,
 7276        }
 7277    }
 7278
 7279    fn should_show_edit_predictions(&self) -> bool {
 7280        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7281    }
 7282
 7283    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7284        matches!(
 7285            self.edit_prediction_preview,
 7286            EditPredictionPreview::Active { .. }
 7287        )
 7288    }
 7289
 7290    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7291        let cursor = self.selections.newest_anchor().head();
 7292        if let Some((buffer, cursor_position)) =
 7293            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7294        {
 7295            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7296        } else {
 7297            false
 7298        }
 7299    }
 7300
 7301    pub fn supports_minimap(&self, cx: &App) -> bool {
 7302        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7303    }
 7304
 7305    fn edit_predictions_enabled_in_buffer(
 7306        &self,
 7307        buffer: &Entity<Buffer>,
 7308        buffer_position: language::Anchor,
 7309        cx: &App,
 7310    ) -> bool {
 7311        maybe!({
 7312            if self.read_only(cx) {
 7313                return Some(false);
 7314            }
 7315            let provider = self.edit_prediction_provider()?;
 7316            if !provider.is_enabled(buffer, buffer_position, cx) {
 7317                return Some(false);
 7318            }
 7319            let buffer = buffer.read(cx);
 7320            let Some(file) = buffer.file() else {
 7321                return Some(true);
 7322            };
 7323            let settings = all_language_settings(Some(file), cx);
 7324            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7325        })
 7326        .unwrap_or(false)
 7327    }
 7328
 7329    fn cycle_edit_prediction(
 7330        &mut self,
 7331        direction: Direction,
 7332        window: &mut Window,
 7333        cx: &mut Context<Self>,
 7334    ) -> Option<()> {
 7335        let provider = self.edit_prediction_provider()?;
 7336        let cursor = self.selections.newest_anchor().head();
 7337        let (buffer, cursor_buffer_position) =
 7338            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7339        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7340            return None;
 7341        }
 7342
 7343        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7344        self.update_visible_edit_prediction(window, cx);
 7345
 7346        Some(())
 7347    }
 7348
 7349    pub fn show_edit_prediction(
 7350        &mut self,
 7351        _: &ShowEditPrediction,
 7352        window: &mut Window,
 7353        cx: &mut Context<Self>,
 7354    ) {
 7355        if !self.has_active_edit_prediction() {
 7356            self.refresh_edit_prediction(false, true, window, cx);
 7357            return;
 7358        }
 7359
 7360        self.update_visible_edit_prediction(window, cx);
 7361    }
 7362
 7363    pub fn display_cursor_names(
 7364        &mut self,
 7365        _: &DisplayCursorNames,
 7366        window: &mut Window,
 7367        cx: &mut Context<Self>,
 7368    ) {
 7369        self.show_cursor_names(window, cx);
 7370    }
 7371
 7372    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7373        self.show_cursor_names = true;
 7374        cx.notify();
 7375        cx.spawn_in(window, async move |this, cx| {
 7376            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7377            this.update(cx, |this, cx| {
 7378                this.show_cursor_names = false;
 7379                cx.notify()
 7380            })
 7381            .ok()
 7382        })
 7383        .detach();
 7384    }
 7385
 7386    pub fn next_edit_prediction(
 7387        &mut self,
 7388        _: &NextEditPrediction,
 7389        window: &mut Window,
 7390        cx: &mut Context<Self>,
 7391    ) {
 7392        if self.has_active_edit_prediction() {
 7393            self.cycle_edit_prediction(Direction::Next, window, cx);
 7394        } else {
 7395            let is_copilot_disabled = self
 7396                .refresh_edit_prediction(false, true, window, cx)
 7397                .is_none();
 7398            if is_copilot_disabled {
 7399                cx.propagate();
 7400            }
 7401        }
 7402    }
 7403
 7404    pub fn previous_edit_prediction(
 7405        &mut self,
 7406        _: &PreviousEditPrediction,
 7407        window: &mut Window,
 7408        cx: &mut Context<Self>,
 7409    ) {
 7410        if self.has_active_edit_prediction() {
 7411            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7412        } else {
 7413            let is_copilot_disabled = self
 7414                .refresh_edit_prediction(false, true, window, cx)
 7415                .is_none();
 7416            if is_copilot_disabled {
 7417                cx.propagate();
 7418            }
 7419        }
 7420    }
 7421
 7422    pub fn accept_edit_prediction(
 7423        &mut self,
 7424        _: &AcceptEditPrediction,
 7425        window: &mut Window,
 7426        cx: &mut Context<Self>,
 7427    ) {
 7428        if self.show_edit_predictions_in_menu() {
 7429            self.hide_context_menu(window, cx);
 7430        }
 7431
 7432        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7433            return;
 7434        };
 7435
 7436        match &active_edit_prediction.completion {
 7437            EditPrediction::MoveWithin { target, .. } => {
 7438                let target = *target;
 7439
 7440                if let Some(position_map) = &self.last_position_map {
 7441                    if position_map
 7442                        .visible_row_range
 7443                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7444                        || !self.edit_prediction_requires_modifier()
 7445                    {
 7446                        self.unfold_ranges(&[target..target], true, false, cx);
 7447                        // Note that this is also done in vim's handler of the Tab action.
 7448                        self.change_selections(
 7449                            SelectionEffects::scroll(Autoscroll::newest()),
 7450                            window,
 7451                            cx,
 7452                            |selections| {
 7453                                selections.select_anchor_ranges([target..target]);
 7454                            },
 7455                        );
 7456                        self.clear_row_highlights::<EditPredictionPreview>();
 7457
 7458                        self.edit_prediction_preview
 7459                            .set_previous_scroll_position(None);
 7460                    } else {
 7461                        self.edit_prediction_preview
 7462                            .set_previous_scroll_position(Some(
 7463                                position_map.snapshot.scroll_anchor,
 7464                            ));
 7465
 7466                        self.highlight_rows::<EditPredictionPreview>(
 7467                            target..target,
 7468                            cx.theme().colors().editor_highlighted_line_background,
 7469                            RowHighlightOptions {
 7470                                autoscroll: true,
 7471                                ..Default::default()
 7472                            },
 7473                            cx,
 7474                        );
 7475                        self.request_autoscroll(Autoscroll::fit(), cx);
 7476                    }
 7477                }
 7478            }
 7479            EditPrediction::MoveOutside { snapshot, target } => {
 7480                if let Some(workspace) = self.workspace() {
 7481                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7482                        .detach_and_log_err(cx);
 7483                }
 7484            }
 7485            EditPrediction::Edit { edits, .. } => {
 7486                self.report_edit_prediction_event(
 7487                    active_edit_prediction.completion_id.clone(),
 7488                    true,
 7489                    cx,
 7490                );
 7491
 7492                if let Some(provider) = self.edit_prediction_provider() {
 7493                    provider.accept(cx);
 7494                }
 7495
 7496                // Store the transaction ID and selections before applying the edit
 7497                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7498
 7499                let snapshot = self.buffer.read(cx).snapshot(cx);
 7500                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7501
 7502                self.buffer.update(cx, |buffer, cx| {
 7503                    buffer.edit(edits.iter().cloned(), None, cx)
 7504                });
 7505
 7506                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7507                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7508                });
 7509
 7510                let selections = self.selections.disjoint_anchors_arc();
 7511                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7512                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7513                    if has_new_transaction {
 7514                        self.selection_history
 7515                            .insert_transaction(transaction_id_now, selections);
 7516                    }
 7517                }
 7518
 7519                self.update_visible_edit_prediction(window, cx);
 7520                if self.active_edit_prediction.is_none() {
 7521                    self.refresh_edit_prediction(true, true, window, cx);
 7522                }
 7523
 7524                cx.notify();
 7525            }
 7526        }
 7527
 7528        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7529    }
 7530
 7531    pub fn accept_partial_edit_prediction(
 7532        &mut self,
 7533        _: &AcceptPartialEditPrediction,
 7534        window: &mut Window,
 7535        cx: &mut Context<Self>,
 7536    ) {
 7537        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7538            return;
 7539        };
 7540        if self.selections.count() != 1 {
 7541            return;
 7542        }
 7543
 7544        match &active_edit_prediction.completion {
 7545            EditPrediction::MoveWithin { target, .. } => {
 7546                let target = *target;
 7547                self.change_selections(
 7548                    SelectionEffects::scroll(Autoscroll::newest()),
 7549                    window,
 7550                    cx,
 7551                    |selections| {
 7552                        selections.select_anchor_ranges([target..target]);
 7553                    },
 7554                );
 7555            }
 7556            EditPrediction::MoveOutside { snapshot, target } => {
 7557                if let Some(workspace) = self.workspace() {
 7558                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7559                        .detach_and_log_err(cx);
 7560                }
 7561            }
 7562            EditPrediction::Edit { edits, .. } => {
 7563                self.report_edit_prediction_event(
 7564                    active_edit_prediction.completion_id.clone(),
 7565                    true,
 7566                    cx,
 7567                );
 7568
 7569                // Find an insertion that starts at the cursor position.
 7570                let snapshot = self.buffer.read(cx).snapshot(cx);
 7571                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7572                let insertion = edits.iter().find_map(|(range, text)| {
 7573                    let range = range.to_offset(&snapshot);
 7574                    if range.is_empty() && range.start == cursor_offset {
 7575                        Some(text)
 7576                    } else {
 7577                        None
 7578                    }
 7579                });
 7580
 7581                if let Some(text) = insertion {
 7582                    let mut partial_completion = text
 7583                        .chars()
 7584                        .by_ref()
 7585                        .take_while(|c| c.is_alphabetic())
 7586                        .collect::<String>();
 7587                    if partial_completion.is_empty() {
 7588                        partial_completion = text
 7589                            .chars()
 7590                            .by_ref()
 7591                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7592                            .collect::<String>();
 7593                    }
 7594
 7595                    cx.emit(EditorEvent::InputHandled {
 7596                        utf16_range_to_replace: None,
 7597                        text: partial_completion.clone().into(),
 7598                    });
 7599
 7600                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7601
 7602                    self.refresh_edit_prediction(true, true, window, cx);
 7603                    cx.notify();
 7604                } else {
 7605                    self.accept_edit_prediction(&Default::default(), window, cx);
 7606                }
 7607            }
 7608        }
 7609    }
 7610
 7611    fn discard_edit_prediction(
 7612        &mut self,
 7613        should_report_edit_prediction_event: bool,
 7614        cx: &mut Context<Self>,
 7615    ) -> bool {
 7616        if should_report_edit_prediction_event {
 7617            let completion_id = self
 7618                .active_edit_prediction
 7619                .as_ref()
 7620                .and_then(|active_completion| active_completion.completion_id.clone());
 7621
 7622            self.report_edit_prediction_event(completion_id, false, cx);
 7623        }
 7624
 7625        if let Some(provider) = self.edit_prediction_provider() {
 7626            provider.discard(cx);
 7627        }
 7628
 7629        self.take_active_edit_prediction(cx)
 7630    }
 7631
 7632    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7633        let Some(provider) = self.edit_prediction_provider() else {
 7634            return;
 7635        };
 7636
 7637        let Some((_, buffer, _)) = self
 7638            .buffer
 7639            .read(cx)
 7640            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7641        else {
 7642            return;
 7643        };
 7644
 7645        let extension = buffer
 7646            .read(cx)
 7647            .file()
 7648            .and_then(|file| Some(file.path().extension()?.to_string()));
 7649
 7650        let event_type = match accepted {
 7651            true => "Edit Prediction Accepted",
 7652            false => "Edit Prediction Discarded",
 7653        };
 7654        telemetry::event!(
 7655            event_type,
 7656            provider = provider.name(),
 7657            prediction_id = id,
 7658            suggestion_accepted = accepted,
 7659            file_extension = extension,
 7660        );
 7661    }
 7662
 7663    fn open_editor_at_anchor(
 7664        snapshot: &language::BufferSnapshot,
 7665        target: language::Anchor,
 7666        workspace: &Entity<Workspace>,
 7667        window: &mut Window,
 7668        cx: &mut App,
 7669    ) -> Task<Result<()>> {
 7670        workspace.update(cx, |workspace, cx| {
 7671            let path = snapshot.file().map(|file| file.full_path(cx));
 7672            let Some(path) =
 7673                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7674            else {
 7675                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7676            };
 7677            let target = text::ToPoint::to_point(&target, snapshot);
 7678            let item = workspace.open_path(path, None, true, window, cx);
 7679            window.spawn(cx, async move |cx| {
 7680                let Some(editor) = item.await?.downcast::<Editor>() else {
 7681                    return Ok(());
 7682                };
 7683                editor
 7684                    .update_in(cx, |editor, window, cx| {
 7685                        editor.go_to_singleton_buffer_point(target, window, cx);
 7686                    })
 7687                    .ok();
 7688                anyhow::Ok(())
 7689            })
 7690        })
 7691    }
 7692
 7693    pub fn has_active_edit_prediction(&self) -> bool {
 7694        self.active_edit_prediction.is_some()
 7695    }
 7696
 7697    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7698        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7699            return false;
 7700        };
 7701
 7702        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7703        self.clear_highlights::<EditPredictionHighlight>(cx);
 7704        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7705        true
 7706    }
 7707
 7708    /// Returns true when we're displaying the edit prediction popover below the cursor
 7709    /// like we are not previewing and the LSP autocomplete menu is visible
 7710    /// or we are in `when_holding_modifier` mode.
 7711    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7712        if self.edit_prediction_preview_is_active()
 7713            || !self.show_edit_predictions_in_menu()
 7714            || !self.edit_predictions_enabled()
 7715        {
 7716            return false;
 7717        }
 7718
 7719        if self.has_visible_completions_menu() {
 7720            return true;
 7721        }
 7722
 7723        has_completion && self.edit_prediction_requires_modifier()
 7724    }
 7725
 7726    fn handle_modifiers_changed(
 7727        &mut self,
 7728        modifiers: Modifiers,
 7729        position_map: &PositionMap,
 7730        window: &mut Window,
 7731        cx: &mut Context<Self>,
 7732    ) {
 7733        if self.show_edit_predictions_in_menu() {
 7734            self.update_edit_prediction_preview(&modifiers, window, cx);
 7735        }
 7736
 7737        self.update_selection_mode(&modifiers, position_map, window, cx);
 7738
 7739        let mouse_position = window.mouse_position();
 7740        if !position_map.text_hitbox.is_hovered(window) {
 7741            return;
 7742        }
 7743
 7744        self.update_hovered_link(
 7745            position_map.point_for_position(mouse_position),
 7746            &position_map.snapshot,
 7747            modifiers,
 7748            window,
 7749            cx,
 7750        )
 7751    }
 7752
 7753    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7754        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7755        if invert {
 7756            match multi_cursor_setting {
 7757                MultiCursorModifier::Alt => modifiers.alt,
 7758                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7759            }
 7760        } else {
 7761            match multi_cursor_setting {
 7762                MultiCursorModifier::Alt => modifiers.secondary(),
 7763                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7764            }
 7765        }
 7766    }
 7767
 7768    fn columnar_selection_mode(
 7769        modifiers: &Modifiers,
 7770        cx: &mut Context<Self>,
 7771    ) -> Option<ColumnarMode> {
 7772        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7773            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7774                Some(ColumnarMode::FromMouse)
 7775            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7776                Some(ColumnarMode::FromSelection)
 7777            } else {
 7778                None
 7779            }
 7780        } else {
 7781            None
 7782        }
 7783    }
 7784
 7785    fn update_selection_mode(
 7786        &mut self,
 7787        modifiers: &Modifiers,
 7788        position_map: &PositionMap,
 7789        window: &mut Window,
 7790        cx: &mut Context<Self>,
 7791    ) {
 7792        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7793            return;
 7794        };
 7795        if self.selections.pending_anchor().is_none() {
 7796            return;
 7797        }
 7798
 7799        let mouse_position = window.mouse_position();
 7800        let point_for_position = position_map.point_for_position(mouse_position);
 7801        let position = point_for_position.previous_valid;
 7802
 7803        self.select(
 7804            SelectPhase::BeginColumnar {
 7805                position,
 7806                reset: false,
 7807                mode,
 7808                goal_column: point_for_position.exact_unclipped.column(),
 7809            },
 7810            window,
 7811            cx,
 7812        );
 7813    }
 7814
 7815    fn update_edit_prediction_preview(
 7816        &mut self,
 7817        modifiers: &Modifiers,
 7818        window: &mut Window,
 7819        cx: &mut Context<Self>,
 7820    ) {
 7821        let mut modifiers_held = false;
 7822        if let Some(accept_keystroke) = self
 7823            .accept_edit_prediction_keybind(false, window, cx)
 7824            .keystroke()
 7825        {
 7826            modifiers_held = modifiers_held
 7827                || (accept_keystroke.modifiers() == modifiers
 7828                    && accept_keystroke.modifiers().modified());
 7829        };
 7830        if let Some(accept_partial_keystroke) = self
 7831            .accept_edit_prediction_keybind(true, window, cx)
 7832            .keystroke()
 7833        {
 7834            modifiers_held = modifiers_held
 7835                || (accept_partial_keystroke.modifiers() == modifiers
 7836                    && accept_partial_keystroke.modifiers().modified());
 7837        }
 7838
 7839        if modifiers_held {
 7840            if matches!(
 7841                self.edit_prediction_preview,
 7842                EditPredictionPreview::Inactive { .. }
 7843            ) {
 7844                self.edit_prediction_preview = EditPredictionPreview::Active {
 7845                    previous_scroll_position: None,
 7846                    since: Instant::now(),
 7847                };
 7848
 7849                self.update_visible_edit_prediction(window, cx);
 7850                cx.notify();
 7851            }
 7852        } else if let EditPredictionPreview::Active {
 7853            previous_scroll_position,
 7854            since,
 7855        } = self.edit_prediction_preview
 7856        {
 7857            if let (Some(previous_scroll_position), Some(position_map)) =
 7858                (previous_scroll_position, self.last_position_map.as_ref())
 7859            {
 7860                self.set_scroll_position(
 7861                    previous_scroll_position
 7862                        .scroll_position(&position_map.snapshot.display_snapshot),
 7863                    window,
 7864                    cx,
 7865                );
 7866            }
 7867
 7868            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7869                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7870            };
 7871            self.clear_row_highlights::<EditPredictionPreview>();
 7872            self.update_visible_edit_prediction(window, cx);
 7873            cx.notify();
 7874        }
 7875    }
 7876
 7877    fn update_visible_edit_prediction(
 7878        &mut self,
 7879        _window: &mut Window,
 7880        cx: &mut Context<Self>,
 7881    ) -> Option<()> {
 7882        if DisableAiSettings::get_global(cx).disable_ai {
 7883            return None;
 7884        }
 7885
 7886        if self.ime_transaction.is_some() {
 7887            self.discard_edit_prediction(false, cx);
 7888            return None;
 7889        }
 7890
 7891        let selection = self.selections.newest_anchor();
 7892        let cursor = selection.head();
 7893        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7894        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7895        let excerpt_id = cursor.excerpt_id;
 7896
 7897        let show_in_menu = self.show_edit_predictions_in_menu();
 7898        let completions_menu_has_precedence = !show_in_menu
 7899            && (self.context_menu.borrow().is_some()
 7900                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7901
 7902        if completions_menu_has_precedence
 7903            || !offset_selection.is_empty()
 7904            || self
 7905                .active_edit_prediction
 7906                .as_ref()
 7907                .is_some_and(|completion| {
 7908                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7909                        return false;
 7910                    };
 7911                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7912                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7913                    !invalidation_range.contains(&offset_selection.head())
 7914                })
 7915        {
 7916            self.discard_edit_prediction(false, cx);
 7917            return None;
 7918        }
 7919
 7920        self.take_active_edit_prediction(cx);
 7921        let Some(provider) = self.edit_prediction_provider() else {
 7922            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7923            return None;
 7924        };
 7925
 7926        let (buffer, cursor_buffer_position) =
 7927            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7928
 7929        self.edit_prediction_settings =
 7930            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7931
 7932        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7933
 7934        if self.edit_prediction_indent_conflict {
 7935            let cursor_point = cursor.to_point(&multibuffer);
 7936
 7937            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7938
 7939            if let Some((_, indent)) = indents.iter().next()
 7940                && indent.len == cursor_point.column
 7941            {
 7942                self.edit_prediction_indent_conflict = false;
 7943            }
 7944        }
 7945
 7946        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7947
 7948        let (completion_id, edits, edit_preview) = match edit_prediction {
 7949            edit_prediction::EditPrediction::Local {
 7950                id,
 7951                edits,
 7952                edit_preview,
 7953            } => (id, edits, edit_preview),
 7954            edit_prediction::EditPrediction::Jump {
 7955                id,
 7956                snapshot,
 7957                target,
 7958            } => {
 7959                self.stale_edit_prediction_in_menu = None;
 7960                self.active_edit_prediction = Some(EditPredictionState {
 7961                    inlay_ids: vec![],
 7962                    completion: EditPrediction::MoveOutside { snapshot, target },
 7963                    completion_id: id,
 7964                    invalidation_range: None,
 7965                });
 7966                cx.notify();
 7967                return Some(());
 7968            }
 7969        };
 7970
 7971        let edits = edits
 7972            .into_iter()
 7973            .flat_map(|(range, new_text)| {
 7974                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7975                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7976                Some((start..end, new_text))
 7977            })
 7978            .collect::<Vec<_>>();
 7979        if edits.is_empty() {
 7980            return None;
 7981        }
 7982
 7983        let first_edit_start = edits.first().unwrap().0.start;
 7984        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7985        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7986
 7987        let last_edit_end = edits.last().unwrap().0.end;
 7988        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7989        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7990
 7991        let cursor_row = cursor.to_point(&multibuffer).row;
 7992
 7993        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7994
 7995        let mut inlay_ids = Vec::new();
 7996        let invalidation_row_range;
 7997        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7998            Some(cursor_row..edit_end_row)
 7999        } else if cursor_row > edit_end_row {
 8000            Some(edit_start_row..cursor_row)
 8001        } else {
 8002            None
 8003        };
 8004        let supports_jump = self
 8005            .edit_prediction_provider
 8006            .as_ref()
 8007            .map(|provider| provider.provider.supports_jump_to_edit())
 8008            .unwrap_or(true);
 8009
 8010        let is_move = supports_jump
 8011            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8012        let completion = if is_move {
 8013            invalidation_row_range =
 8014                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8015            let target = first_edit_start;
 8016            EditPrediction::MoveWithin { target, snapshot }
 8017        } else {
 8018            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8019                && !self.edit_predictions_hidden_for_vim_mode;
 8020
 8021            if show_completions_in_buffer {
 8022                if edits
 8023                    .iter()
 8024                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8025                {
 8026                    let mut inlays = Vec::new();
 8027                    for (range, new_text) in &edits {
 8028                        let inlay = Inlay::edit_prediction(
 8029                            post_inc(&mut self.next_inlay_id),
 8030                            range.start,
 8031                            new_text.as_str(),
 8032                        );
 8033                        inlay_ids.push(inlay.id);
 8034                        inlays.push(inlay);
 8035                    }
 8036
 8037                    self.splice_inlays(&[], inlays, cx);
 8038                } else {
 8039                    let background_color = cx.theme().status().deleted_background;
 8040                    self.highlight_text::<EditPredictionHighlight>(
 8041                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8042                        HighlightStyle {
 8043                            background_color: Some(background_color),
 8044                            ..Default::default()
 8045                        },
 8046                        cx,
 8047                    );
 8048                }
 8049            }
 8050
 8051            invalidation_row_range = edit_start_row..edit_end_row;
 8052
 8053            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8054                if provider.show_tab_accept_marker() {
 8055                    EditDisplayMode::TabAccept
 8056                } else {
 8057                    EditDisplayMode::Inline
 8058                }
 8059            } else {
 8060                EditDisplayMode::DiffPopover
 8061            };
 8062
 8063            EditPrediction::Edit {
 8064                edits,
 8065                edit_preview,
 8066                display_mode,
 8067                snapshot,
 8068            }
 8069        };
 8070
 8071        let invalidation_range = multibuffer
 8072            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8073            ..multibuffer.anchor_after(Point::new(
 8074                invalidation_row_range.end,
 8075                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8076            ));
 8077
 8078        self.stale_edit_prediction_in_menu = None;
 8079        self.active_edit_prediction = Some(EditPredictionState {
 8080            inlay_ids,
 8081            completion,
 8082            completion_id,
 8083            invalidation_range: Some(invalidation_range),
 8084        });
 8085
 8086        cx.notify();
 8087
 8088        Some(())
 8089    }
 8090
 8091    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8092        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8093    }
 8094
 8095    fn clear_tasks(&mut self) {
 8096        self.tasks.clear()
 8097    }
 8098
 8099    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8100        if self.tasks.insert(key, value).is_some() {
 8101            // This case should hopefully be rare, but just in case...
 8102            log::error!(
 8103                "multiple different run targets found on a single line, only the last target will be rendered"
 8104            )
 8105        }
 8106    }
 8107
 8108    /// Get all display points of breakpoints that will be rendered within editor
 8109    ///
 8110    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8111    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8112    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8113    fn active_breakpoints(
 8114        &self,
 8115        range: Range<DisplayRow>,
 8116        window: &mut Window,
 8117        cx: &mut Context<Self>,
 8118    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8119        let mut breakpoint_display_points = HashMap::default();
 8120
 8121        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8122            return breakpoint_display_points;
 8123        };
 8124
 8125        let snapshot = self.snapshot(window, cx);
 8126
 8127        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8128        let Some(project) = self.project() else {
 8129            return breakpoint_display_points;
 8130        };
 8131
 8132        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8133            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8134
 8135        for (buffer_snapshot, range, excerpt_id) in
 8136            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8137        {
 8138            let Some(buffer) = project
 8139                .read(cx)
 8140                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8141            else {
 8142                continue;
 8143            };
 8144            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8145                &buffer,
 8146                Some(
 8147                    buffer_snapshot.anchor_before(range.start)
 8148                        ..buffer_snapshot.anchor_after(range.end),
 8149                ),
 8150                buffer_snapshot,
 8151                cx,
 8152            );
 8153            for (breakpoint, state) in breakpoints {
 8154                let multi_buffer_anchor =
 8155                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8156                let position = multi_buffer_anchor
 8157                    .to_point(multi_buffer_snapshot)
 8158                    .to_display_point(&snapshot);
 8159
 8160                breakpoint_display_points.insert(
 8161                    position.row(),
 8162                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8163                );
 8164            }
 8165        }
 8166
 8167        breakpoint_display_points
 8168    }
 8169
 8170    fn breakpoint_context_menu(
 8171        &self,
 8172        anchor: Anchor,
 8173        window: &mut Window,
 8174        cx: &mut Context<Self>,
 8175    ) -> Entity<ui::ContextMenu> {
 8176        let weak_editor = cx.weak_entity();
 8177        let focus_handle = self.focus_handle(cx);
 8178
 8179        let row = self
 8180            .buffer
 8181            .read(cx)
 8182            .snapshot(cx)
 8183            .summary_for_anchor::<Point>(&anchor)
 8184            .row;
 8185
 8186        let breakpoint = self
 8187            .breakpoint_at_row(row, window, cx)
 8188            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8189
 8190        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8191            "Edit Log Breakpoint"
 8192        } else {
 8193            "Set Log Breakpoint"
 8194        };
 8195
 8196        let condition_breakpoint_msg = if breakpoint
 8197            .as_ref()
 8198            .is_some_and(|bp| bp.1.condition.is_some())
 8199        {
 8200            "Edit Condition Breakpoint"
 8201        } else {
 8202            "Set Condition Breakpoint"
 8203        };
 8204
 8205        let hit_condition_breakpoint_msg = if breakpoint
 8206            .as_ref()
 8207            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8208        {
 8209            "Edit Hit Condition Breakpoint"
 8210        } else {
 8211            "Set Hit Condition Breakpoint"
 8212        };
 8213
 8214        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8215            "Unset Breakpoint"
 8216        } else {
 8217            "Set Breakpoint"
 8218        };
 8219
 8220        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8221
 8222        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8223            BreakpointState::Enabled => Some("Disable"),
 8224            BreakpointState::Disabled => Some("Enable"),
 8225        });
 8226
 8227        let (anchor, breakpoint) =
 8228            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8229
 8230        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8231            menu.on_blur_subscription(Subscription::new(|| {}))
 8232                .context(focus_handle)
 8233                .when(run_to_cursor, |this| {
 8234                    let weak_editor = weak_editor.clone();
 8235                    this.entry("Run to cursor", None, move |window, cx| {
 8236                        weak_editor
 8237                            .update(cx, |editor, cx| {
 8238                                editor.change_selections(
 8239                                    SelectionEffects::no_scroll(),
 8240                                    window,
 8241                                    cx,
 8242                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8243                                );
 8244                            })
 8245                            .ok();
 8246
 8247                        window.dispatch_action(Box::new(RunToCursor), cx);
 8248                    })
 8249                    .separator()
 8250                })
 8251                .when_some(toggle_state_msg, |this, msg| {
 8252                    this.entry(msg, None, {
 8253                        let weak_editor = weak_editor.clone();
 8254                        let breakpoint = breakpoint.clone();
 8255                        move |_window, cx| {
 8256                            weak_editor
 8257                                .update(cx, |this, cx| {
 8258                                    this.edit_breakpoint_at_anchor(
 8259                                        anchor,
 8260                                        breakpoint.as_ref().clone(),
 8261                                        BreakpointEditAction::InvertState,
 8262                                        cx,
 8263                                    );
 8264                                })
 8265                                .log_err();
 8266                        }
 8267                    })
 8268                })
 8269                .entry(set_breakpoint_msg, None, {
 8270                    let weak_editor = weak_editor.clone();
 8271                    let breakpoint = breakpoint.clone();
 8272                    move |_window, cx| {
 8273                        weak_editor
 8274                            .update(cx, |this, cx| {
 8275                                this.edit_breakpoint_at_anchor(
 8276                                    anchor,
 8277                                    breakpoint.as_ref().clone(),
 8278                                    BreakpointEditAction::Toggle,
 8279                                    cx,
 8280                                );
 8281                            })
 8282                            .log_err();
 8283                    }
 8284                })
 8285                .entry(log_breakpoint_msg, None, {
 8286                    let breakpoint = breakpoint.clone();
 8287                    let weak_editor = weak_editor.clone();
 8288                    move |window, cx| {
 8289                        weak_editor
 8290                            .update(cx, |this, cx| {
 8291                                this.add_edit_breakpoint_block(
 8292                                    anchor,
 8293                                    breakpoint.as_ref(),
 8294                                    BreakpointPromptEditAction::Log,
 8295                                    window,
 8296                                    cx,
 8297                                );
 8298                            })
 8299                            .log_err();
 8300                    }
 8301                })
 8302                .entry(condition_breakpoint_msg, None, {
 8303                    let breakpoint = breakpoint.clone();
 8304                    let weak_editor = weak_editor.clone();
 8305                    move |window, cx| {
 8306                        weak_editor
 8307                            .update(cx, |this, cx| {
 8308                                this.add_edit_breakpoint_block(
 8309                                    anchor,
 8310                                    breakpoint.as_ref(),
 8311                                    BreakpointPromptEditAction::Condition,
 8312                                    window,
 8313                                    cx,
 8314                                );
 8315                            })
 8316                            .log_err();
 8317                    }
 8318                })
 8319                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8320                    weak_editor
 8321                        .update(cx, |this, cx| {
 8322                            this.add_edit_breakpoint_block(
 8323                                anchor,
 8324                                breakpoint.as_ref(),
 8325                                BreakpointPromptEditAction::HitCondition,
 8326                                window,
 8327                                cx,
 8328                            );
 8329                        })
 8330                        .log_err();
 8331                })
 8332        })
 8333    }
 8334
 8335    fn render_breakpoint(
 8336        &self,
 8337        position: Anchor,
 8338        row: DisplayRow,
 8339        breakpoint: &Breakpoint,
 8340        state: Option<BreakpointSessionState>,
 8341        cx: &mut Context<Self>,
 8342    ) -> IconButton {
 8343        let is_rejected = state.is_some_and(|s| !s.verified);
 8344        // Is it a breakpoint that shows up when hovering over gutter?
 8345        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8346            (false, false),
 8347            |PhantomBreakpointIndicator {
 8348                 is_active,
 8349                 display_row,
 8350                 collides_with_existing_breakpoint,
 8351             }| {
 8352                (
 8353                    is_active && display_row == row,
 8354                    collides_with_existing_breakpoint,
 8355                )
 8356            },
 8357        );
 8358
 8359        let (color, icon) = {
 8360            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8361                (false, false) => ui::IconName::DebugBreakpoint,
 8362                (true, false) => ui::IconName::DebugLogBreakpoint,
 8363                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8364                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8365            };
 8366
 8367            let color = if is_phantom {
 8368                Color::Hint
 8369            } else if is_rejected {
 8370                Color::Disabled
 8371            } else {
 8372                Color::Debugger
 8373            };
 8374
 8375            (color, icon)
 8376        };
 8377
 8378        let breakpoint = Arc::from(breakpoint.clone());
 8379
 8380        let alt_as_text = gpui::Keystroke {
 8381            modifiers: Modifiers::secondary_key(),
 8382            ..Default::default()
 8383        };
 8384        let primary_action_text = if breakpoint.is_disabled() {
 8385            "Enable breakpoint"
 8386        } else if is_phantom && !collides_with_existing {
 8387            "Set breakpoint"
 8388        } else {
 8389            "Unset breakpoint"
 8390        };
 8391        let focus_handle = self.focus_handle.clone();
 8392
 8393        let meta = if is_rejected {
 8394            SharedString::from("No executable code is associated with this line.")
 8395        } else if collides_with_existing && !breakpoint.is_disabled() {
 8396            SharedString::from(format!(
 8397                "{alt_as_text}-click to disable,\nright-click for more options."
 8398            ))
 8399        } else {
 8400            SharedString::from("Right-click for more options.")
 8401        };
 8402        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8403            .icon_size(IconSize::XSmall)
 8404            .size(ui::ButtonSize::None)
 8405            .when(is_rejected, |this| {
 8406                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8407            })
 8408            .icon_color(color)
 8409            .style(ButtonStyle::Transparent)
 8410            .on_click(cx.listener({
 8411                move |editor, event: &ClickEvent, window, cx| {
 8412                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8413                        BreakpointEditAction::InvertState
 8414                    } else {
 8415                        BreakpointEditAction::Toggle
 8416                    };
 8417
 8418                    window.focus(&editor.focus_handle(cx));
 8419                    editor.edit_breakpoint_at_anchor(
 8420                        position,
 8421                        breakpoint.as_ref().clone(),
 8422                        edit_action,
 8423                        cx,
 8424                    );
 8425                }
 8426            }))
 8427            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8428                editor.set_breakpoint_context_menu(
 8429                    row,
 8430                    Some(position),
 8431                    event.position(),
 8432                    window,
 8433                    cx,
 8434                );
 8435            }))
 8436            .tooltip(move |window, cx| {
 8437                Tooltip::with_meta_in(
 8438                    primary_action_text,
 8439                    Some(&ToggleBreakpoint),
 8440                    meta.clone(),
 8441                    &focus_handle,
 8442                    window,
 8443                    cx,
 8444                )
 8445            })
 8446    }
 8447
 8448    fn build_tasks_context(
 8449        project: &Entity<Project>,
 8450        buffer: &Entity<Buffer>,
 8451        buffer_row: u32,
 8452        tasks: &Arc<RunnableTasks>,
 8453        cx: &mut Context<Self>,
 8454    ) -> Task<Option<task::TaskContext>> {
 8455        let position = Point::new(buffer_row, tasks.column);
 8456        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8457        let location = Location {
 8458            buffer: buffer.clone(),
 8459            range: range_start..range_start,
 8460        };
 8461        // Fill in the environmental variables from the tree-sitter captures
 8462        let mut captured_task_variables = TaskVariables::default();
 8463        for (capture_name, value) in tasks.extra_variables.clone() {
 8464            captured_task_variables.insert(
 8465                task::VariableName::Custom(capture_name.into()),
 8466                value.clone(),
 8467            );
 8468        }
 8469        project.update(cx, |project, cx| {
 8470            project.task_store().update(cx, |task_store, cx| {
 8471                task_store.task_context_for_location(captured_task_variables, location, cx)
 8472            })
 8473        })
 8474    }
 8475
 8476    pub fn spawn_nearest_task(
 8477        &mut self,
 8478        action: &SpawnNearestTask,
 8479        window: &mut Window,
 8480        cx: &mut Context<Self>,
 8481    ) {
 8482        let Some((workspace, _)) = self.workspace.clone() else {
 8483            return;
 8484        };
 8485        let Some(project) = self.project.clone() else {
 8486            return;
 8487        };
 8488
 8489        // Try to find a closest, enclosing node using tree-sitter that has a task
 8490        let Some((buffer, buffer_row, tasks)) = self
 8491            .find_enclosing_node_task(cx)
 8492            // Or find the task that's closest in row-distance.
 8493            .or_else(|| self.find_closest_task(cx))
 8494        else {
 8495            return;
 8496        };
 8497
 8498        let reveal_strategy = action.reveal;
 8499        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8500        cx.spawn_in(window, async move |_, cx| {
 8501            let context = task_context.await?;
 8502            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8503
 8504            let resolved = &mut resolved_task.resolved;
 8505            resolved.reveal = reveal_strategy;
 8506
 8507            workspace
 8508                .update_in(cx, |workspace, window, cx| {
 8509                    workspace.schedule_resolved_task(
 8510                        task_source_kind,
 8511                        resolved_task,
 8512                        false,
 8513                        window,
 8514                        cx,
 8515                    );
 8516                })
 8517                .ok()
 8518        })
 8519        .detach();
 8520    }
 8521
 8522    fn find_closest_task(
 8523        &mut self,
 8524        cx: &mut Context<Self>,
 8525    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8526        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8527
 8528        let ((buffer_id, row), tasks) = self
 8529            .tasks
 8530            .iter()
 8531            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8532
 8533        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8534        let tasks = Arc::new(tasks.to_owned());
 8535        Some((buffer, *row, tasks))
 8536    }
 8537
 8538    fn find_enclosing_node_task(
 8539        &mut self,
 8540        cx: &mut Context<Self>,
 8541    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8542        let snapshot = self.buffer.read(cx).snapshot(cx);
 8543        let offset = self.selections.newest::<usize>(cx).head();
 8544        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8545        let buffer_id = excerpt.buffer().remote_id();
 8546
 8547        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8548        let mut cursor = layer.node().walk();
 8549
 8550        while cursor.goto_first_child_for_byte(offset).is_some() {
 8551            if cursor.node().end_byte() == offset {
 8552                cursor.goto_next_sibling();
 8553            }
 8554        }
 8555
 8556        // Ascend to the smallest ancestor that contains the range and has a task.
 8557        loop {
 8558            let node = cursor.node();
 8559            let node_range = node.byte_range();
 8560            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8561
 8562            // Check if this node contains our offset
 8563            if node_range.start <= offset && node_range.end >= offset {
 8564                // If it contains offset, check for task
 8565                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8566                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8567                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8568                }
 8569            }
 8570
 8571            if !cursor.goto_parent() {
 8572                break;
 8573            }
 8574        }
 8575        None
 8576    }
 8577
 8578    fn render_run_indicator(
 8579        &self,
 8580        _style: &EditorStyle,
 8581        is_active: bool,
 8582        row: DisplayRow,
 8583        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8584        cx: &mut Context<Self>,
 8585    ) -> IconButton {
 8586        let color = Color::Muted;
 8587        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8588
 8589        IconButton::new(
 8590            ("run_indicator", row.0 as usize),
 8591            ui::IconName::PlayOutlined,
 8592        )
 8593        .shape(ui::IconButtonShape::Square)
 8594        .icon_size(IconSize::XSmall)
 8595        .icon_color(color)
 8596        .toggle_state(is_active)
 8597        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8598            let quick_launch = match e {
 8599                ClickEvent::Keyboard(_) => true,
 8600                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8601            };
 8602
 8603            window.focus(&editor.focus_handle(cx));
 8604            editor.toggle_code_actions(
 8605                &ToggleCodeActions {
 8606                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8607                    quick_launch,
 8608                },
 8609                window,
 8610                cx,
 8611            );
 8612        }))
 8613        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8614            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8615        }))
 8616    }
 8617
 8618    pub fn context_menu_visible(&self) -> bool {
 8619        !self.edit_prediction_preview_is_active()
 8620            && self
 8621                .context_menu
 8622                .borrow()
 8623                .as_ref()
 8624                .is_some_and(|menu| menu.visible())
 8625    }
 8626
 8627    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8628        self.context_menu
 8629            .borrow()
 8630            .as_ref()
 8631            .map(|menu| menu.origin())
 8632    }
 8633
 8634    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8635        self.context_menu_options = Some(options);
 8636    }
 8637
 8638    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8639    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8640
 8641    fn render_edit_prediction_popover(
 8642        &mut self,
 8643        text_bounds: &Bounds<Pixels>,
 8644        content_origin: gpui::Point<Pixels>,
 8645        right_margin: Pixels,
 8646        editor_snapshot: &EditorSnapshot,
 8647        visible_row_range: Range<DisplayRow>,
 8648        scroll_top: ScrollOffset,
 8649        scroll_bottom: ScrollOffset,
 8650        line_layouts: &[LineWithInvisibles],
 8651        line_height: Pixels,
 8652        scroll_position: gpui::Point<ScrollOffset>,
 8653        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8654        newest_selection_head: Option<DisplayPoint>,
 8655        editor_width: Pixels,
 8656        style: &EditorStyle,
 8657        window: &mut Window,
 8658        cx: &mut App,
 8659    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8660        if self.mode().is_minimap() {
 8661            return None;
 8662        }
 8663        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8664
 8665        if self.edit_prediction_visible_in_cursor_popover(true) {
 8666            return None;
 8667        }
 8668
 8669        match &active_edit_prediction.completion {
 8670            EditPrediction::MoveWithin { target, .. } => {
 8671                let target_display_point = target.to_display_point(editor_snapshot);
 8672
 8673                if self.edit_prediction_requires_modifier() {
 8674                    if !self.edit_prediction_preview_is_active() {
 8675                        return None;
 8676                    }
 8677
 8678                    self.render_edit_prediction_modifier_jump_popover(
 8679                        text_bounds,
 8680                        content_origin,
 8681                        visible_row_range,
 8682                        line_layouts,
 8683                        line_height,
 8684                        scroll_pixel_position,
 8685                        newest_selection_head,
 8686                        target_display_point,
 8687                        window,
 8688                        cx,
 8689                    )
 8690                } else {
 8691                    self.render_edit_prediction_eager_jump_popover(
 8692                        text_bounds,
 8693                        content_origin,
 8694                        editor_snapshot,
 8695                        visible_row_range,
 8696                        scroll_top,
 8697                        scroll_bottom,
 8698                        line_height,
 8699                        scroll_pixel_position,
 8700                        target_display_point,
 8701                        editor_width,
 8702                        window,
 8703                        cx,
 8704                    )
 8705                }
 8706            }
 8707            EditPrediction::Edit {
 8708                display_mode: EditDisplayMode::Inline,
 8709                ..
 8710            } => None,
 8711            EditPrediction::Edit {
 8712                display_mode: EditDisplayMode::TabAccept,
 8713                edits,
 8714                ..
 8715            } => {
 8716                let range = &edits.first()?.0;
 8717                let target_display_point = range.end.to_display_point(editor_snapshot);
 8718
 8719                self.render_edit_prediction_end_of_line_popover(
 8720                    "Accept",
 8721                    editor_snapshot,
 8722                    visible_row_range,
 8723                    target_display_point,
 8724                    line_height,
 8725                    scroll_pixel_position,
 8726                    content_origin,
 8727                    editor_width,
 8728                    window,
 8729                    cx,
 8730                )
 8731            }
 8732            EditPrediction::Edit {
 8733                edits,
 8734                edit_preview,
 8735                display_mode: EditDisplayMode::DiffPopover,
 8736                snapshot,
 8737            } => self.render_edit_prediction_diff_popover(
 8738                text_bounds,
 8739                content_origin,
 8740                right_margin,
 8741                editor_snapshot,
 8742                visible_row_range,
 8743                line_layouts,
 8744                line_height,
 8745                scroll_position,
 8746                scroll_pixel_position,
 8747                newest_selection_head,
 8748                editor_width,
 8749                style,
 8750                edits,
 8751                edit_preview,
 8752                snapshot,
 8753                window,
 8754                cx,
 8755            ),
 8756            EditPrediction::MoveOutside { snapshot, .. } => {
 8757                let file_name = snapshot
 8758                    .file()
 8759                    .map(|file| file.file_name(cx))
 8760                    .unwrap_or("untitled");
 8761                let mut element = self
 8762                    .render_edit_prediction_line_popover(
 8763                        format!("Jump to {file_name}"),
 8764                        Some(IconName::ZedPredict),
 8765                        window,
 8766                        cx,
 8767                    )
 8768                    .into_any();
 8769
 8770                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8771                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8772                let origin_y = text_bounds.size.height - size.height - px(30.);
 8773                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8774                element.prepaint_at(origin, window, cx);
 8775
 8776                Some((element, origin))
 8777            }
 8778        }
 8779    }
 8780
 8781    fn render_edit_prediction_modifier_jump_popover(
 8782        &mut self,
 8783        text_bounds: &Bounds<Pixels>,
 8784        content_origin: gpui::Point<Pixels>,
 8785        visible_row_range: Range<DisplayRow>,
 8786        line_layouts: &[LineWithInvisibles],
 8787        line_height: Pixels,
 8788        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8789        newest_selection_head: Option<DisplayPoint>,
 8790        target_display_point: DisplayPoint,
 8791        window: &mut Window,
 8792        cx: &mut App,
 8793    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8794        let scrolled_content_origin =
 8795            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8796
 8797        const SCROLL_PADDING_Y: Pixels = px(12.);
 8798
 8799        if target_display_point.row() < visible_row_range.start {
 8800            return self.render_edit_prediction_scroll_popover(
 8801                |_| SCROLL_PADDING_Y,
 8802                IconName::ArrowUp,
 8803                visible_row_range,
 8804                line_layouts,
 8805                newest_selection_head,
 8806                scrolled_content_origin,
 8807                window,
 8808                cx,
 8809            );
 8810        } else if target_display_point.row() >= visible_row_range.end {
 8811            return self.render_edit_prediction_scroll_popover(
 8812                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8813                IconName::ArrowDown,
 8814                visible_row_range,
 8815                line_layouts,
 8816                newest_selection_head,
 8817                scrolled_content_origin,
 8818                window,
 8819                cx,
 8820            );
 8821        }
 8822
 8823        const POLE_WIDTH: Pixels = px(2.);
 8824
 8825        let line_layout =
 8826            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8827        let target_column = target_display_point.column() as usize;
 8828
 8829        let target_x = line_layout.x_for_index(target_column);
 8830        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8831            - scroll_pixel_position.y;
 8832
 8833        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8834
 8835        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8836        border_color.l += 0.001;
 8837
 8838        let mut element = v_flex()
 8839            .items_end()
 8840            .when(flag_on_right, |el| el.items_start())
 8841            .child(if flag_on_right {
 8842                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8843                    .rounded_bl(px(0.))
 8844                    .rounded_tl(px(0.))
 8845                    .border_l_2()
 8846                    .border_color(border_color)
 8847            } else {
 8848                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8849                    .rounded_br(px(0.))
 8850                    .rounded_tr(px(0.))
 8851                    .border_r_2()
 8852                    .border_color(border_color)
 8853            })
 8854            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8855            .into_any();
 8856
 8857        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8858
 8859        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8860            - point(
 8861                if flag_on_right {
 8862                    POLE_WIDTH
 8863                } else {
 8864                    size.width - POLE_WIDTH
 8865                },
 8866                size.height - line_height,
 8867            );
 8868
 8869        origin.x = origin.x.max(content_origin.x);
 8870
 8871        element.prepaint_at(origin, window, cx);
 8872
 8873        Some((element, origin))
 8874    }
 8875
 8876    fn render_edit_prediction_scroll_popover(
 8877        &mut self,
 8878        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8879        scroll_icon: IconName,
 8880        visible_row_range: Range<DisplayRow>,
 8881        line_layouts: &[LineWithInvisibles],
 8882        newest_selection_head: Option<DisplayPoint>,
 8883        scrolled_content_origin: gpui::Point<Pixels>,
 8884        window: &mut Window,
 8885        cx: &mut App,
 8886    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8887        let mut element = self
 8888            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8889            .into_any();
 8890
 8891        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8892
 8893        let cursor = newest_selection_head?;
 8894        let cursor_row_layout =
 8895            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8896        let cursor_column = cursor.column() as usize;
 8897
 8898        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8899
 8900        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8901
 8902        element.prepaint_at(origin, window, cx);
 8903        Some((element, origin))
 8904    }
 8905
 8906    fn render_edit_prediction_eager_jump_popover(
 8907        &mut self,
 8908        text_bounds: &Bounds<Pixels>,
 8909        content_origin: gpui::Point<Pixels>,
 8910        editor_snapshot: &EditorSnapshot,
 8911        visible_row_range: Range<DisplayRow>,
 8912        scroll_top: ScrollOffset,
 8913        scroll_bottom: ScrollOffset,
 8914        line_height: Pixels,
 8915        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8916        target_display_point: DisplayPoint,
 8917        editor_width: Pixels,
 8918        window: &mut Window,
 8919        cx: &mut App,
 8920    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8921        if target_display_point.row().as_f64() < scroll_top {
 8922            let mut element = self
 8923                .render_edit_prediction_line_popover(
 8924                    "Jump to Edit",
 8925                    Some(IconName::ArrowUp),
 8926                    window,
 8927                    cx,
 8928                )
 8929                .into_any();
 8930
 8931            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8932            let offset = point(
 8933                (text_bounds.size.width - size.width) / 2.,
 8934                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8935            );
 8936
 8937            let origin = text_bounds.origin + offset;
 8938            element.prepaint_at(origin, window, cx);
 8939            Some((element, origin))
 8940        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8941            let mut element = self
 8942                .render_edit_prediction_line_popover(
 8943                    "Jump to Edit",
 8944                    Some(IconName::ArrowDown),
 8945                    window,
 8946                    cx,
 8947                )
 8948                .into_any();
 8949
 8950            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8951            let offset = point(
 8952                (text_bounds.size.width - size.width) / 2.,
 8953                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8954            );
 8955
 8956            let origin = text_bounds.origin + offset;
 8957            element.prepaint_at(origin, window, cx);
 8958            Some((element, origin))
 8959        } else {
 8960            self.render_edit_prediction_end_of_line_popover(
 8961                "Jump to Edit",
 8962                editor_snapshot,
 8963                visible_row_range,
 8964                target_display_point,
 8965                line_height,
 8966                scroll_pixel_position,
 8967                content_origin,
 8968                editor_width,
 8969                window,
 8970                cx,
 8971            )
 8972        }
 8973    }
 8974
 8975    fn render_edit_prediction_end_of_line_popover(
 8976        self: &mut Editor,
 8977        label: &'static str,
 8978        editor_snapshot: &EditorSnapshot,
 8979        visible_row_range: Range<DisplayRow>,
 8980        target_display_point: DisplayPoint,
 8981        line_height: Pixels,
 8982        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8983        content_origin: gpui::Point<Pixels>,
 8984        editor_width: Pixels,
 8985        window: &mut Window,
 8986        cx: &mut App,
 8987    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8988        let target_line_end = DisplayPoint::new(
 8989            target_display_point.row(),
 8990            editor_snapshot.line_len(target_display_point.row()),
 8991        );
 8992
 8993        let mut element = self
 8994            .render_edit_prediction_line_popover(label, None, window, cx)
 8995            .into_any();
 8996
 8997        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8998
 8999        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9000
 9001        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9002        let mut origin = start_point
 9003            + line_origin
 9004            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9005        origin.x = origin.x.max(content_origin.x);
 9006
 9007        let max_x = content_origin.x + editor_width - size.width;
 9008
 9009        if origin.x > max_x {
 9010            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9011
 9012            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9013                origin.y += offset;
 9014                IconName::ArrowUp
 9015            } else {
 9016                origin.y -= offset;
 9017                IconName::ArrowDown
 9018            };
 9019
 9020            element = self
 9021                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9022                .into_any();
 9023
 9024            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9025
 9026            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9027        }
 9028
 9029        element.prepaint_at(origin, window, cx);
 9030        Some((element, origin))
 9031    }
 9032
 9033    fn render_edit_prediction_diff_popover(
 9034        self: &Editor,
 9035        text_bounds: &Bounds<Pixels>,
 9036        content_origin: gpui::Point<Pixels>,
 9037        right_margin: Pixels,
 9038        editor_snapshot: &EditorSnapshot,
 9039        visible_row_range: Range<DisplayRow>,
 9040        line_layouts: &[LineWithInvisibles],
 9041        line_height: Pixels,
 9042        scroll_position: gpui::Point<ScrollOffset>,
 9043        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9044        newest_selection_head: Option<DisplayPoint>,
 9045        editor_width: Pixels,
 9046        style: &EditorStyle,
 9047        edits: &Vec<(Range<Anchor>, String)>,
 9048        edit_preview: &Option<language::EditPreview>,
 9049        snapshot: &language::BufferSnapshot,
 9050        window: &mut Window,
 9051        cx: &mut App,
 9052    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9053        let edit_start = edits
 9054            .first()
 9055            .unwrap()
 9056            .0
 9057            .start
 9058            .to_display_point(editor_snapshot);
 9059        let edit_end = edits
 9060            .last()
 9061            .unwrap()
 9062            .0
 9063            .end
 9064            .to_display_point(editor_snapshot);
 9065
 9066        let is_visible = visible_row_range.contains(&edit_start.row())
 9067            || visible_row_range.contains(&edit_end.row());
 9068        if !is_visible {
 9069            return None;
 9070        }
 9071
 9072        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9073            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9074        } else {
 9075            // Fallback for providers without edit_preview
 9076            crate::edit_prediction_fallback_text(edits, cx)
 9077        };
 9078
 9079        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9080        let line_count = highlighted_edits.text.lines().count();
 9081
 9082        const BORDER_WIDTH: Pixels = px(1.);
 9083
 9084        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9085        let has_keybind = keybind.is_some();
 9086
 9087        let mut element = h_flex()
 9088            .items_start()
 9089            .child(
 9090                h_flex()
 9091                    .bg(cx.theme().colors().editor_background)
 9092                    .border(BORDER_WIDTH)
 9093                    .shadow_xs()
 9094                    .border_color(cx.theme().colors().border)
 9095                    .rounded_l_lg()
 9096                    .when(line_count > 1, |el| el.rounded_br_lg())
 9097                    .pr_1()
 9098                    .child(styled_text),
 9099            )
 9100            .child(
 9101                h_flex()
 9102                    .h(line_height + BORDER_WIDTH * 2.)
 9103                    .px_1p5()
 9104                    .gap_1()
 9105                    // Workaround: For some reason, there's a gap if we don't do this
 9106                    .ml(-BORDER_WIDTH)
 9107                    .shadow(vec![gpui::BoxShadow {
 9108                        color: gpui::black().opacity(0.05),
 9109                        offset: point(px(1.), px(1.)),
 9110                        blur_radius: px(2.),
 9111                        spread_radius: px(0.),
 9112                    }])
 9113                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9114                    .border(BORDER_WIDTH)
 9115                    .border_color(cx.theme().colors().border)
 9116                    .rounded_r_lg()
 9117                    .id("edit_prediction_diff_popover_keybind")
 9118                    .when(!has_keybind, |el| {
 9119                        let status_colors = cx.theme().status();
 9120
 9121                        el.bg(status_colors.error_background)
 9122                            .border_color(status_colors.error.opacity(0.6))
 9123                            .child(Icon::new(IconName::Info).color(Color::Error))
 9124                            .cursor_default()
 9125                            .hoverable_tooltip(move |_window, cx| {
 9126                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9127                            })
 9128                    })
 9129                    .children(keybind),
 9130            )
 9131            .into_any();
 9132
 9133        let longest_row =
 9134            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9135        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9136            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9137        } else {
 9138            layout_line(
 9139                longest_row,
 9140                editor_snapshot,
 9141                style,
 9142                editor_width,
 9143                |_| false,
 9144                window,
 9145                cx,
 9146            )
 9147            .width
 9148        };
 9149
 9150        let viewport_bounds =
 9151            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9152                right: -right_margin,
 9153                ..Default::default()
 9154            });
 9155
 9156        let x_after_longest = Pixels::from(
 9157            ScrollPixelOffset::from(
 9158                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9159            ) - scroll_pixel_position.x,
 9160        );
 9161
 9162        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9163
 9164        // Fully visible if it can be displayed within the window (allow overlapping other
 9165        // panes). However, this is only allowed if the popover starts within text_bounds.
 9166        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9167            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9168
 9169        let mut origin = if can_position_to_the_right {
 9170            point(
 9171                x_after_longest,
 9172                text_bounds.origin.y
 9173                    + Pixels::from(
 9174                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9175                            - scroll_pixel_position.y,
 9176                    ),
 9177            )
 9178        } else {
 9179            let cursor_row = newest_selection_head.map(|head| head.row());
 9180            let above_edit = edit_start
 9181                .row()
 9182                .0
 9183                .checked_sub(line_count as u32)
 9184                .map(DisplayRow);
 9185            let below_edit = Some(edit_end.row() + 1);
 9186            let above_cursor =
 9187                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9188            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9189
 9190            // Place the edit popover adjacent to the edit if there is a location
 9191            // available that is onscreen and does not obscure the cursor. Otherwise,
 9192            // place it adjacent to the cursor.
 9193            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9194                .into_iter()
 9195                .flatten()
 9196                .find(|&start_row| {
 9197                    let end_row = start_row + line_count as u32;
 9198                    visible_row_range.contains(&start_row)
 9199                        && visible_row_range.contains(&end_row)
 9200                        && cursor_row
 9201                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9202                })?;
 9203
 9204            content_origin
 9205                + point(
 9206                    Pixels::from(-scroll_pixel_position.x),
 9207                    Pixels::from(
 9208                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9209                    ),
 9210                )
 9211        };
 9212
 9213        origin.x -= BORDER_WIDTH;
 9214
 9215        window.defer_draw(element, origin, 1);
 9216
 9217        // Do not return an element, since it will already be drawn due to defer_draw.
 9218        None
 9219    }
 9220
 9221    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9222        px(30.)
 9223    }
 9224
 9225    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9226        if self.read_only(cx) {
 9227            cx.theme().players().read_only()
 9228        } else {
 9229            self.style.as_ref().unwrap().local_player
 9230        }
 9231    }
 9232
 9233    fn render_edit_prediction_accept_keybind(
 9234        &self,
 9235        window: &mut Window,
 9236        cx: &App,
 9237    ) -> Option<AnyElement> {
 9238        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9239        let accept_keystroke = accept_binding.keystroke()?;
 9240
 9241        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9242
 9243        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9244            Color::Accent
 9245        } else {
 9246            Color::Muted
 9247        };
 9248
 9249        h_flex()
 9250            .px_0p5()
 9251            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9252            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9253            .text_size(TextSize::XSmall.rems(cx))
 9254            .child(h_flex().children(ui::render_modifiers(
 9255                accept_keystroke.modifiers(),
 9256                PlatformStyle::platform(),
 9257                Some(modifiers_color),
 9258                Some(IconSize::XSmall.rems().into()),
 9259                true,
 9260            )))
 9261            .when(is_platform_style_mac, |parent| {
 9262                parent.child(accept_keystroke.key().to_string())
 9263            })
 9264            .when(!is_platform_style_mac, |parent| {
 9265                parent.child(
 9266                    Key::new(
 9267                        util::capitalize(accept_keystroke.key()),
 9268                        Some(Color::Default),
 9269                    )
 9270                    .size(Some(IconSize::XSmall.rems().into())),
 9271                )
 9272            })
 9273            .into_any()
 9274            .into()
 9275    }
 9276
 9277    fn render_edit_prediction_line_popover(
 9278        &self,
 9279        label: impl Into<SharedString>,
 9280        icon: Option<IconName>,
 9281        window: &mut Window,
 9282        cx: &App,
 9283    ) -> Stateful<Div> {
 9284        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9285
 9286        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9287        let has_keybind = keybind.is_some();
 9288
 9289        h_flex()
 9290            .id("ep-line-popover")
 9291            .py_0p5()
 9292            .pl_1()
 9293            .pr(padding_right)
 9294            .gap_1()
 9295            .rounded_md()
 9296            .border_1()
 9297            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9298            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9299            .shadow_xs()
 9300            .when(!has_keybind, |el| {
 9301                let status_colors = cx.theme().status();
 9302
 9303                el.bg(status_colors.error_background)
 9304                    .border_color(status_colors.error.opacity(0.6))
 9305                    .pl_2()
 9306                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9307                    .cursor_default()
 9308                    .hoverable_tooltip(move |_window, cx| {
 9309                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9310                    })
 9311            })
 9312            .children(keybind)
 9313            .child(
 9314                Label::new(label)
 9315                    .size(LabelSize::Small)
 9316                    .when(!has_keybind, |el| {
 9317                        el.color(cx.theme().status().error.into()).strikethrough()
 9318                    }),
 9319            )
 9320            .when(!has_keybind, |el| {
 9321                el.child(
 9322                    h_flex().ml_1().child(
 9323                        Icon::new(IconName::Info)
 9324                            .size(IconSize::Small)
 9325                            .color(cx.theme().status().error.into()),
 9326                    ),
 9327                )
 9328            })
 9329            .when_some(icon, |element, icon| {
 9330                element.child(
 9331                    div()
 9332                        .mt(px(1.5))
 9333                        .child(Icon::new(icon).size(IconSize::Small)),
 9334                )
 9335            })
 9336    }
 9337
 9338    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9339        let accent_color = cx.theme().colors().text_accent;
 9340        let editor_bg_color = cx.theme().colors().editor_background;
 9341        editor_bg_color.blend(accent_color.opacity(0.1))
 9342    }
 9343
 9344    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9345        let accent_color = cx.theme().colors().text_accent;
 9346        let editor_bg_color = cx.theme().colors().editor_background;
 9347        editor_bg_color.blend(accent_color.opacity(0.6))
 9348    }
 9349    fn get_prediction_provider_icon_name(
 9350        provider: &Option<RegisteredEditPredictionProvider>,
 9351    ) -> IconName {
 9352        match provider {
 9353            Some(provider) => match provider.provider.name() {
 9354                "copilot" => IconName::Copilot,
 9355                "supermaven" => IconName::Supermaven,
 9356                _ => IconName::ZedPredict,
 9357            },
 9358            None => IconName::ZedPredict,
 9359        }
 9360    }
 9361
 9362    fn render_edit_prediction_cursor_popover(
 9363        &self,
 9364        min_width: Pixels,
 9365        max_width: Pixels,
 9366        cursor_point: Point,
 9367        style: &EditorStyle,
 9368        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9369        _window: &Window,
 9370        cx: &mut Context<Editor>,
 9371    ) -> Option<AnyElement> {
 9372        let provider = self.edit_prediction_provider.as_ref()?;
 9373        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9374
 9375        let is_refreshing = provider.provider.is_refreshing(cx);
 9376
 9377        fn pending_completion_container(icon: IconName) -> Div {
 9378            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9379        }
 9380
 9381        let completion = match &self.active_edit_prediction {
 9382            Some(prediction) => {
 9383                if !self.has_visible_completions_menu() {
 9384                    const RADIUS: Pixels = px(6.);
 9385                    const BORDER_WIDTH: Pixels = px(1.);
 9386
 9387                    return Some(
 9388                        h_flex()
 9389                            .elevation_2(cx)
 9390                            .border(BORDER_WIDTH)
 9391                            .border_color(cx.theme().colors().border)
 9392                            .when(accept_keystroke.is_none(), |el| {
 9393                                el.border_color(cx.theme().status().error)
 9394                            })
 9395                            .rounded(RADIUS)
 9396                            .rounded_tl(px(0.))
 9397                            .overflow_hidden()
 9398                            .child(div().px_1p5().child(match &prediction.completion {
 9399                                EditPrediction::MoveWithin { target, snapshot } => {
 9400                                    use text::ToPoint as _;
 9401                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9402                                    {
 9403                                        Icon::new(IconName::ZedPredictDown)
 9404                                    } else {
 9405                                        Icon::new(IconName::ZedPredictUp)
 9406                                    }
 9407                                }
 9408                                EditPrediction::MoveOutside { .. } => {
 9409                                    // TODO [zeta2] custom icon for external jump?
 9410                                    Icon::new(provider_icon)
 9411                                }
 9412                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9413                            }))
 9414                            .child(
 9415                                h_flex()
 9416                                    .gap_1()
 9417                                    .py_1()
 9418                                    .px_2()
 9419                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9420                                    .border_l_1()
 9421                                    .border_color(cx.theme().colors().border)
 9422                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9423                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9424                                        el.child(
 9425                                            Label::new("Hold")
 9426                                                .size(LabelSize::Small)
 9427                                                .when(accept_keystroke.is_none(), |el| {
 9428                                                    el.strikethrough()
 9429                                                })
 9430                                                .line_height_style(LineHeightStyle::UiLabel),
 9431                                        )
 9432                                    })
 9433                                    .id("edit_prediction_cursor_popover_keybind")
 9434                                    .when(accept_keystroke.is_none(), |el| {
 9435                                        let status_colors = cx.theme().status();
 9436
 9437                                        el.bg(status_colors.error_background)
 9438                                            .border_color(status_colors.error.opacity(0.6))
 9439                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9440                                            .cursor_default()
 9441                                            .hoverable_tooltip(move |_window, cx| {
 9442                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9443                                                    .into()
 9444                                            })
 9445                                    })
 9446                                    .when_some(
 9447                                        accept_keystroke.as_ref(),
 9448                                        |el, accept_keystroke| {
 9449                                            el.child(h_flex().children(ui::render_modifiers(
 9450                                                accept_keystroke.modifiers(),
 9451                                                PlatformStyle::platform(),
 9452                                                Some(Color::Default),
 9453                                                Some(IconSize::XSmall.rems().into()),
 9454                                                false,
 9455                                            )))
 9456                                        },
 9457                                    ),
 9458                            )
 9459                            .into_any(),
 9460                    );
 9461                }
 9462
 9463                self.render_edit_prediction_cursor_popover_preview(
 9464                    prediction,
 9465                    cursor_point,
 9466                    style,
 9467                    cx,
 9468                )?
 9469            }
 9470
 9471            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9472                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9473                    stale_completion,
 9474                    cursor_point,
 9475                    style,
 9476                    cx,
 9477                )?,
 9478
 9479                None => pending_completion_container(provider_icon)
 9480                    .child(Label::new("...").size(LabelSize::Small)),
 9481            },
 9482
 9483            None => pending_completion_container(provider_icon)
 9484                .child(Label::new("...").size(LabelSize::Small)),
 9485        };
 9486
 9487        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9488            completion
 9489                .with_animation(
 9490                    "loading-completion",
 9491                    Animation::new(Duration::from_secs(2))
 9492                        .repeat()
 9493                        .with_easing(pulsating_between(0.4, 0.8)),
 9494                    |label, delta| label.opacity(delta),
 9495                )
 9496                .into_any_element()
 9497        } else {
 9498            completion.into_any_element()
 9499        };
 9500
 9501        let has_completion = self.active_edit_prediction.is_some();
 9502
 9503        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9504        Some(
 9505            h_flex()
 9506                .min_w(min_width)
 9507                .max_w(max_width)
 9508                .flex_1()
 9509                .elevation_2(cx)
 9510                .border_color(cx.theme().colors().border)
 9511                .child(
 9512                    div()
 9513                        .flex_1()
 9514                        .py_1()
 9515                        .px_2()
 9516                        .overflow_hidden()
 9517                        .child(completion),
 9518                )
 9519                .when_some(accept_keystroke, |el, accept_keystroke| {
 9520                    if !accept_keystroke.modifiers().modified() {
 9521                        return el;
 9522                    }
 9523
 9524                    el.child(
 9525                        h_flex()
 9526                            .h_full()
 9527                            .border_l_1()
 9528                            .rounded_r_lg()
 9529                            .border_color(cx.theme().colors().border)
 9530                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9531                            .gap_1()
 9532                            .py_1()
 9533                            .px_2()
 9534                            .child(
 9535                                h_flex()
 9536                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9537                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9538                                    .child(h_flex().children(ui::render_modifiers(
 9539                                        accept_keystroke.modifiers(),
 9540                                        PlatformStyle::platform(),
 9541                                        Some(if !has_completion {
 9542                                            Color::Muted
 9543                                        } else {
 9544                                            Color::Default
 9545                                        }),
 9546                                        None,
 9547                                        false,
 9548                                    ))),
 9549                            )
 9550                            .child(Label::new("Preview").into_any_element())
 9551                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9552                    )
 9553                })
 9554                .into_any(),
 9555        )
 9556    }
 9557
 9558    fn render_edit_prediction_cursor_popover_preview(
 9559        &self,
 9560        completion: &EditPredictionState,
 9561        cursor_point: Point,
 9562        style: &EditorStyle,
 9563        cx: &mut Context<Editor>,
 9564    ) -> Option<Div> {
 9565        use text::ToPoint as _;
 9566
 9567        fn render_relative_row_jump(
 9568            prefix: impl Into<String>,
 9569            current_row: u32,
 9570            target_row: u32,
 9571        ) -> Div {
 9572            let (row_diff, arrow) = if target_row < current_row {
 9573                (current_row - target_row, IconName::ArrowUp)
 9574            } else {
 9575                (target_row - current_row, IconName::ArrowDown)
 9576            };
 9577
 9578            h_flex()
 9579                .child(
 9580                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9581                        .color(Color::Muted)
 9582                        .size(LabelSize::Small),
 9583                )
 9584                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9585        }
 9586
 9587        let supports_jump = self
 9588            .edit_prediction_provider
 9589            .as_ref()
 9590            .map(|provider| provider.provider.supports_jump_to_edit())
 9591            .unwrap_or(true);
 9592
 9593        match &completion.completion {
 9594            EditPrediction::MoveWithin {
 9595                target, snapshot, ..
 9596            } => {
 9597                if !supports_jump {
 9598                    return None;
 9599                }
 9600
 9601                Some(
 9602                    h_flex()
 9603                        .px_2()
 9604                        .gap_2()
 9605                        .flex_1()
 9606                        .child(
 9607                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9608                                Icon::new(IconName::ZedPredictDown)
 9609                            } else {
 9610                                Icon::new(IconName::ZedPredictUp)
 9611                            },
 9612                        )
 9613                        .child(Label::new("Jump to Edit")),
 9614                )
 9615            }
 9616            EditPrediction::MoveOutside { snapshot, .. } => {
 9617                let file_name = snapshot
 9618                    .file()
 9619                    .map(|file| file.file_name(cx))
 9620                    .unwrap_or("untitled");
 9621                Some(
 9622                    h_flex()
 9623                        .px_2()
 9624                        .gap_2()
 9625                        .flex_1()
 9626                        .child(Icon::new(IconName::ZedPredict))
 9627                        .child(Label::new(format!("Jump to {file_name}"))),
 9628                )
 9629            }
 9630            EditPrediction::Edit {
 9631                edits,
 9632                edit_preview,
 9633                snapshot,
 9634                display_mode: _,
 9635            } => {
 9636                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9637
 9638                let (highlighted_edits, has_more_lines) =
 9639                    if let Some(edit_preview) = edit_preview.as_ref() {
 9640                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9641                            .first_line_preview()
 9642                    } else {
 9643                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9644                    };
 9645
 9646                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9647                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9648
 9649                let preview = h_flex()
 9650                    .gap_1()
 9651                    .min_w_16()
 9652                    .child(styled_text)
 9653                    .when(has_more_lines, |parent| parent.child(""));
 9654
 9655                let left = if supports_jump && first_edit_row != cursor_point.row {
 9656                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9657                        .into_any_element()
 9658                } else {
 9659                    let icon_name =
 9660                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9661                    Icon::new(icon_name).into_any_element()
 9662                };
 9663
 9664                Some(
 9665                    h_flex()
 9666                        .h_full()
 9667                        .flex_1()
 9668                        .gap_2()
 9669                        .pr_1()
 9670                        .overflow_x_hidden()
 9671                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9672                        .child(left)
 9673                        .child(preview),
 9674                )
 9675            }
 9676        }
 9677    }
 9678
 9679    pub fn render_context_menu(
 9680        &self,
 9681        style: &EditorStyle,
 9682        max_height_in_lines: u32,
 9683        window: &mut Window,
 9684        cx: &mut Context<Editor>,
 9685    ) -> Option<AnyElement> {
 9686        let menu = self.context_menu.borrow();
 9687        let menu = menu.as_ref()?;
 9688        if !menu.visible() {
 9689            return None;
 9690        };
 9691        Some(menu.render(style, max_height_in_lines, window, cx))
 9692    }
 9693
 9694    fn render_context_menu_aside(
 9695        &mut self,
 9696        max_size: Size<Pixels>,
 9697        window: &mut Window,
 9698        cx: &mut Context<Editor>,
 9699    ) -> Option<AnyElement> {
 9700        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9701            if menu.visible() {
 9702                menu.render_aside(max_size, window, cx)
 9703            } else {
 9704                None
 9705            }
 9706        })
 9707    }
 9708
 9709    fn hide_context_menu(
 9710        &mut self,
 9711        window: &mut Window,
 9712        cx: &mut Context<Self>,
 9713    ) -> Option<CodeContextMenu> {
 9714        cx.notify();
 9715        self.completion_tasks.clear();
 9716        let context_menu = self.context_menu.borrow_mut().take();
 9717        self.stale_edit_prediction_in_menu.take();
 9718        self.update_visible_edit_prediction(window, cx);
 9719        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9720            && let Some(completion_provider) = &self.completion_provider
 9721        {
 9722            completion_provider.selection_changed(None, window, cx);
 9723        }
 9724        context_menu
 9725    }
 9726
 9727    fn show_snippet_choices(
 9728        &mut self,
 9729        choices: &Vec<String>,
 9730        selection: Range<Anchor>,
 9731        cx: &mut Context<Self>,
 9732    ) {
 9733        let Some((_, buffer, _)) = self
 9734            .buffer()
 9735            .read(cx)
 9736            .excerpt_containing(selection.start, cx)
 9737        else {
 9738            return;
 9739        };
 9740        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9741        else {
 9742            return;
 9743        };
 9744        if buffer != end_buffer {
 9745            log::error!("expected anchor range to have matching buffer IDs");
 9746            return;
 9747        }
 9748
 9749        let id = post_inc(&mut self.next_completion_id);
 9750        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9751        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9752            CompletionsMenu::new_snippet_choices(
 9753                id,
 9754                true,
 9755                choices,
 9756                selection,
 9757                buffer,
 9758                snippet_sort_order,
 9759            ),
 9760        ));
 9761    }
 9762
 9763    pub fn insert_snippet(
 9764        &mut self,
 9765        insertion_ranges: &[Range<usize>],
 9766        snippet: Snippet,
 9767        window: &mut Window,
 9768        cx: &mut Context<Self>,
 9769    ) -> Result<()> {
 9770        struct Tabstop<T> {
 9771            is_end_tabstop: bool,
 9772            ranges: Vec<Range<T>>,
 9773            choices: Option<Vec<String>>,
 9774        }
 9775
 9776        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9777            let snippet_text: Arc<str> = snippet.text.clone().into();
 9778            let edits = insertion_ranges
 9779                .iter()
 9780                .cloned()
 9781                .map(|range| (range, snippet_text.clone()));
 9782            let autoindent_mode = AutoindentMode::Block {
 9783                original_indent_columns: Vec::new(),
 9784            };
 9785            buffer.edit(edits, Some(autoindent_mode), cx);
 9786
 9787            let snapshot = &*buffer.read(cx);
 9788            let snippet = &snippet;
 9789            snippet
 9790                .tabstops
 9791                .iter()
 9792                .map(|tabstop| {
 9793                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9794                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9795                    });
 9796                    let mut tabstop_ranges = tabstop
 9797                        .ranges
 9798                        .iter()
 9799                        .flat_map(|tabstop_range| {
 9800                            let mut delta = 0_isize;
 9801                            insertion_ranges.iter().map(move |insertion_range| {
 9802                                let insertion_start = insertion_range.start as isize + delta;
 9803                                delta +=
 9804                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9805
 9806                                let start = ((insertion_start + tabstop_range.start) as usize)
 9807                                    .min(snapshot.len());
 9808                                let end = ((insertion_start + tabstop_range.end) as usize)
 9809                                    .min(snapshot.len());
 9810                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9811                            })
 9812                        })
 9813                        .collect::<Vec<_>>();
 9814                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9815
 9816                    Tabstop {
 9817                        is_end_tabstop,
 9818                        ranges: tabstop_ranges,
 9819                        choices: tabstop.choices.clone(),
 9820                    }
 9821                })
 9822                .collect::<Vec<_>>()
 9823        });
 9824        if let Some(tabstop) = tabstops.first() {
 9825            self.change_selections(Default::default(), window, cx, |s| {
 9826                // Reverse order so that the first range is the newest created selection.
 9827                // Completions will use it and autoscroll will prioritize it.
 9828                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9829            });
 9830
 9831            if let Some(choices) = &tabstop.choices
 9832                && let Some(selection) = tabstop.ranges.first()
 9833            {
 9834                self.show_snippet_choices(choices, selection.clone(), cx)
 9835            }
 9836
 9837            // If we're already at the last tabstop and it's at the end of the snippet,
 9838            // we're done, we don't need to keep the state around.
 9839            if !tabstop.is_end_tabstop {
 9840                let choices = tabstops
 9841                    .iter()
 9842                    .map(|tabstop| tabstop.choices.clone())
 9843                    .collect();
 9844
 9845                let ranges = tabstops
 9846                    .into_iter()
 9847                    .map(|tabstop| tabstop.ranges)
 9848                    .collect::<Vec<_>>();
 9849
 9850                self.snippet_stack.push(SnippetState {
 9851                    active_index: 0,
 9852                    ranges,
 9853                    choices,
 9854                });
 9855            }
 9856
 9857            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9858            if self.autoclose_regions.is_empty() {
 9859                let snapshot = self.buffer.read(cx).snapshot(cx);
 9860                let mut all_selections = self.selections.all::<Point>(cx);
 9861                for selection in &mut all_selections {
 9862                    let selection_head = selection.head();
 9863                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9864                        continue;
 9865                    };
 9866
 9867                    let mut bracket_pair = None;
 9868                    let max_lookup_length = scope
 9869                        .brackets()
 9870                        .map(|(pair, _)| {
 9871                            pair.start
 9872                                .as_str()
 9873                                .chars()
 9874                                .count()
 9875                                .max(pair.end.as_str().chars().count())
 9876                        })
 9877                        .max();
 9878                    if let Some(max_lookup_length) = max_lookup_length {
 9879                        let next_text = snapshot
 9880                            .chars_at(selection_head)
 9881                            .take(max_lookup_length)
 9882                            .collect::<String>();
 9883                        let prev_text = snapshot
 9884                            .reversed_chars_at(selection_head)
 9885                            .take(max_lookup_length)
 9886                            .collect::<String>();
 9887
 9888                        for (pair, enabled) in scope.brackets() {
 9889                            if enabled
 9890                                && pair.close
 9891                                && prev_text.starts_with(pair.start.as_str())
 9892                                && next_text.starts_with(pair.end.as_str())
 9893                            {
 9894                                bracket_pair = Some(pair.clone());
 9895                                break;
 9896                            }
 9897                        }
 9898                    }
 9899
 9900                    if let Some(pair) = bracket_pair {
 9901                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9902                        let autoclose_enabled =
 9903                            self.use_autoclose && snapshot_settings.use_autoclose;
 9904                        if autoclose_enabled {
 9905                            let start = snapshot.anchor_after(selection_head);
 9906                            let end = snapshot.anchor_after(selection_head);
 9907                            self.autoclose_regions.push(AutocloseRegion {
 9908                                selection_id: selection.id,
 9909                                range: start..end,
 9910                                pair,
 9911                            });
 9912                        }
 9913                    }
 9914                }
 9915            }
 9916        }
 9917        Ok(())
 9918    }
 9919
 9920    pub fn move_to_next_snippet_tabstop(
 9921        &mut self,
 9922        window: &mut Window,
 9923        cx: &mut Context<Self>,
 9924    ) -> bool {
 9925        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9926    }
 9927
 9928    pub fn move_to_prev_snippet_tabstop(
 9929        &mut self,
 9930        window: &mut Window,
 9931        cx: &mut Context<Self>,
 9932    ) -> bool {
 9933        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9934    }
 9935
 9936    pub fn move_to_snippet_tabstop(
 9937        &mut self,
 9938        bias: Bias,
 9939        window: &mut Window,
 9940        cx: &mut Context<Self>,
 9941    ) -> bool {
 9942        if let Some(mut snippet) = self.snippet_stack.pop() {
 9943            match bias {
 9944                Bias::Left => {
 9945                    if snippet.active_index > 0 {
 9946                        snippet.active_index -= 1;
 9947                    } else {
 9948                        self.snippet_stack.push(snippet);
 9949                        return false;
 9950                    }
 9951                }
 9952                Bias::Right => {
 9953                    if snippet.active_index + 1 < snippet.ranges.len() {
 9954                        snippet.active_index += 1;
 9955                    } else {
 9956                        self.snippet_stack.push(snippet);
 9957                        return false;
 9958                    }
 9959                }
 9960            }
 9961            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9962                self.change_selections(Default::default(), window, cx, |s| {
 9963                    // Reverse order so that the first range is the newest created selection.
 9964                    // Completions will use it and autoscroll will prioritize it.
 9965                    s.select_ranges(current_ranges.iter().rev().cloned())
 9966                });
 9967
 9968                if let Some(choices) = &snippet.choices[snippet.active_index]
 9969                    && let Some(selection) = current_ranges.first()
 9970                {
 9971                    self.show_snippet_choices(choices, selection.clone(), cx);
 9972                }
 9973
 9974                // If snippet state is not at the last tabstop, push it back on the stack
 9975                if snippet.active_index + 1 < snippet.ranges.len() {
 9976                    self.snippet_stack.push(snippet);
 9977                }
 9978                return true;
 9979            }
 9980        }
 9981
 9982        false
 9983    }
 9984
 9985    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9986        self.transact(window, cx, |this, window, cx| {
 9987            this.select_all(&SelectAll, window, cx);
 9988            this.insert("", window, cx);
 9989        });
 9990    }
 9991
 9992    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9993        if self.read_only(cx) {
 9994            return;
 9995        }
 9996        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9997        self.transact(window, cx, |this, window, cx| {
 9998            this.select_autoclose_pair(window, cx);
 9999            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10000            if !this.linked_edit_ranges.is_empty() {
10001                let selections = this.selections.all::<MultiBufferPoint>(cx);
10002                let snapshot = this.buffer.read(cx).snapshot(cx);
10003
10004                for selection in selections.iter() {
10005                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10006                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10007                    if selection_start.buffer_id != selection_end.buffer_id {
10008                        continue;
10009                    }
10010                    if let Some(ranges) =
10011                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10012                    {
10013                        for (buffer, entries) in ranges {
10014                            linked_ranges.entry(buffer).or_default().extend(entries);
10015                        }
10016                    }
10017                }
10018            }
10019
10020            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10021            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10022            for selection in &mut selections {
10023                if selection.is_empty() {
10024                    let old_head = selection.head();
10025                    let mut new_head =
10026                        movement::left(&display_map, old_head.to_display_point(&display_map))
10027                            .to_point(&display_map);
10028                    if let Some((buffer, line_buffer_range)) = display_map
10029                        .buffer_snapshot()
10030                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10031                    {
10032                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10033                        let indent_len = match indent_size.kind {
10034                            IndentKind::Space => {
10035                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10036                            }
10037                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10038                        };
10039                        if old_head.column <= indent_size.len && old_head.column > 0 {
10040                            let indent_len = indent_len.get();
10041                            new_head = cmp::min(
10042                                new_head,
10043                                MultiBufferPoint::new(
10044                                    old_head.row,
10045                                    ((old_head.column - 1) / indent_len) * indent_len,
10046                                ),
10047                            );
10048                        }
10049                    }
10050
10051                    selection.set_head(new_head, SelectionGoal::None);
10052                }
10053            }
10054
10055            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10056            this.insert("", window, cx);
10057            let empty_str: Arc<str> = Arc::from("");
10058            for (buffer, edits) in linked_ranges {
10059                let snapshot = buffer.read(cx).snapshot();
10060                use text::ToPoint as TP;
10061
10062                let edits = edits
10063                    .into_iter()
10064                    .map(|range| {
10065                        let end_point = TP::to_point(&range.end, &snapshot);
10066                        let mut start_point = TP::to_point(&range.start, &snapshot);
10067
10068                        if end_point == start_point {
10069                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10070                                .saturating_sub(1);
10071                            start_point =
10072                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10073                        };
10074
10075                        (start_point..end_point, empty_str.clone())
10076                    })
10077                    .sorted_by_key(|(range, _)| range.start)
10078                    .collect::<Vec<_>>();
10079                buffer.update(cx, |this, cx| {
10080                    this.edit(edits, None, cx);
10081                })
10082            }
10083            this.refresh_edit_prediction(true, false, window, cx);
10084            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
10085        });
10086    }
10087
10088    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10089        if self.read_only(cx) {
10090            return;
10091        }
10092        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10093        self.transact(window, cx, |this, window, cx| {
10094            this.change_selections(Default::default(), window, cx, |s| {
10095                s.move_with(|map, selection| {
10096                    if selection.is_empty() {
10097                        let cursor = movement::right(map, selection.head());
10098                        selection.end = cursor;
10099                        selection.reversed = true;
10100                        selection.goal = SelectionGoal::None;
10101                    }
10102                })
10103            });
10104            this.insert("", window, cx);
10105            this.refresh_edit_prediction(true, false, window, cx);
10106        });
10107    }
10108
10109    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10110        if self.mode.is_single_line() {
10111            cx.propagate();
10112            return;
10113        }
10114
10115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10116        if self.move_to_prev_snippet_tabstop(window, cx) {
10117            return;
10118        }
10119        self.outdent(&Outdent, window, cx);
10120    }
10121
10122    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10123        if self.mode.is_single_line() {
10124            cx.propagate();
10125            return;
10126        }
10127
10128        if self.move_to_next_snippet_tabstop(window, cx) {
10129            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10130            return;
10131        }
10132        if self.read_only(cx) {
10133            return;
10134        }
10135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10136        let mut selections = self.selections.all_adjusted(cx);
10137        let buffer = self.buffer.read(cx);
10138        let snapshot = buffer.snapshot(cx);
10139        let rows_iter = selections.iter().map(|s| s.head().row);
10140        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10141
10142        let has_some_cursor_in_whitespace = selections
10143            .iter()
10144            .filter(|selection| selection.is_empty())
10145            .any(|selection| {
10146                let cursor = selection.head();
10147                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10148                cursor.column < current_indent.len
10149            });
10150
10151        let mut edits = Vec::new();
10152        let mut prev_edited_row = 0;
10153        let mut row_delta = 0;
10154        for selection in &mut selections {
10155            if selection.start.row != prev_edited_row {
10156                row_delta = 0;
10157            }
10158            prev_edited_row = selection.end.row;
10159
10160            // If the selection is non-empty, then increase the indentation of the selected lines.
10161            if !selection.is_empty() {
10162                row_delta =
10163                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10164                continue;
10165            }
10166
10167            let cursor = selection.head();
10168            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10169            if let Some(suggested_indent) =
10170                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10171            {
10172                // Don't do anything if already at suggested indent
10173                // and there is any other cursor which is not
10174                if has_some_cursor_in_whitespace
10175                    && cursor.column == current_indent.len
10176                    && current_indent.len == suggested_indent.len
10177                {
10178                    continue;
10179                }
10180
10181                // Adjust line and move cursor to suggested indent
10182                // if cursor is not at suggested indent
10183                if cursor.column < suggested_indent.len
10184                    && cursor.column <= current_indent.len
10185                    && current_indent.len <= suggested_indent.len
10186                {
10187                    selection.start = Point::new(cursor.row, suggested_indent.len);
10188                    selection.end = selection.start;
10189                    if row_delta == 0 {
10190                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10191                            cursor.row,
10192                            current_indent,
10193                            suggested_indent,
10194                        ));
10195                        row_delta = suggested_indent.len - current_indent.len;
10196                    }
10197                    continue;
10198                }
10199
10200                // If current indent is more than suggested indent
10201                // only move cursor to current indent and skip indent
10202                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10203                    selection.start = Point::new(cursor.row, current_indent.len);
10204                    selection.end = selection.start;
10205                    continue;
10206                }
10207            }
10208
10209            // Otherwise, insert a hard or soft tab.
10210            let settings = buffer.language_settings_at(cursor, cx);
10211            let tab_size = if settings.hard_tabs {
10212                IndentSize::tab()
10213            } else {
10214                let tab_size = settings.tab_size.get();
10215                let indent_remainder = snapshot
10216                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10217                    .flat_map(str::chars)
10218                    .fold(row_delta % tab_size, |counter: u32, c| {
10219                        if c == '\t' {
10220                            0
10221                        } else {
10222                            (counter + 1) % tab_size
10223                        }
10224                    });
10225
10226                let chars_to_next_tab_stop = tab_size - indent_remainder;
10227                IndentSize::spaces(chars_to_next_tab_stop)
10228            };
10229            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10230            selection.end = selection.start;
10231            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10232            row_delta += tab_size.len;
10233        }
10234
10235        self.transact(window, cx, |this, window, cx| {
10236            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10237            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10238            this.refresh_edit_prediction(true, false, window, cx);
10239        });
10240    }
10241
10242    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10243        if self.read_only(cx) {
10244            return;
10245        }
10246        if self.mode.is_single_line() {
10247            cx.propagate();
10248            return;
10249        }
10250
10251        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10252        let mut selections = self.selections.all::<Point>(cx);
10253        let mut prev_edited_row = 0;
10254        let mut row_delta = 0;
10255        let mut edits = Vec::new();
10256        let buffer = self.buffer.read(cx);
10257        let snapshot = buffer.snapshot(cx);
10258        for selection in &mut selections {
10259            if selection.start.row != prev_edited_row {
10260                row_delta = 0;
10261            }
10262            prev_edited_row = selection.end.row;
10263
10264            row_delta =
10265                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10266        }
10267
10268        self.transact(window, cx, |this, window, cx| {
10269            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10270            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10271        });
10272    }
10273
10274    fn indent_selection(
10275        buffer: &MultiBuffer,
10276        snapshot: &MultiBufferSnapshot,
10277        selection: &mut Selection<Point>,
10278        edits: &mut Vec<(Range<Point>, String)>,
10279        delta_for_start_row: u32,
10280        cx: &App,
10281    ) -> u32 {
10282        let settings = buffer.language_settings_at(selection.start, cx);
10283        let tab_size = settings.tab_size.get();
10284        let indent_kind = if settings.hard_tabs {
10285            IndentKind::Tab
10286        } else {
10287            IndentKind::Space
10288        };
10289        let mut start_row = selection.start.row;
10290        let mut end_row = selection.end.row + 1;
10291
10292        // If a selection ends at the beginning of a line, don't indent
10293        // that last line.
10294        if selection.end.column == 0 && selection.end.row > selection.start.row {
10295            end_row -= 1;
10296        }
10297
10298        // Avoid re-indenting a row that has already been indented by a
10299        // previous selection, but still update this selection's column
10300        // to reflect that indentation.
10301        if delta_for_start_row > 0 {
10302            start_row += 1;
10303            selection.start.column += delta_for_start_row;
10304            if selection.end.row == selection.start.row {
10305                selection.end.column += delta_for_start_row;
10306            }
10307        }
10308
10309        let mut delta_for_end_row = 0;
10310        let has_multiple_rows = start_row + 1 != end_row;
10311        for row in start_row..end_row {
10312            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10313            let indent_delta = match (current_indent.kind, indent_kind) {
10314                (IndentKind::Space, IndentKind::Space) => {
10315                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10316                    IndentSize::spaces(columns_to_next_tab_stop)
10317                }
10318                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10319                (_, IndentKind::Tab) => IndentSize::tab(),
10320            };
10321
10322            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10323                0
10324            } else {
10325                selection.start.column
10326            };
10327            let row_start = Point::new(row, start);
10328            edits.push((
10329                row_start..row_start,
10330                indent_delta.chars().collect::<String>(),
10331            ));
10332
10333            // Update this selection's endpoints to reflect the indentation.
10334            if row == selection.start.row {
10335                selection.start.column += indent_delta.len;
10336            }
10337            if row == selection.end.row {
10338                selection.end.column += indent_delta.len;
10339                delta_for_end_row = indent_delta.len;
10340            }
10341        }
10342
10343        if selection.start.row == selection.end.row {
10344            delta_for_start_row + delta_for_end_row
10345        } else {
10346            delta_for_end_row
10347        }
10348    }
10349
10350    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10351        if self.read_only(cx) {
10352            return;
10353        }
10354        if self.mode.is_single_line() {
10355            cx.propagate();
10356            return;
10357        }
10358
10359        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10360        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10361        let selections = self.selections.all::<Point>(cx);
10362        let mut deletion_ranges = Vec::new();
10363        let mut last_outdent = None;
10364        {
10365            let buffer = self.buffer.read(cx);
10366            let snapshot = buffer.snapshot(cx);
10367            for selection in &selections {
10368                let settings = buffer.language_settings_at(selection.start, cx);
10369                let tab_size = settings.tab_size.get();
10370                let mut rows = selection.spanned_rows(false, &display_map);
10371
10372                // Avoid re-outdenting a row that has already been outdented by a
10373                // previous selection.
10374                if let Some(last_row) = last_outdent
10375                    && last_row == rows.start
10376                {
10377                    rows.start = rows.start.next_row();
10378                }
10379                let has_multiple_rows = rows.len() > 1;
10380                for row in rows.iter_rows() {
10381                    let indent_size = snapshot.indent_size_for_line(row);
10382                    if indent_size.len > 0 {
10383                        let deletion_len = match indent_size.kind {
10384                            IndentKind::Space => {
10385                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10386                                if columns_to_prev_tab_stop == 0 {
10387                                    tab_size
10388                                } else {
10389                                    columns_to_prev_tab_stop
10390                                }
10391                            }
10392                            IndentKind::Tab => 1,
10393                        };
10394                        let start = if has_multiple_rows
10395                            || deletion_len > selection.start.column
10396                            || indent_size.len < selection.start.column
10397                        {
10398                            0
10399                        } else {
10400                            selection.start.column - deletion_len
10401                        };
10402                        deletion_ranges.push(
10403                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10404                        );
10405                        last_outdent = Some(row);
10406                    }
10407                }
10408            }
10409        }
10410
10411        self.transact(window, cx, |this, window, cx| {
10412            this.buffer.update(cx, |buffer, cx| {
10413                let empty_str: Arc<str> = Arc::default();
10414                buffer.edit(
10415                    deletion_ranges
10416                        .into_iter()
10417                        .map(|range| (range, empty_str.clone())),
10418                    None,
10419                    cx,
10420                );
10421            });
10422            let selections = this.selections.all::<usize>(cx);
10423            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10424        });
10425    }
10426
10427    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10428        if self.read_only(cx) {
10429            return;
10430        }
10431        if self.mode.is_single_line() {
10432            cx.propagate();
10433            return;
10434        }
10435
10436        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10437        let selections = self
10438            .selections
10439            .all::<usize>(cx)
10440            .into_iter()
10441            .map(|s| s.range());
10442
10443        self.transact(window, cx, |this, window, cx| {
10444            this.buffer.update(cx, |buffer, cx| {
10445                buffer.autoindent_ranges(selections, cx);
10446            });
10447            let selections = this.selections.all::<usize>(cx);
10448            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10449        });
10450    }
10451
10452    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10453        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10454        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10455        let selections = self.selections.all::<Point>(cx);
10456
10457        let mut new_cursors = Vec::new();
10458        let mut edit_ranges = Vec::new();
10459        let mut selections = selections.iter().peekable();
10460        while let Some(selection) = selections.next() {
10461            let mut rows = selection.spanned_rows(false, &display_map);
10462
10463            // Accumulate contiguous regions of rows that we want to delete.
10464            while let Some(next_selection) = selections.peek() {
10465                let next_rows = next_selection.spanned_rows(false, &display_map);
10466                if next_rows.start <= rows.end {
10467                    rows.end = next_rows.end;
10468                    selections.next().unwrap();
10469                } else {
10470                    break;
10471                }
10472            }
10473
10474            let buffer = display_map.buffer_snapshot();
10475            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10476            let edit_end = if buffer.max_point().row >= rows.end.0 {
10477                // If there's a line after the range, delete the \n from the end of the row range
10478                ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer)
10479            } else {
10480                // If there isn't a line after the range, delete the \n from the line before the
10481                // start of the row range
10482                edit_start = edit_start.saturating_sub(1);
10483                buffer.len()
10484            };
10485
10486            let (cursor, goal) = movement::down_by_rows(
10487                &display_map,
10488                selection.head().to_display_point(&display_map),
10489                rows.len() as u32,
10490                selection.goal,
10491                false,
10492                &self.text_layout_details(window),
10493            );
10494
10495            new_cursors.push((
10496                selection.id,
10497                buffer.anchor_after(cursor.to_point(&display_map)),
10498                goal,
10499            ));
10500            edit_ranges.push(edit_start..edit_end);
10501        }
10502
10503        self.transact(window, cx, |this, window, cx| {
10504            let buffer = this.buffer.update(cx, |buffer, cx| {
10505                let empty_str: Arc<str> = Arc::default();
10506                buffer.edit(
10507                    edit_ranges
10508                        .into_iter()
10509                        .map(|range| (range, empty_str.clone())),
10510                    None,
10511                    cx,
10512                );
10513                buffer.snapshot(cx)
10514            });
10515            let new_selections = new_cursors
10516                .into_iter()
10517                .map(|(id, cursor, goal)| {
10518                    let cursor = cursor.to_point(&buffer);
10519                    Selection {
10520                        id,
10521                        start: cursor,
10522                        end: cursor,
10523                        reversed: false,
10524                        goal,
10525                    }
10526                })
10527                .collect();
10528
10529            this.change_selections(Default::default(), window, cx, |s| {
10530                s.select(new_selections);
10531            });
10532        });
10533    }
10534
10535    pub fn join_lines_impl(
10536        &mut self,
10537        insert_whitespace: bool,
10538        window: &mut Window,
10539        cx: &mut Context<Self>,
10540    ) {
10541        if self.read_only(cx) {
10542            return;
10543        }
10544        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10545        for selection in self.selections.all::<Point>(cx) {
10546            let start = MultiBufferRow(selection.start.row);
10547            // Treat single line selections as if they include the next line. Otherwise this action
10548            // would do nothing for single line selections individual cursors.
10549            let end = if selection.start.row == selection.end.row {
10550                MultiBufferRow(selection.start.row + 1)
10551            } else {
10552                MultiBufferRow(selection.end.row)
10553            };
10554
10555            if let Some(last_row_range) = row_ranges.last_mut()
10556                && start <= last_row_range.end
10557            {
10558                last_row_range.end = end;
10559                continue;
10560            }
10561            row_ranges.push(start..end);
10562        }
10563
10564        let snapshot = self.buffer.read(cx).snapshot(cx);
10565        let mut cursor_positions = Vec::new();
10566        for row_range in &row_ranges {
10567            let anchor = snapshot.anchor_before(Point::new(
10568                row_range.end.previous_row().0,
10569                snapshot.line_len(row_range.end.previous_row()),
10570            ));
10571            cursor_positions.push(anchor..anchor);
10572        }
10573
10574        self.transact(window, cx, |this, window, cx| {
10575            for row_range in row_ranges.into_iter().rev() {
10576                for row in row_range.iter_rows().rev() {
10577                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10578                    let next_line_row = row.next_row();
10579                    let indent = snapshot.indent_size_for_line(next_line_row);
10580                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10581
10582                    let replace =
10583                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10584                            " "
10585                        } else {
10586                            ""
10587                        };
10588
10589                    this.buffer.update(cx, |buffer, cx| {
10590                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10591                    });
10592                }
10593            }
10594
10595            this.change_selections(Default::default(), window, cx, |s| {
10596                s.select_anchor_ranges(cursor_positions)
10597            });
10598        });
10599    }
10600
10601    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10602        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10603        self.join_lines_impl(true, window, cx);
10604    }
10605
10606    pub fn sort_lines_case_sensitive(
10607        &mut self,
10608        _: &SortLinesCaseSensitive,
10609        window: &mut Window,
10610        cx: &mut Context<Self>,
10611    ) {
10612        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10613    }
10614
10615    pub fn sort_lines_by_length(
10616        &mut self,
10617        _: &SortLinesByLength,
10618        window: &mut Window,
10619        cx: &mut Context<Self>,
10620    ) {
10621        self.manipulate_immutable_lines(window, cx, |lines| {
10622            lines.sort_by_key(|&line| line.chars().count())
10623        })
10624    }
10625
10626    pub fn sort_lines_case_insensitive(
10627        &mut self,
10628        _: &SortLinesCaseInsensitive,
10629        window: &mut Window,
10630        cx: &mut Context<Self>,
10631    ) {
10632        self.manipulate_immutable_lines(window, cx, |lines| {
10633            lines.sort_by_key(|line| line.to_lowercase())
10634        })
10635    }
10636
10637    pub fn unique_lines_case_insensitive(
10638        &mut self,
10639        _: &UniqueLinesCaseInsensitive,
10640        window: &mut Window,
10641        cx: &mut Context<Self>,
10642    ) {
10643        self.manipulate_immutable_lines(window, cx, |lines| {
10644            let mut seen = HashSet::default();
10645            lines.retain(|line| seen.insert(line.to_lowercase()));
10646        })
10647    }
10648
10649    pub fn unique_lines_case_sensitive(
10650        &mut self,
10651        _: &UniqueLinesCaseSensitive,
10652        window: &mut Window,
10653        cx: &mut Context<Self>,
10654    ) {
10655        self.manipulate_immutable_lines(window, cx, |lines| {
10656            let mut seen = HashSet::default();
10657            lines.retain(|line| seen.insert(*line));
10658        })
10659    }
10660
10661    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10662        let snapshot = self.buffer.read(cx).snapshot(cx);
10663        for selection in self.selections.disjoint_anchors_arc().iter() {
10664            if snapshot
10665                .language_at(selection.start)
10666                .and_then(|lang| lang.config().wrap_characters.as_ref())
10667                .is_some()
10668            {
10669                return true;
10670            }
10671        }
10672        false
10673    }
10674
10675    fn wrap_selections_in_tag(
10676        &mut self,
10677        _: &WrapSelectionsInTag,
10678        window: &mut Window,
10679        cx: &mut Context<Self>,
10680    ) {
10681        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10682
10683        let snapshot = self.buffer.read(cx).snapshot(cx);
10684
10685        let mut edits = Vec::new();
10686        let mut boundaries = Vec::new();
10687
10688        for selection in self.selections.all::<Point>(cx).iter() {
10689            let Some(wrap_config) = snapshot
10690                .language_at(selection.start)
10691                .and_then(|lang| lang.config().wrap_characters.clone())
10692            else {
10693                continue;
10694            };
10695
10696            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10697            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10698
10699            let start_before = snapshot.anchor_before(selection.start);
10700            let end_after = snapshot.anchor_after(selection.end);
10701
10702            edits.push((start_before..start_before, open_tag));
10703            edits.push((end_after..end_after, close_tag));
10704
10705            boundaries.push((
10706                start_before,
10707                end_after,
10708                wrap_config.start_prefix.len(),
10709                wrap_config.end_suffix.len(),
10710            ));
10711        }
10712
10713        if edits.is_empty() {
10714            return;
10715        }
10716
10717        self.transact(window, cx, |this, window, cx| {
10718            let buffer = this.buffer.update(cx, |buffer, cx| {
10719                buffer.edit(edits, None, cx);
10720                buffer.snapshot(cx)
10721            });
10722
10723            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10724            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10725                boundaries.into_iter()
10726            {
10727                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10728                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10729                new_selections.push(open_offset..open_offset);
10730                new_selections.push(close_offset..close_offset);
10731            }
10732
10733            this.change_selections(Default::default(), window, cx, |s| {
10734                s.select_ranges(new_selections);
10735            });
10736
10737            this.request_autoscroll(Autoscroll::fit(), cx);
10738        });
10739    }
10740
10741    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10742        let Some(project) = self.project.clone() else {
10743            return;
10744        };
10745        self.reload(project, window, cx)
10746            .detach_and_notify_err(window, cx);
10747    }
10748
10749    pub fn restore_file(
10750        &mut self,
10751        _: &::git::RestoreFile,
10752        window: &mut Window,
10753        cx: &mut Context<Self>,
10754    ) {
10755        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10756        let mut buffer_ids = HashSet::default();
10757        let snapshot = self.buffer().read(cx).snapshot(cx);
10758        for selection in self.selections.all::<usize>(cx) {
10759            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10760        }
10761
10762        let buffer = self.buffer().read(cx);
10763        let ranges = buffer_ids
10764            .into_iter()
10765            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10766            .collect::<Vec<_>>();
10767
10768        self.restore_hunks_in_ranges(ranges, window, cx);
10769    }
10770
10771    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10773        let selections = self
10774            .selections
10775            .all(cx)
10776            .into_iter()
10777            .map(|s| s.range())
10778            .collect();
10779        self.restore_hunks_in_ranges(selections, window, cx);
10780    }
10781
10782    pub fn restore_hunks_in_ranges(
10783        &mut self,
10784        ranges: Vec<Range<Point>>,
10785        window: &mut Window,
10786        cx: &mut Context<Editor>,
10787    ) {
10788        let mut revert_changes = HashMap::default();
10789        let chunk_by = self
10790            .snapshot(window, cx)
10791            .hunks_for_ranges(ranges)
10792            .into_iter()
10793            .chunk_by(|hunk| hunk.buffer_id);
10794        for (buffer_id, hunks) in &chunk_by {
10795            let hunks = hunks.collect::<Vec<_>>();
10796            for hunk in &hunks {
10797                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10798            }
10799            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10800        }
10801        drop(chunk_by);
10802        if !revert_changes.is_empty() {
10803            self.transact(window, cx, |editor, window, cx| {
10804                editor.restore(revert_changes, window, cx);
10805            });
10806        }
10807    }
10808
10809    pub fn open_active_item_in_terminal(
10810        &mut self,
10811        _: &OpenInTerminal,
10812        window: &mut Window,
10813        cx: &mut Context<Self>,
10814    ) {
10815        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10816            let project_path = buffer.read(cx).project_path(cx)?;
10817            let project = self.project()?.read(cx);
10818            let entry = project.entry_for_path(&project_path, cx)?;
10819            let parent = match &entry.canonical_path {
10820                Some(canonical_path) => canonical_path.to_path_buf(),
10821                None => project.absolute_path(&project_path, cx)?,
10822            }
10823            .parent()?
10824            .to_path_buf();
10825            Some(parent)
10826        }) {
10827            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10828        }
10829    }
10830
10831    fn set_breakpoint_context_menu(
10832        &mut self,
10833        display_row: DisplayRow,
10834        position: Option<Anchor>,
10835        clicked_point: gpui::Point<Pixels>,
10836        window: &mut Window,
10837        cx: &mut Context<Self>,
10838    ) {
10839        let source = self
10840            .buffer
10841            .read(cx)
10842            .snapshot(cx)
10843            .anchor_before(Point::new(display_row.0, 0u32));
10844
10845        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10846
10847        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10848            self,
10849            source,
10850            clicked_point,
10851            context_menu,
10852            window,
10853            cx,
10854        );
10855    }
10856
10857    fn add_edit_breakpoint_block(
10858        &mut self,
10859        anchor: Anchor,
10860        breakpoint: &Breakpoint,
10861        edit_action: BreakpointPromptEditAction,
10862        window: &mut Window,
10863        cx: &mut Context<Self>,
10864    ) {
10865        let weak_editor = cx.weak_entity();
10866        let bp_prompt = cx.new(|cx| {
10867            BreakpointPromptEditor::new(
10868                weak_editor,
10869                anchor,
10870                breakpoint.clone(),
10871                edit_action,
10872                window,
10873                cx,
10874            )
10875        });
10876
10877        let height = bp_prompt.update(cx, |this, cx| {
10878            this.prompt
10879                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10880        });
10881        let cloned_prompt = bp_prompt.clone();
10882        let blocks = vec![BlockProperties {
10883            style: BlockStyle::Sticky,
10884            placement: BlockPlacement::Above(anchor),
10885            height: Some(height),
10886            render: Arc::new(move |cx| {
10887                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10888                cloned_prompt.clone().into_any_element()
10889            }),
10890            priority: 0,
10891        }];
10892
10893        let focus_handle = bp_prompt.focus_handle(cx);
10894        window.focus(&focus_handle);
10895
10896        let block_ids = self.insert_blocks(blocks, None, cx);
10897        bp_prompt.update(cx, |prompt, _| {
10898            prompt.add_block_ids(block_ids);
10899        });
10900    }
10901
10902    pub(crate) fn breakpoint_at_row(
10903        &self,
10904        row: u32,
10905        window: &mut Window,
10906        cx: &mut Context<Self>,
10907    ) -> Option<(Anchor, Breakpoint)> {
10908        let snapshot = self.snapshot(window, cx);
10909        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10910
10911        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10912    }
10913
10914    pub(crate) fn breakpoint_at_anchor(
10915        &self,
10916        breakpoint_position: Anchor,
10917        snapshot: &EditorSnapshot,
10918        cx: &mut Context<Self>,
10919    ) -> Option<(Anchor, Breakpoint)> {
10920        let buffer = self
10921            .buffer
10922            .read(cx)
10923            .buffer_for_anchor(breakpoint_position, cx)?;
10924
10925        let enclosing_excerpt = breakpoint_position.excerpt_id;
10926        let buffer_snapshot = buffer.read(cx).snapshot();
10927
10928        let row = buffer_snapshot
10929            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10930            .row;
10931
10932        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10933        let anchor_end = snapshot
10934            .buffer_snapshot()
10935            .anchor_after(Point::new(row, line_len));
10936
10937        self.breakpoint_store
10938            .as_ref()?
10939            .read_with(cx, |breakpoint_store, cx| {
10940                breakpoint_store
10941                    .breakpoints(
10942                        &buffer,
10943                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10944                        &buffer_snapshot,
10945                        cx,
10946                    )
10947                    .next()
10948                    .and_then(|(bp, _)| {
10949                        let breakpoint_row = buffer_snapshot
10950                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10951                            .row;
10952
10953                        if breakpoint_row == row {
10954                            snapshot
10955                                .buffer_snapshot()
10956                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10957                                .map(|position| (position, bp.bp.clone()))
10958                        } else {
10959                            None
10960                        }
10961                    })
10962            })
10963    }
10964
10965    pub fn edit_log_breakpoint(
10966        &mut self,
10967        _: &EditLogBreakpoint,
10968        window: &mut Window,
10969        cx: &mut Context<Self>,
10970    ) {
10971        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10972            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10973                message: None,
10974                state: BreakpointState::Enabled,
10975                condition: None,
10976                hit_condition: None,
10977            });
10978
10979            self.add_edit_breakpoint_block(
10980                anchor,
10981                &breakpoint,
10982                BreakpointPromptEditAction::Log,
10983                window,
10984                cx,
10985            );
10986        }
10987    }
10988
10989    fn breakpoints_at_cursors(
10990        &self,
10991        window: &mut Window,
10992        cx: &mut Context<Self>,
10993    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10994        let snapshot = self.snapshot(window, cx);
10995        let cursors = self
10996            .selections
10997            .disjoint_anchors_arc()
10998            .iter()
10999            .map(|selection| {
11000                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11001
11002                let breakpoint_position = self
11003                    .breakpoint_at_row(cursor_position.row, window, cx)
11004                    .map(|bp| bp.0)
11005                    .unwrap_or_else(|| {
11006                        snapshot
11007                            .display_snapshot
11008                            .buffer_snapshot()
11009                            .anchor_after(Point::new(cursor_position.row, 0))
11010                    });
11011
11012                let breakpoint = self
11013                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11014                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11015
11016                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11017            })
11018            // 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.
11019            .collect::<HashMap<Anchor, _>>();
11020
11021        cursors.into_iter().collect()
11022    }
11023
11024    pub fn enable_breakpoint(
11025        &mut self,
11026        _: &crate::actions::EnableBreakpoint,
11027        window: &mut Window,
11028        cx: &mut Context<Self>,
11029    ) {
11030        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11031            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11032                continue;
11033            };
11034            self.edit_breakpoint_at_anchor(
11035                anchor,
11036                breakpoint,
11037                BreakpointEditAction::InvertState,
11038                cx,
11039            );
11040        }
11041    }
11042
11043    pub fn disable_breakpoint(
11044        &mut self,
11045        _: &crate::actions::DisableBreakpoint,
11046        window: &mut Window,
11047        cx: &mut Context<Self>,
11048    ) {
11049        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11050            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11051                continue;
11052            };
11053            self.edit_breakpoint_at_anchor(
11054                anchor,
11055                breakpoint,
11056                BreakpointEditAction::InvertState,
11057                cx,
11058            );
11059        }
11060    }
11061
11062    pub fn toggle_breakpoint(
11063        &mut self,
11064        _: &crate::actions::ToggleBreakpoint,
11065        window: &mut Window,
11066        cx: &mut Context<Self>,
11067    ) {
11068        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11069            if let Some(breakpoint) = breakpoint {
11070                self.edit_breakpoint_at_anchor(
11071                    anchor,
11072                    breakpoint,
11073                    BreakpointEditAction::Toggle,
11074                    cx,
11075                );
11076            } else {
11077                self.edit_breakpoint_at_anchor(
11078                    anchor,
11079                    Breakpoint::new_standard(),
11080                    BreakpointEditAction::Toggle,
11081                    cx,
11082                );
11083            }
11084        }
11085    }
11086
11087    pub fn edit_breakpoint_at_anchor(
11088        &mut self,
11089        breakpoint_position: Anchor,
11090        breakpoint: Breakpoint,
11091        edit_action: BreakpointEditAction,
11092        cx: &mut Context<Self>,
11093    ) {
11094        let Some(breakpoint_store) = &self.breakpoint_store else {
11095            return;
11096        };
11097
11098        let Some(buffer) = self
11099            .buffer
11100            .read(cx)
11101            .buffer_for_anchor(breakpoint_position, cx)
11102        else {
11103            return;
11104        };
11105
11106        breakpoint_store.update(cx, |breakpoint_store, cx| {
11107            breakpoint_store.toggle_breakpoint(
11108                buffer,
11109                BreakpointWithPosition {
11110                    position: breakpoint_position.text_anchor,
11111                    bp: breakpoint,
11112                },
11113                edit_action,
11114                cx,
11115            );
11116        });
11117
11118        cx.notify();
11119    }
11120
11121    #[cfg(any(test, feature = "test-support"))]
11122    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11123        self.breakpoint_store.clone()
11124    }
11125
11126    pub fn prepare_restore_change(
11127        &self,
11128        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11129        hunk: &MultiBufferDiffHunk,
11130        cx: &mut App,
11131    ) -> Option<()> {
11132        if hunk.is_created_file() {
11133            return None;
11134        }
11135        let buffer = self.buffer.read(cx);
11136        let diff = buffer.diff_for(hunk.buffer_id)?;
11137        let buffer = buffer.buffer(hunk.buffer_id)?;
11138        let buffer = buffer.read(cx);
11139        let original_text = diff
11140            .read(cx)
11141            .base_text()
11142            .as_rope()
11143            .slice(hunk.diff_base_byte_range.clone());
11144        let buffer_snapshot = buffer.snapshot();
11145        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11146        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11147            probe
11148                .0
11149                .start
11150                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11151                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11152        }) {
11153            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11154            Some(())
11155        } else {
11156            None
11157        }
11158    }
11159
11160    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11161        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11162    }
11163
11164    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11165        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11166    }
11167
11168    fn manipulate_lines<M>(
11169        &mut self,
11170        window: &mut Window,
11171        cx: &mut Context<Self>,
11172        mut manipulate: M,
11173    ) where
11174        M: FnMut(&str) -> LineManipulationResult,
11175    {
11176        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11177
11178        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11179        let buffer = self.buffer.read(cx).snapshot(cx);
11180
11181        let mut edits = Vec::new();
11182
11183        let selections = self.selections.all::<Point>(cx);
11184        let mut selections = selections.iter().peekable();
11185        let mut contiguous_row_selections = Vec::new();
11186        let mut new_selections = Vec::new();
11187        let mut added_lines = 0;
11188        let mut removed_lines = 0;
11189
11190        while let Some(selection) = selections.next() {
11191            let (start_row, end_row) = consume_contiguous_rows(
11192                &mut contiguous_row_selections,
11193                selection,
11194                &display_map,
11195                &mut selections,
11196            );
11197
11198            let start_point = Point::new(start_row.0, 0);
11199            let end_point = Point::new(
11200                end_row.previous_row().0,
11201                buffer.line_len(end_row.previous_row()),
11202            );
11203            let text = buffer
11204                .text_for_range(start_point..end_point)
11205                .collect::<String>();
11206
11207            let LineManipulationResult {
11208                new_text,
11209                line_count_before,
11210                line_count_after,
11211            } = manipulate(&text);
11212
11213            edits.push((start_point..end_point, new_text));
11214
11215            // Selections must change based on added and removed line count
11216            let start_row =
11217                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11218            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11219            new_selections.push(Selection {
11220                id: selection.id,
11221                start: start_row,
11222                end: end_row,
11223                goal: SelectionGoal::None,
11224                reversed: selection.reversed,
11225            });
11226
11227            if line_count_after > line_count_before {
11228                added_lines += line_count_after - line_count_before;
11229            } else if line_count_before > line_count_after {
11230                removed_lines += line_count_before - line_count_after;
11231            }
11232        }
11233
11234        self.transact(window, cx, |this, window, cx| {
11235            let buffer = this.buffer.update(cx, |buffer, cx| {
11236                buffer.edit(edits, None, cx);
11237                buffer.snapshot(cx)
11238            });
11239
11240            // Recalculate offsets on newly edited buffer
11241            let new_selections = new_selections
11242                .iter()
11243                .map(|s| {
11244                    let start_point = Point::new(s.start.0, 0);
11245                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11246                    Selection {
11247                        id: s.id,
11248                        start: buffer.point_to_offset(start_point),
11249                        end: buffer.point_to_offset(end_point),
11250                        goal: s.goal,
11251                        reversed: s.reversed,
11252                    }
11253                })
11254                .collect();
11255
11256            this.change_selections(Default::default(), window, cx, |s| {
11257                s.select(new_selections);
11258            });
11259
11260            this.request_autoscroll(Autoscroll::fit(), cx);
11261        });
11262    }
11263
11264    fn manipulate_immutable_lines<Fn>(
11265        &mut self,
11266        window: &mut Window,
11267        cx: &mut Context<Self>,
11268        mut callback: Fn,
11269    ) where
11270        Fn: FnMut(&mut Vec<&str>),
11271    {
11272        self.manipulate_lines(window, cx, |text| {
11273            let mut lines: Vec<&str> = text.split('\n').collect();
11274            let line_count_before = lines.len();
11275
11276            callback(&mut lines);
11277
11278            LineManipulationResult {
11279                new_text: lines.join("\n"),
11280                line_count_before,
11281                line_count_after: lines.len(),
11282            }
11283        });
11284    }
11285
11286    fn manipulate_mutable_lines<Fn>(
11287        &mut self,
11288        window: &mut Window,
11289        cx: &mut Context<Self>,
11290        mut callback: Fn,
11291    ) where
11292        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11293    {
11294        self.manipulate_lines(window, cx, |text| {
11295            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11296            let line_count_before = lines.len();
11297
11298            callback(&mut lines);
11299
11300            LineManipulationResult {
11301                new_text: lines.join("\n"),
11302                line_count_before,
11303                line_count_after: lines.len(),
11304            }
11305        });
11306    }
11307
11308    pub fn convert_indentation_to_spaces(
11309        &mut self,
11310        _: &ConvertIndentationToSpaces,
11311        window: &mut Window,
11312        cx: &mut Context<Self>,
11313    ) {
11314        let settings = self.buffer.read(cx).language_settings(cx);
11315        let tab_size = settings.tab_size.get() as usize;
11316
11317        self.manipulate_mutable_lines(window, cx, |lines| {
11318            // Allocates a reasonably sized scratch buffer once for the whole loop
11319            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11320            // Avoids recomputing spaces that could be inserted many times
11321            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11322                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11323                .collect();
11324
11325            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11326                let mut chars = line.as_ref().chars();
11327                let mut col = 0;
11328                let mut changed = false;
11329
11330                for ch in chars.by_ref() {
11331                    match ch {
11332                        ' ' => {
11333                            reindented_line.push(' ');
11334                            col += 1;
11335                        }
11336                        '\t' => {
11337                            // \t are converted to spaces depending on the current column
11338                            let spaces_len = tab_size - (col % tab_size);
11339                            reindented_line.extend(&space_cache[spaces_len - 1]);
11340                            col += spaces_len;
11341                            changed = true;
11342                        }
11343                        _ => {
11344                            // If we dont append before break, the character is consumed
11345                            reindented_line.push(ch);
11346                            break;
11347                        }
11348                    }
11349                }
11350
11351                if !changed {
11352                    reindented_line.clear();
11353                    continue;
11354                }
11355                // Append the rest of the line and replace old reference with new one
11356                reindented_line.extend(chars);
11357                *line = Cow::Owned(reindented_line.clone());
11358                reindented_line.clear();
11359            }
11360        });
11361    }
11362
11363    pub fn convert_indentation_to_tabs(
11364        &mut self,
11365        _: &ConvertIndentationToTabs,
11366        window: &mut Window,
11367        cx: &mut Context<Self>,
11368    ) {
11369        let settings = self.buffer.read(cx).language_settings(cx);
11370        let tab_size = settings.tab_size.get() as usize;
11371
11372        self.manipulate_mutable_lines(window, cx, |lines| {
11373            // Allocates a reasonably sized buffer once for the whole loop
11374            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11375            // Avoids recomputing spaces that could be inserted many times
11376            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11377                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11378                .collect();
11379
11380            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11381                let mut chars = line.chars();
11382                let mut spaces_count = 0;
11383                let mut first_non_indent_char = None;
11384                let mut changed = false;
11385
11386                for ch in chars.by_ref() {
11387                    match ch {
11388                        ' ' => {
11389                            // Keep track of spaces. Append \t when we reach tab_size
11390                            spaces_count += 1;
11391                            changed = true;
11392                            if spaces_count == tab_size {
11393                                reindented_line.push('\t');
11394                                spaces_count = 0;
11395                            }
11396                        }
11397                        '\t' => {
11398                            reindented_line.push('\t');
11399                            spaces_count = 0;
11400                        }
11401                        _ => {
11402                            // Dont append it yet, we might have remaining spaces
11403                            first_non_indent_char = Some(ch);
11404                            break;
11405                        }
11406                    }
11407                }
11408
11409                if !changed {
11410                    reindented_line.clear();
11411                    continue;
11412                }
11413                // Remaining spaces that didn't make a full tab stop
11414                if spaces_count > 0 {
11415                    reindented_line.extend(&space_cache[spaces_count - 1]);
11416                }
11417                // If we consume an extra character that was not indentation, add it back
11418                if let Some(extra_char) = first_non_indent_char {
11419                    reindented_line.push(extra_char);
11420                }
11421                // Append the rest of the line and replace old reference with new one
11422                reindented_line.extend(chars);
11423                *line = Cow::Owned(reindented_line.clone());
11424                reindented_line.clear();
11425            }
11426        });
11427    }
11428
11429    pub fn convert_to_upper_case(
11430        &mut self,
11431        _: &ConvertToUpperCase,
11432        window: &mut Window,
11433        cx: &mut Context<Self>,
11434    ) {
11435        self.manipulate_text(window, cx, |text| text.to_uppercase())
11436    }
11437
11438    pub fn convert_to_lower_case(
11439        &mut self,
11440        _: &ConvertToLowerCase,
11441        window: &mut Window,
11442        cx: &mut Context<Self>,
11443    ) {
11444        self.manipulate_text(window, cx, |text| text.to_lowercase())
11445    }
11446
11447    pub fn convert_to_title_case(
11448        &mut self,
11449        _: &ConvertToTitleCase,
11450        window: &mut Window,
11451        cx: &mut Context<Self>,
11452    ) {
11453        self.manipulate_text(window, cx, |text| {
11454            text.split('\n')
11455                .map(|line| line.to_case(Case::Title))
11456                .join("\n")
11457        })
11458    }
11459
11460    pub fn convert_to_snake_case(
11461        &mut self,
11462        _: &ConvertToSnakeCase,
11463        window: &mut Window,
11464        cx: &mut Context<Self>,
11465    ) {
11466        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11467    }
11468
11469    pub fn convert_to_kebab_case(
11470        &mut self,
11471        _: &ConvertToKebabCase,
11472        window: &mut Window,
11473        cx: &mut Context<Self>,
11474    ) {
11475        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11476    }
11477
11478    pub fn convert_to_upper_camel_case(
11479        &mut self,
11480        _: &ConvertToUpperCamelCase,
11481        window: &mut Window,
11482        cx: &mut Context<Self>,
11483    ) {
11484        self.manipulate_text(window, cx, |text| {
11485            text.split('\n')
11486                .map(|line| line.to_case(Case::UpperCamel))
11487                .join("\n")
11488        })
11489    }
11490
11491    pub fn convert_to_lower_camel_case(
11492        &mut self,
11493        _: &ConvertToLowerCamelCase,
11494        window: &mut Window,
11495        cx: &mut Context<Self>,
11496    ) {
11497        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11498    }
11499
11500    pub fn convert_to_opposite_case(
11501        &mut self,
11502        _: &ConvertToOppositeCase,
11503        window: &mut Window,
11504        cx: &mut Context<Self>,
11505    ) {
11506        self.manipulate_text(window, cx, |text| {
11507            text.chars()
11508                .fold(String::with_capacity(text.len()), |mut t, c| {
11509                    if c.is_uppercase() {
11510                        t.extend(c.to_lowercase());
11511                    } else {
11512                        t.extend(c.to_uppercase());
11513                    }
11514                    t
11515                })
11516        })
11517    }
11518
11519    pub fn convert_to_sentence_case(
11520        &mut self,
11521        _: &ConvertToSentenceCase,
11522        window: &mut Window,
11523        cx: &mut Context<Self>,
11524    ) {
11525        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11526    }
11527
11528    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11529        self.manipulate_text(window, cx, |text| {
11530            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11531            if has_upper_case_characters {
11532                text.to_lowercase()
11533            } else {
11534                text.to_uppercase()
11535            }
11536        })
11537    }
11538
11539    pub fn convert_to_rot13(
11540        &mut self,
11541        _: &ConvertToRot13,
11542        window: &mut Window,
11543        cx: &mut Context<Self>,
11544    ) {
11545        self.manipulate_text(window, cx, |text| {
11546            text.chars()
11547                .map(|c| match c {
11548                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11549                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11550                    _ => c,
11551                })
11552                .collect()
11553        })
11554    }
11555
11556    pub fn convert_to_rot47(
11557        &mut self,
11558        _: &ConvertToRot47,
11559        window: &mut Window,
11560        cx: &mut Context<Self>,
11561    ) {
11562        self.manipulate_text(window, cx, |text| {
11563            text.chars()
11564                .map(|c| {
11565                    let code_point = c as u32;
11566                    if code_point >= 33 && code_point <= 126 {
11567                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11568                    }
11569                    c
11570                })
11571                .collect()
11572        })
11573    }
11574
11575    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11576    where
11577        Fn: FnMut(&str) -> String,
11578    {
11579        let buffer = self.buffer.read(cx).snapshot(cx);
11580
11581        let mut new_selections = Vec::new();
11582        let mut edits = Vec::new();
11583        let mut selection_adjustment = 0i32;
11584
11585        for selection in self.selections.all_adjusted(cx) {
11586            let selection_is_empty = selection.is_empty();
11587
11588            let (start, end) = if selection_is_empty {
11589                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11590                (word_range.start, word_range.end)
11591            } else {
11592                (
11593                    buffer.point_to_offset(selection.start),
11594                    buffer.point_to_offset(selection.end),
11595                )
11596            };
11597
11598            let text = buffer.text_for_range(start..end).collect::<String>();
11599            let old_length = text.len() as i32;
11600            let text = callback(&text);
11601
11602            new_selections.push(Selection {
11603                start: (start as i32 - selection_adjustment) as usize,
11604                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11605                goal: SelectionGoal::None,
11606                id: selection.id,
11607                reversed: selection.reversed,
11608            });
11609
11610            selection_adjustment += old_length - text.len() as i32;
11611
11612            edits.push((start..end, text));
11613        }
11614
11615        self.transact(window, cx, |this, window, cx| {
11616            this.buffer.update(cx, |buffer, cx| {
11617                buffer.edit(edits, None, cx);
11618            });
11619
11620            this.change_selections(Default::default(), window, cx, |s| {
11621                s.select(new_selections);
11622            });
11623
11624            this.request_autoscroll(Autoscroll::fit(), cx);
11625        });
11626    }
11627
11628    pub fn move_selection_on_drop(
11629        &mut self,
11630        selection: &Selection<Anchor>,
11631        target: DisplayPoint,
11632        is_cut: bool,
11633        window: &mut Window,
11634        cx: &mut Context<Self>,
11635    ) {
11636        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11637        let buffer = display_map.buffer_snapshot();
11638        let mut edits = Vec::new();
11639        let insert_point = display_map
11640            .clip_point(target, Bias::Left)
11641            .to_point(&display_map);
11642        let text = buffer
11643            .text_for_range(selection.start..selection.end)
11644            .collect::<String>();
11645        if is_cut {
11646            edits.push(((selection.start..selection.end), String::new()));
11647        }
11648        let insert_anchor = buffer.anchor_before(insert_point);
11649        edits.push(((insert_anchor..insert_anchor), text));
11650        let last_edit_start = insert_anchor.bias_left(buffer);
11651        let last_edit_end = insert_anchor.bias_right(buffer);
11652        self.transact(window, cx, |this, window, cx| {
11653            this.buffer.update(cx, |buffer, cx| {
11654                buffer.edit(edits, None, cx);
11655            });
11656            this.change_selections(Default::default(), window, cx, |s| {
11657                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11658            });
11659        });
11660    }
11661
11662    pub fn clear_selection_drag_state(&mut self) {
11663        self.selection_drag_state = SelectionDragState::None;
11664    }
11665
11666    pub fn duplicate(
11667        &mut self,
11668        upwards: bool,
11669        whole_lines: bool,
11670        window: &mut Window,
11671        cx: &mut Context<Self>,
11672    ) {
11673        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11674
11675        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11676        let buffer = display_map.buffer_snapshot();
11677        let selections = self.selections.all::<Point>(cx);
11678
11679        let mut edits = Vec::new();
11680        let mut selections_iter = selections.iter().peekable();
11681        while let Some(selection) = selections_iter.next() {
11682            let mut rows = selection.spanned_rows(false, &display_map);
11683            // duplicate line-wise
11684            if whole_lines || selection.start == selection.end {
11685                // Avoid duplicating the same lines twice.
11686                while let Some(next_selection) = selections_iter.peek() {
11687                    let next_rows = next_selection.spanned_rows(false, &display_map);
11688                    if next_rows.start < rows.end {
11689                        rows.end = next_rows.end;
11690                        selections_iter.next().unwrap();
11691                    } else {
11692                        break;
11693                    }
11694                }
11695
11696                // Copy the text from the selected row region and splice it either at the start
11697                // or end of the region.
11698                let start = Point::new(rows.start.0, 0);
11699                let end = Point::new(
11700                    rows.end.previous_row().0,
11701                    buffer.line_len(rows.end.previous_row()),
11702                );
11703
11704                let mut text = buffer.text_for_range(start..end).collect::<String>();
11705
11706                let insert_location = if upwards {
11707                    // When duplicating upward, we need to insert before the current line.
11708                    // If we're on the last line and it doesn't end with a newline,
11709                    // we need to add a newline before the duplicated content.
11710                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11711                        && buffer.max_point().column > 0
11712                        && !text.ends_with('\n');
11713
11714                    if needs_leading_newline {
11715                        text.insert(0, '\n');
11716                        end
11717                    } else {
11718                        text.push('\n');
11719                        Point::new(rows.end.0, 0)
11720                    }
11721                } else {
11722                    text.push('\n');
11723                    start
11724                };
11725                edits.push((insert_location..insert_location, text));
11726            } else {
11727                // duplicate character-wise
11728                let start = selection.start;
11729                let end = selection.end;
11730                let text = buffer.text_for_range(start..end).collect::<String>();
11731                edits.push((selection.end..selection.end, text));
11732            }
11733        }
11734
11735        self.transact(window, cx, |this, _, cx| {
11736            this.buffer.update(cx, |buffer, cx| {
11737                buffer.edit(edits, None, cx);
11738            });
11739
11740            this.request_autoscroll(Autoscroll::fit(), cx);
11741        });
11742    }
11743
11744    pub fn duplicate_line_up(
11745        &mut self,
11746        _: &DuplicateLineUp,
11747        window: &mut Window,
11748        cx: &mut Context<Self>,
11749    ) {
11750        self.duplicate(true, true, window, cx);
11751    }
11752
11753    pub fn duplicate_line_down(
11754        &mut self,
11755        _: &DuplicateLineDown,
11756        window: &mut Window,
11757        cx: &mut Context<Self>,
11758    ) {
11759        self.duplicate(false, true, window, cx);
11760    }
11761
11762    pub fn duplicate_selection(
11763        &mut self,
11764        _: &DuplicateSelection,
11765        window: &mut Window,
11766        cx: &mut Context<Self>,
11767    ) {
11768        self.duplicate(false, false, window, cx);
11769    }
11770
11771    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11772        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11773        if self.mode.is_single_line() {
11774            cx.propagate();
11775            return;
11776        }
11777
11778        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11779        let buffer = self.buffer.read(cx).snapshot(cx);
11780
11781        let mut edits = Vec::new();
11782        let mut unfold_ranges = Vec::new();
11783        let mut refold_creases = Vec::new();
11784
11785        let selections = self.selections.all::<Point>(cx);
11786        let mut selections = selections.iter().peekable();
11787        let mut contiguous_row_selections = Vec::new();
11788        let mut new_selections = Vec::new();
11789
11790        while let Some(selection) = selections.next() {
11791            // Find all the selections that span a contiguous row range
11792            let (start_row, end_row) = consume_contiguous_rows(
11793                &mut contiguous_row_selections,
11794                selection,
11795                &display_map,
11796                &mut selections,
11797            );
11798
11799            // Move the text spanned by the row range to be before the line preceding the row range
11800            if start_row.0 > 0 {
11801                let range_to_move = Point::new(
11802                    start_row.previous_row().0,
11803                    buffer.line_len(start_row.previous_row()),
11804                )
11805                    ..Point::new(
11806                        end_row.previous_row().0,
11807                        buffer.line_len(end_row.previous_row()),
11808                    );
11809                let insertion_point = display_map
11810                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11811                    .0;
11812
11813                // Don't move lines across excerpts
11814                if buffer
11815                    .excerpt_containing(insertion_point..range_to_move.end)
11816                    .is_some()
11817                {
11818                    let text = buffer
11819                        .text_for_range(range_to_move.clone())
11820                        .flat_map(|s| s.chars())
11821                        .skip(1)
11822                        .chain(['\n'])
11823                        .collect::<String>();
11824
11825                    edits.push((
11826                        buffer.anchor_after(range_to_move.start)
11827                            ..buffer.anchor_before(range_to_move.end),
11828                        String::new(),
11829                    ));
11830                    let insertion_anchor = buffer.anchor_after(insertion_point);
11831                    edits.push((insertion_anchor..insertion_anchor, text));
11832
11833                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11834
11835                    // Move selections up
11836                    new_selections.extend(contiguous_row_selections.drain(..).map(
11837                        |mut selection| {
11838                            selection.start.row -= row_delta;
11839                            selection.end.row -= row_delta;
11840                            selection
11841                        },
11842                    ));
11843
11844                    // Move folds up
11845                    unfold_ranges.push(range_to_move.clone());
11846                    for fold in display_map.folds_in_range(
11847                        buffer.anchor_before(range_to_move.start)
11848                            ..buffer.anchor_after(range_to_move.end),
11849                    ) {
11850                        let mut start = fold.range.start.to_point(&buffer);
11851                        let mut end = fold.range.end.to_point(&buffer);
11852                        start.row -= row_delta;
11853                        end.row -= row_delta;
11854                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11855                    }
11856                }
11857            }
11858
11859            // If we didn't move line(s), preserve the existing selections
11860            new_selections.append(&mut contiguous_row_selections);
11861        }
11862
11863        self.transact(window, cx, |this, window, cx| {
11864            this.unfold_ranges(&unfold_ranges, true, true, cx);
11865            this.buffer.update(cx, |buffer, cx| {
11866                for (range, text) in edits {
11867                    buffer.edit([(range, text)], None, cx);
11868                }
11869            });
11870            this.fold_creases(refold_creases, true, window, cx);
11871            this.change_selections(Default::default(), window, cx, |s| {
11872                s.select(new_selections);
11873            })
11874        });
11875    }
11876
11877    pub fn move_line_down(
11878        &mut self,
11879        _: &MoveLineDown,
11880        window: &mut Window,
11881        cx: &mut Context<Self>,
11882    ) {
11883        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11884        if self.mode.is_single_line() {
11885            cx.propagate();
11886            return;
11887        }
11888
11889        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11890        let buffer = self.buffer.read(cx).snapshot(cx);
11891
11892        let mut edits = Vec::new();
11893        let mut unfold_ranges = Vec::new();
11894        let mut refold_creases = Vec::new();
11895
11896        let selections = self.selections.all::<Point>(cx);
11897        let mut selections = selections.iter().peekable();
11898        let mut contiguous_row_selections = Vec::new();
11899        let mut new_selections = Vec::new();
11900
11901        while let Some(selection) = selections.next() {
11902            // Find all the selections that span a contiguous row range
11903            let (start_row, end_row) = consume_contiguous_rows(
11904                &mut contiguous_row_selections,
11905                selection,
11906                &display_map,
11907                &mut selections,
11908            );
11909
11910            // Move the text spanned by the row range to be after the last line of the row range
11911            if end_row.0 <= buffer.max_point().row {
11912                let range_to_move =
11913                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11914                let insertion_point = display_map
11915                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11916                    .0;
11917
11918                // Don't move lines across excerpt boundaries
11919                if buffer
11920                    .excerpt_containing(range_to_move.start..insertion_point)
11921                    .is_some()
11922                {
11923                    let mut text = String::from("\n");
11924                    text.extend(buffer.text_for_range(range_to_move.clone()));
11925                    text.pop(); // Drop trailing newline
11926                    edits.push((
11927                        buffer.anchor_after(range_to_move.start)
11928                            ..buffer.anchor_before(range_to_move.end),
11929                        String::new(),
11930                    ));
11931                    let insertion_anchor = buffer.anchor_after(insertion_point);
11932                    edits.push((insertion_anchor..insertion_anchor, text));
11933
11934                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11935
11936                    // Move selections down
11937                    new_selections.extend(contiguous_row_selections.drain(..).map(
11938                        |mut selection| {
11939                            selection.start.row += row_delta;
11940                            selection.end.row += row_delta;
11941                            selection
11942                        },
11943                    ));
11944
11945                    // Move folds down
11946                    unfold_ranges.push(range_to_move.clone());
11947                    for fold in display_map.folds_in_range(
11948                        buffer.anchor_before(range_to_move.start)
11949                            ..buffer.anchor_after(range_to_move.end),
11950                    ) {
11951                        let mut start = fold.range.start.to_point(&buffer);
11952                        let mut end = fold.range.end.to_point(&buffer);
11953                        start.row += row_delta;
11954                        end.row += row_delta;
11955                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11956                    }
11957                }
11958            }
11959
11960            // If we didn't move line(s), preserve the existing selections
11961            new_selections.append(&mut contiguous_row_selections);
11962        }
11963
11964        self.transact(window, cx, |this, window, cx| {
11965            this.unfold_ranges(&unfold_ranges, true, true, cx);
11966            this.buffer.update(cx, |buffer, cx| {
11967                for (range, text) in edits {
11968                    buffer.edit([(range, text)], None, cx);
11969                }
11970            });
11971            this.fold_creases(refold_creases, true, window, cx);
11972            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11973        });
11974    }
11975
11976    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11978        let text_layout_details = &self.text_layout_details(window);
11979        self.transact(window, cx, |this, window, cx| {
11980            let edits = this.change_selections(Default::default(), window, cx, |s| {
11981                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11982                s.move_with(|display_map, selection| {
11983                    if !selection.is_empty() {
11984                        return;
11985                    }
11986
11987                    let mut head = selection.head();
11988                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11989                    if head.column() == display_map.line_len(head.row()) {
11990                        transpose_offset = display_map
11991                            .buffer_snapshot()
11992                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11993                    }
11994
11995                    if transpose_offset == 0 {
11996                        return;
11997                    }
11998
11999                    *head.column_mut() += 1;
12000                    head = display_map.clip_point(head, Bias::Right);
12001                    let goal = SelectionGoal::HorizontalPosition(
12002                        display_map
12003                            .x_for_display_point(head, text_layout_details)
12004                            .into(),
12005                    );
12006                    selection.collapse_to(head, goal);
12007
12008                    let transpose_start = display_map
12009                        .buffer_snapshot()
12010                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12011                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12012                        let transpose_end = display_map
12013                            .buffer_snapshot()
12014                            .clip_offset(transpose_offset + 1, Bias::Right);
12015                        if let Some(ch) = display_map
12016                            .buffer_snapshot()
12017                            .chars_at(transpose_start)
12018                            .next()
12019                        {
12020                            edits.push((transpose_start..transpose_offset, String::new()));
12021                            edits.push((transpose_end..transpose_end, ch.to_string()));
12022                        }
12023                    }
12024                });
12025                edits
12026            });
12027            this.buffer
12028                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12029            let selections = this.selections.all::<usize>(cx);
12030            this.change_selections(Default::default(), window, cx, |s| {
12031                s.select(selections);
12032            });
12033        });
12034    }
12035
12036    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12037        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12038        if self.mode.is_single_line() {
12039            cx.propagate();
12040            return;
12041        }
12042
12043        self.rewrap_impl(RewrapOptions::default(), cx)
12044    }
12045
12046    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12047        let buffer = self.buffer.read(cx).snapshot(cx);
12048        let selections = self.selections.all::<Point>(cx);
12049
12050        #[derive(Clone, Debug, PartialEq)]
12051        enum CommentFormat {
12052            /// single line comment, with prefix for line
12053            Line(String),
12054            /// single line within a block comment, with prefix for line
12055            BlockLine(String),
12056            /// a single line of a block comment that includes the initial delimiter
12057            BlockCommentWithStart(BlockCommentConfig),
12058            /// a single line of a block comment that includes the ending delimiter
12059            BlockCommentWithEnd(BlockCommentConfig),
12060        }
12061
12062        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12063        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12064            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12065                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12066                .peekable();
12067
12068            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12069                row
12070            } else {
12071                return Vec::new();
12072            };
12073
12074            let language_settings = buffer.language_settings_at(selection.head(), cx);
12075            let language_scope = buffer.language_scope_at(selection.head());
12076
12077            let indent_and_prefix_for_row =
12078                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12079                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12080                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12081                        &language_scope
12082                    {
12083                        let indent_end = Point::new(row, indent.len);
12084                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12085                        let line_text_after_indent = buffer
12086                            .text_for_range(indent_end..line_end)
12087                            .collect::<String>();
12088
12089                        let is_within_comment_override = buffer
12090                            .language_scope_at(indent_end)
12091                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12092                        let comment_delimiters = if is_within_comment_override {
12093                            // we are within a comment syntax node, but we don't
12094                            // yet know what kind of comment: block, doc or line
12095                            match (
12096                                language_scope.documentation_comment(),
12097                                language_scope.block_comment(),
12098                            ) {
12099                                (Some(config), _) | (_, Some(config))
12100                                    if buffer.contains_str_at(indent_end, &config.start) =>
12101                                {
12102                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12103                                }
12104                                (Some(config), _) | (_, Some(config))
12105                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12106                                {
12107                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12108                                }
12109                                (Some(config), _) | (_, Some(config))
12110                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12111                                {
12112                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12113                                }
12114                                (_, _) => language_scope
12115                                    .line_comment_prefixes()
12116                                    .iter()
12117                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12118                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12119                            }
12120                        } else {
12121                            // we not in an overridden comment node, but we may
12122                            // be within a non-overridden line comment node
12123                            language_scope
12124                                .line_comment_prefixes()
12125                                .iter()
12126                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12127                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12128                        };
12129
12130                        let rewrap_prefix = language_scope
12131                            .rewrap_prefixes()
12132                            .iter()
12133                            .find_map(|prefix_regex| {
12134                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12135                                    if mat.start() == 0 {
12136                                        Some(mat.as_str().to_string())
12137                                    } else {
12138                                        None
12139                                    }
12140                                })
12141                            })
12142                            .flatten();
12143                        (comment_delimiters, rewrap_prefix)
12144                    } else {
12145                        (None, None)
12146                    };
12147                    (indent, comment_prefix, rewrap_prefix)
12148                };
12149
12150            let mut ranges = Vec::new();
12151            let from_empty_selection = selection.is_empty();
12152
12153            let mut current_range_start = first_row;
12154            let mut prev_row = first_row;
12155            let (
12156                mut current_range_indent,
12157                mut current_range_comment_delimiters,
12158                mut current_range_rewrap_prefix,
12159            ) = indent_and_prefix_for_row(first_row);
12160
12161            for row in non_blank_rows_iter.skip(1) {
12162                let has_paragraph_break = row > prev_row + 1;
12163
12164                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12165                    indent_and_prefix_for_row(row);
12166
12167                let has_indent_change = row_indent != current_range_indent;
12168                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12169
12170                let has_boundary_change = has_comment_change
12171                    || row_rewrap_prefix.is_some()
12172                    || (has_indent_change && current_range_comment_delimiters.is_some());
12173
12174                if has_paragraph_break || has_boundary_change {
12175                    ranges.push((
12176                        language_settings.clone(),
12177                        Point::new(current_range_start, 0)
12178                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12179                        current_range_indent,
12180                        current_range_comment_delimiters.clone(),
12181                        current_range_rewrap_prefix.clone(),
12182                        from_empty_selection,
12183                    ));
12184                    current_range_start = row;
12185                    current_range_indent = row_indent;
12186                    current_range_comment_delimiters = row_comment_delimiters;
12187                    current_range_rewrap_prefix = row_rewrap_prefix;
12188                }
12189                prev_row = row;
12190            }
12191
12192            ranges.push((
12193                language_settings.clone(),
12194                Point::new(current_range_start, 0)
12195                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12196                current_range_indent,
12197                current_range_comment_delimiters,
12198                current_range_rewrap_prefix,
12199                from_empty_selection,
12200            ));
12201
12202            ranges
12203        });
12204
12205        let mut edits = Vec::new();
12206        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12207
12208        for (
12209            language_settings,
12210            wrap_range,
12211            mut indent_size,
12212            comment_prefix,
12213            rewrap_prefix,
12214            from_empty_selection,
12215        ) in wrap_ranges
12216        {
12217            let mut start_row = wrap_range.start.row;
12218            let mut end_row = wrap_range.end.row;
12219
12220            // Skip selections that overlap with a range that has already been rewrapped.
12221            let selection_range = start_row..end_row;
12222            if rewrapped_row_ranges
12223                .iter()
12224                .any(|range| range.overlaps(&selection_range))
12225            {
12226                continue;
12227            }
12228
12229            let tab_size = language_settings.tab_size;
12230
12231            let (line_prefix, inside_comment) = match &comment_prefix {
12232                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12233                    (Some(prefix.as_str()), true)
12234                }
12235                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12236                    (Some(prefix.as_ref()), true)
12237                }
12238                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12239                    start: _,
12240                    end: _,
12241                    prefix,
12242                    tab_size,
12243                })) => {
12244                    indent_size.len += tab_size;
12245                    (Some(prefix.as_ref()), true)
12246                }
12247                None => (None, false),
12248            };
12249            let indent_prefix = indent_size.chars().collect::<String>();
12250            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12251
12252            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12253                RewrapBehavior::InComments => inside_comment,
12254                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12255                RewrapBehavior::Anywhere => true,
12256            };
12257
12258            let should_rewrap = options.override_language_settings
12259                || allow_rewrap_based_on_language
12260                || self.hard_wrap.is_some();
12261            if !should_rewrap {
12262                continue;
12263            }
12264
12265            if from_empty_selection {
12266                'expand_upwards: while start_row > 0 {
12267                    let prev_row = start_row - 1;
12268                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12269                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12270                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12271                    {
12272                        start_row = prev_row;
12273                    } else {
12274                        break 'expand_upwards;
12275                    }
12276                }
12277
12278                'expand_downwards: while end_row < buffer.max_point().row {
12279                    let next_row = end_row + 1;
12280                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12281                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12282                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12283                    {
12284                        end_row = next_row;
12285                    } else {
12286                        break 'expand_downwards;
12287                    }
12288                }
12289            }
12290
12291            let start = Point::new(start_row, 0);
12292            let start_offset = ToOffset::to_offset(&start, &buffer);
12293            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12294            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12295            let mut first_line_delimiter = None;
12296            let mut last_line_delimiter = None;
12297            let Some(lines_without_prefixes) = selection_text
12298                .lines()
12299                .enumerate()
12300                .map(|(ix, line)| {
12301                    let line_trimmed = line.trim_start();
12302                    if rewrap_prefix.is_some() && ix > 0 {
12303                        Ok(line_trimmed)
12304                    } else if let Some(
12305                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12306                            start,
12307                            prefix,
12308                            end,
12309                            tab_size,
12310                        })
12311                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12312                            start,
12313                            prefix,
12314                            end,
12315                            tab_size,
12316                        }),
12317                    ) = &comment_prefix
12318                    {
12319                        let line_trimmed = line_trimmed
12320                            .strip_prefix(start.as_ref())
12321                            .map(|s| {
12322                                let mut indent_size = indent_size;
12323                                indent_size.len -= tab_size;
12324                                let indent_prefix: String = indent_size.chars().collect();
12325                                first_line_delimiter = Some((indent_prefix, start));
12326                                s.trim_start()
12327                            })
12328                            .unwrap_or(line_trimmed);
12329                        let line_trimmed = line_trimmed
12330                            .strip_suffix(end.as_ref())
12331                            .map(|s| {
12332                                last_line_delimiter = Some(end);
12333                                s.trim_end()
12334                            })
12335                            .unwrap_or(line_trimmed);
12336                        let line_trimmed = line_trimmed
12337                            .strip_prefix(prefix.as_ref())
12338                            .unwrap_or(line_trimmed);
12339                        Ok(line_trimmed)
12340                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12341                        line_trimmed.strip_prefix(prefix).with_context(|| {
12342                            format!("line did not start with prefix {prefix:?}: {line:?}")
12343                        })
12344                    } else {
12345                        line_trimmed
12346                            .strip_prefix(&line_prefix.trim_start())
12347                            .with_context(|| {
12348                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12349                            })
12350                    }
12351                })
12352                .collect::<Result<Vec<_>, _>>()
12353                .log_err()
12354            else {
12355                continue;
12356            };
12357
12358            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12359                buffer
12360                    .language_settings_at(Point::new(start_row, 0), cx)
12361                    .preferred_line_length as usize
12362            });
12363
12364            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12365                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12366            } else {
12367                line_prefix.clone()
12368            };
12369
12370            let wrapped_text = {
12371                let mut wrapped_text = wrap_with_prefix(
12372                    line_prefix,
12373                    subsequent_lines_prefix,
12374                    lines_without_prefixes.join("\n"),
12375                    wrap_column,
12376                    tab_size,
12377                    options.preserve_existing_whitespace,
12378                );
12379
12380                if let Some((indent, delimiter)) = first_line_delimiter {
12381                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12382                }
12383                if let Some(last_line) = last_line_delimiter {
12384                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12385                }
12386
12387                wrapped_text
12388            };
12389
12390            // TODO: should always use char-based diff while still supporting cursor behavior that
12391            // matches vim.
12392            let mut diff_options = DiffOptions::default();
12393            if options.override_language_settings {
12394                diff_options.max_word_diff_len = 0;
12395                diff_options.max_word_diff_line_count = 0;
12396            } else {
12397                diff_options.max_word_diff_len = usize::MAX;
12398                diff_options.max_word_diff_line_count = usize::MAX;
12399            }
12400
12401            for (old_range, new_text) in
12402                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12403            {
12404                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12405                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12406                edits.push((edit_start..edit_end, new_text));
12407            }
12408
12409            rewrapped_row_ranges.push(start_row..=end_row);
12410        }
12411
12412        self.buffer
12413            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12414    }
12415
12416    pub fn cut_common(
12417        &mut self,
12418        cut_no_selection_line: bool,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) -> ClipboardItem {
12422        let mut text = String::new();
12423        let buffer = self.buffer.read(cx).snapshot(cx);
12424        let mut selections = self.selections.all::<Point>(cx);
12425        let mut clipboard_selections = Vec::with_capacity(selections.len());
12426        {
12427            let max_point = buffer.max_point();
12428            let mut is_first = true;
12429            for selection in &mut selections {
12430                let is_entire_line =
12431                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12432                if is_entire_line {
12433                    selection.start = Point::new(selection.start.row, 0);
12434                    if !selection.is_empty() && selection.end.column == 0 {
12435                        selection.end = cmp::min(max_point, selection.end);
12436                    } else {
12437                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12438                    }
12439                    selection.goal = SelectionGoal::None;
12440                }
12441                if is_first {
12442                    is_first = false;
12443                } else {
12444                    text += "\n";
12445                }
12446                let mut len = 0;
12447                for chunk in buffer.text_for_range(selection.start..selection.end) {
12448                    text.push_str(chunk);
12449                    len += chunk.len();
12450                }
12451                clipboard_selections.push(ClipboardSelection {
12452                    len,
12453                    is_entire_line,
12454                    first_line_indent: buffer
12455                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12456                        .len,
12457                });
12458            }
12459        }
12460
12461        self.transact(window, cx, |this, window, cx| {
12462            this.change_selections(Default::default(), window, cx, |s| {
12463                s.select(selections);
12464            });
12465            this.insert("", window, cx);
12466        });
12467        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12468    }
12469
12470    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12471        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12472        let item = self.cut_common(true, window, cx);
12473        cx.write_to_clipboard(item);
12474    }
12475
12476    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12477        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12478        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12479            s.move_with(|snapshot, sel| {
12480                if sel.is_empty() {
12481                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12482                }
12483                if sel.is_empty() {
12484                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12485                }
12486            });
12487        });
12488        let item = self.cut_common(false, window, cx);
12489        cx.set_global(KillRing(item))
12490    }
12491
12492    pub fn kill_ring_yank(
12493        &mut self,
12494        _: &KillRingYank,
12495        window: &mut Window,
12496        cx: &mut Context<Self>,
12497    ) {
12498        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12499        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12500            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12501                (kill_ring.text().to_string(), kill_ring.metadata_json())
12502            } else {
12503                return;
12504            }
12505        } else {
12506            return;
12507        };
12508        self.do_paste(&text, metadata, false, window, cx);
12509    }
12510
12511    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12512        self.do_copy(true, cx);
12513    }
12514
12515    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12516        self.do_copy(false, cx);
12517    }
12518
12519    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12520        let selections = self.selections.all::<Point>(cx);
12521        let buffer = self.buffer.read(cx).read(cx);
12522        let mut text = String::new();
12523
12524        let mut clipboard_selections = Vec::with_capacity(selections.len());
12525        {
12526            let max_point = buffer.max_point();
12527            let mut is_first = true;
12528            for selection in &selections {
12529                let mut start = selection.start;
12530                let mut end = selection.end;
12531                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12532                let mut add_trailing_newline = false;
12533                if is_entire_line {
12534                    start = Point::new(start.row, 0);
12535                    let next_line_start = Point::new(end.row + 1, 0);
12536                    if next_line_start <= max_point {
12537                        end = next_line_start;
12538                    } else {
12539                        // We're on the last line without a trailing newline.
12540                        // Copy to the end of the line and add a newline afterwards.
12541                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12542                        add_trailing_newline = true;
12543                    }
12544                }
12545
12546                let mut trimmed_selections = Vec::new();
12547                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12548                    let row = MultiBufferRow(start.row);
12549                    let first_indent = buffer.indent_size_for_line(row);
12550                    if first_indent.len == 0 || start.column > first_indent.len {
12551                        trimmed_selections.push(start..end);
12552                    } else {
12553                        trimmed_selections.push(
12554                            Point::new(row.0, first_indent.len)
12555                                ..Point::new(row.0, buffer.line_len(row)),
12556                        );
12557                        for row in start.row + 1..=end.row {
12558                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12559                            if row == end.row {
12560                                line_len = end.column;
12561                            }
12562                            if line_len == 0 {
12563                                trimmed_selections
12564                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12565                                continue;
12566                            }
12567                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12568                            if row_indent_size.len >= first_indent.len {
12569                                trimmed_selections.push(
12570                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12571                                );
12572                            } else {
12573                                trimmed_selections.clear();
12574                                trimmed_selections.push(start..end);
12575                                break;
12576                            }
12577                        }
12578                    }
12579                } else {
12580                    trimmed_selections.push(start..end);
12581                }
12582
12583                for trimmed_range in trimmed_selections {
12584                    if is_first {
12585                        is_first = false;
12586                    } else {
12587                        text += "\n";
12588                    }
12589                    let mut len = 0;
12590                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12591                        text.push_str(chunk);
12592                        len += chunk.len();
12593                    }
12594                    if add_trailing_newline {
12595                        text.push('\n');
12596                        len += 1;
12597                    }
12598                    clipboard_selections.push(ClipboardSelection {
12599                        len,
12600                        is_entire_line,
12601                        first_line_indent: buffer
12602                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12603                            .len,
12604                    });
12605                }
12606            }
12607        }
12608
12609        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12610            text,
12611            clipboard_selections,
12612        ));
12613    }
12614
12615    pub fn do_paste(
12616        &mut self,
12617        text: &String,
12618        clipboard_selections: Option<Vec<ClipboardSelection>>,
12619        handle_entire_lines: bool,
12620        window: &mut Window,
12621        cx: &mut Context<Self>,
12622    ) {
12623        if self.read_only(cx) {
12624            return;
12625        }
12626
12627        let clipboard_text = Cow::Borrowed(text.as_str());
12628
12629        self.transact(window, cx, |this, window, cx| {
12630            let had_active_edit_prediction = this.has_active_edit_prediction();
12631            let old_selections = this.selections.all::<usize>(cx);
12632            let cursor_offset = this.selections.last::<usize>(cx).head();
12633
12634            if let Some(mut clipboard_selections) = clipboard_selections {
12635                let all_selections_were_entire_line =
12636                    clipboard_selections.iter().all(|s| s.is_entire_line);
12637                let first_selection_indent_column =
12638                    clipboard_selections.first().map(|s| s.first_line_indent);
12639                if clipboard_selections.len() != old_selections.len() {
12640                    clipboard_selections.drain(..);
12641                }
12642                let mut auto_indent_on_paste = true;
12643
12644                this.buffer.update(cx, |buffer, cx| {
12645                    let snapshot = buffer.read(cx);
12646                    auto_indent_on_paste = snapshot
12647                        .language_settings_at(cursor_offset, cx)
12648                        .auto_indent_on_paste;
12649
12650                    let mut start_offset = 0;
12651                    let mut edits = Vec::new();
12652                    let mut original_indent_columns = Vec::new();
12653                    for (ix, selection) in old_selections.iter().enumerate() {
12654                        let to_insert;
12655                        let entire_line;
12656                        let original_indent_column;
12657                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12658                            let end_offset = start_offset + clipboard_selection.len;
12659                            to_insert = &clipboard_text[start_offset..end_offset];
12660                            entire_line = clipboard_selection.is_entire_line;
12661                            start_offset = end_offset + 1;
12662                            original_indent_column = Some(clipboard_selection.first_line_indent);
12663                        } else {
12664                            to_insert = &*clipboard_text;
12665                            entire_line = all_selections_were_entire_line;
12666                            original_indent_column = first_selection_indent_column
12667                        }
12668
12669                        let (range, to_insert) =
12670                            if selection.is_empty() && handle_entire_lines && entire_line {
12671                                // If the corresponding selection was empty when this slice of the
12672                                // clipboard text was written, then the entire line containing the
12673                                // selection was copied. If this selection is also currently empty,
12674                                // then paste the line before the current line of the buffer.
12675                                let column = selection.start.to_point(&snapshot).column as usize;
12676                                let line_start = selection.start - column;
12677                                (line_start..line_start, Cow::Borrowed(to_insert))
12678                            } else {
12679                                let language = snapshot.language_at(selection.head());
12680                                let range = selection.range();
12681                                if let Some(language) = language
12682                                    && language.name() == "Markdown".into()
12683                                {
12684                                    edit_for_markdown_paste(
12685                                        &snapshot,
12686                                        range,
12687                                        to_insert,
12688                                        url::Url::parse(to_insert).ok(),
12689                                    )
12690                                } else {
12691                                    (range, Cow::Borrowed(to_insert))
12692                                }
12693                            };
12694
12695                        edits.push((range, to_insert));
12696                        original_indent_columns.push(original_indent_column);
12697                    }
12698                    drop(snapshot);
12699
12700                    buffer.edit(
12701                        edits,
12702                        if auto_indent_on_paste {
12703                            Some(AutoindentMode::Block {
12704                                original_indent_columns,
12705                            })
12706                        } else {
12707                            None
12708                        },
12709                        cx,
12710                    );
12711                });
12712
12713                let selections = this.selections.all::<usize>(cx);
12714                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12715            } else {
12716                let url = url::Url::parse(&clipboard_text).ok();
12717
12718                let auto_indent_mode = if !clipboard_text.is_empty() {
12719                    Some(AutoindentMode::Block {
12720                        original_indent_columns: Vec::new(),
12721                    })
12722                } else {
12723                    None
12724                };
12725
12726                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12727                    let snapshot = buffer.snapshot(cx);
12728
12729                    let anchors = old_selections
12730                        .iter()
12731                        .map(|s| {
12732                            let anchor = snapshot.anchor_after(s.head());
12733                            s.map(|_| anchor)
12734                        })
12735                        .collect::<Vec<_>>();
12736
12737                    let mut edits = Vec::new();
12738
12739                    for selection in old_selections.iter() {
12740                        let language = snapshot.language_at(selection.head());
12741                        let range = selection.range();
12742
12743                        let (edit_range, edit_text) = if let Some(language) = language
12744                            && language.name() == "Markdown".into()
12745                        {
12746                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12747                        } else {
12748                            (range, clipboard_text.clone())
12749                        };
12750
12751                        edits.push((edit_range, edit_text));
12752                    }
12753
12754                    drop(snapshot);
12755                    buffer.edit(edits, auto_indent_mode, cx);
12756
12757                    anchors
12758                });
12759
12760                this.change_selections(Default::default(), window, cx, |s| {
12761                    s.select_anchors(selection_anchors);
12762                });
12763            }
12764
12765            let trigger_in_words =
12766                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12767
12768            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12769        });
12770    }
12771
12772    pub fn diff_clipboard_with_selection(
12773        &mut self,
12774        _: &DiffClipboardWithSelection,
12775        window: &mut Window,
12776        cx: &mut Context<Self>,
12777    ) {
12778        let selections = self.selections.all::<usize>(cx);
12779
12780        if selections.is_empty() {
12781            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12782            return;
12783        };
12784
12785        let clipboard_text = match cx.read_from_clipboard() {
12786            Some(item) => match item.entries().first() {
12787                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12788                _ => None,
12789            },
12790            None => None,
12791        };
12792
12793        let Some(clipboard_text) = clipboard_text else {
12794            log::warn!("Clipboard doesn't contain text.");
12795            return;
12796        };
12797
12798        window.dispatch_action(
12799            Box::new(DiffClipboardWithSelectionData {
12800                clipboard_text,
12801                editor: cx.entity(),
12802            }),
12803            cx,
12804        );
12805    }
12806
12807    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12808        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12809        if let Some(item) = cx.read_from_clipboard() {
12810            let entries = item.entries();
12811
12812            match entries.first() {
12813                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12814                // of all the pasted entries.
12815                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12816                    .do_paste(
12817                        clipboard_string.text(),
12818                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12819                        true,
12820                        window,
12821                        cx,
12822                    ),
12823                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12824            }
12825        }
12826    }
12827
12828    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12829        if self.read_only(cx) {
12830            return;
12831        }
12832
12833        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12834
12835        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12836            if let Some((selections, _)) =
12837                self.selection_history.transaction(transaction_id).cloned()
12838            {
12839                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12840                    s.select_anchors(selections.to_vec());
12841                });
12842            } else {
12843                log::error!(
12844                    "No entry in selection_history found for undo. \
12845                     This may correspond to a bug where undo does not update the selection. \
12846                     If this is occurring, please add details to \
12847                     https://github.com/zed-industries/zed/issues/22692"
12848                );
12849            }
12850            self.request_autoscroll(Autoscroll::fit(), cx);
12851            self.unmark_text(window, cx);
12852            self.refresh_edit_prediction(true, false, window, cx);
12853            cx.emit(EditorEvent::Edited { transaction_id });
12854            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12855        }
12856    }
12857
12858    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12859        if self.read_only(cx) {
12860            return;
12861        }
12862
12863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12864
12865        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12866            if let Some((_, Some(selections))) =
12867                self.selection_history.transaction(transaction_id).cloned()
12868            {
12869                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12870                    s.select_anchors(selections.to_vec());
12871                });
12872            } else {
12873                log::error!(
12874                    "No entry in selection_history found for redo. \
12875                     This may correspond to a bug where undo does not update the selection. \
12876                     If this is occurring, please add details to \
12877                     https://github.com/zed-industries/zed/issues/22692"
12878                );
12879            }
12880            self.request_autoscroll(Autoscroll::fit(), cx);
12881            self.unmark_text(window, cx);
12882            self.refresh_edit_prediction(true, false, window, cx);
12883            cx.emit(EditorEvent::Edited { transaction_id });
12884        }
12885    }
12886
12887    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12888        self.buffer
12889            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12890    }
12891
12892    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12893        self.buffer
12894            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12895    }
12896
12897    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12898        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12899        self.change_selections(Default::default(), window, cx, |s| {
12900            s.move_with(|map, selection| {
12901                let cursor = if selection.is_empty() {
12902                    movement::left(map, selection.start)
12903                } else {
12904                    selection.start
12905                };
12906                selection.collapse_to(cursor, SelectionGoal::None);
12907            });
12908        })
12909    }
12910
12911    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12913        self.change_selections(Default::default(), window, cx, |s| {
12914            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12915        })
12916    }
12917
12918    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12920        self.change_selections(Default::default(), window, cx, |s| {
12921            s.move_with(|map, selection| {
12922                let cursor = if selection.is_empty() {
12923                    movement::right(map, selection.end)
12924                } else {
12925                    selection.end
12926                };
12927                selection.collapse_to(cursor, SelectionGoal::None)
12928            });
12929        })
12930    }
12931
12932    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12933        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12934        self.change_selections(Default::default(), window, cx, |s| {
12935            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12936        });
12937    }
12938
12939    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12940        if self.take_rename(true, window, cx).is_some() {
12941            return;
12942        }
12943
12944        if self.mode.is_single_line() {
12945            cx.propagate();
12946            return;
12947        }
12948
12949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12950
12951        let text_layout_details = &self.text_layout_details(window);
12952        let selection_count = self.selections.count();
12953        let first_selection = self.selections.first_anchor();
12954
12955        self.change_selections(Default::default(), window, cx, |s| {
12956            s.move_with(|map, selection| {
12957                if !selection.is_empty() {
12958                    selection.goal = SelectionGoal::None;
12959                }
12960                let (cursor, goal) = movement::up(
12961                    map,
12962                    selection.start,
12963                    selection.goal,
12964                    false,
12965                    text_layout_details,
12966                );
12967                selection.collapse_to(cursor, goal);
12968            });
12969        });
12970
12971        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12972        {
12973            cx.propagate();
12974        }
12975    }
12976
12977    pub fn move_up_by_lines(
12978        &mut self,
12979        action: &MoveUpByLines,
12980        window: &mut Window,
12981        cx: &mut Context<Self>,
12982    ) {
12983        if self.take_rename(true, window, cx).is_some() {
12984            return;
12985        }
12986
12987        if self.mode.is_single_line() {
12988            cx.propagate();
12989            return;
12990        }
12991
12992        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12993
12994        let text_layout_details = &self.text_layout_details(window);
12995
12996        self.change_selections(Default::default(), window, cx, |s| {
12997            s.move_with(|map, selection| {
12998                if !selection.is_empty() {
12999                    selection.goal = SelectionGoal::None;
13000                }
13001                let (cursor, goal) = movement::up_by_rows(
13002                    map,
13003                    selection.start,
13004                    action.lines,
13005                    selection.goal,
13006                    false,
13007                    text_layout_details,
13008                );
13009                selection.collapse_to(cursor, goal);
13010            });
13011        })
13012    }
13013
13014    pub fn move_down_by_lines(
13015        &mut self,
13016        action: &MoveDownByLines,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        if self.take_rename(true, window, cx).is_some() {
13021            return;
13022        }
13023
13024        if self.mode.is_single_line() {
13025            cx.propagate();
13026            return;
13027        }
13028
13029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13030
13031        let text_layout_details = &self.text_layout_details(window);
13032
13033        self.change_selections(Default::default(), window, cx, |s| {
13034            s.move_with(|map, selection| {
13035                if !selection.is_empty() {
13036                    selection.goal = SelectionGoal::None;
13037                }
13038                let (cursor, goal) = movement::down_by_rows(
13039                    map,
13040                    selection.start,
13041                    action.lines,
13042                    selection.goal,
13043                    false,
13044                    text_layout_details,
13045                );
13046                selection.collapse_to(cursor, goal);
13047            });
13048        })
13049    }
13050
13051    pub fn select_down_by_lines(
13052        &mut self,
13053        action: &SelectDownByLines,
13054        window: &mut Window,
13055        cx: &mut Context<Self>,
13056    ) {
13057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13058        let text_layout_details = &self.text_layout_details(window);
13059        self.change_selections(Default::default(), window, cx, |s| {
13060            s.move_heads_with(|map, head, goal| {
13061                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13062            })
13063        })
13064    }
13065
13066    pub fn select_up_by_lines(
13067        &mut self,
13068        action: &SelectUpByLines,
13069        window: &mut Window,
13070        cx: &mut Context<Self>,
13071    ) {
13072        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13073        let text_layout_details = &self.text_layout_details(window);
13074        self.change_selections(Default::default(), window, cx, |s| {
13075            s.move_heads_with(|map, head, goal| {
13076                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13077            })
13078        })
13079    }
13080
13081    pub fn select_page_up(
13082        &mut self,
13083        _: &SelectPageUp,
13084        window: &mut Window,
13085        cx: &mut Context<Self>,
13086    ) {
13087        let Some(row_count) = self.visible_row_count() else {
13088            return;
13089        };
13090
13091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13092
13093        let text_layout_details = &self.text_layout_details(window);
13094
13095        self.change_selections(Default::default(), window, cx, |s| {
13096            s.move_heads_with(|map, head, goal| {
13097                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13098            })
13099        })
13100    }
13101
13102    pub fn move_page_up(
13103        &mut self,
13104        action: &MovePageUp,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) {
13108        if self.take_rename(true, window, cx).is_some() {
13109            return;
13110        }
13111
13112        if self
13113            .context_menu
13114            .borrow_mut()
13115            .as_mut()
13116            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13117            .unwrap_or(false)
13118        {
13119            return;
13120        }
13121
13122        if matches!(self.mode, EditorMode::SingleLine) {
13123            cx.propagate();
13124            return;
13125        }
13126
13127        let Some(row_count) = self.visible_row_count() else {
13128            return;
13129        };
13130
13131        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13132
13133        let effects = if action.center_cursor {
13134            SelectionEffects::scroll(Autoscroll::center())
13135        } else {
13136            SelectionEffects::default()
13137        };
13138
13139        let text_layout_details = &self.text_layout_details(window);
13140
13141        self.change_selections(effects, window, cx, |s| {
13142            s.move_with(|map, selection| {
13143                if !selection.is_empty() {
13144                    selection.goal = SelectionGoal::None;
13145                }
13146                let (cursor, goal) = movement::up_by_rows(
13147                    map,
13148                    selection.end,
13149                    row_count,
13150                    selection.goal,
13151                    false,
13152                    text_layout_details,
13153                );
13154                selection.collapse_to(cursor, goal);
13155            });
13156        });
13157    }
13158
13159    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13160        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13161        let text_layout_details = &self.text_layout_details(window);
13162        self.change_selections(Default::default(), window, cx, |s| {
13163            s.move_heads_with(|map, head, goal| {
13164                movement::up(map, head, goal, false, text_layout_details)
13165            })
13166        })
13167    }
13168
13169    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13170        self.take_rename(true, window, cx);
13171
13172        if self.mode.is_single_line() {
13173            cx.propagate();
13174            return;
13175        }
13176
13177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13178
13179        let text_layout_details = &self.text_layout_details(window);
13180        let selection_count = self.selections.count();
13181        let first_selection = self.selections.first_anchor();
13182
13183        self.change_selections(Default::default(), window, cx, |s| {
13184            s.move_with(|map, selection| {
13185                if !selection.is_empty() {
13186                    selection.goal = SelectionGoal::None;
13187                }
13188                let (cursor, goal) = movement::down(
13189                    map,
13190                    selection.end,
13191                    selection.goal,
13192                    false,
13193                    text_layout_details,
13194                );
13195                selection.collapse_to(cursor, goal);
13196            });
13197        });
13198
13199        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13200        {
13201            cx.propagate();
13202        }
13203    }
13204
13205    pub fn select_page_down(
13206        &mut self,
13207        _: &SelectPageDown,
13208        window: &mut Window,
13209        cx: &mut Context<Self>,
13210    ) {
13211        let Some(row_count) = self.visible_row_count() else {
13212            return;
13213        };
13214
13215        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13216
13217        let text_layout_details = &self.text_layout_details(window);
13218
13219        self.change_selections(Default::default(), window, cx, |s| {
13220            s.move_heads_with(|map, head, goal| {
13221                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13222            })
13223        })
13224    }
13225
13226    pub fn move_page_down(
13227        &mut self,
13228        action: &MovePageDown,
13229        window: &mut Window,
13230        cx: &mut Context<Self>,
13231    ) {
13232        if self.take_rename(true, window, cx).is_some() {
13233            return;
13234        }
13235
13236        if self
13237            .context_menu
13238            .borrow_mut()
13239            .as_mut()
13240            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13241            .unwrap_or(false)
13242        {
13243            return;
13244        }
13245
13246        if matches!(self.mode, EditorMode::SingleLine) {
13247            cx.propagate();
13248            return;
13249        }
13250
13251        let Some(row_count) = self.visible_row_count() else {
13252            return;
13253        };
13254
13255        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13256
13257        let effects = if action.center_cursor {
13258            SelectionEffects::scroll(Autoscroll::center())
13259        } else {
13260            SelectionEffects::default()
13261        };
13262
13263        let text_layout_details = &self.text_layout_details(window);
13264        self.change_selections(effects, window, cx, |s| {
13265            s.move_with(|map, selection| {
13266                if !selection.is_empty() {
13267                    selection.goal = SelectionGoal::None;
13268                }
13269                let (cursor, goal) = movement::down_by_rows(
13270                    map,
13271                    selection.end,
13272                    row_count,
13273                    selection.goal,
13274                    false,
13275                    text_layout_details,
13276                );
13277                selection.collapse_to(cursor, goal);
13278            });
13279        });
13280    }
13281
13282    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13284        let text_layout_details = &self.text_layout_details(window);
13285        self.change_selections(Default::default(), window, cx, |s| {
13286            s.move_heads_with(|map, head, goal| {
13287                movement::down(map, head, goal, false, text_layout_details)
13288            })
13289        });
13290    }
13291
13292    pub fn context_menu_first(
13293        &mut self,
13294        _: &ContextMenuFirst,
13295        window: &mut Window,
13296        cx: &mut Context<Self>,
13297    ) {
13298        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13299            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13300        }
13301    }
13302
13303    pub fn context_menu_prev(
13304        &mut self,
13305        _: &ContextMenuPrevious,
13306        window: &mut Window,
13307        cx: &mut Context<Self>,
13308    ) {
13309        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13310            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13311        }
13312    }
13313
13314    pub fn context_menu_next(
13315        &mut self,
13316        _: &ContextMenuNext,
13317        window: &mut Window,
13318        cx: &mut Context<Self>,
13319    ) {
13320        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13321            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13322        }
13323    }
13324
13325    pub fn context_menu_last(
13326        &mut self,
13327        _: &ContextMenuLast,
13328        window: &mut Window,
13329        cx: &mut Context<Self>,
13330    ) {
13331        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13332            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13333        }
13334    }
13335
13336    pub fn signature_help_prev(
13337        &mut self,
13338        _: &SignatureHelpPrevious,
13339        _: &mut Window,
13340        cx: &mut Context<Self>,
13341    ) {
13342        if let Some(popover) = self.signature_help_state.popover_mut() {
13343            if popover.current_signature == 0 {
13344                popover.current_signature = popover.signatures.len() - 1;
13345            } else {
13346                popover.current_signature -= 1;
13347            }
13348            cx.notify();
13349        }
13350    }
13351
13352    pub fn signature_help_next(
13353        &mut self,
13354        _: &SignatureHelpNext,
13355        _: &mut Window,
13356        cx: &mut Context<Self>,
13357    ) {
13358        if let Some(popover) = self.signature_help_state.popover_mut() {
13359            if popover.current_signature + 1 == popover.signatures.len() {
13360                popover.current_signature = 0;
13361            } else {
13362                popover.current_signature += 1;
13363            }
13364            cx.notify();
13365        }
13366    }
13367
13368    pub fn move_to_previous_word_start(
13369        &mut self,
13370        _: &MoveToPreviousWordStart,
13371        window: &mut Window,
13372        cx: &mut Context<Self>,
13373    ) {
13374        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13375        self.change_selections(Default::default(), window, cx, |s| {
13376            s.move_cursors_with(|map, head, _| {
13377                (
13378                    movement::previous_word_start(map, head),
13379                    SelectionGoal::None,
13380                )
13381            });
13382        })
13383    }
13384
13385    pub fn move_to_previous_subword_start(
13386        &mut self,
13387        _: &MoveToPreviousSubwordStart,
13388        window: &mut Window,
13389        cx: &mut Context<Self>,
13390    ) {
13391        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13392        self.change_selections(Default::default(), window, cx, |s| {
13393            s.move_cursors_with(|map, head, _| {
13394                (
13395                    movement::previous_subword_start(map, head),
13396                    SelectionGoal::None,
13397                )
13398            });
13399        })
13400    }
13401
13402    pub fn select_to_previous_word_start(
13403        &mut self,
13404        _: &SelectToPreviousWordStart,
13405        window: &mut Window,
13406        cx: &mut Context<Self>,
13407    ) {
13408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13409        self.change_selections(Default::default(), window, cx, |s| {
13410            s.move_heads_with(|map, head, _| {
13411                (
13412                    movement::previous_word_start(map, head),
13413                    SelectionGoal::None,
13414                )
13415            });
13416        })
13417    }
13418
13419    pub fn select_to_previous_subword_start(
13420        &mut self,
13421        _: &SelectToPreviousSubwordStart,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13426        self.change_selections(Default::default(), window, cx, |s| {
13427            s.move_heads_with(|map, head, _| {
13428                (
13429                    movement::previous_subword_start(map, head),
13430                    SelectionGoal::None,
13431                )
13432            });
13433        })
13434    }
13435
13436    pub fn delete_to_previous_word_start(
13437        &mut self,
13438        action: &DeleteToPreviousWordStart,
13439        window: &mut Window,
13440        cx: &mut Context<Self>,
13441    ) {
13442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13443        self.transact(window, cx, |this, window, cx| {
13444            this.select_autoclose_pair(window, cx);
13445            this.change_selections(Default::default(), window, cx, |s| {
13446                s.move_with(|map, selection| {
13447                    if selection.is_empty() {
13448                        let mut cursor = if action.ignore_newlines {
13449                            movement::previous_word_start(map, selection.head())
13450                        } else {
13451                            movement::previous_word_start_or_newline(map, selection.head())
13452                        };
13453                        cursor = movement::adjust_greedy_deletion(
13454                            map,
13455                            selection.head(),
13456                            cursor,
13457                            action.ignore_brackets,
13458                        );
13459                        selection.set_head(cursor, SelectionGoal::None);
13460                    }
13461                });
13462            });
13463            this.insert("", window, cx);
13464        });
13465    }
13466
13467    pub fn delete_to_previous_subword_start(
13468        &mut self,
13469        _: &DeleteToPreviousSubwordStart,
13470        window: &mut Window,
13471        cx: &mut Context<Self>,
13472    ) {
13473        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13474        self.transact(window, cx, |this, window, cx| {
13475            this.select_autoclose_pair(window, cx);
13476            this.change_selections(Default::default(), window, cx, |s| {
13477                s.move_with(|map, selection| {
13478                    if selection.is_empty() {
13479                        let mut cursor = movement::previous_subword_start(map, selection.head());
13480                        cursor =
13481                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13482                        selection.set_head(cursor, SelectionGoal::None);
13483                    }
13484                });
13485            });
13486            this.insert("", window, cx);
13487        });
13488    }
13489
13490    pub fn move_to_next_word_end(
13491        &mut self,
13492        _: &MoveToNextWordEnd,
13493        window: &mut Window,
13494        cx: &mut Context<Self>,
13495    ) {
13496        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13497        self.change_selections(Default::default(), window, cx, |s| {
13498            s.move_cursors_with(|map, head, _| {
13499                (movement::next_word_end(map, head), SelectionGoal::None)
13500            });
13501        })
13502    }
13503
13504    pub fn move_to_next_subword_end(
13505        &mut self,
13506        _: &MoveToNextSubwordEnd,
13507        window: &mut Window,
13508        cx: &mut Context<Self>,
13509    ) {
13510        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13511        self.change_selections(Default::default(), window, cx, |s| {
13512            s.move_cursors_with(|map, head, _| {
13513                (movement::next_subword_end(map, head), SelectionGoal::None)
13514            });
13515        })
13516    }
13517
13518    pub fn select_to_next_word_end(
13519        &mut self,
13520        _: &SelectToNextWordEnd,
13521        window: &mut Window,
13522        cx: &mut Context<Self>,
13523    ) {
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13525        self.change_selections(Default::default(), window, cx, |s| {
13526            s.move_heads_with(|map, head, _| {
13527                (movement::next_word_end(map, head), SelectionGoal::None)
13528            });
13529        })
13530    }
13531
13532    pub fn select_to_next_subword_end(
13533        &mut self,
13534        _: &SelectToNextSubwordEnd,
13535        window: &mut Window,
13536        cx: &mut Context<Self>,
13537    ) {
13538        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13539        self.change_selections(Default::default(), window, cx, |s| {
13540            s.move_heads_with(|map, head, _| {
13541                (movement::next_subword_end(map, head), SelectionGoal::None)
13542            });
13543        })
13544    }
13545
13546    pub fn delete_to_next_word_end(
13547        &mut self,
13548        action: &DeleteToNextWordEnd,
13549        window: &mut Window,
13550        cx: &mut Context<Self>,
13551    ) {
13552        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13553        self.transact(window, cx, |this, window, cx| {
13554            this.change_selections(Default::default(), window, cx, |s| {
13555                s.move_with(|map, selection| {
13556                    if selection.is_empty() {
13557                        let mut cursor = if action.ignore_newlines {
13558                            movement::next_word_end(map, selection.head())
13559                        } else {
13560                            movement::next_word_end_or_newline(map, selection.head())
13561                        };
13562                        cursor = movement::adjust_greedy_deletion(
13563                            map,
13564                            selection.head(),
13565                            cursor,
13566                            action.ignore_brackets,
13567                        );
13568                        selection.set_head(cursor, SelectionGoal::None);
13569                    }
13570                });
13571            });
13572            this.insert("", window, cx);
13573        });
13574    }
13575
13576    pub fn delete_to_next_subword_end(
13577        &mut self,
13578        _: &DeleteToNextSubwordEnd,
13579        window: &mut Window,
13580        cx: &mut Context<Self>,
13581    ) {
13582        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13583        self.transact(window, cx, |this, window, cx| {
13584            this.change_selections(Default::default(), window, cx, |s| {
13585                s.move_with(|map, selection| {
13586                    if selection.is_empty() {
13587                        let mut cursor = movement::next_subword_end(map, selection.head());
13588                        cursor =
13589                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13590                        selection.set_head(cursor, SelectionGoal::None);
13591                    }
13592                });
13593            });
13594            this.insert("", window, cx);
13595        });
13596    }
13597
13598    pub fn move_to_beginning_of_line(
13599        &mut self,
13600        action: &MoveToBeginningOfLine,
13601        window: &mut Window,
13602        cx: &mut Context<Self>,
13603    ) {
13604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13605        self.change_selections(Default::default(), window, cx, |s| {
13606            s.move_cursors_with(|map, head, _| {
13607                (
13608                    movement::indented_line_beginning(
13609                        map,
13610                        head,
13611                        action.stop_at_soft_wraps,
13612                        action.stop_at_indent,
13613                    ),
13614                    SelectionGoal::None,
13615                )
13616            });
13617        })
13618    }
13619
13620    pub fn select_to_beginning_of_line(
13621        &mut self,
13622        action: &SelectToBeginningOfLine,
13623        window: &mut Window,
13624        cx: &mut Context<Self>,
13625    ) {
13626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13627        self.change_selections(Default::default(), window, cx, |s| {
13628            s.move_heads_with(|map, head, _| {
13629                (
13630                    movement::indented_line_beginning(
13631                        map,
13632                        head,
13633                        action.stop_at_soft_wraps,
13634                        action.stop_at_indent,
13635                    ),
13636                    SelectionGoal::None,
13637                )
13638            });
13639        });
13640    }
13641
13642    pub fn delete_to_beginning_of_line(
13643        &mut self,
13644        action: &DeleteToBeginningOfLine,
13645        window: &mut Window,
13646        cx: &mut Context<Self>,
13647    ) {
13648        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13649        self.transact(window, cx, |this, window, cx| {
13650            this.change_selections(Default::default(), window, cx, |s| {
13651                s.move_with(|_, selection| {
13652                    selection.reversed = true;
13653                });
13654            });
13655
13656            this.select_to_beginning_of_line(
13657                &SelectToBeginningOfLine {
13658                    stop_at_soft_wraps: false,
13659                    stop_at_indent: action.stop_at_indent,
13660                },
13661                window,
13662                cx,
13663            );
13664            this.backspace(&Backspace, window, cx);
13665        });
13666    }
13667
13668    pub fn move_to_end_of_line(
13669        &mut self,
13670        action: &MoveToEndOfLine,
13671        window: &mut Window,
13672        cx: &mut Context<Self>,
13673    ) {
13674        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13675        self.change_selections(Default::default(), window, cx, |s| {
13676            s.move_cursors_with(|map, head, _| {
13677                (
13678                    movement::line_end(map, head, action.stop_at_soft_wraps),
13679                    SelectionGoal::None,
13680                )
13681            });
13682        })
13683    }
13684
13685    pub fn select_to_end_of_line(
13686        &mut self,
13687        action: &SelectToEndOfLine,
13688        window: &mut Window,
13689        cx: &mut Context<Self>,
13690    ) {
13691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13692        self.change_selections(Default::default(), window, cx, |s| {
13693            s.move_heads_with(|map, head, _| {
13694                (
13695                    movement::line_end(map, head, action.stop_at_soft_wraps),
13696                    SelectionGoal::None,
13697                )
13698            });
13699        })
13700    }
13701
13702    pub fn delete_to_end_of_line(
13703        &mut self,
13704        _: &DeleteToEndOfLine,
13705        window: &mut Window,
13706        cx: &mut Context<Self>,
13707    ) {
13708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13709        self.transact(window, cx, |this, window, cx| {
13710            this.select_to_end_of_line(
13711                &SelectToEndOfLine {
13712                    stop_at_soft_wraps: false,
13713                },
13714                window,
13715                cx,
13716            );
13717            this.delete(&Delete, window, cx);
13718        });
13719    }
13720
13721    pub fn cut_to_end_of_line(
13722        &mut self,
13723        action: &CutToEndOfLine,
13724        window: &mut Window,
13725        cx: &mut Context<Self>,
13726    ) {
13727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13728        self.transact(window, cx, |this, window, cx| {
13729            this.select_to_end_of_line(
13730                &SelectToEndOfLine {
13731                    stop_at_soft_wraps: false,
13732                },
13733                window,
13734                cx,
13735            );
13736            if !action.stop_at_newlines {
13737                this.change_selections(Default::default(), window, cx, |s| {
13738                    s.move_with(|_, sel| {
13739                        if sel.is_empty() {
13740                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13741                        }
13742                    });
13743                });
13744            }
13745            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13746            let item = this.cut_common(false, window, cx);
13747            cx.write_to_clipboard(item);
13748        });
13749    }
13750
13751    pub fn move_to_start_of_paragraph(
13752        &mut self,
13753        _: &MoveToStartOfParagraph,
13754        window: &mut Window,
13755        cx: &mut Context<Self>,
13756    ) {
13757        if matches!(self.mode, EditorMode::SingleLine) {
13758            cx.propagate();
13759            return;
13760        }
13761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13762        self.change_selections(Default::default(), window, cx, |s| {
13763            s.move_with(|map, selection| {
13764                selection.collapse_to(
13765                    movement::start_of_paragraph(map, selection.head(), 1),
13766                    SelectionGoal::None,
13767                )
13768            });
13769        })
13770    }
13771
13772    pub fn move_to_end_of_paragraph(
13773        &mut self,
13774        _: &MoveToEndOfParagraph,
13775        window: &mut Window,
13776        cx: &mut Context<Self>,
13777    ) {
13778        if matches!(self.mode, EditorMode::SingleLine) {
13779            cx.propagate();
13780            return;
13781        }
13782        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13783        self.change_selections(Default::default(), window, cx, |s| {
13784            s.move_with(|map, selection| {
13785                selection.collapse_to(
13786                    movement::end_of_paragraph(map, selection.head(), 1),
13787                    SelectionGoal::None,
13788                )
13789            });
13790        })
13791    }
13792
13793    pub fn select_to_start_of_paragraph(
13794        &mut self,
13795        _: &SelectToStartOfParagraph,
13796        window: &mut Window,
13797        cx: &mut Context<Self>,
13798    ) {
13799        if matches!(self.mode, EditorMode::SingleLine) {
13800            cx.propagate();
13801            return;
13802        }
13803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13804        self.change_selections(Default::default(), window, cx, |s| {
13805            s.move_heads_with(|map, head, _| {
13806                (
13807                    movement::start_of_paragraph(map, head, 1),
13808                    SelectionGoal::None,
13809                )
13810            });
13811        })
13812    }
13813
13814    pub fn select_to_end_of_paragraph(
13815        &mut self,
13816        _: &SelectToEndOfParagraph,
13817        window: &mut Window,
13818        cx: &mut Context<Self>,
13819    ) {
13820        if matches!(self.mode, EditorMode::SingleLine) {
13821            cx.propagate();
13822            return;
13823        }
13824        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13825        self.change_selections(Default::default(), window, cx, |s| {
13826            s.move_heads_with(|map, head, _| {
13827                (
13828                    movement::end_of_paragraph(map, head, 1),
13829                    SelectionGoal::None,
13830                )
13831            });
13832        })
13833    }
13834
13835    pub fn move_to_start_of_excerpt(
13836        &mut self,
13837        _: &MoveToStartOfExcerpt,
13838        window: &mut Window,
13839        cx: &mut Context<Self>,
13840    ) {
13841        if matches!(self.mode, EditorMode::SingleLine) {
13842            cx.propagate();
13843            return;
13844        }
13845        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13846        self.change_selections(Default::default(), window, cx, |s| {
13847            s.move_with(|map, selection| {
13848                selection.collapse_to(
13849                    movement::start_of_excerpt(
13850                        map,
13851                        selection.head(),
13852                        workspace::searchable::Direction::Prev,
13853                    ),
13854                    SelectionGoal::None,
13855                )
13856            });
13857        })
13858    }
13859
13860    pub fn move_to_start_of_next_excerpt(
13861        &mut self,
13862        _: &MoveToStartOfNextExcerpt,
13863        window: &mut Window,
13864        cx: &mut Context<Self>,
13865    ) {
13866        if matches!(self.mode, EditorMode::SingleLine) {
13867            cx.propagate();
13868            return;
13869        }
13870
13871        self.change_selections(Default::default(), window, cx, |s| {
13872            s.move_with(|map, selection| {
13873                selection.collapse_to(
13874                    movement::start_of_excerpt(
13875                        map,
13876                        selection.head(),
13877                        workspace::searchable::Direction::Next,
13878                    ),
13879                    SelectionGoal::None,
13880                )
13881            });
13882        })
13883    }
13884
13885    pub fn move_to_end_of_excerpt(
13886        &mut self,
13887        _: &MoveToEndOfExcerpt,
13888        window: &mut Window,
13889        cx: &mut Context<Self>,
13890    ) {
13891        if matches!(self.mode, EditorMode::SingleLine) {
13892            cx.propagate();
13893            return;
13894        }
13895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13896        self.change_selections(Default::default(), window, cx, |s| {
13897            s.move_with(|map, selection| {
13898                selection.collapse_to(
13899                    movement::end_of_excerpt(
13900                        map,
13901                        selection.head(),
13902                        workspace::searchable::Direction::Next,
13903                    ),
13904                    SelectionGoal::None,
13905                )
13906            });
13907        })
13908    }
13909
13910    pub fn move_to_end_of_previous_excerpt(
13911        &mut self,
13912        _: &MoveToEndOfPreviousExcerpt,
13913        window: &mut Window,
13914        cx: &mut Context<Self>,
13915    ) {
13916        if matches!(self.mode, EditorMode::SingleLine) {
13917            cx.propagate();
13918            return;
13919        }
13920        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13921        self.change_selections(Default::default(), window, cx, |s| {
13922            s.move_with(|map, selection| {
13923                selection.collapse_to(
13924                    movement::end_of_excerpt(
13925                        map,
13926                        selection.head(),
13927                        workspace::searchable::Direction::Prev,
13928                    ),
13929                    SelectionGoal::None,
13930                )
13931            });
13932        })
13933    }
13934
13935    pub fn select_to_start_of_excerpt(
13936        &mut self,
13937        _: &SelectToStartOfExcerpt,
13938        window: &mut Window,
13939        cx: &mut Context<Self>,
13940    ) {
13941        if matches!(self.mode, EditorMode::SingleLine) {
13942            cx.propagate();
13943            return;
13944        }
13945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13946        self.change_selections(Default::default(), window, cx, |s| {
13947            s.move_heads_with(|map, head, _| {
13948                (
13949                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13950                    SelectionGoal::None,
13951                )
13952            });
13953        })
13954    }
13955
13956    pub fn select_to_start_of_next_excerpt(
13957        &mut self,
13958        _: &SelectToStartOfNextExcerpt,
13959        window: &mut Window,
13960        cx: &mut Context<Self>,
13961    ) {
13962        if matches!(self.mode, EditorMode::SingleLine) {
13963            cx.propagate();
13964            return;
13965        }
13966        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13967        self.change_selections(Default::default(), window, cx, |s| {
13968            s.move_heads_with(|map, head, _| {
13969                (
13970                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13971                    SelectionGoal::None,
13972                )
13973            });
13974        })
13975    }
13976
13977    pub fn select_to_end_of_excerpt(
13978        &mut self,
13979        _: &SelectToEndOfExcerpt,
13980        window: &mut Window,
13981        cx: &mut Context<Self>,
13982    ) {
13983        if matches!(self.mode, EditorMode::SingleLine) {
13984            cx.propagate();
13985            return;
13986        }
13987        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13988        self.change_selections(Default::default(), window, cx, |s| {
13989            s.move_heads_with(|map, head, _| {
13990                (
13991                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13992                    SelectionGoal::None,
13993                )
13994            });
13995        })
13996    }
13997
13998    pub fn select_to_end_of_previous_excerpt(
13999        &mut self,
14000        _: &SelectToEndOfPreviousExcerpt,
14001        window: &mut Window,
14002        cx: &mut Context<Self>,
14003    ) {
14004        if matches!(self.mode, EditorMode::SingleLine) {
14005            cx.propagate();
14006            return;
14007        }
14008        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14009        self.change_selections(Default::default(), window, cx, |s| {
14010            s.move_heads_with(|map, head, _| {
14011                (
14012                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14013                    SelectionGoal::None,
14014                )
14015            });
14016        })
14017    }
14018
14019    pub fn move_to_beginning(
14020        &mut self,
14021        _: &MoveToBeginning,
14022        window: &mut Window,
14023        cx: &mut Context<Self>,
14024    ) {
14025        if matches!(self.mode, EditorMode::SingleLine) {
14026            cx.propagate();
14027            return;
14028        }
14029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14030        self.change_selections(Default::default(), window, cx, |s| {
14031            s.select_ranges(vec![0..0]);
14032        });
14033    }
14034
14035    pub fn select_to_beginning(
14036        &mut self,
14037        _: &SelectToBeginning,
14038        window: &mut Window,
14039        cx: &mut Context<Self>,
14040    ) {
14041        let mut selection = self.selections.last::<Point>(cx);
14042        selection.set_head(Point::zero(), SelectionGoal::None);
14043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14044        self.change_selections(Default::default(), window, cx, |s| {
14045            s.select(vec![selection]);
14046        });
14047    }
14048
14049    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14050        if matches!(self.mode, EditorMode::SingleLine) {
14051            cx.propagate();
14052            return;
14053        }
14054        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14055        let cursor = self.buffer.read(cx).read(cx).len();
14056        self.change_selections(Default::default(), window, cx, |s| {
14057            s.select_ranges(vec![cursor..cursor])
14058        });
14059    }
14060
14061    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14062        self.nav_history = nav_history;
14063    }
14064
14065    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14066        self.nav_history.as_ref()
14067    }
14068
14069    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14070        self.push_to_nav_history(
14071            self.selections.newest_anchor().head(),
14072            None,
14073            false,
14074            true,
14075            cx,
14076        );
14077    }
14078
14079    fn push_to_nav_history(
14080        &mut self,
14081        cursor_anchor: Anchor,
14082        new_position: Option<Point>,
14083        is_deactivate: bool,
14084        always: bool,
14085        cx: &mut Context<Self>,
14086    ) {
14087        if let Some(nav_history) = self.nav_history.as_mut() {
14088            let buffer = self.buffer.read(cx).read(cx);
14089            let cursor_position = cursor_anchor.to_point(&buffer);
14090            let scroll_state = self.scroll_manager.anchor();
14091            let scroll_top_row = scroll_state.top_row(&buffer);
14092            drop(buffer);
14093
14094            if let Some(new_position) = new_position {
14095                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14096                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14097                    return;
14098                }
14099            }
14100
14101            nav_history.push(
14102                Some(NavigationData {
14103                    cursor_anchor,
14104                    cursor_position,
14105                    scroll_anchor: scroll_state,
14106                    scroll_top_row,
14107                }),
14108                cx,
14109            );
14110            cx.emit(EditorEvent::PushedToNavHistory {
14111                anchor: cursor_anchor,
14112                is_deactivate,
14113            })
14114        }
14115    }
14116
14117    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14119        let buffer = self.buffer.read(cx).snapshot(cx);
14120        let mut selection = self.selections.first::<usize>(cx);
14121        selection.set_head(buffer.len(), SelectionGoal::None);
14122        self.change_selections(Default::default(), window, cx, |s| {
14123            s.select(vec![selection]);
14124        });
14125    }
14126
14127    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14129        let end = self.buffer.read(cx).read(cx).len();
14130        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14131            s.select_ranges(vec![0..end]);
14132        });
14133    }
14134
14135    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14137        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14138        let mut selections = self.selections.all::<Point>(cx);
14139        let max_point = display_map.buffer_snapshot().max_point();
14140        for selection in &mut selections {
14141            let rows = selection.spanned_rows(true, &display_map);
14142            selection.start = Point::new(rows.start.0, 0);
14143            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14144            selection.reversed = false;
14145        }
14146        self.change_selections(Default::default(), window, cx, |s| {
14147            s.select(selections);
14148        });
14149    }
14150
14151    pub fn split_selection_into_lines(
14152        &mut self,
14153        action: &SplitSelectionIntoLines,
14154        window: &mut Window,
14155        cx: &mut Context<Self>,
14156    ) {
14157        let selections = self
14158            .selections
14159            .all::<Point>(cx)
14160            .into_iter()
14161            .map(|selection| selection.start..selection.end)
14162            .collect::<Vec<_>>();
14163        self.unfold_ranges(&selections, true, true, cx);
14164
14165        let mut new_selection_ranges = Vec::new();
14166        {
14167            let buffer = self.buffer.read(cx).read(cx);
14168            for selection in selections {
14169                for row in selection.start.row..selection.end.row {
14170                    let line_start = Point::new(row, 0);
14171                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14172
14173                    if action.keep_selections {
14174                        // Keep the selection range for each line
14175                        let selection_start = if row == selection.start.row {
14176                            selection.start
14177                        } else {
14178                            line_start
14179                        };
14180                        new_selection_ranges.push(selection_start..line_end);
14181                    } else {
14182                        // Collapse to cursor at end of line
14183                        new_selection_ranges.push(line_end..line_end);
14184                    }
14185                }
14186
14187                let is_multiline_selection = selection.start.row != selection.end.row;
14188                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14189                // so this action feels more ergonomic when paired with other selection operations
14190                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14191                if !should_skip_last {
14192                    if action.keep_selections {
14193                        if is_multiline_selection {
14194                            let line_start = Point::new(selection.end.row, 0);
14195                            new_selection_ranges.push(line_start..selection.end);
14196                        } else {
14197                            new_selection_ranges.push(selection.start..selection.end);
14198                        }
14199                    } else {
14200                        new_selection_ranges.push(selection.end..selection.end);
14201                    }
14202                }
14203            }
14204        }
14205        self.change_selections(Default::default(), window, cx, |s| {
14206            s.select_ranges(new_selection_ranges);
14207        });
14208    }
14209
14210    pub fn add_selection_above(
14211        &mut self,
14212        _: &AddSelectionAbove,
14213        window: &mut Window,
14214        cx: &mut Context<Self>,
14215    ) {
14216        self.add_selection(true, window, cx);
14217    }
14218
14219    pub fn add_selection_below(
14220        &mut self,
14221        _: &AddSelectionBelow,
14222        window: &mut Window,
14223        cx: &mut Context<Self>,
14224    ) {
14225        self.add_selection(false, window, cx);
14226    }
14227
14228    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14230
14231        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14232        let all_selections = self.selections.all::<Point>(cx);
14233        let text_layout_details = self.text_layout_details(window);
14234
14235        let (mut columnar_selections, new_selections_to_columnarize) = {
14236            if let Some(state) = self.add_selections_state.as_ref() {
14237                let columnar_selection_ids: HashSet<_> = state
14238                    .groups
14239                    .iter()
14240                    .flat_map(|group| group.stack.iter())
14241                    .copied()
14242                    .collect();
14243
14244                all_selections
14245                    .into_iter()
14246                    .partition(|s| columnar_selection_ids.contains(&s.id))
14247            } else {
14248                (Vec::new(), all_selections)
14249            }
14250        };
14251
14252        let mut state = self
14253            .add_selections_state
14254            .take()
14255            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14256
14257        for selection in new_selections_to_columnarize {
14258            let range = selection.display_range(&display_map).sorted();
14259            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14260            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14261            let positions = start_x.min(end_x)..start_x.max(end_x);
14262            let mut stack = Vec::new();
14263            for row in range.start.row().0..=range.end.row().0 {
14264                if let Some(selection) = self.selections.build_columnar_selection(
14265                    &display_map,
14266                    DisplayRow(row),
14267                    &positions,
14268                    selection.reversed,
14269                    &text_layout_details,
14270                ) {
14271                    stack.push(selection.id);
14272                    columnar_selections.push(selection);
14273                }
14274            }
14275            if !stack.is_empty() {
14276                if above {
14277                    stack.reverse();
14278                }
14279                state.groups.push(AddSelectionsGroup { above, stack });
14280            }
14281        }
14282
14283        let mut final_selections = Vec::new();
14284        let end_row = if above {
14285            DisplayRow(0)
14286        } else {
14287            display_map.max_point().row()
14288        };
14289
14290        let mut last_added_item_per_group = HashMap::default();
14291        for group in state.groups.iter_mut() {
14292            if let Some(last_id) = group.stack.last() {
14293                last_added_item_per_group.insert(*last_id, group);
14294            }
14295        }
14296
14297        for selection in columnar_selections {
14298            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14299                if above == group.above {
14300                    let range = selection.display_range(&display_map).sorted();
14301                    debug_assert_eq!(range.start.row(), range.end.row());
14302                    let mut row = range.start.row();
14303                    let positions =
14304                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14305                            Pixels::from(start)..Pixels::from(end)
14306                        } else {
14307                            let start_x =
14308                                display_map.x_for_display_point(range.start, &text_layout_details);
14309                            let end_x =
14310                                display_map.x_for_display_point(range.end, &text_layout_details);
14311                            start_x.min(end_x)..start_x.max(end_x)
14312                        };
14313
14314                    let mut maybe_new_selection = None;
14315                    while row != end_row {
14316                        if above {
14317                            row.0 -= 1;
14318                        } else {
14319                            row.0 += 1;
14320                        }
14321                        if let Some(new_selection) = self.selections.build_columnar_selection(
14322                            &display_map,
14323                            row,
14324                            &positions,
14325                            selection.reversed,
14326                            &text_layout_details,
14327                        ) {
14328                            maybe_new_selection = Some(new_selection);
14329                            break;
14330                        }
14331                    }
14332
14333                    if let Some(new_selection) = maybe_new_selection {
14334                        group.stack.push(new_selection.id);
14335                        if above {
14336                            final_selections.push(new_selection);
14337                            final_selections.push(selection);
14338                        } else {
14339                            final_selections.push(selection);
14340                            final_selections.push(new_selection);
14341                        }
14342                    } else {
14343                        final_selections.push(selection);
14344                    }
14345                } else {
14346                    group.stack.pop();
14347                }
14348            } else {
14349                final_selections.push(selection);
14350            }
14351        }
14352
14353        self.change_selections(Default::default(), window, cx, |s| {
14354            s.select(final_selections);
14355        });
14356
14357        let final_selection_ids: HashSet<_> = self
14358            .selections
14359            .all::<Point>(cx)
14360            .iter()
14361            .map(|s| s.id)
14362            .collect();
14363        state.groups.retain_mut(|group| {
14364            // selections might get merged above so we remove invalid items from stacks
14365            group.stack.retain(|id| final_selection_ids.contains(id));
14366
14367            // single selection in stack can be treated as initial state
14368            group.stack.len() > 1
14369        });
14370
14371        if !state.groups.is_empty() {
14372            self.add_selections_state = Some(state);
14373        }
14374    }
14375
14376    fn select_match_ranges(
14377        &mut self,
14378        range: Range<usize>,
14379        reversed: bool,
14380        replace_newest: bool,
14381        auto_scroll: Option<Autoscroll>,
14382        window: &mut Window,
14383        cx: &mut Context<Editor>,
14384    ) {
14385        self.unfold_ranges(
14386            std::slice::from_ref(&range),
14387            false,
14388            auto_scroll.is_some(),
14389            cx,
14390        );
14391        let effects = if let Some(scroll) = auto_scroll {
14392            SelectionEffects::scroll(scroll)
14393        } else {
14394            SelectionEffects::no_scroll()
14395        };
14396        self.change_selections(effects, window, cx, |s| {
14397            if replace_newest {
14398                s.delete(s.newest_anchor().id);
14399            }
14400            if reversed {
14401                s.insert_range(range.end..range.start);
14402            } else {
14403                s.insert_range(range);
14404            }
14405        });
14406    }
14407
14408    pub fn select_next_match_internal(
14409        &mut self,
14410        display_map: &DisplaySnapshot,
14411        replace_newest: bool,
14412        autoscroll: Option<Autoscroll>,
14413        window: &mut Window,
14414        cx: &mut Context<Self>,
14415    ) -> Result<()> {
14416        let buffer = display_map.buffer_snapshot();
14417        let mut selections = self.selections.all::<usize>(cx);
14418        if let Some(mut select_next_state) = self.select_next_state.take() {
14419            let query = &select_next_state.query;
14420            if !select_next_state.done {
14421                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14422                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14423                let mut next_selected_range = None;
14424
14425                let bytes_after_last_selection =
14426                    buffer.bytes_in_range(last_selection.end..buffer.len());
14427                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14428                let query_matches = query
14429                    .stream_find_iter(bytes_after_last_selection)
14430                    .map(|result| (last_selection.end, result))
14431                    .chain(
14432                        query
14433                            .stream_find_iter(bytes_before_first_selection)
14434                            .map(|result| (0, result)),
14435                    );
14436
14437                for (start_offset, query_match) in query_matches {
14438                    let query_match = query_match.unwrap(); // can only fail due to I/O
14439                    let offset_range =
14440                        start_offset + query_match.start()..start_offset + query_match.end();
14441
14442                    if !select_next_state.wordwise
14443                        || (!buffer.is_inside_word(offset_range.start, None)
14444                            && !buffer.is_inside_word(offset_range.end, None))
14445                    {
14446                        // TODO: This is n^2, because we might check all the selections
14447                        if !selections
14448                            .iter()
14449                            .any(|selection| selection.range().overlaps(&offset_range))
14450                        {
14451                            next_selected_range = Some(offset_range);
14452                            break;
14453                        }
14454                    }
14455                }
14456
14457                if let Some(next_selected_range) = next_selected_range {
14458                    self.select_match_ranges(
14459                        next_selected_range,
14460                        last_selection.reversed,
14461                        replace_newest,
14462                        autoscroll,
14463                        window,
14464                        cx,
14465                    );
14466                } else {
14467                    select_next_state.done = true;
14468                }
14469            }
14470
14471            self.select_next_state = Some(select_next_state);
14472        } else {
14473            let mut only_carets = true;
14474            let mut same_text_selected = true;
14475            let mut selected_text = None;
14476
14477            let mut selections_iter = selections.iter().peekable();
14478            while let Some(selection) = selections_iter.next() {
14479                if selection.start != selection.end {
14480                    only_carets = false;
14481                }
14482
14483                if same_text_selected {
14484                    if selected_text.is_none() {
14485                        selected_text =
14486                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14487                    }
14488
14489                    if let Some(next_selection) = selections_iter.peek() {
14490                        if next_selection.range().len() == selection.range().len() {
14491                            let next_selected_text = buffer
14492                                .text_for_range(next_selection.range())
14493                                .collect::<String>();
14494                            if Some(next_selected_text) != selected_text {
14495                                same_text_selected = false;
14496                                selected_text = None;
14497                            }
14498                        } else {
14499                            same_text_selected = false;
14500                            selected_text = None;
14501                        }
14502                    }
14503                }
14504            }
14505
14506            if only_carets {
14507                for selection in &mut selections {
14508                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14509                    selection.start = word_range.start;
14510                    selection.end = word_range.end;
14511                    selection.goal = SelectionGoal::None;
14512                    selection.reversed = false;
14513                    self.select_match_ranges(
14514                        selection.start..selection.end,
14515                        selection.reversed,
14516                        replace_newest,
14517                        autoscroll,
14518                        window,
14519                        cx,
14520                    );
14521                }
14522
14523                if selections.len() == 1 {
14524                    let selection = selections
14525                        .last()
14526                        .expect("ensured that there's only one selection");
14527                    let query = buffer
14528                        .text_for_range(selection.start..selection.end)
14529                        .collect::<String>();
14530                    let is_empty = query.is_empty();
14531                    let select_state = SelectNextState {
14532                        query: AhoCorasick::new(&[query])?,
14533                        wordwise: true,
14534                        done: is_empty,
14535                    };
14536                    self.select_next_state = Some(select_state);
14537                } else {
14538                    self.select_next_state = None;
14539                }
14540            } else if let Some(selected_text) = selected_text {
14541                self.select_next_state = Some(SelectNextState {
14542                    query: AhoCorasick::new(&[selected_text])?,
14543                    wordwise: false,
14544                    done: false,
14545                });
14546                self.select_next_match_internal(
14547                    display_map,
14548                    replace_newest,
14549                    autoscroll,
14550                    window,
14551                    cx,
14552                )?;
14553            }
14554        }
14555        Ok(())
14556    }
14557
14558    pub fn select_all_matches(
14559        &mut self,
14560        _action: &SelectAllMatches,
14561        window: &mut Window,
14562        cx: &mut Context<Self>,
14563    ) -> Result<()> {
14564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14565
14566        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14567
14568        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14569        let Some(select_next_state) = self.select_next_state.as_mut() else {
14570            return Ok(());
14571        };
14572        if select_next_state.done {
14573            return Ok(());
14574        }
14575
14576        let mut new_selections = Vec::new();
14577
14578        let reversed = self.selections.oldest::<usize>(cx).reversed;
14579        let buffer = display_map.buffer_snapshot();
14580        let query_matches = select_next_state
14581            .query
14582            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14583
14584        for query_match in query_matches.into_iter() {
14585            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14586            let offset_range = if reversed {
14587                query_match.end()..query_match.start()
14588            } else {
14589                query_match.start()..query_match.end()
14590            };
14591
14592            if !select_next_state.wordwise
14593                || (!buffer.is_inside_word(offset_range.start, None)
14594                    && !buffer.is_inside_word(offset_range.end, None))
14595            {
14596                new_selections.push(offset_range.start..offset_range.end);
14597            }
14598        }
14599
14600        select_next_state.done = true;
14601
14602        if new_selections.is_empty() {
14603            log::error!("bug: new_selections is empty in select_all_matches");
14604            return Ok(());
14605        }
14606
14607        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14608        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14609            selections.select_ranges(new_selections)
14610        });
14611
14612        Ok(())
14613    }
14614
14615    pub fn select_next(
14616        &mut self,
14617        action: &SelectNext,
14618        window: &mut Window,
14619        cx: &mut Context<Self>,
14620    ) -> Result<()> {
14621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14622        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14623        self.select_next_match_internal(
14624            &display_map,
14625            action.replace_newest,
14626            Some(Autoscroll::newest()),
14627            window,
14628            cx,
14629        )?;
14630        Ok(())
14631    }
14632
14633    pub fn select_previous(
14634        &mut self,
14635        action: &SelectPrevious,
14636        window: &mut Window,
14637        cx: &mut Context<Self>,
14638    ) -> Result<()> {
14639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14640        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14641        let buffer = display_map.buffer_snapshot();
14642        let mut selections = self.selections.all::<usize>(cx);
14643        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14644            let query = &select_prev_state.query;
14645            if !select_prev_state.done {
14646                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14647                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14648                let mut next_selected_range = None;
14649                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14650                let bytes_before_last_selection =
14651                    buffer.reversed_bytes_in_range(0..last_selection.start);
14652                let bytes_after_first_selection =
14653                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14654                let query_matches = query
14655                    .stream_find_iter(bytes_before_last_selection)
14656                    .map(|result| (last_selection.start, result))
14657                    .chain(
14658                        query
14659                            .stream_find_iter(bytes_after_first_selection)
14660                            .map(|result| (buffer.len(), result)),
14661                    );
14662                for (end_offset, query_match) in query_matches {
14663                    let query_match = query_match.unwrap(); // can only fail due to I/O
14664                    let offset_range =
14665                        end_offset - query_match.end()..end_offset - query_match.start();
14666
14667                    if !select_prev_state.wordwise
14668                        || (!buffer.is_inside_word(offset_range.start, None)
14669                            && !buffer.is_inside_word(offset_range.end, None))
14670                    {
14671                        next_selected_range = Some(offset_range);
14672                        break;
14673                    }
14674                }
14675
14676                if let Some(next_selected_range) = next_selected_range {
14677                    self.select_match_ranges(
14678                        next_selected_range,
14679                        last_selection.reversed,
14680                        action.replace_newest,
14681                        Some(Autoscroll::newest()),
14682                        window,
14683                        cx,
14684                    );
14685                } else {
14686                    select_prev_state.done = true;
14687                }
14688            }
14689
14690            self.select_prev_state = Some(select_prev_state);
14691        } else {
14692            let mut only_carets = true;
14693            let mut same_text_selected = true;
14694            let mut selected_text = None;
14695
14696            let mut selections_iter = selections.iter().peekable();
14697            while let Some(selection) = selections_iter.next() {
14698                if selection.start != selection.end {
14699                    only_carets = false;
14700                }
14701
14702                if same_text_selected {
14703                    if selected_text.is_none() {
14704                        selected_text =
14705                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14706                    }
14707
14708                    if let Some(next_selection) = selections_iter.peek() {
14709                        if next_selection.range().len() == selection.range().len() {
14710                            let next_selected_text = buffer
14711                                .text_for_range(next_selection.range())
14712                                .collect::<String>();
14713                            if Some(next_selected_text) != selected_text {
14714                                same_text_selected = false;
14715                                selected_text = None;
14716                            }
14717                        } else {
14718                            same_text_selected = false;
14719                            selected_text = None;
14720                        }
14721                    }
14722                }
14723            }
14724
14725            if only_carets {
14726                for selection in &mut selections {
14727                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14728                    selection.start = word_range.start;
14729                    selection.end = word_range.end;
14730                    selection.goal = SelectionGoal::None;
14731                    selection.reversed = false;
14732                    self.select_match_ranges(
14733                        selection.start..selection.end,
14734                        selection.reversed,
14735                        action.replace_newest,
14736                        Some(Autoscroll::newest()),
14737                        window,
14738                        cx,
14739                    );
14740                }
14741                if selections.len() == 1 {
14742                    let selection = selections
14743                        .last()
14744                        .expect("ensured that there's only one selection");
14745                    let query = buffer
14746                        .text_for_range(selection.start..selection.end)
14747                        .collect::<String>();
14748                    let is_empty = query.is_empty();
14749                    let select_state = SelectNextState {
14750                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14751                        wordwise: true,
14752                        done: is_empty,
14753                    };
14754                    self.select_prev_state = Some(select_state);
14755                } else {
14756                    self.select_prev_state = None;
14757                }
14758            } else if let Some(selected_text) = selected_text {
14759                self.select_prev_state = Some(SelectNextState {
14760                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14761                    wordwise: false,
14762                    done: false,
14763                });
14764                self.select_previous(action, window, cx)?;
14765            }
14766        }
14767        Ok(())
14768    }
14769
14770    pub fn find_next_match(
14771        &mut self,
14772        _: &FindNextMatch,
14773        window: &mut Window,
14774        cx: &mut Context<Self>,
14775    ) -> Result<()> {
14776        let selections = self.selections.disjoint_anchors_arc();
14777        match selections.first() {
14778            Some(first) if selections.len() >= 2 => {
14779                self.change_selections(Default::default(), window, cx, |s| {
14780                    s.select_ranges([first.range()]);
14781                });
14782            }
14783            _ => self.select_next(
14784                &SelectNext {
14785                    replace_newest: true,
14786                },
14787                window,
14788                cx,
14789            )?,
14790        }
14791        Ok(())
14792    }
14793
14794    pub fn find_previous_match(
14795        &mut self,
14796        _: &FindPreviousMatch,
14797        window: &mut Window,
14798        cx: &mut Context<Self>,
14799    ) -> Result<()> {
14800        let selections = self.selections.disjoint_anchors_arc();
14801        match selections.last() {
14802            Some(last) if selections.len() >= 2 => {
14803                self.change_selections(Default::default(), window, cx, |s| {
14804                    s.select_ranges([last.range()]);
14805                });
14806            }
14807            _ => self.select_previous(
14808                &SelectPrevious {
14809                    replace_newest: true,
14810                },
14811                window,
14812                cx,
14813            )?,
14814        }
14815        Ok(())
14816    }
14817
14818    pub fn toggle_comments(
14819        &mut self,
14820        action: &ToggleComments,
14821        window: &mut Window,
14822        cx: &mut Context<Self>,
14823    ) {
14824        if self.read_only(cx) {
14825            return;
14826        }
14827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14828        let text_layout_details = &self.text_layout_details(window);
14829        self.transact(window, cx, |this, window, cx| {
14830            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14831            let mut edits = Vec::new();
14832            let mut selection_edit_ranges = Vec::new();
14833            let mut last_toggled_row = None;
14834            let snapshot = this.buffer.read(cx).read(cx);
14835            let empty_str: Arc<str> = Arc::default();
14836            let mut suffixes_inserted = Vec::new();
14837            let ignore_indent = action.ignore_indent;
14838
14839            fn comment_prefix_range(
14840                snapshot: &MultiBufferSnapshot,
14841                row: MultiBufferRow,
14842                comment_prefix: &str,
14843                comment_prefix_whitespace: &str,
14844                ignore_indent: bool,
14845            ) -> Range<Point> {
14846                let indent_size = if ignore_indent {
14847                    0
14848                } else {
14849                    snapshot.indent_size_for_line(row).len
14850                };
14851
14852                let start = Point::new(row.0, indent_size);
14853
14854                let mut line_bytes = snapshot
14855                    .bytes_in_range(start..snapshot.max_point())
14856                    .flatten()
14857                    .copied();
14858
14859                // If this line currently begins with the line comment prefix, then record
14860                // the range containing the prefix.
14861                if line_bytes
14862                    .by_ref()
14863                    .take(comment_prefix.len())
14864                    .eq(comment_prefix.bytes())
14865                {
14866                    // Include any whitespace that matches the comment prefix.
14867                    let matching_whitespace_len = line_bytes
14868                        .zip(comment_prefix_whitespace.bytes())
14869                        .take_while(|(a, b)| a == b)
14870                        .count() as u32;
14871                    let end = Point::new(
14872                        start.row,
14873                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14874                    );
14875                    start..end
14876                } else {
14877                    start..start
14878                }
14879            }
14880
14881            fn comment_suffix_range(
14882                snapshot: &MultiBufferSnapshot,
14883                row: MultiBufferRow,
14884                comment_suffix: &str,
14885                comment_suffix_has_leading_space: bool,
14886            ) -> Range<Point> {
14887                let end = Point::new(row.0, snapshot.line_len(row));
14888                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14889
14890                let mut line_end_bytes = snapshot
14891                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14892                    .flatten()
14893                    .copied();
14894
14895                let leading_space_len = if suffix_start_column > 0
14896                    && line_end_bytes.next() == Some(b' ')
14897                    && comment_suffix_has_leading_space
14898                {
14899                    1
14900                } else {
14901                    0
14902                };
14903
14904                // If this line currently begins with the line comment prefix, then record
14905                // the range containing the prefix.
14906                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14907                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14908                    start..end
14909                } else {
14910                    end..end
14911                }
14912            }
14913
14914            // TODO: Handle selections that cross excerpts
14915            for selection in &mut selections {
14916                let start_column = snapshot
14917                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14918                    .len;
14919                let language = if let Some(language) =
14920                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14921                {
14922                    language
14923                } else {
14924                    continue;
14925                };
14926
14927                selection_edit_ranges.clear();
14928
14929                // If multiple selections contain a given row, avoid processing that
14930                // row more than once.
14931                let mut start_row = MultiBufferRow(selection.start.row);
14932                if last_toggled_row == Some(start_row) {
14933                    start_row = start_row.next_row();
14934                }
14935                let end_row =
14936                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14937                        MultiBufferRow(selection.end.row - 1)
14938                    } else {
14939                        MultiBufferRow(selection.end.row)
14940                    };
14941                last_toggled_row = Some(end_row);
14942
14943                if start_row > end_row {
14944                    continue;
14945                }
14946
14947                // If the language has line comments, toggle those.
14948                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14949
14950                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14951                if ignore_indent {
14952                    full_comment_prefixes = full_comment_prefixes
14953                        .into_iter()
14954                        .map(|s| Arc::from(s.trim_end()))
14955                        .collect();
14956                }
14957
14958                if !full_comment_prefixes.is_empty() {
14959                    let first_prefix = full_comment_prefixes
14960                        .first()
14961                        .expect("prefixes is non-empty");
14962                    let prefix_trimmed_lengths = full_comment_prefixes
14963                        .iter()
14964                        .map(|p| p.trim_end_matches(' ').len())
14965                        .collect::<SmallVec<[usize; 4]>>();
14966
14967                    let mut all_selection_lines_are_comments = true;
14968
14969                    for row in start_row.0..=end_row.0 {
14970                        let row = MultiBufferRow(row);
14971                        if start_row < end_row && snapshot.is_line_blank(row) {
14972                            continue;
14973                        }
14974
14975                        let prefix_range = full_comment_prefixes
14976                            .iter()
14977                            .zip(prefix_trimmed_lengths.iter().copied())
14978                            .map(|(prefix, trimmed_prefix_len)| {
14979                                comment_prefix_range(
14980                                    snapshot.deref(),
14981                                    row,
14982                                    &prefix[..trimmed_prefix_len],
14983                                    &prefix[trimmed_prefix_len..],
14984                                    ignore_indent,
14985                                )
14986                            })
14987                            .max_by_key(|range| range.end.column - range.start.column)
14988                            .expect("prefixes is non-empty");
14989
14990                        if prefix_range.is_empty() {
14991                            all_selection_lines_are_comments = false;
14992                        }
14993
14994                        selection_edit_ranges.push(prefix_range);
14995                    }
14996
14997                    if all_selection_lines_are_comments {
14998                        edits.extend(
14999                            selection_edit_ranges
15000                                .iter()
15001                                .cloned()
15002                                .map(|range| (range, empty_str.clone())),
15003                        );
15004                    } else {
15005                        let min_column = selection_edit_ranges
15006                            .iter()
15007                            .map(|range| range.start.column)
15008                            .min()
15009                            .unwrap_or(0);
15010                        edits.extend(selection_edit_ranges.iter().map(|range| {
15011                            let position = Point::new(range.start.row, min_column);
15012                            (position..position, first_prefix.clone())
15013                        }));
15014                    }
15015                } else if let Some(BlockCommentConfig {
15016                    start: full_comment_prefix,
15017                    end: comment_suffix,
15018                    ..
15019                }) = language.block_comment()
15020                {
15021                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15022                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15023                    let prefix_range = comment_prefix_range(
15024                        snapshot.deref(),
15025                        start_row,
15026                        comment_prefix,
15027                        comment_prefix_whitespace,
15028                        ignore_indent,
15029                    );
15030                    let suffix_range = comment_suffix_range(
15031                        snapshot.deref(),
15032                        end_row,
15033                        comment_suffix.trim_start_matches(' '),
15034                        comment_suffix.starts_with(' '),
15035                    );
15036
15037                    if prefix_range.is_empty() || suffix_range.is_empty() {
15038                        edits.push((
15039                            prefix_range.start..prefix_range.start,
15040                            full_comment_prefix.clone(),
15041                        ));
15042                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15043                        suffixes_inserted.push((end_row, comment_suffix.len()));
15044                    } else {
15045                        edits.push((prefix_range, empty_str.clone()));
15046                        edits.push((suffix_range, empty_str.clone()));
15047                    }
15048                } else {
15049                    continue;
15050                }
15051            }
15052
15053            drop(snapshot);
15054            this.buffer.update(cx, |buffer, cx| {
15055                buffer.edit(edits, None, cx);
15056            });
15057
15058            // Adjust selections so that they end before any comment suffixes that
15059            // were inserted.
15060            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15061            let mut selections = this.selections.all::<Point>(cx);
15062            let snapshot = this.buffer.read(cx).read(cx);
15063            for selection in &mut selections {
15064                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15065                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15066                        Ordering::Less => {
15067                            suffixes_inserted.next();
15068                            continue;
15069                        }
15070                        Ordering::Greater => break,
15071                        Ordering::Equal => {
15072                            if selection.end.column == snapshot.line_len(row) {
15073                                if selection.is_empty() {
15074                                    selection.start.column -= suffix_len as u32;
15075                                }
15076                                selection.end.column -= suffix_len as u32;
15077                            }
15078                            break;
15079                        }
15080                    }
15081                }
15082            }
15083
15084            drop(snapshot);
15085            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15086
15087            let selections = this.selections.all::<Point>(cx);
15088            let selections_on_single_row = selections.windows(2).all(|selections| {
15089                selections[0].start.row == selections[1].start.row
15090                    && selections[0].end.row == selections[1].end.row
15091                    && selections[0].start.row == selections[0].end.row
15092            });
15093            let selections_selecting = selections
15094                .iter()
15095                .any(|selection| selection.start != selection.end);
15096            let advance_downwards = action.advance_downwards
15097                && selections_on_single_row
15098                && !selections_selecting
15099                && !matches!(this.mode, EditorMode::SingleLine);
15100
15101            if advance_downwards {
15102                let snapshot = this.buffer.read(cx).snapshot(cx);
15103
15104                this.change_selections(Default::default(), window, cx, |s| {
15105                    s.move_cursors_with(|display_snapshot, display_point, _| {
15106                        let mut point = display_point.to_point(display_snapshot);
15107                        point.row += 1;
15108                        point = snapshot.clip_point(point, Bias::Left);
15109                        let display_point = point.to_display_point(display_snapshot);
15110                        let goal = SelectionGoal::HorizontalPosition(
15111                            display_snapshot
15112                                .x_for_display_point(display_point, text_layout_details)
15113                                .into(),
15114                        );
15115                        (display_point, goal)
15116                    })
15117                });
15118            }
15119        });
15120    }
15121
15122    pub fn select_enclosing_symbol(
15123        &mut self,
15124        _: &SelectEnclosingSymbol,
15125        window: &mut Window,
15126        cx: &mut Context<Self>,
15127    ) {
15128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15129
15130        let buffer = self.buffer.read(cx).snapshot(cx);
15131        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
15132
15133        fn update_selection(
15134            selection: &Selection<usize>,
15135            buffer_snap: &MultiBufferSnapshot,
15136        ) -> Option<Selection<usize>> {
15137            let cursor = selection.head();
15138            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15139            for symbol in symbols.iter().rev() {
15140                let start = symbol.range.start.to_offset(buffer_snap);
15141                let end = symbol.range.end.to_offset(buffer_snap);
15142                let new_range = start..end;
15143                if start < selection.start || end > selection.end {
15144                    return Some(Selection {
15145                        id: selection.id,
15146                        start: new_range.start,
15147                        end: new_range.end,
15148                        goal: SelectionGoal::None,
15149                        reversed: selection.reversed,
15150                    });
15151                }
15152            }
15153            None
15154        }
15155
15156        let mut selected_larger_symbol = false;
15157        let new_selections = old_selections
15158            .iter()
15159            .map(|selection| match update_selection(selection, &buffer) {
15160                Some(new_selection) => {
15161                    if new_selection.range() != selection.range() {
15162                        selected_larger_symbol = true;
15163                    }
15164                    new_selection
15165                }
15166                None => selection.clone(),
15167            })
15168            .collect::<Vec<_>>();
15169
15170        if selected_larger_symbol {
15171            self.change_selections(Default::default(), window, cx, |s| {
15172                s.select(new_selections);
15173            });
15174        }
15175    }
15176
15177    pub fn select_larger_syntax_node(
15178        &mut self,
15179        _: &SelectLargerSyntaxNode,
15180        window: &mut Window,
15181        cx: &mut Context<Self>,
15182    ) {
15183        let Some(visible_row_count) = self.visible_row_count() else {
15184            return;
15185        };
15186        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15187        if old_selections.is_empty() {
15188            return;
15189        }
15190
15191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15192
15193        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15194        let buffer = self.buffer.read(cx).snapshot(cx);
15195
15196        let mut selected_larger_node = false;
15197        let mut new_selections = old_selections
15198            .iter()
15199            .map(|selection| {
15200                let old_range = selection.start..selection.end;
15201
15202                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15203                    // manually select word at selection
15204                    if ["string_content", "inline"].contains(&node.kind()) {
15205                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15206                        // ignore if word is already selected
15207                        if !word_range.is_empty() && old_range != word_range {
15208                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15209                            // only select word if start and end point belongs to same word
15210                            if word_range == last_word_range {
15211                                selected_larger_node = true;
15212                                return Selection {
15213                                    id: selection.id,
15214                                    start: word_range.start,
15215                                    end: word_range.end,
15216                                    goal: SelectionGoal::None,
15217                                    reversed: selection.reversed,
15218                                };
15219                            }
15220                        }
15221                    }
15222                }
15223
15224                let mut new_range = old_range.clone();
15225                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15226                    new_range = range;
15227                    if !node.is_named() {
15228                        continue;
15229                    }
15230                    if !display_map.intersects_fold(new_range.start)
15231                        && !display_map.intersects_fold(new_range.end)
15232                    {
15233                        break;
15234                    }
15235                }
15236
15237                selected_larger_node |= new_range != old_range;
15238                Selection {
15239                    id: selection.id,
15240                    start: new_range.start,
15241                    end: new_range.end,
15242                    goal: SelectionGoal::None,
15243                    reversed: selection.reversed,
15244                }
15245            })
15246            .collect::<Vec<_>>();
15247
15248        if !selected_larger_node {
15249            return; // don't put this call in the history
15250        }
15251
15252        // scroll based on transformation done to the last selection created by the user
15253        let (last_old, last_new) = old_selections
15254            .last()
15255            .zip(new_selections.last().cloned())
15256            .expect("old_selections isn't empty");
15257
15258        // revert selection
15259        let is_selection_reversed = {
15260            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15261            new_selections.last_mut().expect("checked above").reversed =
15262                should_newest_selection_be_reversed;
15263            should_newest_selection_be_reversed
15264        };
15265
15266        if selected_larger_node {
15267            self.select_syntax_node_history.disable_clearing = true;
15268            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15269                s.select(new_selections.clone());
15270            });
15271            self.select_syntax_node_history.disable_clearing = false;
15272        }
15273
15274        let start_row = last_new.start.to_display_point(&display_map).row().0;
15275        let end_row = last_new.end.to_display_point(&display_map).row().0;
15276        let selection_height = end_row - start_row + 1;
15277        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15278
15279        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15280        let scroll_behavior = if fits_on_the_screen {
15281            self.request_autoscroll(Autoscroll::fit(), cx);
15282            SelectSyntaxNodeScrollBehavior::FitSelection
15283        } else if is_selection_reversed {
15284            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15285            SelectSyntaxNodeScrollBehavior::CursorTop
15286        } else {
15287            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15288            SelectSyntaxNodeScrollBehavior::CursorBottom
15289        };
15290
15291        self.select_syntax_node_history.push((
15292            old_selections,
15293            scroll_behavior,
15294            is_selection_reversed,
15295        ));
15296    }
15297
15298    pub fn select_smaller_syntax_node(
15299        &mut self,
15300        _: &SelectSmallerSyntaxNode,
15301        window: &mut Window,
15302        cx: &mut Context<Self>,
15303    ) {
15304        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15305
15306        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15307            self.select_syntax_node_history.pop()
15308        {
15309            if let Some(selection) = selections.last_mut() {
15310                selection.reversed = is_selection_reversed;
15311            }
15312
15313            self.select_syntax_node_history.disable_clearing = true;
15314            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15315                s.select(selections.to_vec());
15316            });
15317            self.select_syntax_node_history.disable_clearing = false;
15318
15319            match scroll_behavior {
15320                SelectSyntaxNodeScrollBehavior::CursorTop => {
15321                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15322                }
15323                SelectSyntaxNodeScrollBehavior::FitSelection => {
15324                    self.request_autoscroll(Autoscroll::fit(), cx);
15325                }
15326                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15327                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15328                }
15329            }
15330        }
15331    }
15332
15333    pub fn unwrap_syntax_node(
15334        &mut self,
15335        _: &UnwrapSyntaxNode,
15336        window: &mut Window,
15337        cx: &mut Context<Self>,
15338    ) {
15339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15340
15341        let buffer = self.buffer.read(cx).snapshot(cx);
15342        let selections = self
15343            .selections
15344            .all::<usize>(cx)
15345            .into_iter()
15346            // subtracting the offset requires sorting
15347            .sorted_by_key(|i| i.start);
15348
15349        let full_edits = selections
15350            .into_iter()
15351            .filter_map(|selection| {
15352                let child = if selection.is_empty()
15353                    && let Some((_, ancestor_range)) =
15354                        buffer.syntax_ancestor(selection.start..selection.end)
15355                {
15356                    ancestor_range
15357                } else {
15358                    selection.range()
15359                };
15360
15361                let mut parent = child.clone();
15362                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15363                    parent = ancestor_range;
15364                    if parent.start < child.start || parent.end > child.end {
15365                        break;
15366                    }
15367                }
15368
15369                if parent == child {
15370                    return None;
15371                }
15372                let text = buffer.text_for_range(child).collect::<String>();
15373                Some((selection.id, parent, text))
15374            })
15375            .collect::<Vec<_>>();
15376        if full_edits.is_empty() {
15377            return;
15378        }
15379
15380        self.transact(window, cx, |this, window, cx| {
15381            this.buffer.update(cx, |buffer, cx| {
15382                buffer.edit(
15383                    full_edits
15384                        .iter()
15385                        .map(|(_, p, t)| (p.clone(), t.clone()))
15386                        .collect::<Vec<_>>(),
15387                    None,
15388                    cx,
15389                );
15390            });
15391            this.change_selections(Default::default(), window, cx, |s| {
15392                let mut offset = 0;
15393                let mut selections = vec![];
15394                for (id, parent, text) in full_edits {
15395                    let start = parent.start - offset;
15396                    offset += parent.len() - text.len();
15397                    selections.push(Selection {
15398                        id,
15399                        start,
15400                        end: start + text.len(),
15401                        reversed: false,
15402                        goal: Default::default(),
15403                    });
15404                }
15405                s.select(selections);
15406            });
15407        });
15408    }
15409
15410    pub fn select_next_syntax_node(
15411        &mut self,
15412        _: &SelectNextSyntaxNode,
15413        window: &mut Window,
15414        cx: &mut Context<Self>,
15415    ) {
15416        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15417        if old_selections.is_empty() {
15418            return;
15419        }
15420
15421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15422
15423        let buffer = self.buffer.read(cx).snapshot(cx);
15424        let mut selected_sibling = false;
15425
15426        let new_selections = old_selections
15427            .iter()
15428            .map(|selection| {
15429                let old_range = selection.start..selection.end;
15430
15431                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15432                    let new_range = node.byte_range();
15433                    selected_sibling = true;
15434                    Selection {
15435                        id: selection.id,
15436                        start: new_range.start,
15437                        end: new_range.end,
15438                        goal: SelectionGoal::None,
15439                        reversed: selection.reversed,
15440                    }
15441                } else {
15442                    selection.clone()
15443                }
15444            })
15445            .collect::<Vec<_>>();
15446
15447        if selected_sibling {
15448            self.change_selections(
15449                SelectionEffects::scroll(Autoscroll::fit()),
15450                window,
15451                cx,
15452                |s| {
15453                    s.select(new_selections);
15454                },
15455            );
15456        }
15457    }
15458
15459    pub fn select_prev_syntax_node(
15460        &mut self,
15461        _: &SelectPreviousSyntaxNode,
15462        window: &mut Window,
15463        cx: &mut Context<Self>,
15464    ) {
15465        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15466        if old_selections.is_empty() {
15467            return;
15468        }
15469
15470        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15471
15472        let buffer = self.buffer.read(cx).snapshot(cx);
15473        let mut selected_sibling = false;
15474
15475        let new_selections = old_selections
15476            .iter()
15477            .map(|selection| {
15478                let old_range = selection.start..selection.end;
15479
15480                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15481                    let new_range = node.byte_range();
15482                    selected_sibling = true;
15483                    Selection {
15484                        id: selection.id,
15485                        start: new_range.start,
15486                        end: new_range.end,
15487                        goal: SelectionGoal::None,
15488                        reversed: selection.reversed,
15489                    }
15490                } else {
15491                    selection.clone()
15492                }
15493            })
15494            .collect::<Vec<_>>();
15495
15496        if selected_sibling {
15497            self.change_selections(
15498                SelectionEffects::scroll(Autoscroll::fit()),
15499                window,
15500                cx,
15501                |s| {
15502                    s.select(new_selections);
15503                },
15504            );
15505        }
15506    }
15507
15508    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15509        if !EditorSettings::get_global(cx).gutter.runnables {
15510            self.clear_tasks();
15511            return Task::ready(());
15512        }
15513        let project = self.project().map(Entity::downgrade);
15514        let task_sources = self.lsp_task_sources(cx);
15515        let multi_buffer = self.buffer.downgrade();
15516        cx.spawn_in(window, async move |editor, cx| {
15517            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15518            let Some(project) = project.and_then(|p| p.upgrade()) else {
15519                return;
15520            };
15521            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15522                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15523            }) else {
15524                return;
15525            };
15526
15527            let hide_runnables = project
15528                .update(cx, |project, _| project.is_via_collab())
15529                .unwrap_or(true);
15530            if hide_runnables {
15531                return;
15532            }
15533            let new_rows =
15534                cx.background_spawn({
15535                    let snapshot = display_snapshot.clone();
15536                    async move {
15537                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15538                    }
15539                })
15540                    .await;
15541            let Ok(lsp_tasks) =
15542                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15543            else {
15544                return;
15545            };
15546            let lsp_tasks = lsp_tasks.await;
15547
15548            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15549                lsp_tasks
15550                    .into_iter()
15551                    .flat_map(|(kind, tasks)| {
15552                        tasks.into_iter().filter_map(move |(location, task)| {
15553                            Some((kind.clone(), location?, task))
15554                        })
15555                    })
15556                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15557                        let buffer = location.target.buffer;
15558                        let buffer_snapshot = buffer.read(cx).snapshot();
15559                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15560                            |(excerpt_id, snapshot, _)| {
15561                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15562                                    display_snapshot
15563                                        .buffer_snapshot()
15564                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15565                                } else {
15566                                    None
15567                                }
15568                            },
15569                        );
15570                        if let Some(offset) = offset {
15571                            let task_buffer_range =
15572                                location.target.range.to_point(&buffer_snapshot);
15573                            let context_buffer_range =
15574                                task_buffer_range.to_offset(&buffer_snapshot);
15575                            let context_range = BufferOffset(context_buffer_range.start)
15576                                ..BufferOffset(context_buffer_range.end);
15577
15578                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15579                                .or_insert_with(|| RunnableTasks {
15580                                    templates: Vec::new(),
15581                                    offset,
15582                                    column: task_buffer_range.start.column,
15583                                    extra_variables: HashMap::default(),
15584                                    context_range,
15585                                })
15586                                .templates
15587                                .push((kind, task.original_task().clone()));
15588                        }
15589
15590                        acc
15591                    })
15592            }) else {
15593                return;
15594            };
15595
15596            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15597                buffer.language_settings(cx).tasks.prefer_lsp
15598            }) else {
15599                return;
15600            };
15601
15602            let rows = Self::runnable_rows(
15603                project,
15604                display_snapshot,
15605                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15606                new_rows,
15607                cx.clone(),
15608            )
15609            .await;
15610            editor
15611                .update(cx, |editor, _| {
15612                    editor.clear_tasks();
15613                    for (key, mut value) in rows {
15614                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15615                            value.templates.extend(lsp_tasks.templates);
15616                        }
15617
15618                        editor.insert_tasks(key, value);
15619                    }
15620                    for (key, value) in lsp_tasks_by_rows {
15621                        editor.insert_tasks(key, value);
15622                    }
15623                })
15624                .ok();
15625        })
15626    }
15627    fn fetch_runnable_ranges(
15628        snapshot: &DisplaySnapshot,
15629        range: Range<Anchor>,
15630    ) -> Vec<language::RunnableRange> {
15631        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15632    }
15633
15634    fn runnable_rows(
15635        project: Entity<Project>,
15636        snapshot: DisplaySnapshot,
15637        prefer_lsp: bool,
15638        runnable_ranges: Vec<RunnableRange>,
15639        cx: AsyncWindowContext,
15640    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15641        cx.spawn(async move |cx| {
15642            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15643            for mut runnable in runnable_ranges {
15644                let Some(tasks) = cx
15645                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15646                    .ok()
15647                else {
15648                    continue;
15649                };
15650                let mut tasks = tasks.await;
15651
15652                if prefer_lsp {
15653                    tasks.retain(|(task_kind, _)| {
15654                        !matches!(task_kind, TaskSourceKind::Language { .. })
15655                    });
15656                }
15657                if tasks.is_empty() {
15658                    continue;
15659                }
15660
15661                let point = runnable
15662                    .run_range
15663                    .start
15664                    .to_point(&snapshot.buffer_snapshot());
15665                let Some(row) = snapshot
15666                    .buffer_snapshot()
15667                    .buffer_line_for_row(MultiBufferRow(point.row))
15668                    .map(|(_, range)| range.start.row)
15669                else {
15670                    continue;
15671                };
15672
15673                let context_range =
15674                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15675                runnable_rows.push((
15676                    (runnable.buffer_id, row),
15677                    RunnableTasks {
15678                        templates: tasks,
15679                        offset: snapshot
15680                            .buffer_snapshot()
15681                            .anchor_before(runnable.run_range.start),
15682                        context_range,
15683                        column: point.column,
15684                        extra_variables: runnable.extra_captures,
15685                    },
15686                ));
15687            }
15688            runnable_rows
15689        })
15690    }
15691
15692    fn templates_with_tags(
15693        project: &Entity<Project>,
15694        runnable: &mut Runnable,
15695        cx: &mut App,
15696    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15697        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15698            let (worktree_id, file) = project
15699                .buffer_for_id(runnable.buffer, cx)
15700                .and_then(|buffer| buffer.read(cx).file())
15701                .map(|file| (file.worktree_id(cx), file.clone()))
15702                .unzip();
15703
15704            (
15705                project.task_store().read(cx).task_inventory().cloned(),
15706                worktree_id,
15707                file,
15708            )
15709        });
15710
15711        let tags = mem::take(&mut runnable.tags);
15712        let language = runnable.language.clone();
15713        cx.spawn(async move |cx| {
15714            let mut templates_with_tags = Vec::new();
15715            if let Some(inventory) = inventory {
15716                for RunnableTag(tag) in tags {
15717                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15718                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15719                    }) else {
15720                        return templates_with_tags;
15721                    };
15722                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15723                        move |(_, template)| {
15724                            template.tags.iter().any(|source_tag| source_tag == &tag)
15725                        },
15726                    ));
15727                }
15728            }
15729            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15730
15731            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15732                // Strongest source wins; if we have worktree tag binding, prefer that to
15733                // global and language bindings;
15734                // if we have a global binding, prefer that to language binding.
15735                let first_mismatch = templates_with_tags
15736                    .iter()
15737                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15738                if let Some(index) = first_mismatch {
15739                    templates_with_tags.truncate(index);
15740                }
15741            }
15742
15743            templates_with_tags
15744        })
15745    }
15746
15747    pub fn move_to_enclosing_bracket(
15748        &mut self,
15749        _: &MoveToEnclosingBracket,
15750        window: &mut Window,
15751        cx: &mut Context<Self>,
15752    ) {
15753        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15754        self.change_selections(Default::default(), window, cx, |s| {
15755            s.move_offsets_with(|snapshot, selection| {
15756                let Some(enclosing_bracket_ranges) =
15757                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15758                else {
15759                    return;
15760                };
15761
15762                let mut best_length = usize::MAX;
15763                let mut best_inside = false;
15764                let mut best_in_bracket_range = false;
15765                let mut best_destination = None;
15766                for (open, close) in enclosing_bracket_ranges {
15767                    let close = close.to_inclusive();
15768                    let length = close.end() - open.start;
15769                    let inside = selection.start >= open.end && selection.end <= *close.start();
15770                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15771                        || close.contains(&selection.head());
15772
15773                    // If best is next to a bracket and current isn't, skip
15774                    if !in_bracket_range && best_in_bracket_range {
15775                        continue;
15776                    }
15777
15778                    // Prefer smaller lengths unless best is inside and current isn't
15779                    if length > best_length && (best_inside || !inside) {
15780                        continue;
15781                    }
15782
15783                    best_length = length;
15784                    best_inside = inside;
15785                    best_in_bracket_range = in_bracket_range;
15786                    best_destination = Some(
15787                        if close.contains(&selection.start) && close.contains(&selection.end) {
15788                            if inside { open.end } else { open.start }
15789                        } else if inside {
15790                            *close.start()
15791                        } else {
15792                            *close.end()
15793                        },
15794                    );
15795                }
15796
15797                if let Some(destination) = best_destination {
15798                    selection.collapse_to(destination, SelectionGoal::None);
15799                }
15800            })
15801        });
15802    }
15803
15804    pub fn undo_selection(
15805        &mut self,
15806        _: &UndoSelection,
15807        window: &mut Window,
15808        cx: &mut Context<Self>,
15809    ) {
15810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15811        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15812            self.selection_history.mode = SelectionHistoryMode::Undoing;
15813            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15814                this.end_selection(window, cx);
15815                this.change_selections(
15816                    SelectionEffects::scroll(Autoscroll::newest()),
15817                    window,
15818                    cx,
15819                    |s| s.select_anchors(entry.selections.to_vec()),
15820                );
15821            });
15822            self.selection_history.mode = SelectionHistoryMode::Normal;
15823
15824            self.select_next_state = entry.select_next_state;
15825            self.select_prev_state = entry.select_prev_state;
15826            self.add_selections_state = entry.add_selections_state;
15827        }
15828    }
15829
15830    pub fn redo_selection(
15831        &mut self,
15832        _: &RedoSelection,
15833        window: &mut Window,
15834        cx: &mut Context<Self>,
15835    ) {
15836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15837        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15838            self.selection_history.mode = SelectionHistoryMode::Redoing;
15839            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15840                this.end_selection(window, cx);
15841                this.change_selections(
15842                    SelectionEffects::scroll(Autoscroll::newest()),
15843                    window,
15844                    cx,
15845                    |s| s.select_anchors(entry.selections.to_vec()),
15846                );
15847            });
15848            self.selection_history.mode = SelectionHistoryMode::Normal;
15849
15850            self.select_next_state = entry.select_next_state;
15851            self.select_prev_state = entry.select_prev_state;
15852            self.add_selections_state = entry.add_selections_state;
15853        }
15854    }
15855
15856    pub fn expand_excerpts(
15857        &mut self,
15858        action: &ExpandExcerpts,
15859        _: &mut Window,
15860        cx: &mut Context<Self>,
15861    ) {
15862        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15863    }
15864
15865    pub fn expand_excerpts_down(
15866        &mut self,
15867        action: &ExpandExcerptsDown,
15868        _: &mut Window,
15869        cx: &mut Context<Self>,
15870    ) {
15871        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15872    }
15873
15874    pub fn expand_excerpts_up(
15875        &mut self,
15876        action: &ExpandExcerptsUp,
15877        _: &mut Window,
15878        cx: &mut Context<Self>,
15879    ) {
15880        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15881    }
15882
15883    pub fn expand_excerpts_for_direction(
15884        &mut self,
15885        lines: u32,
15886        direction: ExpandExcerptDirection,
15887
15888        cx: &mut Context<Self>,
15889    ) {
15890        let selections = self.selections.disjoint_anchors_arc();
15891
15892        let lines = if lines == 0 {
15893            EditorSettings::get_global(cx).expand_excerpt_lines
15894        } else {
15895            lines
15896        };
15897
15898        self.buffer.update(cx, |buffer, cx| {
15899            let snapshot = buffer.snapshot(cx);
15900            let mut excerpt_ids = selections
15901                .iter()
15902                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15903                .collect::<Vec<_>>();
15904            excerpt_ids.sort();
15905            excerpt_ids.dedup();
15906            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15907        })
15908    }
15909
15910    pub fn expand_excerpt(
15911        &mut self,
15912        excerpt: ExcerptId,
15913        direction: ExpandExcerptDirection,
15914        window: &mut Window,
15915        cx: &mut Context<Self>,
15916    ) {
15917        let current_scroll_position = self.scroll_position(cx);
15918        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15919        let mut should_scroll_up = false;
15920
15921        if direction == ExpandExcerptDirection::Down {
15922            let multi_buffer = self.buffer.read(cx);
15923            let snapshot = multi_buffer.snapshot(cx);
15924            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15925                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15926                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15927            {
15928                let buffer_snapshot = buffer.read(cx).snapshot();
15929                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15930                let last_row = buffer_snapshot.max_point().row;
15931                let lines_below = last_row.saturating_sub(excerpt_end_row);
15932                should_scroll_up = lines_below >= lines_to_expand;
15933            }
15934        }
15935
15936        self.buffer.update(cx, |buffer, cx| {
15937            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15938        });
15939
15940        if should_scroll_up {
15941            let new_scroll_position =
15942                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
15943            self.set_scroll_position(new_scroll_position, window, cx);
15944        }
15945    }
15946
15947    pub fn go_to_singleton_buffer_point(
15948        &mut self,
15949        point: Point,
15950        window: &mut Window,
15951        cx: &mut Context<Self>,
15952    ) {
15953        self.go_to_singleton_buffer_range(point..point, window, cx);
15954    }
15955
15956    pub fn go_to_singleton_buffer_range(
15957        &mut self,
15958        range: Range<Point>,
15959        window: &mut Window,
15960        cx: &mut Context<Self>,
15961    ) {
15962        let multibuffer = self.buffer().read(cx);
15963        let Some(buffer) = multibuffer.as_singleton() else {
15964            return;
15965        };
15966        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15967            return;
15968        };
15969        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15970            return;
15971        };
15972        self.change_selections(
15973            SelectionEffects::default().nav_history(true),
15974            window,
15975            cx,
15976            |s| s.select_anchor_ranges([start..end]),
15977        );
15978    }
15979
15980    pub fn go_to_diagnostic(
15981        &mut self,
15982        action: &GoToDiagnostic,
15983        window: &mut Window,
15984        cx: &mut Context<Self>,
15985    ) {
15986        if !self.diagnostics_enabled() {
15987            return;
15988        }
15989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15990        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15991    }
15992
15993    pub fn go_to_prev_diagnostic(
15994        &mut self,
15995        action: &GoToPreviousDiagnostic,
15996        window: &mut Window,
15997        cx: &mut Context<Self>,
15998    ) {
15999        if !self.diagnostics_enabled() {
16000            return;
16001        }
16002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16003        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16004    }
16005
16006    pub fn go_to_diagnostic_impl(
16007        &mut self,
16008        direction: Direction,
16009        severity: GoToDiagnosticSeverityFilter,
16010        window: &mut Window,
16011        cx: &mut Context<Self>,
16012    ) {
16013        let buffer = self.buffer.read(cx).snapshot(cx);
16014        let selection = self.selections.newest::<usize>(cx);
16015
16016        let mut active_group_id = None;
16017        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16018            && active_group.active_range.start.to_offset(&buffer) == selection.start
16019        {
16020            active_group_id = Some(active_group.group_id);
16021        }
16022
16023        fn filtered<'a>(
16024            snapshot: EditorSnapshot,
16025            severity: GoToDiagnosticSeverityFilter,
16026            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16027        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16028            diagnostics
16029                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16030                .filter(|entry| entry.range.start != entry.range.end)
16031                .filter(|entry| !entry.diagnostic.is_unnecessary)
16032                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16033        }
16034
16035        let snapshot = self.snapshot(window, cx);
16036        let before = filtered(
16037            snapshot.clone(),
16038            severity,
16039            buffer
16040                .diagnostics_in_range(0..selection.start)
16041                .filter(|entry| entry.range.start <= selection.start),
16042        );
16043        let after = filtered(
16044            snapshot,
16045            severity,
16046            buffer
16047                .diagnostics_in_range(selection.start..buffer.len())
16048                .filter(|entry| entry.range.start >= selection.start),
16049        );
16050
16051        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16052        if direction == Direction::Prev {
16053            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16054            {
16055                for diagnostic in prev_diagnostics.into_iter().rev() {
16056                    if diagnostic.range.start != selection.start
16057                        || active_group_id
16058                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16059                    {
16060                        found = Some(diagnostic);
16061                        break 'outer;
16062                    }
16063                }
16064            }
16065        } else {
16066            for diagnostic in after.chain(before) {
16067                if diagnostic.range.start != selection.start
16068                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16069                {
16070                    found = Some(diagnostic);
16071                    break;
16072                }
16073            }
16074        }
16075        let Some(next_diagnostic) = found else {
16076            return;
16077        };
16078
16079        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16080        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16081            return;
16082        };
16083        self.change_selections(Default::default(), window, cx, |s| {
16084            s.select_ranges(vec![
16085                next_diagnostic.range.start..next_diagnostic.range.start,
16086            ])
16087        });
16088        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16089        self.refresh_edit_prediction(false, true, window, cx);
16090    }
16091
16092    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16093        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16094        let snapshot = self.snapshot(window, cx);
16095        let selection = self.selections.newest::<Point>(cx);
16096        self.go_to_hunk_before_or_after_position(
16097            &snapshot,
16098            selection.head(),
16099            Direction::Next,
16100            window,
16101            cx,
16102        );
16103    }
16104
16105    pub fn go_to_hunk_before_or_after_position(
16106        &mut self,
16107        snapshot: &EditorSnapshot,
16108        position: Point,
16109        direction: Direction,
16110        window: &mut Window,
16111        cx: &mut Context<Editor>,
16112    ) {
16113        let row = if direction == Direction::Next {
16114            self.hunk_after_position(snapshot, position)
16115                .map(|hunk| hunk.row_range.start)
16116        } else {
16117            self.hunk_before_position(snapshot, position)
16118        };
16119
16120        if let Some(row) = row {
16121            let destination = Point::new(row.0, 0);
16122            let autoscroll = Autoscroll::center();
16123
16124            self.unfold_ranges(&[destination..destination], false, false, cx);
16125            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16126                s.select_ranges([destination..destination]);
16127            });
16128        }
16129    }
16130
16131    fn hunk_after_position(
16132        &mut self,
16133        snapshot: &EditorSnapshot,
16134        position: Point,
16135    ) -> Option<MultiBufferDiffHunk> {
16136        snapshot
16137            .buffer_snapshot()
16138            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16139            .find(|hunk| hunk.row_range.start.0 > position.row)
16140            .or_else(|| {
16141                snapshot
16142                    .buffer_snapshot()
16143                    .diff_hunks_in_range(Point::zero()..position)
16144                    .find(|hunk| hunk.row_range.end.0 < position.row)
16145            })
16146    }
16147
16148    fn go_to_prev_hunk(
16149        &mut self,
16150        _: &GoToPreviousHunk,
16151        window: &mut Window,
16152        cx: &mut Context<Self>,
16153    ) {
16154        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16155        let snapshot = self.snapshot(window, cx);
16156        let selection = self.selections.newest::<Point>(cx);
16157        self.go_to_hunk_before_or_after_position(
16158            &snapshot,
16159            selection.head(),
16160            Direction::Prev,
16161            window,
16162            cx,
16163        );
16164    }
16165
16166    fn hunk_before_position(
16167        &mut self,
16168        snapshot: &EditorSnapshot,
16169        position: Point,
16170    ) -> Option<MultiBufferRow> {
16171        snapshot
16172            .buffer_snapshot()
16173            .diff_hunk_before(position)
16174            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16175    }
16176
16177    fn go_to_next_change(
16178        &mut self,
16179        _: &GoToNextChange,
16180        window: &mut Window,
16181        cx: &mut Context<Self>,
16182    ) {
16183        if let Some(selections) = self
16184            .change_list
16185            .next_change(1, Direction::Next)
16186            .map(|s| s.to_vec())
16187        {
16188            self.change_selections(Default::default(), window, cx, |s| {
16189                let map = s.display_map();
16190                s.select_display_ranges(selections.iter().map(|a| {
16191                    let point = a.to_display_point(&map);
16192                    point..point
16193                }))
16194            })
16195        }
16196    }
16197
16198    fn go_to_previous_change(
16199        &mut self,
16200        _: &GoToPreviousChange,
16201        window: &mut Window,
16202        cx: &mut Context<Self>,
16203    ) {
16204        if let Some(selections) = self
16205            .change_list
16206            .next_change(1, Direction::Prev)
16207            .map(|s| s.to_vec())
16208        {
16209            self.change_selections(Default::default(), window, cx, |s| {
16210                let map = s.display_map();
16211                s.select_display_ranges(selections.iter().map(|a| {
16212                    let point = a.to_display_point(&map);
16213                    point..point
16214                }))
16215            })
16216        }
16217    }
16218
16219    pub fn go_to_next_document_highlight(
16220        &mut self,
16221        _: &GoToNextDocumentHighlight,
16222        window: &mut Window,
16223        cx: &mut Context<Self>,
16224    ) {
16225        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16226    }
16227
16228    pub fn go_to_prev_document_highlight(
16229        &mut self,
16230        _: &GoToPreviousDocumentHighlight,
16231        window: &mut Window,
16232        cx: &mut Context<Self>,
16233    ) {
16234        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16235    }
16236
16237    pub fn go_to_document_highlight_before_or_after_position(
16238        &mut self,
16239        direction: Direction,
16240        window: &mut Window,
16241        cx: &mut Context<Editor>,
16242    ) {
16243        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16244        let snapshot = self.snapshot(window, cx);
16245        let buffer = &snapshot.buffer_snapshot();
16246        let position = self.selections.newest::<Point>(cx).head();
16247        let anchor_position = buffer.anchor_after(position);
16248
16249        // Get all document highlights (both read and write)
16250        let mut all_highlights = Vec::new();
16251
16252        if let Some((_, read_highlights)) = self
16253            .background_highlights
16254            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16255        {
16256            all_highlights.extend(read_highlights.iter());
16257        }
16258
16259        if let Some((_, write_highlights)) = self
16260            .background_highlights
16261            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16262        {
16263            all_highlights.extend(write_highlights.iter());
16264        }
16265
16266        if all_highlights.is_empty() {
16267            return;
16268        }
16269
16270        // Sort highlights by position
16271        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16272
16273        let target_highlight = match direction {
16274            Direction::Next => {
16275                // Find the first highlight after the current position
16276                all_highlights
16277                    .iter()
16278                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16279            }
16280            Direction::Prev => {
16281                // Find the last highlight before the current position
16282                all_highlights
16283                    .iter()
16284                    .rev()
16285                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16286            }
16287        };
16288
16289        if let Some(highlight) = target_highlight {
16290            let destination = highlight.start.to_point(buffer);
16291            let autoscroll = Autoscroll::center();
16292
16293            self.unfold_ranges(&[destination..destination], false, false, cx);
16294            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16295                s.select_ranges([destination..destination]);
16296            });
16297        }
16298    }
16299
16300    fn go_to_line<T: 'static>(
16301        &mut self,
16302        position: Anchor,
16303        highlight_color: Option<Hsla>,
16304        window: &mut Window,
16305        cx: &mut Context<Self>,
16306    ) {
16307        let snapshot = self.snapshot(window, cx).display_snapshot;
16308        let position = position.to_point(&snapshot.buffer_snapshot());
16309        let start = snapshot
16310            .buffer_snapshot()
16311            .clip_point(Point::new(position.row, 0), Bias::Left);
16312        let end = start + Point::new(1, 0);
16313        let start = snapshot.buffer_snapshot().anchor_before(start);
16314        let end = snapshot.buffer_snapshot().anchor_before(end);
16315
16316        self.highlight_rows::<T>(
16317            start..end,
16318            highlight_color
16319                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16320            Default::default(),
16321            cx,
16322        );
16323
16324        if self.buffer.read(cx).is_singleton() {
16325            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16326        }
16327    }
16328
16329    pub fn go_to_definition(
16330        &mut self,
16331        _: &GoToDefinition,
16332        window: &mut Window,
16333        cx: &mut Context<Self>,
16334    ) -> Task<Result<Navigated>> {
16335        let definition =
16336            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16337        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16338        cx.spawn_in(window, async move |editor, cx| {
16339            if definition.await? == Navigated::Yes {
16340                return Ok(Navigated::Yes);
16341            }
16342            match fallback_strategy {
16343                GoToDefinitionFallback::None => Ok(Navigated::No),
16344                GoToDefinitionFallback::FindAllReferences => {
16345                    match editor.update_in(cx, |editor, window, cx| {
16346                        editor.find_all_references(&FindAllReferences, window, cx)
16347                    })? {
16348                        Some(references) => references.await,
16349                        None => Ok(Navigated::No),
16350                    }
16351                }
16352            }
16353        })
16354    }
16355
16356    pub fn go_to_declaration(
16357        &mut self,
16358        _: &GoToDeclaration,
16359        window: &mut Window,
16360        cx: &mut Context<Self>,
16361    ) -> Task<Result<Navigated>> {
16362        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16363    }
16364
16365    pub fn go_to_declaration_split(
16366        &mut self,
16367        _: &GoToDeclaration,
16368        window: &mut Window,
16369        cx: &mut Context<Self>,
16370    ) -> Task<Result<Navigated>> {
16371        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16372    }
16373
16374    pub fn go_to_implementation(
16375        &mut self,
16376        _: &GoToImplementation,
16377        window: &mut Window,
16378        cx: &mut Context<Self>,
16379    ) -> Task<Result<Navigated>> {
16380        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16381    }
16382
16383    pub fn go_to_implementation_split(
16384        &mut self,
16385        _: &GoToImplementationSplit,
16386        window: &mut Window,
16387        cx: &mut Context<Self>,
16388    ) -> Task<Result<Navigated>> {
16389        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16390    }
16391
16392    pub fn go_to_type_definition(
16393        &mut self,
16394        _: &GoToTypeDefinition,
16395        window: &mut Window,
16396        cx: &mut Context<Self>,
16397    ) -> Task<Result<Navigated>> {
16398        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16399    }
16400
16401    pub fn go_to_definition_split(
16402        &mut self,
16403        _: &GoToDefinitionSplit,
16404        window: &mut Window,
16405        cx: &mut Context<Self>,
16406    ) -> Task<Result<Navigated>> {
16407        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16408    }
16409
16410    pub fn go_to_type_definition_split(
16411        &mut self,
16412        _: &GoToTypeDefinitionSplit,
16413        window: &mut Window,
16414        cx: &mut Context<Self>,
16415    ) -> Task<Result<Navigated>> {
16416        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16417    }
16418
16419    fn go_to_definition_of_kind(
16420        &mut self,
16421        kind: GotoDefinitionKind,
16422        split: bool,
16423        window: &mut Window,
16424        cx: &mut Context<Self>,
16425    ) -> Task<Result<Navigated>> {
16426        let Some(provider) = self.semantics_provider.clone() else {
16427            return Task::ready(Ok(Navigated::No));
16428        };
16429        let head = self.selections.newest::<usize>(cx).head();
16430        let buffer = self.buffer.read(cx);
16431        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16432            return Task::ready(Ok(Navigated::No));
16433        };
16434        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16435            return Task::ready(Ok(Navigated::No));
16436        };
16437
16438        cx.spawn_in(window, async move |editor, cx| {
16439            let Some(definitions) = definitions.await? else {
16440                return Ok(Navigated::No);
16441            };
16442            let navigated = editor
16443                .update_in(cx, |editor, window, cx| {
16444                    editor.navigate_to_hover_links(
16445                        Some(kind),
16446                        definitions
16447                            .into_iter()
16448                            .filter(|location| {
16449                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16450                            })
16451                            .map(HoverLink::Text)
16452                            .collect::<Vec<_>>(),
16453                        split,
16454                        window,
16455                        cx,
16456                    )
16457                })?
16458                .await?;
16459            anyhow::Ok(navigated)
16460        })
16461    }
16462
16463    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16464        let selection = self.selections.newest_anchor();
16465        let head = selection.head();
16466        let tail = selection.tail();
16467
16468        let Some((buffer, start_position)) =
16469            self.buffer.read(cx).text_anchor_for_position(head, cx)
16470        else {
16471            return;
16472        };
16473
16474        let end_position = if head != tail {
16475            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16476                return;
16477            };
16478            Some(pos)
16479        } else {
16480            None
16481        };
16482
16483        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16484            let url = if let Some(end_pos) = end_position {
16485                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16486            } else {
16487                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16488            };
16489
16490            if let Some(url) = url {
16491                cx.update(|window, cx| {
16492                    if parse_zed_link(&url, cx).is_some() {
16493                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16494                    } else {
16495                        cx.open_url(&url);
16496                    }
16497                })?;
16498            }
16499
16500            anyhow::Ok(())
16501        });
16502
16503        url_finder.detach();
16504    }
16505
16506    pub fn open_selected_filename(
16507        &mut self,
16508        _: &OpenSelectedFilename,
16509        window: &mut Window,
16510        cx: &mut Context<Self>,
16511    ) {
16512        let Some(workspace) = self.workspace() else {
16513            return;
16514        };
16515
16516        let position = self.selections.newest_anchor().head();
16517
16518        let Some((buffer, buffer_position)) =
16519            self.buffer.read(cx).text_anchor_for_position(position, cx)
16520        else {
16521            return;
16522        };
16523
16524        let project = self.project.clone();
16525
16526        cx.spawn_in(window, async move |_, cx| {
16527            let result = find_file(&buffer, project, buffer_position, cx).await;
16528
16529            if let Some((_, path)) = result {
16530                workspace
16531                    .update_in(cx, |workspace, window, cx| {
16532                        workspace.open_resolved_path(path, window, cx)
16533                    })?
16534                    .await?;
16535            }
16536            anyhow::Ok(())
16537        })
16538        .detach();
16539    }
16540
16541    pub(crate) fn navigate_to_hover_links(
16542        &mut self,
16543        kind: Option<GotoDefinitionKind>,
16544        definitions: Vec<HoverLink>,
16545        split: bool,
16546        window: &mut Window,
16547        cx: &mut Context<Editor>,
16548    ) -> Task<Result<Navigated>> {
16549        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16550        let mut first_url_or_file = None;
16551        let definitions: Vec<_> = definitions
16552            .into_iter()
16553            .filter_map(|def| match def {
16554                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16555                HoverLink::InlayHint(lsp_location, server_id) => {
16556                    let computation =
16557                        self.compute_target_location(lsp_location, server_id, window, cx);
16558                    Some(cx.background_spawn(computation))
16559                }
16560                HoverLink::Url(url) => {
16561                    first_url_or_file = Some(Either::Left(url));
16562                    None
16563                }
16564                HoverLink::File(path) => {
16565                    first_url_or_file = Some(Either::Right(path));
16566                    None
16567                }
16568            })
16569            .collect();
16570
16571        let workspace = self.workspace();
16572
16573        cx.spawn_in(window, async move |editor, cx| {
16574            let locations: Vec<Location> = future::join_all(definitions)
16575                .await
16576                .into_iter()
16577                .filter_map(|location| location.transpose())
16578                .collect::<Result<_>>()
16579                .context("location tasks")?;
16580            let mut locations = cx.update(|_, cx| {
16581                locations
16582                    .into_iter()
16583                    .map(|location| {
16584                        let buffer = location.buffer.read(cx);
16585                        (location.buffer, location.range.to_point(buffer))
16586                    })
16587                    .into_group_map()
16588            })?;
16589            let mut num_locations = 0;
16590            for ranges in locations.values_mut() {
16591                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16592                ranges.dedup();
16593                num_locations += ranges.len();
16594            }
16595
16596            if num_locations > 1 {
16597                let Some(workspace) = workspace else {
16598                    return Ok(Navigated::No);
16599                };
16600
16601                let tab_kind = match kind {
16602                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16603                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16604                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16605                    Some(GotoDefinitionKind::Type) => "Types",
16606                };
16607                let title = editor
16608                    .update_in(cx, |_, _, cx| {
16609                        let target = locations
16610                            .iter()
16611                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16612                            .map(|(buffer, location)| {
16613                                buffer
16614                                    .read(cx)
16615                                    .text_for_range(location.clone())
16616                                    .collect::<String>()
16617                            })
16618                            .filter(|text| !text.contains('\n'))
16619                            .unique()
16620                            .take(3)
16621                            .join(", ");
16622                        if target.is_empty() {
16623                            tab_kind.to_owned()
16624                        } else {
16625                            format!("{tab_kind} for {target}")
16626                        }
16627                    })
16628                    .context("buffer title")?;
16629
16630                let opened = workspace
16631                    .update_in(cx, |workspace, window, cx| {
16632                        Self::open_locations_in_multibuffer(
16633                            workspace,
16634                            locations,
16635                            title,
16636                            split,
16637                            MultibufferSelectionMode::First,
16638                            window,
16639                            cx,
16640                        )
16641                    })
16642                    .is_ok();
16643
16644                anyhow::Ok(Navigated::from_bool(opened))
16645            } else if num_locations == 0 {
16646                // If there is one url or file, open it directly
16647                match first_url_or_file {
16648                    Some(Either::Left(url)) => {
16649                        cx.update(|_, cx| cx.open_url(&url))?;
16650                        Ok(Navigated::Yes)
16651                    }
16652                    Some(Either::Right(path)) => {
16653                        let Some(workspace) = workspace else {
16654                            return Ok(Navigated::No);
16655                        };
16656
16657                        workspace
16658                            .update_in(cx, |workspace, window, cx| {
16659                                workspace.open_resolved_path(path, window, cx)
16660                            })?
16661                            .await?;
16662                        Ok(Navigated::Yes)
16663                    }
16664                    None => Ok(Navigated::No),
16665                }
16666            } else {
16667                let Some(workspace) = workspace else {
16668                    return Ok(Navigated::No);
16669                };
16670
16671                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16672                let target_range = target_ranges.first().unwrap().clone();
16673
16674                editor.update_in(cx, |editor, window, cx| {
16675                    let range = target_range.to_point(target_buffer.read(cx));
16676                    let range = editor.range_for_match(&range);
16677                    let range = collapse_multiline_range(range);
16678
16679                    if !split
16680                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16681                    {
16682                        editor.go_to_singleton_buffer_range(range, window, cx);
16683                    } else {
16684                        let pane = workspace.read(cx).active_pane().clone();
16685                        window.defer(cx, move |window, cx| {
16686                            let target_editor: Entity<Self> =
16687                                workspace.update(cx, |workspace, cx| {
16688                                    let pane = if split {
16689                                        workspace.adjacent_pane(window, cx)
16690                                    } else {
16691                                        workspace.active_pane().clone()
16692                                    };
16693
16694                                    workspace.open_project_item(
16695                                        pane,
16696                                        target_buffer.clone(),
16697                                        true,
16698                                        true,
16699                                        window,
16700                                        cx,
16701                                    )
16702                                });
16703                            target_editor.update(cx, |target_editor, cx| {
16704                                // When selecting a definition in a different buffer, disable the nav history
16705                                // to avoid creating a history entry at the previous cursor location.
16706                                pane.update(cx, |pane, _| pane.disable_history());
16707                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16708                                pane.update(cx, |pane, _| pane.enable_history());
16709                            });
16710                        });
16711                    }
16712                    Navigated::Yes
16713                })
16714            }
16715        })
16716    }
16717
16718    fn compute_target_location(
16719        &self,
16720        lsp_location: lsp::Location,
16721        server_id: LanguageServerId,
16722        window: &mut Window,
16723        cx: &mut Context<Self>,
16724    ) -> Task<anyhow::Result<Option<Location>>> {
16725        let Some(project) = self.project.clone() else {
16726            return Task::ready(Ok(None));
16727        };
16728
16729        cx.spawn_in(window, async move |editor, cx| {
16730            let location_task = editor.update(cx, |_, cx| {
16731                project.update(cx, |project, cx| {
16732                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16733                })
16734            })?;
16735            let location = Some({
16736                let target_buffer_handle = location_task.await.context("open local buffer")?;
16737                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16738                    let target_start = target_buffer
16739                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16740                    let target_end = target_buffer
16741                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16742                    target_buffer.anchor_after(target_start)
16743                        ..target_buffer.anchor_before(target_end)
16744                })?;
16745                Location {
16746                    buffer: target_buffer_handle,
16747                    range,
16748                }
16749            });
16750            Ok(location)
16751        })
16752    }
16753
16754    pub fn find_all_references(
16755        &mut self,
16756        _: &FindAllReferences,
16757        window: &mut Window,
16758        cx: &mut Context<Self>,
16759    ) -> Option<Task<Result<Navigated>>> {
16760        let selection = self.selections.newest::<usize>(cx);
16761        let multi_buffer = self.buffer.read(cx);
16762        let head = selection.head();
16763
16764        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16765        let head_anchor = multi_buffer_snapshot.anchor_at(
16766            head,
16767            if head < selection.tail() {
16768                Bias::Right
16769            } else {
16770                Bias::Left
16771            },
16772        );
16773
16774        match self
16775            .find_all_references_task_sources
16776            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16777        {
16778            Ok(_) => {
16779                log::info!(
16780                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16781                );
16782                return None;
16783            }
16784            Err(i) => {
16785                self.find_all_references_task_sources.insert(i, head_anchor);
16786            }
16787        }
16788
16789        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16790        let workspace = self.workspace()?;
16791        let project = workspace.read(cx).project().clone();
16792        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16793        Some(cx.spawn_in(window, async move |editor, cx| {
16794            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16795                if let Ok(i) = editor
16796                    .find_all_references_task_sources
16797                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16798                {
16799                    editor.find_all_references_task_sources.remove(i);
16800                }
16801            });
16802
16803            let Some(locations) = references.await? else {
16804                return anyhow::Ok(Navigated::No);
16805            };
16806            let mut locations = cx.update(|_, cx| {
16807                locations
16808                    .into_iter()
16809                    .map(|location| {
16810                        let buffer = location.buffer.read(cx);
16811                        (location.buffer, location.range.to_point(buffer))
16812                    })
16813                    .into_group_map()
16814            })?;
16815            if locations.is_empty() {
16816                return anyhow::Ok(Navigated::No);
16817            }
16818            for ranges in locations.values_mut() {
16819                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16820                ranges.dedup();
16821            }
16822
16823            workspace.update_in(cx, |workspace, window, cx| {
16824                let target = locations
16825                    .iter()
16826                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16827                    .map(|(buffer, location)| {
16828                        buffer
16829                            .read(cx)
16830                            .text_for_range(location.clone())
16831                            .collect::<String>()
16832                    })
16833                    .filter(|text| !text.contains('\n'))
16834                    .unique()
16835                    .take(3)
16836                    .join(", ");
16837                let title = if target.is_empty() {
16838                    "References".to_owned()
16839                } else {
16840                    format!("References to {target}")
16841                };
16842                Self::open_locations_in_multibuffer(
16843                    workspace,
16844                    locations,
16845                    title,
16846                    false,
16847                    MultibufferSelectionMode::First,
16848                    window,
16849                    cx,
16850                );
16851                Navigated::Yes
16852            })
16853        }))
16854    }
16855
16856    /// Opens a multibuffer with the given project locations in it
16857    pub fn open_locations_in_multibuffer(
16858        workspace: &mut Workspace,
16859        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16860        title: String,
16861        split: bool,
16862        multibuffer_selection_mode: MultibufferSelectionMode,
16863        window: &mut Window,
16864        cx: &mut Context<Workspace>,
16865    ) {
16866        if locations.is_empty() {
16867            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16868            return;
16869        }
16870
16871        let capability = workspace.project().read(cx).capability();
16872        let mut ranges = <Vec<Range<Anchor>>>::new();
16873
16874        // a key to find existing multibuffer editors with the same set of locations
16875        // to prevent us from opening more and more multibuffer tabs for searches and the like
16876        let mut key = (title.clone(), vec![]);
16877        let excerpt_buffer = cx.new(|cx| {
16878            let key = &mut key.1;
16879            let mut multibuffer = MultiBuffer::new(capability);
16880            for (buffer, mut ranges_for_buffer) in locations {
16881                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16882                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16883                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16884                    PathKey::for_buffer(&buffer, cx),
16885                    buffer.clone(),
16886                    ranges_for_buffer,
16887                    multibuffer_context_lines(cx),
16888                    cx,
16889                );
16890                ranges.extend(new_ranges)
16891            }
16892
16893            multibuffer.with_title(title)
16894        });
16895        let existing = workspace.active_pane().update(cx, |pane, cx| {
16896            pane.items()
16897                .filter_map(|item| item.downcast::<Editor>())
16898                .find(|editor| {
16899                    editor
16900                        .read(cx)
16901                        .lookup_key
16902                        .as_ref()
16903                        .and_then(|it| {
16904                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16905                        })
16906                        .is_some_and(|it| *it == key)
16907                })
16908        });
16909        let editor = existing.unwrap_or_else(|| {
16910            cx.new(|cx| {
16911                let mut editor = Editor::for_multibuffer(
16912                    excerpt_buffer,
16913                    Some(workspace.project().clone()),
16914                    window,
16915                    cx,
16916                );
16917                editor.lookup_key = Some(Box::new(key));
16918                editor
16919            })
16920        });
16921        editor.update(cx, |editor, cx| {
16922            match multibuffer_selection_mode {
16923                MultibufferSelectionMode::First => {
16924                    if let Some(first_range) = ranges.first() {
16925                        editor.change_selections(
16926                            SelectionEffects::no_scroll(),
16927                            window,
16928                            cx,
16929                            |selections| {
16930                                selections.clear_disjoint();
16931                                selections
16932                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16933                            },
16934                        );
16935                    }
16936                    editor.highlight_background::<Self>(
16937                        &ranges,
16938                        |theme| theme.colors().editor_highlighted_line_background,
16939                        cx,
16940                    );
16941                }
16942                MultibufferSelectionMode::All => {
16943                    editor.change_selections(
16944                        SelectionEffects::no_scroll(),
16945                        window,
16946                        cx,
16947                        |selections| {
16948                            selections.clear_disjoint();
16949                            selections.select_anchor_ranges(ranges);
16950                        },
16951                    );
16952                }
16953            }
16954            editor.register_buffers_with_language_servers(cx);
16955        });
16956
16957        let item = Box::new(editor);
16958        let item_id = item.item_id();
16959
16960        if split {
16961            let pane = workspace.adjacent_pane(window, cx);
16962            workspace.add_item(pane, item, None, true, true, window, cx);
16963        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16964            let (preview_item_id, preview_item_idx) =
16965                workspace.active_pane().read_with(cx, |pane, _| {
16966                    (pane.preview_item_id(), pane.preview_item_idx())
16967                });
16968
16969            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16970
16971            if let Some(preview_item_id) = preview_item_id {
16972                workspace.active_pane().update(cx, |pane, cx| {
16973                    pane.remove_item(preview_item_id, false, false, window, cx);
16974                });
16975            }
16976        } else {
16977            workspace.add_item_to_active_pane(item, None, true, window, cx);
16978        }
16979        workspace.active_pane().update(cx, |pane, cx| {
16980            pane.set_preview_item_id(Some(item_id), cx);
16981        });
16982    }
16983
16984    pub fn rename(
16985        &mut self,
16986        _: &Rename,
16987        window: &mut Window,
16988        cx: &mut Context<Self>,
16989    ) -> Option<Task<Result<()>>> {
16990        use language::ToOffset as _;
16991
16992        let provider = self.semantics_provider.clone()?;
16993        let selection = self.selections.newest_anchor().clone();
16994        let (cursor_buffer, cursor_buffer_position) = self
16995            .buffer
16996            .read(cx)
16997            .text_anchor_for_position(selection.head(), cx)?;
16998        let (tail_buffer, cursor_buffer_position_end) = self
16999            .buffer
17000            .read(cx)
17001            .text_anchor_for_position(selection.tail(), cx)?;
17002        if tail_buffer != cursor_buffer {
17003            return None;
17004        }
17005
17006        let snapshot = cursor_buffer.read(cx).snapshot();
17007        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17008        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17009        let prepare_rename = provider
17010            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17011            .unwrap_or_else(|| Task::ready(Ok(None)));
17012        drop(snapshot);
17013
17014        Some(cx.spawn_in(window, async move |this, cx| {
17015            let rename_range = if let Some(range) = prepare_rename.await? {
17016                Some(range)
17017            } else {
17018                this.update(cx, |this, cx| {
17019                    let buffer = this.buffer.read(cx).snapshot(cx);
17020                    let mut buffer_highlights = this
17021                        .document_highlights_for_position(selection.head(), &buffer)
17022                        .filter(|highlight| {
17023                            highlight.start.excerpt_id == selection.head().excerpt_id
17024                                && highlight.end.excerpt_id == selection.head().excerpt_id
17025                        });
17026                    buffer_highlights
17027                        .next()
17028                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17029                })?
17030            };
17031            if let Some(rename_range) = rename_range {
17032                this.update_in(cx, |this, window, cx| {
17033                    let snapshot = cursor_buffer.read(cx).snapshot();
17034                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17035                    let cursor_offset_in_rename_range =
17036                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17037                    let cursor_offset_in_rename_range_end =
17038                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17039
17040                    this.take_rename(false, window, cx);
17041                    let buffer = this.buffer.read(cx).read(cx);
17042                    let cursor_offset = selection.head().to_offset(&buffer);
17043                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17044                    let rename_end = rename_start + rename_buffer_range.len();
17045                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17046                    let mut old_highlight_id = None;
17047                    let old_name: Arc<str> = buffer
17048                        .chunks(rename_start..rename_end, true)
17049                        .map(|chunk| {
17050                            if old_highlight_id.is_none() {
17051                                old_highlight_id = chunk.syntax_highlight_id;
17052                            }
17053                            chunk.text
17054                        })
17055                        .collect::<String>()
17056                        .into();
17057
17058                    drop(buffer);
17059
17060                    // Position the selection in the rename editor so that it matches the current selection.
17061                    this.show_local_selections = false;
17062                    let rename_editor = cx.new(|cx| {
17063                        let mut editor = Editor::single_line(window, cx);
17064                        editor.buffer.update(cx, |buffer, cx| {
17065                            buffer.edit([(0..0, old_name.clone())], None, cx)
17066                        });
17067                        let rename_selection_range = match cursor_offset_in_rename_range
17068                            .cmp(&cursor_offset_in_rename_range_end)
17069                        {
17070                            Ordering::Equal => {
17071                                editor.select_all(&SelectAll, window, cx);
17072                                return editor;
17073                            }
17074                            Ordering::Less => {
17075                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17076                            }
17077                            Ordering::Greater => {
17078                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17079                            }
17080                        };
17081                        if rename_selection_range.end > old_name.len() {
17082                            editor.select_all(&SelectAll, window, cx);
17083                        } else {
17084                            editor.change_selections(Default::default(), window, cx, |s| {
17085                                s.select_ranges([rename_selection_range]);
17086                            });
17087                        }
17088                        editor
17089                    });
17090                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17091                        if e == &EditorEvent::Focused {
17092                            cx.emit(EditorEvent::FocusedIn)
17093                        }
17094                    })
17095                    .detach();
17096
17097                    let write_highlights =
17098                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17099                    let read_highlights =
17100                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17101                    let ranges = write_highlights
17102                        .iter()
17103                        .flat_map(|(_, ranges)| ranges.iter())
17104                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17105                        .cloned()
17106                        .collect();
17107
17108                    this.highlight_text::<Rename>(
17109                        ranges,
17110                        HighlightStyle {
17111                            fade_out: Some(0.6),
17112                            ..Default::default()
17113                        },
17114                        cx,
17115                    );
17116                    let rename_focus_handle = rename_editor.focus_handle(cx);
17117                    window.focus(&rename_focus_handle);
17118                    let block_id = this.insert_blocks(
17119                        [BlockProperties {
17120                            style: BlockStyle::Flex,
17121                            placement: BlockPlacement::Below(range.start),
17122                            height: Some(1),
17123                            render: Arc::new({
17124                                let rename_editor = rename_editor.clone();
17125                                move |cx: &mut BlockContext| {
17126                                    let mut text_style = cx.editor_style.text.clone();
17127                                    if let Some(highlight_style) = old_highlight_id
17128                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17129                                    {
17130                                        text_style = text_style.highlight(highlight_style);
17131                                    }
17132                                    div()
17133                                        .block_mouse_except_scroll()
17134                                        .pl(cx.anchor_x)
17135                                        .child(EditorElement::new(
17136                                            &rename_editor,
17137                                            EditorStyle {
17138                                                background: cx.theme().system().transparent,
17139                                                local_player: cx.editor_style.local_player,
17140                                                text: text_style,
17141                                                scrollbar_width: cx.editor_style.scrollbar_width,
17142                                                syntax: cx.editor_style.syntax.clone(),
17143                                                status: cx.editor_style.status.clone(),
17144                                                inlay_hints_style: HighlightStyle {
17145                                                    font_weight: Some(FontWeight::BOLD),
17146                                                    ..make_inlay_hints_style(cx.app)
17147                                                },
17148                                                edit_prediction_styles: make_suggestion_styles(
17149                                                    cx.app,
17150                                                ),
17151                                                ..EditorStyle::default()
17152                                            },
17153                                        ))
17154                                        .into_any_element()
17155                                }
17156                            }),
17157                            priority: 0,
17158                        }],
17159                        Some(Autoscroll::fit()),
17160                        cx,
17161                    )[0];
17162                    this.pending_rename = Some(RenameState {
17163                        range,
17164                        old_name,
17165                        editor: rename_editor,
17166                        block_id,
17167                    });
17168                })?;
17169            }
17170
17171            Ok(())
17172        }))
17173    }
17174
17175    pub fn confirm_rename(
17176        &mut self,
17177        _: &ConfirmRename,
17178        window: &mut Window,
17179        cx: &mut Context<Self>,
17180    ) -> Option<Task<Result<()>>> {
17181        let rename = self.take_rename(false, window, cx)?;
17182        let workspace = self.workspace()?.downgrade();
17183        let (buffer, start) = self
17184            .buffer
17185            .read(cx)
17186            .text_anchor_for_position(rename.range.start, cx)?;
17187        let (end_buffer, _) = self
17188            .buffer
17189            .read(cx)
17190            .text_anchor_for_position(rename.range.end, cx)?;
17191        if buffer != end_buffer {
17192            return None;
17193        }
17194
17195        let old_name = rename.old_name;
17196        let new_name = rename.editor.read(cx).text(cx);
17197
17198        let rename = self.semantics_provider.as_ref()?.perform_rename(
17199            &buffer,
17200            start,
17201            new_name.clone(),
17202            cx,
17203        )?;
17204
17205        Some(cx.spawn_in(window, async move |editor, cx| {
17206            let project_transaction = rename.await?;
17207            Self::open_project_transaction(
17208                &editor,
17209                workspace,
17210                project_transaction,
17211                format!("Rename: {}{}", old_name, new_name),
17212                cx,
17213            )
17214            .await?;
17215
17216            editor.update(cx, |editor, cx| {
17217                editor.refresh_document_highlights(cx);
17218            })?;
17219            Ok(())
17220        }))
17221    }
17222
17223    fn take_rename(
17224        &mut self,
17225        moving_cursor: bool,
17226        window: &mut Window,
17227        cx: &mut Context<Self>,
17228    ) -> Option<RenameState> {
17229        let rename = self.pending_rename.take()?;
17230        if rename.editor.focus_handle(cx).is_focused(window) {
17231            window.focus(&self.focus_handle);
17232        }
17233
17234        self.remove_blocks(
17235            [rename.block_id].into_iter().collect(),
17236            Some(Autoscroll::fit()),
17237            cx,
17238        );
17239        self.clear_highlights::<Rename>(cx);
17240        self.show_local_selections = true;
17241
17242        if moving_cursor {
17243            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17244                editor.selections.newest::<usize>(cx).head()
17245            });
17246
17247            // Update the selection to match the position of the selection inside
17248            // the rename editor.
17249            let snapshot = self.buffer.read(cx).read(cx);
17250            let rename_range = rename.range.to_offset(&snapshot);
17251            let cursor_in_editor = snapshot
17252                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17253                .min(rename_range.end);
17254            drop(snapshot);
17255
17256            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17257                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17258            });
17259        } else {
17260            self.refresh_document_highlights(cx);
17261        }
17262
17263        Some(rename)
17264    }
17265
17266    pub fn pending_rename(&self) -> Option<&RenameState> {
17267        self.pending_rename.as_ref()
17268    }
17269
17270    fn format(
17271        &mut self,
17272        _: &Format,
17273        window: &mut Window,
17274        cx: &mut Context<Self>,
17275    ) -> Option<Task<Result<()>>> {
17276        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17277
17278        let project = match &self.project {
17279            Some(project) => project.clone(),
17280            None => return None,
17281        };
17282
17283        Some(self.perform_format(
17284            project,
17285            FormatTrigger::Manual,
17286            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17287            window,
17288            cx,
17289        ))
17290    }
17291
17292    fn format_selections(
17293        &mut self,
17294        _: &FormatSelections,
17295        window: &mut Window,
17296        cx: &mut Context<Self>,
17297    ) -> Option<Task<Result<()>>> {
17298        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17299
17300        let project = match &self.project {
17301            Some(project) => project.clone(),
17302            None => return None,
17303        };
17304
17305        let ranges = self
17306            .selections
17307            .all_adjusted(cx)
17308            .into_iter()
17309            .map(|selection| selection.range())
17310            .collect_vec();
17311
17312        Some(self.perform_format(
17313            project,
17314            FormatTrigger::Manual,
17315            FormatTarget::Ranges(ranges),
17316            window,
17317            cx,
17318        ))
17319    }
17320
17321    fn perform_format(
17322        &mut self,
17323        project: Entity<Project>,
17324        trigger: FormatTrigger,
17325        target: FormatTarget,
17326        window: &mut Window,
17327        cx: &mut Context<Self>,
17328    ) -> Task<Result<()>> {
17329        let buffer = self.buffer.clone();
17330        let (buffers, target) = match target {
17331            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17332            FormatTarget::Ranges(selection_ranges) => {
17333                let multi_buffer = buffer.read(cx);
17334                let snapshot = multi_buffer.read(cx);
17335                let mut buffers = HashSet::default();
17336                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17337                    BTreeMap::new();
17338                for selection_range in selection_ranges {
17339                    for (buffer, buffer_range, _) in
17340                        snapshot.range_to_buffer_ranges(selection_range)
17341                    {
17342                        let buffer_id = buffer.remote_id();
17343                        let start = buffer.anchor_before(buffer_range.start);
17344                        let end = buffer.anchor_after(buffer_range.end);
17345                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17346                        buffer_id_to_ranges
17347                            .entry(buffer_id)
17348                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17349                            .or_insert_with(|| vec![start..end]);
17350                    }
17351                }
17352                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17353            }
17354        };
17355
17356        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17357        let selections_prev = transaction_id_prev
17358            .and_then(|transaction_id_prev| {
17359                // default to selections as they were after the last edit, if we have them,
17360                // instead of how they are now.
17361                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17362                // will take you back to where you made the last edit, instead of staying where you scrolled
17363                self.selection_history
17364                    .transaction(transaction_id_prev)
17365                    .map(|t| t.0.clone())
17366            })
17367            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17368
17369        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17370        let format = project.update(cx, |project, cx| {
17371            project.format(buffers, target, true, trigger, cx)
17372        });
17373
17374        cx.spawn_in(window, async move |editor, cx| {
17375            let transaction = futures::select_biased! {
17376                transaction = format.log_err().fuse() => transaction,
17377                () = timeout => {
17378                    log::warn!("timed out waiting for formatting");
17379                    None
17380                }
17381            };
17382
17383            buffer
17384                .update(cx, |buffer, cx| {
17385                    if let Some(transaction) = transaction
17386                        && !buffer.is_singleton()
17387                    {
17388                        buffer.push_transaction(&transaction.0, cx);
17389                    }
17390                    cx.notify();
17391                })
17392                .ok();
17393
17394            if let Some(transaction_id_now) =
17395                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17396            {
17397                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17398                if has_new_transaction {
17399                    _ = editor.update(cx, |editor, _| {
17400                        editor
17401                            .selection_history
17402                            .insert_transaction(transaction_id_now, selections_prev);
17403                    });
17404                }
17405            }
17406
17407            Ok(())
17408        })
17409    }
17410
17411    fn organize_imports(
17412        &mut self,
17413        _: &OrganizeImports,
17414        window: &mut Window,
17415        cx: &mut Context<Self>,
17416    ) -> Option<Task<Result<()>>> {
17417        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17418        let project = match &self.project {
17419            Some(project) => project.clone(),
17420            None => return None,
17421        };
17422        Some(self.perform_code_action_kind(
17423            project,
17424            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17425            window,
17426            cx,
17427        ))
17428    }
17429
17430    fn perform_code_action_kind(
17431        &mut self,
17432        project: Entity<Project>,
17433        kind: CodeActionKind,
17434        window: &mut Window,
17435        cx: &mut Context<Self>,
17436    ) -> Task<Result<()>> {
17437        let buffer = self.buffer.clone();
17438        let buffers = buffer.read(cx).all_buffers();
17439        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17440        let apply_action = project.update(cx, |project, cx| {
17441            project.apply_code_action_kind(buffers, kind, true, cx)
17442        });
17443        cx.spawn_in(window, async move |_, cx| {
17444            let transaction = futures::select_biased! {
17445                () = timeout => {
17446                    log::warn!("timed out waiting for executing code action");
17447                    None
17448                }
17449                transaction = apply_action.log_err().fuse() => transaction,
17450            };
17451            buffer
17452                .update(cx, |buffer, cx| {
17453                    // check if we need this
17454                    if let Some(transaction) = transaction
17455                        && !buffer.is_singleton()
17456                    {
17457                        buffer.push_transaction(&transaction.0, cx);
17458                    }
17459                    cx.notify();
17460                })
17461                .ok();
17462            Ok(())
17463        })
17464    }
17465
17466    pub fn restart_language_server(
17467        &mut self,
17468        _: &RestartLanguageServer,
17469        _: &mut Window,
17470        cx: &mut Context<Self>,
17471    ) {
17472        if let Some(project) = self.project.clone() {
17473            self.buffer.update(cx, |multi_buffer, cx| {
17474                project.update(cx, |project, cx| {
17475                    project.restart_language_servers_for_buffers(
17476                        multi_buffer.all_buffers().into_iter().collect(),
17477                        HashSet::default(),
17478                        cx,
17479                    );
17480                });
17481            })
17482        }
17483    }
17484
17485    pub fn stop_language_server(
17486        &mut self,
17487        _: &StopLanguageServer,
17488        _: &mut Window,
17489        cx: &mut Context<Self>,
17490    ) {
17491        if let Some(project) = self.project.clone() {
17492            self.buffer.update(cx, |multi_buffer, cx| {
17493                project.update(cx, |project, cx| {
17494                    project.stop_language_servers_for_buffers(
17495                        multi_buffer.all_buffers().into_iter().collect(),
17496                        HashSet::default(),
17497                        cx,
17498                    );
17499                    cx.emit(project::Event::RefreshInlayHints);
17500                });
17501            });
17502        }
17503    }
17504
17505    fn cancel_language_server_work(
17506        workspace: &mut Workspace,
17507        _: &actions::CancelLanguageServerWork,
17508        _: &mut Window,
17509        cx: &mut Context<Workspace>,
17510    ) {
17511        let project = workspace.project();
17512        let buffers = workspace
17513            .active_item(cx)
17514            .and_then(|item| item.act_as::<Editor>(cx))
17515            .map_or(HashSet::default(), |editor| {
17516                editor.read(cx).buffer.read(cx).all_buffers()
17517            });
17518        project.update(cx, |project, cx| {
17519            project.cancel_language_server_work_for_buffers(buffers, cx);
17520        });
17521    }
17522
17523    fn show_character_palette(
17524        &mut self,
17525        _: &ShowCharacterPalette,
17526        window: &mut Window,
17527        _: &mut Context<Self>,
17528    ) {
17529        window.show_character_palette();
17530    }
17531
17532    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17533        if !self.diagnostics_enabled() {
17534            return;
17535        }
17536
17537        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17538            let buffer = self.buffer.read(cx).snapshot(cx);
17539            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17540            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17541            let is_valid = buffer
17542                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17543                .any(|entry| {
17544                    entry.diagnostic.is_primary
17545                        && !entry.range.is_empty()
17546                        && entry.range.start == primary_range_start
17547                        && entry.diagnostic.message == active_diagnostics.active_message
17548                });
17549
17550            if !is_valid {
17551                self.dismiss_diagnostics(cx);
17552            }
17553        }
17554    }
17555
17556    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17557        match &self.active_diagnostics {
17558            ActiveDiagnostic::Group(group) => Some(group),
17559            _ => None,
17560        }
17561    }
17562
17563    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17564        if !self.diagnostics_enabled() {
17565            return;
17566        }
17567        self.dismiss_diagnostics(cx);
17568        self.active_diagnostics = ActiveDiagnostic::All;
17569    }
17570
17571    fn activate_diagnostics(
17572        &mut self,
17573        buffer_id: BufferId,
17574        diagnostic: DiagnosticEntryRef<'_, usize>,
17575        window: &mut Window,
17576        cx: &mut Context<Self>,
17577    ) {
17578        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17579            return;
17580        }
17581        self.dismiss_diagnostics(cx);
17582        let snapshot = self.snapshot(window, cx);
17583        let buffer = self.buffer.read(cx).snapshot(cx);
17584        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17585            return;
17586        };
17587
17588        let diagnostic_group = buffer
17589            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17590            .collect::<Vec<_>>();
17591
17592        let blocks =
17593            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17594
17595        let blocks = self.display_map.update(cx, |display_map, cx| {
17596            display_map.insert_blocks(blocks, cx).into_iter().collect()
17597        });
17598        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17599            active_range: buffer.anchor_before(diagnostic.range.start)
17600                ..buffer.anchor_after(diagnostic.range.end),
17601            active_message: diagnostic.diagnostic.message.clone(),
17602            group_id: diagnostic.diagnostic.group_id,
17603            blocks,
17604        });
17605        cx.notify();
17606    }
17607
17608    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17609        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17610            return;
17611        };
17612
17613        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17614        if let ActiveDiagnostic::Group(group) = prev {
17615            self.display_map.update(cx, |display_map, cx| {
17616                display_map.remove_blocks(group.blocks, cx);
17617            });
17618            cx.notify();
17619        }
17620    }
17621
17622    /// Disable inline diagnostics rendering for this editor.
17623    pub fn disable_inline_diagnostics(&mut self) {
17624        self.inline_diagnostics_enabled = false;
17625        self.inline_diagnostics_update = Task::ready(());
17626        self.inline_diagnostics.clear();
17627    }
17628
17629    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17630        self.diagnostics_enabled = false;
17631        self.dismiss_diagnostics(cx);
17632        self.inline_diagnostics_update = Task::ready(());
17633        self.inline_diagnostics.clear();
17634    }
17635
17636    pub fn disable_word_completions(&mut self) {
17637        self.word_completions_enabled = false;
17638    }
17639
17640    pub fn diagnostics_enabled(&self) -> bool {
17641        self.diagnostics_enabled && self.mode.is_full()
17642    }
17643
17644    pub fn inline_diagnostics_enabled(&self) -> bool {
17645        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17646    }
17647
17648    pub fn show_inline_diagnostics(&self) -> bool {
17649        self.show_inline_diagnostics
17650    }
17651
17652    pub fn toggle_inline_diagnostics(
17653        &mut self,
17654        _: &ToggleInlineDiagnostics,
17655        window: &mut Window,
17656        cx: &mut Context<Editor>,
17657    ) {
17658        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17659        self.refresh_inline_diagnostics(false, window, cx);
17660    }
17661
17662    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17663        self.diagnostics_max_severity = severity;
17664        self.display_map.update(cx, |display_map, _| {
17665            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17666        });
17667    }
17668
17669    pub fn toggle_diagnostics(
17670        &mut self,
17671        _: &ToggleDiagnostics,
17672        window: &mut Window,
17673        cx: &mut Context<Editor>,
17674    ) {
17675        if !self.diagnostics_enabled() {
17676            return;
17677        }
17678
17679        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17680            EditorSettings::get_global(cx)
17681                .diagnostics_max_severity
17682                .filter(|severity| severity != &DiagnosticSeverity::Off)
17683                .unwrap_or(DiagnosticSeverity::Hint)
17684        } else {
17685            DiagnosticSeverity::Off
17686        };
17687        self.set_max_diagnostics_severity(new_severity, cx);
17688        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17689            self.active_diagnostics = ActiveDiagnostic::None;
17690            self.inline_diagnostics_update = Task::ready(());
17691            self.inline_diagnostics.clear();
17692        } else {
17693            self.refresh_inline_diagnostics(false, window, cx);
17694        }
17695
17696        cx.notify();
17697    }
17698
17699    pub fn toggle_minimap(
17700        &mut self,
17701        _: &ToggleMinimap,
17702        window: &mut Window,
17703        cx: &mut Context<Editor>,
17704    ) {
17705        if self.supports_minimap(cx) {
17706            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17707        }
17708    }
17709
17710    fn refresh_inline_diagnostics(
17711        &mut self,
17712        debounce: bool,
17713        window: &mut Window,
17714        cx: &mut Context<Self>,
17715    ) {
17716        let max_severity = ProjectSettings::get_global(cx)
17717            .diagnostics
17718            .inline
17719            .max_severity
17720            .unwrap_or(self.diagnostics_max_severity);
17721
17722        if !self.inline_diagnostics_enabled()
17723            || !self.show_inline_diagnostics
17724            || max_severity == DiagnosticSeverity::Off
17725        {
17726            self.inline_diagnostics_update = Task::ready(());
17727            self.inline_diagnostics.clear();
17728            return;
17729        }
17730
17731        let debounce_ms = ProjectSettings::get_global(cx)
17732            .diagnostics
17733            .inline
17734            .update_debounce_ms;
17735        let debounce = if debounce && debounce_ms > 0 {
17736            Some(Duration::from_millis(debounce_ms))
17737        } else {
17738            None
17739        };
17740        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17741            if let Some(debounce) = debounce {
17742                cx.background_executor().timer(debounce).await;
17743            }
17744            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17745                editor
17746                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17747                    .ok()
17748            }) else {
17749                return;
17750            };
17751
17752            let new_inline_diagnostics = cx
17753                .background_spawn(async move {
17754                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17755                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17756                        let message = diagnostic_entry
17757                            .diagnostic
17758                            .message
17759                            .split_once('\n')
17760                            .map(|(line, _)| line)
17761                            .map(SharedString::new)
17762                            .unwrap_or_else(|| {
17763                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17764                            });
17765                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17766                        let (Ok(i) | Err(i)) = inline_diagnostics
17767                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17768                        inline_diagnostics.insert(
17769                            i,
17770                            (
17771                                start_anchor,
17772                                InlineDiagnostic {
17773                                    message,
17774                                    group_id: diagnostic_entry.diagnostic.group_id,
17775                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17776                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17777                                    severity: diagnostic_entry.diagnostic.severity,
17778                                },
17779                            ),
17780                        );
17781                    }
17782                    inline_diagnostics
17783                })
17784                .await;
17785
17786            editor
17787                .update(cx, |editor, cx| {
17788                    editor.inline_diagnostics = new_inline_diagnostics;
17789                    cx.notify();
17790                })
17791                .ok();
17792        });
17793    }
17794
17795    fn pull_diagnostics(
17796        &mut self,
17797        buffer_id: Option<BufferId>,
17798        window: &Window,
17799        cx: &mut Context<Self>,
17800    ) -> Option<()> {
17801        if !self.mode().is_full() {
17802            return None;
17803        }
17804        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17805            .diagnostics
17806            .lsp_pull_diagnostics;
17807        if !pull_diagnostics_settings.enabled {
17808            return None;
17809        }
17810        let project = self.project()?.downgrade();
17811        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17812        let mut buffers = self.buffer.read(cx).all_buffers();
17813        if let Some(buffer_id) = buffer_id {
17814            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17815        }
17816
17817        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17818            cx.background_executor().timer(debounce).await;
17819
17820            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17821                buffers
17822                    .into_iter()
17823                    .filter_map(|buffer| {
17824                        project
17825                            .update(cx, |project, cx| {
17826                                project.lsp_store().update(cx, |lsp_store, cx| {
17827                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17828                                })
17829                            })
17830                            .ok()
17831                    })
17832                    .collect::<FuturesUnordered<_>>()
17833            }) else {
17834                return;
17835            };
17836
17837            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17838                match pull_task {
17839                    Ok(()) => {
17840                        if editor
17841                            .update_in(cx, |editor, window, cx| {
17842                                editor.update_diagnostics_state(window, cx);
17843                            })
17844                            .is_err()
17845                        {
17846                            return;
17847                        }
17848                    }
17849                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17850                }
17851            }
17852        });
17853
17854        Some(())
17855    }
17856
17857    pub fn set_selections_from_remote(
17858        &mut self,
17859        selections: Vec<Selection<Anchor>>,
17860        pending_selection: Option<Selection<Anchor>>,
17861        window: &mut Window,
17862        cx: &mut Context<Self>,
17863    ) {
17864        let old_cursor_position = self.selections.newest_anchor().head();
17865        self.selections.change_with(cx, |s| {
17866            s.select_anchors(selections);
17867            if let Some(pending_selection) = pending_selection {
17868                s.set_pending(pending_selection, SelectMode::Character);
17869            } else {
17870                s.clear_pending();
17871            }
17872        });
17873        self.selections_did_change(
17874            false,
17875            &old_cursor_position,
17876            SelectionEffects::default(),
17877            window,
17878            cx,
17879        );
17880    }
17881
17882    pub fn transact(
17883        &mut self,
17884        window: &mut Window,
17885        cx: &mut Context<Self>,
17886        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17887    ) -> Option<TransactionId> {
17888        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17889            this.start_transaction_at(Instant::now(), window, cx);
17890            update(this, window, cx);
17891            this.end_transaction_at(Instant::now(), cx)
17892        })
17893    }
17894
17895    pub fn start_transaction_at(
17896        &mut self,
17897        now: Instant,
17898        window: &mut Window,
17899        cx: &mut Context<Self>,
17900    ) -> Option<TransactionId> {
17901        self.end_selection(window, cx);
17902        if let Some(tx_id) = self
17903            .buffer
17904            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17905        {
17906            self.selection_history
17907                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17908            cx.emit(EditorEvent::TransactionBegun {
17909                transaction_id: tx_id,
17910            });
17911            Some(tx_id)
17912        } else {
17913            None
17914        }
17915    }
17916
17917    pub fn end_transaction_at(
17918        &mut self,
17919        now: Instant,
17920        cx: &mut Context<Self>,
17921    ) -> Option<TransactionId> {
17922        if let Some(transaction_id) = self
17923            .buffer
17924            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17925        {
17926            if let Some((_, end_selections)) =
17927                self.selection_history.transaction_mut(transaction_id)
17928            {
17929                *end_selections = Some(self.selections.disjoint_anchors_arc());
17930            } else {
17931                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17932            }
17933
17934            cx.emit(EditorEvent::Edited { transaction_id });
17935            Some(transaction_id)
17936        } else {
17937            None
17938        }
17939    }
17940
17941    pub fn modify_transaction_selection_history(
17942        &mut self,
17943        transaction_id: TransactionId,
17944        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17945    ) -> bool {
17946        self.selection_history
17947            .transaction_mut(transaction_id)
17948            .map(modify)
17949            .is_some()
17950    }
17951
17952    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17953        if self.selection_mark_mode {
17954            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17955                s.move_with(|_, sel| {
17956                    sel.collapse_to(sel.head(), SelectionGoal::None);
17957                });
17958            })
17959        }
17960        self.selection_mark_mode = true;
17961        cx.notify();
17962    }
17963
17964    pub fn swap_selection_ends(
17965        &mut self,
17966        _: &actions::SwapSelectionEnds,
17967        window: &mut Window,
17968        cx: &mut Context<Self>,
17969    ) {
17970        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17971            s.move_with(|_, sel| {
17972                if sel.start != sel.end {
17973                    sel.reversed = !sel.reversed
17974                }
17975            });
17976        });
17977        self.request_autoscroll(Autoscroll::newest(), cx);
17978        cx.notify();
17979    }
17980
17981    pub fn toggle_focus(
17982        workspace: &mut Workspace,
17983        _: &actions::ToggleFocus,
17984        window: &mut Window,
17985        cx: &mut Context<Workspace>,
17986    ) {
17987        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17988            return;
17989        };
17990        workspace.activate_item(&item, true, true, window, cx);
17991    }
17992
17993    pub fn toggle_fold(
17994        &mut self,
17995        _: &actions::ToggleFold,
17996        window: &mut Window,
17997        cx: &mut Context<Self>,
17998    ) {
17999        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18000            let selection = self.selections.newest::<Point>(cx);
18001
18002            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18003            let range = if selection.is_empty() {
18004                let point = selection.head().to_display_point(&display_map);
18005                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18006                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18007                    .to_point(&display_map);
18008                start..end
18009            } else {
18010                selection.range()
18011            };
18012            if display_map.folds_in_range(range).next().is_some() {
18013                self.unfold_lines(&Default::default(), window, cx)
18014            } else {
18015                self.fold(&Default::default(), window, cx)
18016            }
18017        } else {
18018            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18019            let buffer_ids: HashSet<_> = self
18020                .selections
18021                .disjoint_anchor_ranges()
18022                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18023                .collect();
18024
18025            let should_unfold = buffer_ids
18026                .iter()
18027                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18028
18029            for buffer_id in buffer_ids {
18030                if should_unfold {
18031                    self.unfold_buffer(buffer_id, cx);
18032                } else {
18033                    self.fold_buffer(buffer_id, cx);
18034                }
18035            }
18036        }
18037    }
18038
18039    pub fn toggle_fold_recursive(
18040        &mut self,
18041        _: &actions::ToggleFoldRecursive,
18042        window: &mut Window,
18043        cx: &mut Context<Self>,
18044    ) {
18045        let selection = self.selections.newest::<Point>(cx);
18046
18047        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18048        let range = if selection.is_empty() {
18049            let point = selection.head().to_display_point(&display_map);
18050            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18051            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18052                .to_point(&display_map);
18053            start..end
18054        } else {
18055            selection.range()
18056        };
18057        if display_map.folds_in_range(range).next().is_some() {
18058            self.unfold_recursive(&Default::default(), window, cx)
18059        } else {
18060            self.fold_recursive(&Default::default(), window, cx)
18061        }
18062    }
18063
18064    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18065        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18066            let mut to_fold = Vec::new();
18067            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18068            let selections = self.selections.all_adjusted(cx);
18069
18070            for selection in selections {
18071                let range = selection.range().sorted();
18072                let buffer_start_row = range.start.row;
18073
18074                if range.start.row != range.end.row {
18075                    let mut found = false;
18076                    let mut row = range.start.row;
18077                    while row <= range.end.row {
18078                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18079                        {
18080                            found = true;
18081                            row = crease.range().end.row + 1;
18082                            to_fold.push(crease);
18083                        } else {
18084                            row += 1
18085                        }
18086                    }
18087                    if found {
18088                        continue;
18089                    }
18090                }
18091
18092                for row in (0..=range.start.row).rev() {
18093                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18094                        && crease.range().end.row >= buffer_start_row
18095                    {
18096                        to_fold.push(crease);
18097                        if row <= range.start.row {
18098                            break;
18099                        }
18100                    }
18101                }
18102            }
18103
18104            self.fold_creases(to_fold, true, window, cx);
18105        } else {
18106            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18107            let buffer_ids = self
18108                .selections
18109                .disjoint_anchor_ranges()
18110                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18111                .collect::<HashSet<_>>();
18112            for buffer_id in buffer_ids {
18113                self.fold_buffer(buffer_id, cx);
18114            }
18115        }
18116    }
18117
18118    pub fn toggle_fold_all(
18119        &mut self,
18120        _: &actions::ToggleFoldAll,
18121        window: &mut Window,
18122        cx: &mut Context<Self>,
18123    ) {
18124        if self.buffer.read(cx).is_singleton() {
18125            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18126            let has_folds = display_map
18127                .folds_in_range(0..display_map.buffer_snapshot().len())
18128                .next()
18129                .is_some();
18130
18131            if has_folds {
18132                self.unfold_all(&actions::UnfoldAll, window, cx);
18133            } else {
18134                self.fold_all(&actions::FoldAll, window, cx);
18135            }
18136        } else {
18137            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18138            let should_unfold = buffer_ids
18139                .iter()
18140                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18141
18142            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18143                editor
18144                    .update_in(cx, |editor, _, cx| {
18145                        for buffer_id in buffer_ids {
18146                            if should_unfold {
18147                                editor.unfold_buffer(buffer_id, cx);
18148                            } else {
18149                                editor.fold_buffer(buffer_id, cx);
18150                            }
18151                        }
18152                    })
18153                    .ok();
18154            });
18155        }
18156    }
18157
18158    fn fold_at_level(
18159        &mut self,
18160        fold_at: &FoldAtLevel,
18161        window: &mut Window,
18162        cx: &mut Context<Self>,
18163    ) {
18164        if !self.buffer.read(cx).is_singleton() {
18165            return;
18166        }
18167
18168        let fold_at_level = fold_at.0;
18169        let snapshot = self.buffer.read(cx).snapshot(cx);
18170        let mut to_fold = Vec::new();
18171        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18172
18173        let row_ranges_to_keep: Vec<Range<u32>> = self
18174            .selections
18175            .all::<Point>(cx)
18176            .into_iter()
18177            .map(|sel| sel.start.row..sel.end.row)
18178            .collect();
18179
18180        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18181            while start_row < end_row {
18182                match self
18183                    .snapshot(window, cx)
18184                    .crease_for_buffer_row(MultiBufferRow(start_row))
18185                {
18186                    Some(crease) => {
18187                        let nested_start_row = crease.range().start.row + 1;
18188                        let nested_end_row = crease.range().end.row;
18189
18190                        if current_level < fold_at_level {
18191                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18192                        } else if current_level == fold_at_level {
18193                            // Fold iff there is no selection completely contained within the fold region
18194                            if !row_ranges_to_keep.iter().any(|selection| {
18195                                selection.end >= nested_start_row
18196                                    && selection.start <= nested_end_row
18197                            }) {
18198                                to_fold.push(crease);
18199                            }
18200                        }
18201
18202                        start_row = nested_end_row + 1;
18203                    }
18204                    None => start_row += 1,
18205                }
18206            }
18207        }
18208
18209        self.fold_creases(to_fold, true, window, cx);
18210    }
18211
18212    pub fn fold_at_level_1(
18213        &mut self,
18214        _: &actions::FoldAtLevel1,
18215        window: &mut Window,
18216        cx: &mut Context<Self>,
18217    ) {
18218        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18219    }
18220
18221    pub fn fold_at_level_2(
18222        &mut self,
18223        _: &actions::FoldAtLevel2,
18224        window: &mut Window,
18225        cx: &mut Context<Self>,
18226    ) {
18227        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18228    }
18229
18230    pub fn fold_at_level_3(
18231        &mut self,
18232        _: &actions::FoldAtLevel3,
18233        window: &mut Window,
18234        cx: &mut Context<Self>,
18235    ) {
18236        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18237    }
18238
18239    pub fn fold_at_level_4(
18240        &mut self,
18241        _: &actions::FoldAtLevel4,
18242        window: &mut Window,
18243        cx: &mut Context<Self>,
18244    ) {
18245        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18246    }
18247
18248    pub fn fold_at_level_5(
18249        &mut self,
18250        _: &actions::FoldAtLevel5,
18251        window: &mut Window,
18252        cx: &mut Context<Self>,
18253    ) {
18254        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18255    }
18256
18257    pub fn fold_at_level_6(
18258        &mut self,
18259        _: &actions::FoldAtLevel6,
18260        window: &mut Window,
18261        cx: &mut Context<Self>,
18262    ) {
18263        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18264    }
18265
18266    pub fn fold_at_level_7(
18267        &mut self,
18268        _: &actions::FoldAtLevel7,
18269        window: &mut Window,
18270        cx: &mut Context<Self>,
18271    ) {
18272        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18273    }
18274
18275    pub fn fold_at_level_8(
18276        &mut self,
18277        _: &actions::FoldAtLevel8,
18278        window: &mut Window,
18279        cx: &mut Context<Self>,
18280    ) {
18281        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18282    }
18283
18284    pub fn fold_at_level_9(
18285        &mut self,
18286        _: &actions::FoldAtLevel9,
18287        window: &mut Window,
18288        cx: &mut Context<Self>,
18289    ) {
18290        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18291    }
18292
18293    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18294        if self.buffer.read(cx).is_singleton() {
18295            let mut fold_ranges = Vec::new();
18296            let snapshot = self.buffer.read(cx).snapshot(cx);
18297
18298            for row in 0..snapshot.max_row().0 {
18299                if let Some(foldable_range) = self
18300                    .snapshot(window, cx)
18301                    .crease_for_buffer_row(MultiBufferRow(row))
18302                {
18303                    fold_ranges.push(foldable_range);
18304                }
18305            }
18306
18307            self.fold_creases(fold_ranges, true, window, cx);
18308        } else {
18309            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18310                editor
18311                    .update_in(cx, |editor, _, cx| {
18312                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18313                            editor.fold_buffer(buffer_id, cx);
18314                        }
18315                    })
18316                    .ok();
18317            });
18318        }
18319    }
18320
18321    pub fn fold_function_bodies(
18322        &mut self,
18323        _: &actions::FoldFunctionBodies,
18324        window: &mut Window,
18325        cx: &mut Context<Self>,
18326    ) {
18327        let snapshot = self.buffer.read(cx).snapshot(cx);
18328
18329        let ranges = snapshot
18330            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18331            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18332            .collect::<Vec<_>>();
18333
18334        let creases = ranges
18335            .into_iter()
18336            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18337            .collect();
18338
18339        self.fold_creases(creases, true, window, cx);
18340    }
18341
18342    pub fn fold_recursive(
18343        &mut self,
18344        _: &actions::FoldRecursive,
18345        window: &mut Window,
18346        cx: &mut Context<Self>,
18347    ) {
18348        let mut to_fold = Vec::new();
18349        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18350        let selections = self.selections.all_adjusted(cx);
18351
18352        for selection in selections {
18353            let range = selection.range().sorted();
18354            let buffer_start_row = range.start.row;
18355
18356            if range.start.row != range.end.row {
18357                let mut found = false;
18358                for row in range.start.row..=range.end.row {
18359                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18360                        found = true;
18361                        to_fold.push(crease);
18362                    }
18363                }
18364                if found {
18365                    continue;
18366                }
18367            }
18368
18369            for row in (0..=range.start.row).rev() {
18370                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18371                    if crease.range().end.row >= buffer_start_row {
18372                        to_fold.push(crease);
18373                    } else {
18374                        break;
18375                    }
18376                }
18377            }
18378        }
18379
18380        self.fold_creases(to_fold, true, window, cx);
18381    }
18382
18383    pub fn fold_at(
18384        &mut self,
18385        buffer_row: MultiBufferRow,
18386        window: &mut Window,
18387        cx: &mut Context<Self>,
18388    ) {
18389        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18390
18391        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18392            let autoscroll = self
18393                .selections
18394                .all::<Point>(cx)
18395                .iter()
18396                .any(|selection| crease.range().overlaps(&selection.range()));
18397
18398            self.fold_creases(vec![crease], autoscroll, window, cx);
18399        }
18400    }
18401
18402    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18403        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18404            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18405            let buffer = display_map.buffer_snapshot();
18406            let selections = self.selections.all::<Point>(cx);
18407            let ranges = selections
18408                .iter()
18409                .map(|s| {
18410                    let range = s.display_range(&display_map).sorted();
18411                    let mut start = range.start.to_point(&display_map);
18412                    let mut end = range.end.to_point(&display_map);
18413                    start.column = 0;
18414                    end.column = buffer.line_len(MultiBufferRow(end.row));
18415                    start..end
18416                })
18417                .collect::<Vec<_>>();
18418
18419            self.unfold_ranges(&ranges, true, true, cx);
18420        } else {
18421            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18422            let buffer_ids = self
18423                .selections
18424                .disjoint_anchor_ranges()
18425                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18426                .collect::<HashSet<_>>();
18427            for buffer_id in buffer_ids {
18428                self.unfold_buffer(buffer_id, cx);
18429            }
18430        }
18431    }
18432
18433    pub fn unfold_recursive(
18434        &mut self,
18435        _: &UnfoldRecursive,
18436        _window: &mut Window,
18437        cx: &mut Context<Self>,
18438    ) {
18439        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18440        let selections = self.selections.all::<Point>(cx);
18441        let ranges = selections
18442            .iter()
18443            .map(|s| {
18444                let mut range = s.display_range(&display_map).sorted();
18445                *range.start.column_mut() = 0;
18446                *range.end.column_mut() = display_map.line_len(range.end.row());
18447                let start = range.start.to_point(&display_map);
18448                let end = range.end.to_point(&display_map);
18449                start..end
18450            })
18451            .collect::<Vec<_>>();
18452
18453        self.unfold_ranges(&ranges, true, true, cx);
18454    }
18455
18456    pub fn unfold_at(
18457        &mut self,
18458        buffer_row: MultiBufferRow,
18459        _window: &mut Window,
18460        cx: &mut Context<Self>,
18461    ) {
18462        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18463
18464        let intersection_range = Point::new(buffer_row.0, 0)
18465            ..Point::new(
18466                buffer_row.0,
18467                display_map.buffer_snapshot().line_len(buffer_row),
18468            );
18469
18470        let autoscroll = self
18471            .selections
18472            .all::<Point>(cx)
18473            .iter()
18474            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18475
18476        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18477    }
18478
18479    pub fn unfold_all(
18480        &mut self,
18481        _: &actions::UnfoldAll,
18482        _window: &mut Window,
18483        cx: &mut Context<Self>,
18484    ) {
18485        if self.buffer.read(cx).is_singleton() {
18486            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18487            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18488        } else {
18489            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18490                editor
18491                    .update(cx, |editor, cx| {
18492                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18493                            editor.unfold_buffer(buffer_id, cx);
18494                        }
18495                    })
18496                    .ok();
18497            });
18498        }
18499    }
18500
18501    pub fn fold_selected_ranges(
18502        &mut self,
18503        _: &FoldSelectedRanges,
18504        window: &mut Window,
18505        cx: &mut Context<Self>,
18506    ) {
18507        let selections = self.selections.all_adjusted(cx);
18508        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18509        let ranges = selections
18510            .into_iter()
18511            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18512            .collect::<Vec<_>>();
18513        self.fold_creases(ranges, true, window, cx);
18514    }
18515
18516    pub fn fold_ranges<T: ToOffset + Clone>(
18517        &mut self,
18518        ranges: Vec<Range<T>>,
18519        auto_scroll: bool,
18520        window: &mut Window,
18521        cx: &mut Context<Self>,
18522    ) {
18523        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18524        let ranges = ranges
18525            .into_iter()
18526            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18527            .collect::<Vec<_>>();
18528        self.fold_creases(ranges, auto_scroll, window, cx);
18529    }
18530
18531    pub fn fold_creases<T: ToOffset + Clone>(
18532        &mut self,
18533        creases: Vec<Crease<T>>,
18534        auto_scroll: bool,
18535        _window: &mut Window,
18536        cx: &mut Context<Self>,
18537    ) {
18538        if creases.is_empty() {
18539            return;
18540        }
18541
18542        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18543
18544        if auto_scroll {
18545            self.request_autoscroll(Autoscroll::fit(), cx);
18546        }
18547
18548        cx.notify();
18549
18550        self.scrollbar_marker_state.dirty = true;
18551        self.folds_did_change(cx);
18552    }
18553
18554    /// Removes any folds whose ranges intersect any of the given ranges.
18555    pub fn unfold_ranges<T: ToOffset + Clone>(
18556        &mut self,
18557        ranges: &[Range<T>],
18558        inclusive: bool,
18559        auto_scroll: bool,
18560        cx: &mut Context<Self>,
18561    ) {
18562        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18563            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18564        });
18565        self.folds_did_change(cx);
18566    }
18567
18568    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18569        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18570            return;
18571        }
18572        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18573        self.display_map.update(cx, |display_map, cx| {
18574            display_map.fold_buffers([buffer_id], cx)
18575        });
18576        cx.emit(EditorEvent::BufferFoldToggled {
18577            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18578            folded: true,
18579        });
18580        cx.notify();
18581    }
18582
18583    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18584        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18585            return;
18586        }
18587        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18588        self.display_map.update(cx, |display_map, cx| {
18589            display_map.unfold_buffers([buffer_id], cx);
18590        });
18591        cx.emit(EditorEvent::BufferFoldToggled {
18592            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18593            folded: false,
18594        });
18595        cx.notify();
18596    }
18597
18598    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18599        self.display_map.read(cx).is_buffer_folded(buffer)
18600    }
18601
18602    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18603        self.display_map.read(cx).folded_buffers()
18604    }
18605
18606    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18607        self.display_map.update(cx, |display_map, cx| {
18608            display_map.disable_header_for_buffer(buffer_id, cx);
18609        });
18610        cx.notify();
18611    }
18612
18613    /// Removes any folds with the given ranges.
18614    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18615        &mut self,
18616        ranges: &[Range<T>],
18617        type_id: TypeId,
18618        auto_scroll: bool,
18619        cx: &mut Context<Self>,
18620    ) {
18621        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18622            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18623        });
18624        self.folds_did_change(cx);
18625    }
18626
18627    fn remove_folds_with<T: ToOffset + Clone>(
18628        &mut self,
18629        ranges: &[Range<T>],
18630        auto_scroll: bool,
18631        cx: &mut Context<Self>,
18632        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18633    ) {
18634        if ranges.is_empty() {
18635            return;
18636        }
18637
18638        let mut buffers_affected = HashSet::default();
18639        let multi_buffer = self.buffer().read(cx);
18640        for range in ranges {
18641            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18642                buffers_affected.insert(buffer.read(cx).remote_id());
18643            };
18644        }
18645
18646        self.display_map.update(cx, update);
18647
18648        if auto_scroll {
18649            self.request_autoscroll(Autoscroll::fit(), cx);
18650        }
18651
18652        cx.notify();
18653        self.scrollbar_marker_state.dirty = true;
18654        self.active_indent_guides_state.dirty = true;
18655    }
18656
18657    pub fn update_renderer_widths(
18658        &mut self,
18659        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18660        cx: &mut Context<Self>,
18661    ) -> bool {
18662        self.display_map
18663            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18664    }
18665
18666    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18667        self.display_map.read(cx).fold_placeholder.clone()
18668    }
18669
18670    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18671        self.buffer.update(cx, |buffer, cx| {
18672            buffer.set_all_diff_hunks_expanded(cx);
18673        });
18674    }
18675
18676    pub fn expand_all_diff_hunks(
18677        &mut self,
18678        _: &ExpandAllDiffHunks,
18679        _window: &mut Window,
18680        cx: &mut Context<Self>,
18681    ) {
18682        self.buffer.update(cx, |buffer, cx| {
18683            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18684        });
18685    }
18686
18687    pub fn toggle_selected_diff_hunks(
18688        &mut self,
18689        _: &ToggleSelectedDiffHunks,
18690        _window: &mut Window,
18691        cx: &mut Context<Self>,
18692    ) {
18693        let ranges: Vec<_> = self
18694            .selections
18695            .disjoint_anchors()
18696            .iter()
18697            .map(|s| s.range())
18698            .collect();
18699        self.toggle_diff_hunks_in_ranges(ranges, cx);
18700    }
18701
18702    pub fn diff_hunks_in_ranges<'a>(
18703        &'a self,
18704        ranges: &'a [Range<Anchor>],
18705        buffer: &'a MultiBufferSnapshot,
18706    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18707        ranges.iter().flat_map(move |range| {
18708            let end_excerpt_id = range.end.excerpt_id;
18709            let range = range.to_point(buffer);
18710            let mut peek_end = range.end;
18711            if range.end.row < buffer.max_row().0 {
18712                peek_end = Point::new(range.end.row + 1, 0);
18713            }
18714            buffer
18715                .diff_hunks_in_range(range.start..peek_end)
18716                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18717        })
18718    }
18719
18720    pub fn has_stageable_diff_hunks_in_ranges(
18721        &self,
18722        ranges: &[Range<Anchor>],
18723        snapshot: &MultiBufferSnapshot,
18724    ) -> bool {
18725        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18726        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18727    }
18728
18729    pub fn toggle_staged_selected_diff_hunks(
18730        &mut self,
18731        _: &::git::ToggleStaged,
18732        _: &mut Window,
18733        cx: &mut Context<Self>,
18734    ) {
18735        let snapshot = self.buffer.read(cx).snapshot(cx);
18736        let ranges: Vec<_> = self
18737            .selections
18738            .disjoint_anchors()
18739            .iter()
18740            .map(|s| s.range())
18741            .collect();
18742        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18743        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18744    }
18745
18746    pub fn set_render_diff_hunk_controls(
18747        &mut self,
18748        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18749        cx: &mut Context<Self>,
18750    ) {
18751        self.render_diff_hunk_controls = render_diff_hunk_controls;
18752        cx.notify();
18753    }
18754
18755    pub fn stage_and_next(
18756        &mut self,
18757        _: &::git::StageAndNext,
18758        window: &mut Window,
18759        cx: &mut Context<Self>,
18760    ) {
18761        self.do_stage_or_unstage_and_next(true, window, cx);
18762    }
18763
18764    pub fn unstage_and_next(
18765        &mut self,
18766        _: &::git::UnstageAndNext,
18767        window: &mut Window,
18768        cx: &mut Context<Self>,
18769    ) {
18770        self.do_stage_or_unstage_and_next(false, window, cx);
18771    }
18772
18773    pub fn stage_or_unstage_diff_hunks(
18774        &mut self,
18775        stage: bool,
18776        ranges: Vec<Range<Anchor>>,
18777        cx: &mut Context<Self>,
18778    ) {
18779        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18780        cx.spawn(async move |this, cx| {
18781            task.await?;
18782            this.update(cx, |this, cx| {
18783                let snapshot = this.buffer.read(cx).snapshot(cx);
18784                let chunk_by = this
18785                    .diff_hunks_in_ranges(&ranges, &snapshot)
18786                    .chunk_by(|hunk| hunk.buffer_id);
18787                for (buffer_id, hunks) in &chunk_by {
18788                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18789                }
18790            })
18791        })
18792        .detach_and_log_err(cx);
18793    }
18794
18795    fn save_buffers_for_ranges_if_needed(
18796        &mut self,
18797        ranges: &[Range<Anchor>],
18798        cx: &mut Context<Editor>,
18799    ) -> Task<Result<()>> {
18800        let multibuffer = self.buffer.read(cx);
18801        let snapshot = multibuffer.read(cx);
18802        let buffer_ids: HashSet<_> = ranges
18803            .iter()
18804            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18805            .collect();
18806        drop(snapshot);
18807
18808        let mut buffers = HashSet::default();
18809        for buffer_id in buffer_ids {
18810            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18811                let buffer = buffer_entity.read(cx);
18812                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18813                {
18814                    buffers.insert(buffer_entity);
18815                }
18816            }
18817        }
18818
18819        if let Some(project) = &self.project {
18820            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18821        } else {
18822            Task::ready(Ok(()))
18823        }
18824    }
18825
18826    fn do_stage_or_unstage_and_next(
18827        &mut self,
18828        stage: bool,
18829        window: &mut Window,
18830        cx: &mut Context<Self>,
18831    ) {
18832        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18833
18834        if ranges.iter().any(|range| range.start != range.end) {
18835            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18836            return;
18837        }
18838
18839        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18840        let snapshot = self.snapshot(window, cx);
18841        let position = self.selections.newest::<Point>(cx).head();
18842        let mut row = snapshot
18843            .buffer_snapshot()
18844            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18845            .find(|hunk| hunk.row_range.start.0 > position.row)
18846            .map(|hunk| hunk.row_range.start);
18847
18848        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18849        // Outside of the project diff editor, wrap around to the beginning.
18850        if !all_diff_hunks_expanded {
18851            row = row.or_else(|| {
18852                snapshot
18853                    .buffer_snapshot()
18854                    .diff_hunks_in_range(Point::zero()..position)
18855                    .find(|hunk| hunk.row_range.end.0 < position.row)
18856                    .map(|hunk| hunk.row_range.start)
18857            });
18858        }
18859
18860        if let Some(row) = row {
18861            let destination = Point::new(row.0, 0);
18862            let autoscroll = Autoscroll::center();
18863
18864            self.unfold_ranges(&[destination..destination], false, false, cx);
18865            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18866                s.select_ranges([destination..destination]);
18867            });
18868        }
18869    }
18870
18871    fn do_stage_or_unstage(
18872        &self,
18873        stage: bool,
18874        buffer_id: BufferId,
18875        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18876        cx: &mut App,
18877    ) -> Option<()> {
18878        let project = self.project()?;
18879        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18880        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18881        let buffer_snapshot = buffer.read(cx).snapshot();
18882        let file_exists = buffer_snapshot
18883            .file()
18884            .is_some_and(|file| file.disk_state().exists());
18885        diff.update(cx, |diff, cx| {
18886            diff.stage_or_unstage_hunks(
18887                stage,
18888                &hunks
18889                    .map(|hunk| buffer_diff::DiffHunk {
18890                        buffer_range: hunk.buffer_range,
18891                        diff_base_byte_range: hunk.diff_base_byte_range,
18892                        secondary_status: hunk.secondary_status,
18893                        range: Point::zero()..Point::zero(), // unused
18894                    })
18895                    .collect::<Vec<_>>(),
18896                &buffer_snapshot,
18897                file_exists,
18898                cx,
18899            )
18900        });
18901        None
18902    }
18903
18904    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18905        let ranges: Vec<_> = self
18906            .selections
18907            .disjoint_anchors()
18908            .iter()
18909            .map(|s| s.range())
18910            .collect();
18911        self.buffer
18912            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18913    }
18914
18915    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18916        self.buffer.update(cx, |buffer, cx| {
18917            let ranges = vec![Anchor::min()..Anchor::max()];
18918            if !buffer.all_diff_hunks_expanded()
18919                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18920            {
18921                buffer.collapse_diff_hunks(ranges, cx);
18922                true
18923            } else {
18924                false
18925            }
18926        })
18927    }
18928
18929    fn toggle_diff_hunks_in_ranges(
18930        &mut self,
18931        ranges: Vec<Range<Anchor>>,
18932        cx: &mut Context<Editor>,
18933    ) {
18934        self.buffer.update(cx, |buffer, cx| {
18935            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18936            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18937        })
18938    }
18939
18940    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18941        self.buffer.update(cx, |buffer, cx| {
18942            let snapshot = buffer.snapshot(cx);
18943            let excerpt_id = range.end.excerpt_id;
18944            let point_range = range.to_point(&snapshot);
18945            let expand = !buffer.single_hunk_is_expanded(range, cx);
18946            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18947        })
18948    }
18949
18950    pub(crate) fn apply_all_diff_hunks(
18951        &mut self,
18952        _: &ApplyAllDiffHunks,
18953        window: &mut Window,
18954        cx: &mut Context<Self>,
18955    ) {
18956        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18957
18958        let buffers = self.buffer.read(cx).all_buffers();
18959        for branch_buffer in buffers {
18960            branch_buffer.update(cx, |branch_buffer, cx| {
18961                branch_buffer.merge_into_base(Vec::new(), cx);
18962            });
18963        }
18964
18965        if let Some(project) = self.project.clone() {
18966            self.save(
18967                SaveOptions {
18968                    format: true,
18969                    autosave: false,
18970                },
18971                project,
18972                window,
18973                cx,
18974            )
18975            .detach_and_log_err(cx);
18976        }
18977    }
18978
18979    pub(crate) fn apply_selected_diff_hunks(
18980        &mut self,
18981        _: &ApplyDiffHunk,
18982        window: &mut Window,
18983        cx: &mut Context<Self>,
18984    ) {
18985        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18986        let snapshot = self.snapshot(window, cx);
18987        let hunks = snapshot.hunks_for_ranges(
18988            self.selections
18989                .all(cx)
18990                .into_iter()
18991                .map(|selection| selection.range()),
18992        );
18993        let mut ranges_by_buffer = HashMap::default();
18994        self.transact(window, cx, |editor, _window, cx| {
18995            for hunk in hunks {
18996                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18997                    ranges_by_buffer
18998                        .entry(buffer.clone())
18999                        .or_insert_with(Vec::new)
19000                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19001                }
19002            }
19003
19004            for (buffer, ranges) in ranges_by_buffer {
19005                buffer.update(cx, |buffer, cx| {
19006                    buffer.merge_into_base(ranges, cx);
19007                });
19008            }
19009        });
19010
19011        if let Some(project) = self.project.clone() {
19012            self.save(
19013                SaveOptions {
19014                    format: true,
19015                    autosave: false,
19016                },
19017                project,
19018                window,
19019                cx,
19020            )
19021            .detach_and_log_err(cx);
19022        }
19023    }
19024
19025    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19026        if hovered != self.gutter_hovered {
19027            self.gutter_hovered = hovered;
19028            cx.notify();
19029        }
19030    }
19031
19032    pub fn insert_blocks(
19033        &mut self,
19034        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19035        autoscroll: Option<Autoscroll>,
19036        cx: &mut Context<Self>,
19037    ) -> Vec<CustomBlockId> {
19038        let blocks = self
19039            .display_map
19040            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19041        if let Some(autoscroll) = autoscroll {
19042            self.request_autoscroll(autoscroll, cx);
19043        }
19044        cx.notify();
19045        blocks
19046    }
19047
19048    pub fn resize_blocks(
19049        &mut self,
19050        heights: HashMap<CustomBlockId, u32>,
19051        autoscroll: Option<Autoscroll>,
19052        cx: &mut Context<Self>,
19053    ) {
19054        self.display_map
19055            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19056        if let Some(autoscroll) = autoscroll {
19057            self.request_autoscroll(autoscroll, cx);
19058        }
19059        cx.notify();
19060    }
19061
19062    pub fn replace_blocks(
19063        &mut self,
19064        renderers: HashMap<CustomBlockId, RenderBlock>,
19065        autoscroll: Option<Autoscroll>,
19066        cx: &mut Context<Self>,
19067    ) {
19068        self.display_map
19069            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19070        if let Some(autoscroll) = autoscroll {
19071            self.request_autoscroll(autoscroll, cx);
19072        }
19073        cx.notify();
19074    }
19075
19076    pub fn remove_blocks(
19077        &mut self,
19078        block_ids: HashSet<CustomBlockId>,
19079        autoscroll: Option<Autoscroll>,
19080        cx: &mut Context<Self>,
19081    ) {
19082        self.display_map.update(cx, |display_map, cx| {
19083            display_map.remove_blocks(block_ids, cx)
19084        });
19085        if let Some(autoscroll) = autoscroll {
19086            self.request_autoscroll(autoscroll, cx);
19087        }
19088        cx.notify();
19089    }
19090
19091    pub fn row_for_block(
19092        &self,
19093        block_id: CustomBlockId,
19094        cx: &mut Context<Self>,
19095    ) -> Option<DisplayRow> {
19096        self.display_map
19097            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19098    }
19099
19100    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19101        self.focused_block = Some(focused_block);
19102    }
19103
19104    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19105        self.focused_block.take()
19106    }
19107
19108    pub fn insert_creases(
19109        &mut self,
19110        creases: impl IntoIterator<Item = Crease<Anchor>>,
19111        cx: &mut Context<Self>,
19112    ) -> Vec<CreaseId> {
19113        self.display_map
19114            .update(cx, |map, cx| map.insert_creases(creases, cx))
19115    }
19116
19117    pub fn remove_creases(
19118        &mut self,
19119        ids: impl IntoIterator<Item = CreaseId>,
19120        cx: &mut Context<Self>,
19121    ) -> Vec<(CreaseId, Range<Anchor>)> {
19122        self.display_map
19123            .update(cx, |map, cx| map.remove_creases(ids, cx))
19124    }
19125
19126    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19127        self.display_map
19128            .update(cx, |map, cx| map.snapshot(cx))
19129            .longest_row()
19130    }
19131
19132    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19133        self.display_map
19134            .update(cx, |map, cx| map.snapshot(cx))
19135            .max_point()
19136    }
19137
19138    pub fn text(&self, cx: &App) -> String {
19139        self.buffer.read(cx).read(cx).text()
19140    }
19141
19142    pub fn is_empty(&self, cx: &App) -> bool {
19143        self.buffer.read(cx).read(cx).is_empty()
19144    }
19145
19146    pub fn text_option(&self, cx: &App) -> Option<String> {
19147        let text = self.text(cx);
19148        let text = text.trim();
19149
19150        if text.is_empty() {
19151            return None;
19152        }
19153
19154        Some(text.to_string())
19155    }
19156
19157    pub fn set_text(
19158        &mut self,
19159        text: impl Into<Arc<str>>,
19160        window: &mut Window,
19161        cx: &mut Context<Self>,
19162    ) {
19163        self.transact(window, cx, |this, _, cx| {
19164            this.buffer
19165                .read(cx)
19166                .as_singleton()
19167                .expect("you can only call set_text on editors for singleton buffers")
19168                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19169        });
19170    }
19171
19172    pub fn display_text(&self, cx: &mut App) -> String {
19173        self.display_map
19174            .update(cx, |map, cx| map.snapshot(cx))
19175            .text()
19176    }
19177
19178    fn create_minimap(
19179        &self,
19180        minimap_settings: MinimapSettings,
19181        window: &mut Window,
19182        cx: &mut Context<Self>,
19183    ) -> Option<Entity<Self>> {
19184        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19185            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19186    }
19187
19188    fn initialize_new_minimap(
19189        &self,
19190        minimap_settings: MinimapSettings,
19191        window: &mut Window,
19192        cx: &mut Context<Self>,
19193    ) -> Entity<Self> {
19194        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19195
19196        let mut minimap = Editor::new_internal(
19197            EditorMode::Minimap {
19198                parent: cx.weak_entity(),
19199            },
19200            self.buffer.clone(),
19201            None,
19202            Some(self.display_map.clone()),
19203            window,
19204            cx,
19205        );
19206        minimap.scroll_manager.clone_state(&self.scroll_manager);
19207        minimap.set_text_style_refinement(TextStyleRefinement {
19208            font_size: Some(MINIMAP_FONT_SIZE),
19209            font_weight: Some(MINIMAP_FONT_WEIGHT),
19210            ..Default::default()
19211        });
19212        minimap.update_minimap_configuration(minimap_settings, cx);
19213        cx.new(|_| minimap)
19214    }
19215
19216    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19217        let current_line_highlight = minimap_settings
19218            .current_line_highlight
19219            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19220        self.set_current_line_highlight(Some(current_line_highlight));
19221    }
19222
19223    pub fn minimap(&self) -> Option<&Entity<Self>> {
19224        self.minimap
19225            .as_ref()
19226            .filter(|_| self.minimap_visibility.visible())
19227    }
19228
19229    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19230        let mut wrap_guides = smallvec![];
19231
19232        if self.show_wrap_guides == Some(false) {
19233            return wrap_guides;
19234        }
19235
19236        let settings = self.buffer.read(cx).language_settings(cx);
19237        if settings.show_wrap_guides {
19238            match self.soft_wrap_mode(cx) {
19239                SoftWrap::Column(soft_wrap) => {
19240                    wrap_guides.push((soft_wrap as usize, true));
19241                }
19242                SoftWrap::Bounded(soft_wrap) => {
19243                    wrap_guides.push((soft_wrap as usize, true));
19244                }
19245                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19246            }
19247            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19248        }
19249
19250        wrap_guides
19251    }
19252
19253    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19254        let settings = self.buffer.read(cx).language_settings(cx);
19255        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19256        match mode {
19257            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19258                SoftWrap::None
19259            }
19260            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19261            language_settings::SoftWrap::PreferredLineLength => {
19262                SoftWrap::Column(settings.preferred_line_length)
19263            }
19264            language_settings::SoftWrap::Bounded => {
19265                SoftWrap::Bounded(settings.preferred_line_length)
19266            }
19267        }
19268    }
19269
19270    pub fn set_soft_wrap_mode(
19271        &mut self,
19272        mode: language_settings::SoftWrap,
19273
19274        cx: &mut Context<Self>,
19275    ) {
19276        self.soft_wrap_mode_override = Some(mode);
19277        cx.notify();
19278    }
19279
19280    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19281        self.hard_wrap = hard_wrap;
19282        cx.notify();
19283    }
19284
19285    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19286        self.text_style_refinement = Some(style);
19287    }
19288
19289    /// called by the Element so we know what style we were most recently rendered with.
19290    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19291        // We intentionally do not inform the display map about the minimap style
19292        // so that wrapping is not recalculated and stays consistent for the editor
19293        // and its linked minimap.
19294        if !self.mode.is_minimap() {
19295            let font = style.text.font();
19296            let font_size = style.text.font_size.to_pixels(window.rem_size());
19297            let display_map = self
19298                .placeholder_display_map
19299                .as_ref()
19300                .filter(|_| self.is_empty(cx))
19301                .unwrap_or(&self.display_map);
19302
19303            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19304        }
19305        self.style = Some(style);
19306    }
19307
19308    pub fn style(&self) -> Option<&EditorStyle> {
19309        self.style.as_ref()
19310    }
19311
19312    // Called by the element. This method is not designed to be called outside of the editor
19313    // element's layout code because it does not notify when rewrapping is computed synchronously.
19314    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19315        if self.is_empty(cx) {
19316            self.placeholder_display_map
19317                .as_ref()
19318                .map_or(false, |display_map| {
19319                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19320                })
19321        } else {
19322            self.display_map
19323                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19324        }
19325    }
19326
19327    pub fn set_soft_wrap(&mut self) {
19328        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19329    }
19330
19331    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19332        if self.soft_wrap_mode_override.is_some() {
19333            self.soft_wrap_mode_override.take();
19334        } else {
19335            let soft_wrap = match self.soft_wrap_mode(cx) {
19336                SoftWrap::GitDiff => return,
19337                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19338                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19339                    language_settings::SoftWrap::None
19340                }
19341            };
19342            self.soft_wrap_mode_override = Some(soft_wrap);
19343        }
19344        cx.notify();
19345    }
19346
19347    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19348        let Some(workspace) = self.workspace() else {
19349            return;
19350        };
19351        let fs = workspace.read(cx).app_state().fs.clone();
19352        let current_show = TabBarSettings::get_global(cx).show;
19353        update_settings_file(fs, cx, move |setting, _| {
19354            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19355        });
19356    }
19357
19358    pub fn toggle_indent_guides(
19359        &mut self,
19360        _: &ToggleIndentGuides,
19361        _: &mut Window,
19362        cx: &mut Context<Self>,
19363    ) {
19364        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19365            self.buffer
19366                .read(cx)
19367                .language_settings(cx)
19368                .indent_guides
19369                .enabled
19370        });
19371        self.show_indent_guides = Some(!currently_enabled);
19372        cx.notify();
19373    }
19374
19375    fn should_show_indent_guides(&self) -> Option<bool> {
19376        self.show_indent_guides
19377    }
19378
19379    pub fn toggle_line_numbers(
19380        &mut self,
19381        _: &ToggleLineNumbers,
19382        _: &mut Window,
19383        cx: &mut Context<Self>,
19384    ) {
19385        let mut editor_settings = EditorSettings::get_global(cx).clone();
19386        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19387        EditorSettings::override_global(editor_settings, cx);
19388    }
19389
19390    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19391        if let Some(show_line_numbers) = self.show_line_numbers {
19392            return show_line_numbers;
19393        }
19394        EditorSettings::get_global(cx).gutter.line_numbers
19395    }
19396
19397    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19398        self.use_relative_line_numbers
19399            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19400    }
19401
19402    pub fn toggle_relative_line_numbers(
19403        &mut self,
19404        _: &ToggleRelativeLineNumbers,
19405        _: &mut Window,
19406        cx: &mut Context<Self>,
19407    ) {
19408        let is_relative = self.should_use_relative_line_numbers(cx);
19409        self.set_relative_line_number(Some(!is_relative), cx)
19410    }
19411
19412    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19413        self.use_relative_line_numbers = is_relative;
19414        cx.notify();
19415    }
19416
19417    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19418        self.show_gutter = show_gutter;
19419        cx.notify();
19420    }
19421
19422    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19423        self.show_scrollbars = ScrollbarAxes {
19424            horizontal: show,
19425            vertical: show,
19426        };
19427        cx.notify();
19428    }
19429
19430    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19431        self.show_scrollbars.vertical = show;
19432        cx.notify();
19433    }
19434
19435    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19436        self.show_scrollbars.horizontal = show;
19437        cx.notify();
19438    }
19439
19440    pub fn set_minimap_visibility(
19441        &mut self,
19442        minimap_visibility: MinimapVisibility,
19443        window: &mut Window,
19444        cx: &mut Context<Self>,
19445    ) {
19446        if self.minimap_visibility != minimap_visibility {
19447            if minimap_visibility.visible() && self.minimap.is_none() {
19448                let minimap_settings = EditorSettings::get_global(cx).minimap;
19449                self.minimap =
19450                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19451            }
19452            self.minimap_visibility = minimap_visibility;
19453            cx.notify();
19454        }
19455    }
19456
19457    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19458        self.set_show_scrollbars(false, cx);
19459        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19460    }
19461
19462    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19463        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19464    }
19465
19466    /// Normally the text in full mode and auto height editors is padded on the
19467    /// left side by roughly half a character width for improved hit testing.
19468    ///
19469    /// Use this method to disable this for cases where this is not wanted (e.g.
19470    /// if you want to align the editor text with some other text above or below)
19471    /// or if you want to add this padding to single-line editors.
19472    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19473        self.offset_content = offset_content;
19474        cx.notify();
19475    }
19476
19477    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19478        self.show_line_numbers = Some(show_line_numbers);
19479        cx.notify();
19480    }
19481
19482    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19483        self.disable_expand_excerpt_buttons = true;
19484        cx.notify();
19485    }
19486
19487    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19488        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19489        cx.notify();
19490    }
19491
19492    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19493        self.show_code_actions = Some(show_code_actions);
19494        cx.notify();
19495    }
19496
19497    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19498        self.show_runnables = Some(show_runnables);
19499        cx.notify();
19500    }
19501
19502    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19503        self.show_breakpoints = Some(show_breakpoints);
19504        cx.notify();
19505    }
19506
19507    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19508        if self.display_map.read(cx).masked != masked {
19509            self.display_map.update(cx, |map, _| map.masked = masked);
19510        }
19511        cx.notify()
19512    }
19513
19514    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19515        self.show_wrap_guides = Some(show_wrap_guides);
19516        cx.notify();
19517    }
19518
19519    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19520        self.show_indent_guides = Some(show_indent_guides);
19521        cx.notify();
19522    }
19523
19524    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19525        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19526            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19527                && let Some(dir) = file.abs_path(cx).parent()
19528            {
19529                return Some(dir.to_owned());
19530            }
19531        }
19532
19533        None
19534    }
19535
19536    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19537        self.active_excerpt(cx)?
19538            .1
19539            .read(cx)
19540            .file()
19541            .and_then(|f| f.as_local())
19542    }
19543
19544    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19545        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19546            let buffer = buffer.read(cx);
19547            if let Some(project_path) = buffer.project_path(cx) {
19548                let project = self.project()?.read(cx);
19549                project.absolute_path(&project_path, cx)
19550            } else {
19551                buffer
19552                    .file()
19553                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19554            }
19555        })
19556    }
19557
19558    pub fn reveal_in_finder(
19559        &mut self,
19560        _: &RevealInFileManager,
19561        _window: &mut Window,
19562        cx: &mut Context<Self>,
19563    ) {
19564        if let Some(target) = self.target_file(cx) {
19565            cx.reveal_path(&target.abs_path(cx));
19566        }
19567    }
19568
19569    pub fn copy_path(
19570        &mut self,
19571        _: &zed_actions::workspace::CopyPath,
19572        _window: &mut Window,
19573        cx: &mut Context<Self>,
19574    ) {
19575        if let Some(path) = self.target_file_abs_path(cx)
19576            && let Some(path) = path.to_str()
19577        {
19578            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19579        } else {
19580            cx.propagate();
19581        }
19582    }
19583
19584    pub fn copy_relative_path(
19585        &mut self,
19586        _: &zed_actions::workspace::CopyRelativePath,
19587        _window: &mut Window,
19588        cx: &mut Context<Self>,
19589    ) {
19590        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19591            let project = self.project()?.read(cx);
19592            let path = buffer.read(cx).file()?.path();
19593            let path = path.display(project.path_style(cx));
19594            Some(path)
19595        }) {
19596            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19597        } else {
19598            cx.propagate();
19599        }
19600    }
19601
19602    /// Returns the project path for the editor's buffer, if any buffer is
19603    /// opened in the editor.
19604    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19605        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19606            buffer.read(cx).project_path(cx)
19607        } else {
19608            None
19609        }
19610    }
19611
19612    // Returns true if the editor handled a go-to-line request
19613    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19614        maybe!({
19615            let breakpoint_store = self.breakpoint_store.as_ref()?;
19616
19617            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19618            else {
19619                self.clear_row_highlights::<ActiveDebugLine>();
19620                return None;
19621            };
19622
19623            let position = active_stack_frame.position;
19624            let buffer_id = position.buffer_id?;
19625            let snapshot = self
19626                .project
19627                .as_ref()?
19628                .read(cx)
19629                .buffer_for_id(buffer_id, cx)?
19630                .read(cx)
19631                .snapshot();
19632
19633            let mut handled = false;
19634            for (id, ExcerptRange { context, .. }) in
19635                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19636            {
19637                if context.start.cmp(&position, &snapshot).is_ge()
19638                    || context.end.cmp(&position, &snapshot).is_lt()
19639                {
19640                    continue;
19641                }
19642                let snapshot = self.buffer.read(cx).snapshot(cx);
19643                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19644
19645                handled = true;
19646                self.clear_row_highlights::<ActiveDebugLine>();
19647
19648                self.go_to_line::<ActiveDebugLine>(
19649                    multibuffer_anchor,
19650                    Some(cx.theme().colors().editor_debugger_active_line_background),
19651                    window,
19652                    cx,
19653                );
19654
19655                cx.notify();
19656            }
19657
19658            handled.then_some(())
19659        })
19660        .is_some()
19661    }
19662
19663    pub fn copy_file_name_without_extension(
19664        &mut self,
19665        _: &CopyFileNameWithoutExtension,
19666        _: &mut Window,
19667        cx: &mut Context<Self>,
19668    ) {
19669        if let Some(file) = self.target_file(cx)
19670            && let Some(file_stem) = file.path().file_stem()
19671        {
19672            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19673        }
19674    }
19675
19676    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19677        if let Some(file) = self.target_file(cx)
19678            && let Some(name) = file.path().file_name()
19679        {
19680            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19681        }
19682    }
19683
19684    pub fn toggle_git_blame(
19685        &mut self,
19686        _: &::git::Blame,
19687        window: &mut Window,
19688        cx: &mut Context<Self>,
19689    ) {
19690        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19691
19692        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19693            self.start_git_blame(true, window, cx);
19694        }
19695
19696        cx.notify();
19697    }
19698
19699    pub fn toggle_git_blame_inline(
19700        &mut self,
19701        _: &ToggleGitBlameInline,
19702        window: &mut Window,
19703        cx: &mut Context<Self>,
19704    ) {
19705        self.toggle_git_blame_inline_internal(true, window, cx);
19706        cx.notify();
19707    }
19708
19709    pub fn open_git_blame_commit(
19710        &mut self,
19711        _: &OpenGitBlameCommit,
19712        window: &mut Window,
19713        cx: &mut Context<Self>,
19714    ) {
19715        self.open_git_blame_commit_internal(window, cx);
19716    }
19717
19718    fn open_git_blame_commit_internal(
19719        &mut self,
19720        window: &mut Window,
19721        cx: &mut Context<Self>,
19722    ) -> Option<()> {
19723        let blame = self.blame.as_ref()?;
19724        let snapshot = self.snapshot(window, cx);
19725        let cursor = self.selections.newest::<Point>(cx).head();
19726        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19727        let (_, blame_entry) = blame
19728            .update(cx, |blame, cx| {
19729                blame
19730                    .blame_for_rows(
19731                        &[RowInfo {
19732                            buffer_id: Some(buffer.remote_id()),
19733                            buffer_row: Some(point.row),
19734                            ..Default::default()
19735                        }],
19736                        cx,
19737                    )
19738                    .next()
19739            })
19740            .flatten()?;
19741        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19742        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19743        let workspace = self.workspace()?.downgrade();
19744        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19745        None
19746    }
19747
19748    pub fn git_blame_inline_enabled(&self) -> bool {
19749        self.git_blame_inline_enabled
19750    }
19751
19752    pub fn toggle_selection_menu(
19753        &mut self,
19754        _: &ToggleSelectionMenu,
19755        _: &mut Window,
19756        cx: &mut Context<Self>,
19757    ) {
19758        self.show_selection_menu = self
19759            .show_selection_menu
19760            .map(|show_selections_menu| !show_selections_menu)
19761            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19762
19763        cx.notify();
19764    }
19765
19766    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19767        self.show_selection_menu
19768            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19769    }
19770
19771    fn start_git_blame(
19772        &mut self,
19773        user_triggered: bool,
19774        window: &mut Window,
19775        cx: &mut Context<Self>,
19776    ) {
19777        if let Some(project) = self.project() {
19778            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19779                && buffer.read(cx).file().is_none()
19780            {
19781                return;
19782            }
19783
19784            let focused = self.focus_handle(cx).contains_focused(window, cx);
19785
19786            let project = project.clone();
19787            let blame = cx
19788                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19789            self.blame_subscription =
19790                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19791            self.blame = Some(blame);
19792        }
19793    }
19794
19795    fn toggle_git_blame_inline_internal(
19796        &mut self,
19797        user_triggered: bool,
19798        window: &mut Window,
19799        cx: &mut Context<Self>,
19800    ) {
19801        if self.git_blame_inline_enabled {
19802            self.git_blame_inline_enabled = false;
19803            self.show_git_blame_inline = false;
19804            self.show_git_blame_inline_delay_task.take();
19805        } else {
19806            self.git_blame_inline_enabled = true;
19807            self.start_git_blame_inline(user_triggered, window, cx);
19808        }
19809
19810        cx.notify();
19811    }
19812
19813    fn start_git_blame_inline(
19814        &mut self,
19815        user_triggered: bool,
19816        window: &mut Window,
19817        cx: &mut Context<Self>,
19818    ) {
19819        self.start_git_blame(user_triggered, window, cx);
19820
19821        if ProjectSettings::get_global(cx)
19822            .git
19823            .inline_blame_delay()
19824            .is_some()
19825        {
19826            self.start_inline_blame_timer(window, cx);
19827        } else {
19828            self.show_git_blame_inline = true
19829        }
19830    }
19831
19832    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19833        self.blame.as_ref()
19834    }
19835
19836    pub fn show_git_blame_gutter(&self) -> bool {
19837        self.show_git_blame_gutter
19838    }
19839
19840    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19841        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19842    }
19843
19844    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19845        self.show_git_blame_inline
19846            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19847            && !self.newest_selection_head_on_empty_line(cx)
19848            && self.has_blame_entries(cx)
19849    }
19850
19851    fn has_blame_entries(&self, cx: &App) -> bool {
19852        self.blame()
19853            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19854    }
19855
19856    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19857        let cursor_anchor = self.selections.newest_anchor().head();
19858
19859        let snapshot = self.buffer.read(cx).snapshot(cx);
19860        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19861
19862        snapshot.line_len(buffer_row) == 0
19863    }
19864
19865    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19866        let buffer_and_selection = maybe!({
19867            let selection = self.selections.newest::<Point>(cx);
19868            let selection_range = selection.range();
19869
19870            let multi_buffer = self.buffer().read(cx);
19871            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19872            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19873
19874            let (buffer, range, _) = if selection.reversed {
19875                buffer_ranges.first()
19876            } else {
19877                buffer_ranges.last()
19878            }?;
19879
19880            let selection = text::ToPoint::to_point(&range.start, buffer).row
19881                ..text::ToPoint::to_point(&range.end, buffer).row;
19882            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19883        });
19884
19885        let Some((buffer, selection)) = buffer_and_selection else {
19886            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19887        };
19888
19889        let Some(project) = self.project() else {
19890            return Task::ready(Err(anyhow!("editor does not have project")));
19891        };
19892
19893        project.update(cx, |project, cx| {
19894            project.get_permalink_to_line(&buffer, selection, cx)
19895        })
19896    }
19897
19898    pub fn copy_permalink_to_line(
19899        &mut self,
19900        _: &CopyPermalinkToLine,
19901        window: &mut Window,
19902        cx: &mut Context<Self>,
19903    ) {
19904        let permalink_task = self.get_permalink_to_line(cx);
19905        let workspace = self.workspace();
19906
19907        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19908            Ok(permalink) => {
19909                cx.update(|_, cx| {
19910                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19911                })
19912                .ok();
19913            }
19914            Err(err) => {
19915                let message = format!("Failed to copy permalink: {err}");
19916
19917                anyhow::Result::<()>::Err(err).log_err();
19918
19919                if let Some(workspace) = workspace {
19920                    workspace
19921                        .update_in(cx, |workspace, _, cx| {
19922                            struct CopyPermalinkToLine;
19923
19924                            workspace.show_toast(
19925                                Toast::new(
19926                                    NotificationId::unique::<CopyPermalinkToLine>(),
19927                                    message,
19928                                ),
19929                                cx,
19930                            )
19931                        })
19932                        .ok();
19933                }
19934            }
19935        })
19936        .detach();
19937    }
19938
19939    pub fn copy_file_location(
19940        &mut self,
19941        _: &CopyFileLocation,
19942        _: &mut Window,
19943        cx: &mut Context<Self>,
19944    ) {
19945        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19946        if let Some(file) = self.target_file(cx) {
19947            let path = file.path().display(file.path_style(cx));
19948            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19949        }
19950    }
19951
19952    pub fn open_permalink_to_line(
19953        &mut self,
19954        _: &OpenPermalinkToLine,
19955        window: &mut Window,
19956        cx: &mut Context<Self>,
19957    ) {
19958        let permalink_task = self.get_permalink_to_line(cx);
19959        let workspace = self.workspace();
19960
19961        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19962            Ok(permalink) => {
19963                cx.update(|_, cx| {
19964                    cx.open_url(permalink.as_ref());
19965                })
19966                .ok();
19967            }
19968            Err(err) => {
19969                let message = format!("Failed to open permalink: {err}");
19970
19971                anyhow::Result::<()>::Err(err).log_err();
19972
19973                if let Some(workspace) = workspace {
19974                    workspace
19975                        .update(cx, |workspace, cx| {
19976                            struct OpenPermalinkToLine;
19977
19978                            workspace.show_toast(
19979                                Toast::new(
19980                                    NotificationId::unique::<OpenPermalinkToLine>(),
19981                                    message,
19982                                ),
19983                                cx,
19984                            )
19985                        })
19986                        .ok();
19987                }
19988            }
19989        })
19990        .detach();
19991    }
19992
19993    pub fn insert_uuid_v4(
19994        &mut self,
19995        _: &InsertUuidV4,
19996        window: &mut Window,
19997        cx: &mut Context<Self>,
19998    ) {
19999        self.insert_uuid(UuidVersion::V4, window, cx);
20000    }
20001
20002    pub fn insert_uuid_v7(
20003        &mut self,
20004        _: &InsertUuidV7,
20005        window: &mut Window,
20006        cx: &mut Context<Self>,
20007    ) {
20008        self.insert_uuid(UuidVersion::V7, window, cx);
20009    }
20010
20011    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20012        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20013        self.transact(window, cx, |this, window, cx| {
20014            let edits = this
20015                .selections
20016                .all::<Point>(cx)
20017                .into_iter()
20018                .map(|selection| {
20019                    let uuid = match version {
20020                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20021                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20022                    };
20023
20024                    (selection.range(), uuid.to_string())
20025                });
20026            this.edit(edits, cx);
20027            this.refresh_edit_prediction(true, false, window, cx);
20028        });
20029    }
20030
20031    pub fn open_selections_in_multibuffer(
20032        &mut self,
20033        _: &OpenSelectionsInMultibuffer,
20034        window: &mut Window,
20035        cx: &mut Context<Self>,
20036    ) {
20037        let multibuffer = self.buffer.read(cx);
20038
20039        let Some(buffer) = multibuffer.as_singleton() else {
20040            return;
20041        };
20042
20043        let Some(workspace) = self.workspace() else {
20044            return;
20045        };
20046
20047        let title = multibuffer.title(cx).to_string();
20048
20049        let locations = self
20050            .selections
20051            .all_anchors(cx)
20052            .iter()
20053            .map(|selection| {
20054                (
20055                    buffer.clone(),
20056                    (selection.start.text_anchor..selection.end.text_anchor)
20057                        .to_point(buffer.read(cx)),
20058                )
20059            })
20060            .into_group_map();
20061
20062        cx.spawn_in(window, async move |_, cx| {
20063            workspace.update_in(cx, |workspace, window, cx| {
20064                Self::open_locations_in_multibuffer(
20065                    workspace,
20066                    locations,
20067                    format!("Selections for '{title}'"),
20068                    false,
20069                    MultibufferSelectionMode::All,
20070                    window,
20071                    cx,
20072                );
20073            })
20074        })
20075        .detach();
20076    }
20077
20078    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20079    /// last highlight added will be used.
20080    ///
20081    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20082    pub fn highlight_rows<T: 'static>(
20083        &mut self,
20084        range: Range<Anchor>,
20085        color: Hsla,
20086        options: RowHighlightOptions,
20087        cx: &mut Context<Self>,
20088    ) {
20089        let snapshot = self.buffer().read(cx).snapshot(cx);
20090        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20091        let ix = row_highlights.binary_search_by(|highlight| {
20092            Ordering::Equal
20093                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20094                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20095        });
20096
20097        if let Err(mut ix) = ix {
20098            let index = post_inc(&mut self.highlight_order);
20099
20100            // If this range intersects with the preceding highlight, then merge it with
20101            // the preceding highlight. Otherwise insert a new highlight.
20102            let mut merged = false;
20103            if ix > 0 {
20104                let prev_highlight = &mut row_highlights[ix - 1];
20105                if prev_highlight
20106                    .range
20107                    .end
20108                    .cmp(&range.start, &snapshot)
20109                    .is_ge()
20110                {
20111                    ix -= 1;
20112                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20113                        prev_highlight.range.end = range.end;
20114                    }
20115                    merged = true;
20116                    prev_highlight.index = index;
20117                    prev_highlight.color = color;
20118                    prev_highlight.options = options;
20119                }
20120            }
20121
20122            if !merged {
20123                row_highlights.insert(
20124                    ix,
20125                    RowHighlight {
20126                        range,
20127                        index,
20128                        color,
20129                        options,
20130                        type_id: TypeId::of::<T>(),
20131                    },
20132                );
20133            }
20134
20135            // If any of the following highlights intersect with this one, merge them.
20136            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20137                let highlight = &row_highlights[ix];
20138                if next_highlight
20139                    .range
20140                    .start
20141                    .cmp(&highlight.range.end, &snapshot)
20142                    .is_le()
20143                {
20144                    if next_highlight
20145                        .range
20146                        .end
20147                        .cmp(&highlight.range.end, &snapshot)
20148                        .is_gt()
20149                    {
20150                        row_highlights[ix].range.end = next_highlight.range.end;
20151                    }
20152                    row_highlights.remove(ix + 1);
20153                } else {
20154                    break;
20155                }
20156            }
20157        }
20158    }
20159
20160    /// Remove any highlighted row ranges of the given type that intersect the
20161    /// given ranges.
20162    pub fn remove_highlighted_rows<T: 'static>(
20163        &mut self,
20164        ranges_to_remove: Vec<Range<Anchor>>,
20165        cx: &mut Context<Self>,
20166    ) {
20167        let snapshot = self.buffer().read(cx).snapshot(cx);
20168        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20169        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20170        row_highlights.retain(|highlight| {
20171            while let Some(range_to_remove) = ranges_to_remove.peek() {
20172                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20173                    Ordering::Less | Ordering::Equal => {
20174                        ranges_to_remove.next();
20175                    }
20176                    Ordering::Greater => {
20177                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20178                            Ordering::Less | Ordering::Equal => {
20179                                return false;
20180                            }
20181                            Ordering::Greater => break,
20182                        }
20183                    }
20184                }
20185            }
20186
20187            true
20188        })
20189    }
20190
20191    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20192    pub fn clear_row_highlights<T: 'static>(&mut self) {
20193        self.highlighted_rows.remove(&TypeId::of::<T>());
20194    }
20195
20196    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20197    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20198        self.highlighted_rows
20199            .get(&TypeId::of::<T>())
20200            .map_or(&[] as &[_], |vec| vec.as_slice())
20201            .iter()
20202            .map(|highlight| (highlight.range.clone(), highlight.color))
20203    }
20204
20205    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20206    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20207    /// Allows to ignore certain kinds of highlights.
20208    pub fn highlighted_display_rows(
20209        &self,
20210        window: &mut Window,
20211        cx: &mut App,
20212    ) -> BTreeMap<DisplayRow, LineHighlight> {
20213        let snapshot = self.snapshot(window, cx);
20214        let mut used_highlight_orders = HashMap::default();
20215        self.highlighted_rows
20216            .iter()
20217            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20218            .fold(
20219                BTreeMap::<DisplayRow, LineHighlight>::new(),
20220                |mut unique_rows, highlight| {
20221                    let start = highlight.range.start.to_display_point(&snapshot);
20222                    let end = highlight.range.end.to_display_point(&snapshot);
20223                    let start_row = start.row().0;
20224                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20225                        && end.column() == 0
20226                    {
20227                        end.row().0.saturating_sub(1)
20228                    } else {
20229                        end.row().0
20230                    };
20231                    for row in start_row..=end_row {
20232                        let used_index =
20233                            used_highlight_orders.entry(row).or_insert(highlight.index);
20234                        if highlight.index >= *used_index {
20235                            *used_index = highlight.index;
20236                            unique_rows.insert(
20237                                DisplayRow(row),
20238                                LineHighlight {
20239                                    include_gutter: highlight.options.include_gutter,
20240                                    border: None,
20241                                    background: highlight.color.into(),
20242                                    type_id: Some(highlight.type_id),
20243                                },
20244                            );
20245                        }
20246                    }
20247                    unique_rows
20248                },
20249            )
20250    }
20251
20252    pub fn highlighted_display_row_for_autoscroll(
20253        &self,
20254        snapshot: &DisplaySnapshot,
20255    ) -> Option<DisplayRow> {
20256        self.highlighted_rows
20257            .values()
20258            .flat_map(|highlighted_rows| highlighted_rows.iter())
20259            .filter_map(|highlight| {
20260                if highlight.options.autoscroll {
20261                    Some(highlight.range.start.to_display_point(snapshot).row())
20262                } else {
20263                    None
20264                }
20265            })
20266            .min()
20267    }
20268
20269    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20270        self.highlight_background::<SearchWithinRange>(
20271            ranges,
20272            |colors| colors.colors().editor_document_highlight_read_background,
20273            cx,
20274        )
20275    }
20276
20277    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20278        self.breadcrumb_header = Some(new_header);
20279    }
20280
20281    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20282        self.clear_background_highlights::<SearchWithinRange>(cx);
20283    }
20284
20285    pub fn highlight_background<T: 'static>(
20286        &mut self,
20287        ranges: &[Range<Anchor>],
20288        color_fetcher: fn(&Theme) -> Hsla,
20289        cx: &mut Context<Self>,
20290    ) {
20291        self.background_highlights.insert(
20292            HighlightKey::Type(TypeId::of::<T>()),
20293            (color_fetcher, Arc::from(ranges)),
20294        );
20295        self.scrollbar_marker_state.dirty = true;
20296        cx.notify();
20297    }
20298
20299    pub fn highlight_background_key<T: 'static>(
20300        &mut self,
20301        key: usize,
20302        ranges: &[Range<Anchor>],
20303        color_fetcher: fn(&Theme) -> Hsla,
20304        cx: &mut Context<Self>,
20305    ) {
20306        self.background_highlights.insert(
20307            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20308            (color_fetcher, Arc::from(ranges)),
20309        );
20310        self.scrollbar_marker_state.dirty = true;
20311        cx.notify();
20312    }
20313
20314    pub fn clear_background_highlights<T: 'static>(
20315        &mut self,
20316        cx: &mut Context<Self>,
20317    ) -> Option<BackgroundHighlight> {
20318        let text_highlights = self
20319            .background_highlights
20320            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20321        if !text_highlights.1.is_empty() {
20322            self.scrollbar_marker_state.dirty = true;
20323            cx.notify();
20324        }
20325        Some(text_highlights)
20326    }
20327
20328    pub fn highlight_gutter<T: 'static>(
20329        &mut self,
20330        ranges: impl Into<Vec<Range<Anchor>>>,
20331        color_fetcher: fn(&App) -> Hsla,
20332        cx: &mut Context<Self>,
20333    ) {
20334        self.gutter_highlights
20335            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20336        cx.notify();
20337    }
20338
20339    pub fn clear_gutter_highlights<T: 'static>(
20340        &mut self,
20341        cx: &mut Context<Self>,
20342    ) -> Option<GutterHighlight> {
20343        cx.notify();
20344        self.gutter_highlights.remove(&TypeId::of::<T>())
20345    }
20346
20347    pub fn insert_gutter_highlight<T: 'static>(
20348        &mut self,
20349        range: Range<Anchor>,
20350        color_fetcher: fn(&App) -> Hsla,
20351        cx: &mut Context<Self>,
20352    ) {
20353        let snapshot = self.buffer().read(cx).snapshot(cx);
20354        let mut highlights = self
20355            .gutter_highlights
20356            .remove(&TypeId::of::<T>())
20357            .map(|(_, highlights)| highlights)
20358            .unwrap_or_default();
20359        let ix = highlights.binary_search_by(|highlight| {
20360            Ordering::Equal
20361                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20362                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20363        });
20364        if let Err(ix) = ix {
20365            highlights.insert(ix, range);
20366        }
20367        self.gutter_highlights
20368            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20369    }
20370
20371    pub fn remove_gutter_highlights<T: 'static>(
20372        &mut self,
20373        ranges_to_remove: Vec<Range<Anchor>>,
20374        cx: &mut Context<Self>,
20375    ) {
20376        let snapshot = self.buffer().read(cx).snapshot(cx);
20377        let Some((color_fetcher, mut gutter_highlights)) =
20378            self.gutter_highlights.remove(&TypeId::of::<T>())
20379        else {
20380            return;
20381        };
20382        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20383        gutter_highlights.retain(|highlight| {
20384            while let Some(range_to_remove) = ranges_to_remove.peek() {
20385                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20386                    Ordering::Less | Ordering::Equal => {
20387                        ranges_to_remove.next();
20388                    }
20389                    Ordering::Greater => {
20390                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20391                            Ordering::Less | Ordering::Equal => {
20392                                return false;
20393                            }
20394                            Ordering::Greater => break,
20395                        }
20396                    }
20397                }
20398            }
20399
20400            true
20401        });
20402        self.gutter_highlights
20403            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20404    }
20405
20406    #[cfg(feature = "test-support")]
20407    pub fn all_text_highlights(
20408        &self,
20409        window: &mut Window,
20410        cx: &mut Context<Self>,
20411    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20412        let snapshot = self.snapshot(window, cx);
20413        self.display_map.update(cx, |display_map, _| {
20414            display_map
20415                .all_text_highlights()
20416                .map(|highlight| {
20417                    let (style, ranges) = highlight.as_ref();
20418                    (
20419                        *style,
20420                        ranges
20421                            .iter()
20422                            .map(|range| range.clone().to_display_points(&snapshot))
20423                            .collect(),
20424                    )
20425                })
20426                .collect()
20427        })
20428    }
20429
20430    #[cfg(feature = "test-support")]
20431    pub fn all_text_background_highlights(
20432        &self,
20433        window: &mut Window,
20434        cx: &mut Context<Self>,
20435    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20436        let snapshot = self.snapshot(window, cx);
20437        let buffer = &snapshot.buffer_snapshot();
20438        let start = buffer.anchor_before(0);
20439        let end = buffer.anchor_after(buffer.len());
20440        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20441    }
20442
20443    #[cfg(any(test, feature = "test-support"))]
20444    pub fn sorted_background_highlights_in_range(
20445        &self,
20446        search_range: Range<Anchor>,
20447        display_snapshot: &DisplaySnapshot,
20448        theme: &Theme,
20449    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20450        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20451        res.sort_by(|a, b| {
20452            a.0.start
20453                .cmp(&b.0.start)
20454                .then_with(|| a.0.end.cmp(&b.0.end))
20455                .then_with(|| a.1.cmp(&b.1))
20456        });
20457        res
20458    }
20459
20460    #[cfg(feature = "test-support")]
20461    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20462        let snapshot = self.buffer().read(cx).snapshot(cx);
20463
20464        let highlights = self
20465            .background_highlights
20466            .get(&HighlightKey::Type(TypeId::of::<
20467                items::BufferSearchHighlights,
20468            >()));
20469
20470        if let Some((_color, ranges)) = highlights {
20471            ranges
20472                .iter()
20473                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20474                .collect_vec()
20475        } else {
20476            vec![]
20477        }
20478    }
20479
20480    fn document_highlights_for_position<'a>(
20481        &'a self,
20482        position: Anchor,
20483        buffer: &'a MultiBufferSnapshot,
20484    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20485        let read_highlights = self
20486            .background_highlights
20487            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20488            .map(|h| &h.1);
20489        let write_highlights = self
20490            .background_highlights
20491            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20492            .map(|h| &h.1);
20493        let left_position = position.bias_left(buffer);
20494        let right_position = position.bias_right(buffer);
20495        read_highlights
20496            .into_iter()
20497            .chain(write_highlights)
20498            .flat_map(move |ranges| {
20499                let start_ix = match ranges.binary_search_by(|probe| {
20500                    let cmp = probe.end.cmp(&left_position, buffer);
20501                    if cmp.is_ge() {
20502                        Ordering::Greater
20503                    } else {
20504                        Ordering::Less
20505                    }
20506                }) {
20507                    Ok(i) | Err(i) => i,
20508                };
20509
20510                ranges[start_ix..]
20511                    .iter()
20512                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20513            })
20514    }
20515
20516    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20517        self.background_highlights
20518            .get(&HighlightKey::Type(TypeId::of::<T>()))
20519            .is_some_and(|(_, highlights)| !highlights.is_empty())
20520    }
20521
20522    /// Returns all background highlights for a given range.
20523    ///
20524    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20525    pub fn background_highlights_in_range(
20526        &self,
20527        search_range: Range<Anchor>,
20528        display_snapshot: &DisplaySnapshot,
20529        theme: &Theme,
20530    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20531        let mut results = Vec::new();
20532        for (color_fetcher, ranges) in self.background_highlights.values() {
20533            let color = color_fetcher(theme);
20534            let start_ix = match ranges.binary_search_by(|probe| {
20535                let cmp = probe
20536                    .end
20537                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20538                if cmp.is_gt() {
20539                    Ordering::Greater
20540                } else {
20541                    Ordering::Less
20542                }
20543            }) {
20544                Ok(i) | Err(i) => i,
20545            };
20546            for range in &ranges[start_ix..] {
20547                if range
20548                    .start
20549                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20550                    .is_ge()
20551                {
20552                    break;
20553                }
20554
20555                let start = range.start.to_display_point(display_snapshot);
20556                let end = range.end.to_display_point(display_snapshot);
20557                results.push((start..end, color))
20558            }
20559        }
20560        results
20561    }
20562
20563    pub fn gutter_highlights_in_range(
20564        &self,
20565        search_range: Range<Anchor>,
20566        display_snapshot: &DisplaySnapshot,
20567        cx: &App,
20568    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20569        let mut results = Vec::new();
20570        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20571            let color = color_fetcher(cx);
20572            let start_ix = match ranges.binary_search_by(|probe| {
20573                let cmp = probe
20574                    .end
20575                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20576                if cmp.is_gt() {
20577                    Ordering::Greater
20578                } else {
20579                    Ordering::Less
20580                }
20581            }) {
20582                Ok(i) | Err(i) => i,
20583            };
20584            for range in &ranges[start_ix..] {
20585                if range
20586                    .start
20587                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20588                    .is_ge()
20589                {
20590                    break;
20591                }
20592
20593                let start = range.start.to_display_point(display_snapshot);
20594                let end = range.end.to_display_point(display_snapshot);
20595                results.push((start..end, color))
20596            }
20597        }
20598        results
20599    }
20600
20601    /// Get the text ranges corresponding to the redaction query
20602    pub fn redacted_ranges(
20603        &self,
20604        search_range: Range<Anchor>,
20605        display_snapshot: &DisplaySnapshot,
20606        cx: &App,
20607    ) -> Vec<Range<DisplayPoint>> {
20608        display_snapshot
20609            .buffer_snapshot()
20610            .redacted_ranges(search_range, |file| {
20611                if let Some(file) = file {
20612                    file.is_private()
20613                        && EditorSettings::get(
20614                            Some(SettingsLocation {
20615                                worktree_id: file.worktree_id(cx),
20616                                path: file.path().as_ref(),
20617                            }),
20618                            cx,
20619                        )
20620                        .redact_private_values
20621                } else {
20622                    false
20623                }
20624            })
20625            .map(|range| {
20626                range.start.to_display_point(display_snapshot)
20627                    ..range.end.to_display_point(display_snapshot)
20628            })
20629            .collect()
20630    }
20631
20632    pub fn highlight_text_key<T: 'static>(
20633        &mut self,
20634        key: usize,
20635        ranges: Vec<Range<Anchor>>,
20636        style: HighlightStyle,
20637        cx: &mut Context<Self>,
20638    ) {
20639        self.display_map.update(cx, |map, _| {
20640            map.highlight_text(
20641                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20642                ranges,
20643                style,
20644            );
20645        });
20646        cx.notify();
20647    }
20648
20649    pub fn highlight_text<T: 'static>(
20650        &mut self,
20651        ranges: Vec<Range<Anchor>>,
20652        style: HighlightStyle,
20653        cx: &mut Context<Self>,
20654    ) {
20655        self.display_map.update(cx, |map, _| {
20656            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20657        });
20658        cx.notify();
20659    }
20660
20661    pub(crate) fn highlight_inlays<T: 'static>(
20662        &mut self,
20663        highlights: Vec<InlayHighlight>,
20664        style: HighlightStyle,
20665        cx: &mut Context<Self>,
20666    ) {
20667        self.display_map.update(cx, |map, _| {
20668            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20669        });
20670        cx.notify();
20671    }
20672
20673    pub fn text_highlights<'a, T: 'static>(
20674        &'a self,
20675        cx: &'a App,
20676    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20677        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20678    }
20679
20680    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20681        let cleared = self
20682            .display_map
20683            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20684        if cleared {
20685            cx.notify();
20686        }
20687    }
20688
20689    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20690        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20691            && self.focus_handle.is_focused(window)
20692    }
20693
20694    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20695        self.show_cursor_when_unfocused = is_enabled;
20696        cx.notify();
20697    }
20698
20699    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20700        cx.notify();
20701    }
20702
20703    fn on_debug_session_event(
20704        &mut self,
20705        _session: Entity<Session>,
20706        event: &SessionEvent,
20707        cx: &mut Context<Self>,
20708    ) {
20709        if let SessionEvent::InvalidateInlineValue = event {
20710            self.refresh_inline_values(cx);
20711        }
20712    }
20713
20714    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20715        let Some(project) = self.project.clone() else {
20716            return;
20717        };
20718
20719        if !self.inline_value_cache.enabled {
20720            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20721            self.splice_inlays(&inlays, Vec::new(), cx);
20722            return;
20723        }
20724
20725        let current_execution_position = self
20726            .highlighted_rows
20727            .get(&TypeId::of::<ActiveDebugLine>())
20728            .and_then(|lines| lines.last().map(|line| line.range.end));
20729
20730        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20731            let inline_values = editor
20732                .update(cx, |editor, cx| {
20733                    let Some(current_execution_position) = current_execution_position else {
20734                        return Some(Task::ready(Ok(Vec::new())));
20735                    };
20736
20737                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20738                        let snapshot = buffer.snapshot(cx);
20739
20740                        let excerpt = snapshot.excerpt_containing(
20741                            current_execution_position..current_execution_position,
20742                        )?;
20743
20744                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20745                    })?;
20746
20747                    let range =
20748                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20749
20750                    project.inline_values(buffer, range, cx)
20751                })
20752                .ok()
20753                .flatten()?
20754                .await
20755                .context("refreshing debugger inlays")
20756                .log_err()?;
20757
20758            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20759
20760            for (buffer_id, inline_value) in inline_values
20761                .into_iter()
20762                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20763            {
20764                buffer_inline_values
20765                    .entry(buffer_id)
20766                    .or_default()
20767                    .push(inline_value);
20768            }
20769
20770            editor
20771                .update(cx, |editor, cx| {
20772                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20773                    let mut new_inlays = Vec::default();
20774
20775                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20776                        let buffer_id = buffer_snapshot.remote_id();
20777                        buffer_inline_values
20778                            .get(&buffer_id)
20779                            .into_iter()
20780                            .flatten()
20781                            .for_each(|hint| {
20782                                let inlay = Inlay::debugger(
20783                                    post_inc(&mut editor.next_inlay_id),
20784                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20785                                    hint.text(),
20786                                );
20787                                if !inlay.text().chars().contains(&'\n') {
20788                                    new_inlays.push(inlay);
20789                                }
20790                            });
20791                    }
20792
20793                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20794                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20795
20796                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20797                })
20798                .ok()?;
20799            Some(())
20800        });
20801    }
20802
20803    fn on_buffer_event(
20804        &mut self,
20805        multibuffer: &Entity<MultiBuffer>,
20806        event: &multi_buffer::Event,
20807        window: &mut Window,
20808        cx: &mut Context<Self>,
20809    ) {
20810        match event {
20811            multi_buffer::Event::Edited {
20812                singleton_buffer_edited,
20813                edited_buffer,
20814            } => {
20815                self.scrollbar_marker_state.dirty = true;
20816                self.active_indent_guides_state.dirty = true;
20817                self.refresh_active_diagnostics(cx);
20818                self.refresh_code_actions(window, cx);
20819                self.refresh_selected_text_highlights(true, window, cx);
20820                self.refresh_single_line_folds(window, cx);
20821                refresh_matching_bracket_highlights(self, cx);
20822                if self.has_active_edit_prediction() {
20823                    self.update_visible_edit_prediction(window, cx);
20824                }
20825                if let Some(project) = self.project.as_ref()
20826                    && let Some(edited_buffer) = edited_buffer
20827                {
20828                    project.update(cx, |project, cx| {
20829                        self.registered_buffers
20830                            .entry(edited_buffer.read(cx).remote_id())
20831                            .or_insert_with(|| {
20832                                project.register_buffer_with_language_servers(edited_buffer, cx)
20833                            });
20834                    });
20835                }
20836                cx.emit(EditorEvent::BufferEdited);
20837                cx.emit(SearchEvent::MatchesInvalidated);
20838
20839                if let Some(buffer) = edited_buffer {
20840                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20841                }
20842
20843                if *singleton_buffer_edited {
20844                    if let Some(buffer) = edited_buffer
20845                        && buffer.read(cx).file().is_none()
20846                    {
20847                        cx.emit(EditorEvent::TitleChanged);
20848                    }
20849                    if let Some(project) = &self.project {
20850                        #[allow(clippy::mutable_key_type)]
20851                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20852                            multibuffer
20853                                .all_buffers()
20854                                .into_iter()
20855                                .filter_map(|buffer| {
20856                                    buffer.update(cx, |buffer, cx| {
20857                                        let language = buffer.language()?;
20858                                        let should_discard = project.update(cx, |project, cx| {
20859                                            project.is_local()
20860                                                && !project.has_language_servers_for(buffer, cx)
20861                                        });
20862                                        should_discard.not().then_some(language.clone())
20863                                    })
20864                                })
20865                                .collect::<HashSet<_>>()
20866                        });
20867                        if !languages_affected.is_empty() {
20868                            self.refresh_inlay_hints(
20869                                InlayHintRefreshReason::BufferEdited(languages_affected),
20870                                cx,
20871                            );
20872                        }
20873                    }
20874                }
20875
20876                let Some(project) = &self.project else { return };
20877                let (telemetry, is_via_ssh) = {
20878                    let project = project.read(cx);
20879                    let telemetry = project.client().telemetry().clone();
20880                    let is_via_ssh = project.is_via_remote_server();
20881                    (telemetry, is_via_ssh)
20882                };
20883                refresh_linked_ranges(self, window, cx);
20884                telemetry.log_edit_event("editor", is_via_ssh);
20885            }
20886            multi_buffer::Event::ExcerptsAdded {
20887                buffer,
20888                predecessor,
20889                excerpts,
20890            } => {
20891                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20892                let buffer_id = buffer.read(cx).remote_id();
20893                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20894                    && let Some(project) = &self.project
20895                {
20896                    update_uncommitted_diff_for_buffer(
20897                        cx.entity(),
20898                        project,
20899                        [buffer.clone()],
20900                        self.buffer.clone(),
20901                        cx,
20902                    )
20903                    .detach();
20904                }
20905                if self.active_diagnostics != ActiveDiagnostic::All {
20906                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20907                }
20908                cx.emit(EditorEvent::ExcerptsAdded {
20909                    buffer: buffer.clone(),
20910                    predecessor: *predecessor,
20911                    excerpts: excerpts.clone(),
20912                });
20913                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20914            }
20915            multi_buffer::Event::ExcerptsRemoved {
20916                ids,
20917                removed_buffer_ids,
20918            } => {
20919                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20920                let buffer = self.buffer.read(cx);
20921                self.registered_buffers
20922                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20923                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20924                cx.emit(EditorEvent::ExcerptsRemoved {
20925                    ids: ids.clone(),
20926                    removed_buffer_ids: removed_buffer_ids.clone(),
20927                });
20928            }
20929            multi_buffer::Event::ExcerptsEdited {
20930                excerpt_ids,
20931                buffer_ids,
20932            } => {
20933                self.display_map.update(cx, |map, cx| {
20934                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20935                });
20936                cx.emit(EditorEvent::ExcerptsEdited {
20937                    ids: excerpt_ids.clone(),
20938                });
20939            }
20940            multi_buffer::Event::ExcerptsExpanded { ids } => {
20941                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20942                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20943            }
20944            multi_buffer::Event::Reparsed(buffer_id) => {
20945                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20946                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20947
20948                cx.emit(EditorEvent::Reparsed(*buffer_id));
20949            }
20950            multi_buffer::Event::DiffHunksToggled => {
20951                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20952            }
20953            multi_buffer::Event::LanguageChanged(buffer_id) => {
20954                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20955                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20956                cx.emit(EditorEvent::Reparsed(*buffer_id));
20957                cx.notify();
20958            }
20959            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20960            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20961            multi_buffer::Event::FileHandleChanged
20962            | multi_buffer::Event::Reloaded
20963            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20964            multi_buffer::Event::DiagnosticsUpdated => {
20965                self.update_diagnostics_state(window, cx);
20966            }
20967            _ => {}
20968        };
20969    }
20970
20971    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20972        if !self.diagnostics_enabled() {
20973            return;
20974        }
20975        self.refresh_active_diagnostics(cx);
20976        self.refresh_inline_diagnostics(true, window, cx);
20977        self.scrollbar_marker_state.dirty = true;
20978        cx.notify();
20979    }
20980
20981    pub fn start_temporary_diff_override(&mut self) {
20982        self.load_diff_task.take();
20983        self.temporary_diff_override = true;
20984    }
20985
20986    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20987        self.temporary_diff_override = false;
20988        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20989        self.buffer.update(cx, |buffer, cx| {
20990            buffer.set_all_diff_hunks_collapsed(cx);
20991        });
20992
20993        if let Some(project) = self.project.clone() {
20994            self.load_diff_task = Some(
20995                update_uncommitted_diff_for_buffer(
20996                    cx.entity(),
20997                    &project,
20998                    self.buffer.read(cx).all_buffers(),
20999                    self.buffer.clone(),
21000                    cx,
21001                )
21002                .shared(),
21003            );
21004        }
21005    }
21006
21007    fn on_display_map_changed(
21008        &mut self,
21009        _: Entity<DisplayMap>,
21010        _: &mut Window,
21011        cx: &mut Context<Self>,
21012    ) {
21013        cx.notify();
21014    }
21015
21016    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21017        if self.diagnostics_enabled() {
21018            let new_severity = EditorSettings::get_global(cx)
21019                .diagnostics_max_severity
21020                .unwrap_or(DiagnosticSeverity::Hint);
21021            self.set_max_diagnostics_severity(new_severity, cx);
21022        }
21023        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21024        self.update_edit_prediction_settings(cx);
21025        self.refresh_edit_prediction(true, false, window, cx);
21026        self.refresh_inline_values(cx);
21027        self.refresh_inlay_hints(
21028            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21029                self.selections.newest_anchor().head(),
21030                &self.buffer.read(cx).snapshot(cx),
21031                cx,
21032            )),
21033            cx,
21034        );
21035
21036        let old_cursor_shape = self.cursor_shape;
21037        let old_show_breadcrumbs = self.show_breadcrumbs;
21038
21039        {
21040            let editor_settings = EditorSettings::get_global(cx);
21041            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21042            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21043            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21044            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21045        }
21046
21047        if old_cursor_shape != self.cursor_shape {
21048            cx.emit(EditorEvent::CursorShapeChanged);
21049        }
21050
21051        if old_show_breadcrumbs != self.show_breadcrumbs {
21052            cx.emit(EditorEvent::BreadcrumbsChanged);
21053        }
21054
21055        let project_settings = ProjectSettings::get_global(cx);
21056        self.serialize_dirty_buffers =
21057            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21058
21059        if self.mode.is_full() {
21060            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21061            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21062            if self.show_inline_diagnostics != show_inline_diagnostics {
21063                self.show_inline_diagnostics = show_inline_diagnostics;
21064                self.refresh_inline_diagnostics(false, window, cx);
21065            }
21066
21067            if self.git_blame_inline_enabled != inline_blame_enabled {
21068                self.toggle_git_blame_inline_internal(false, window, cx);
21069            }
21070
21071            let minimap_settings = EditorSettings::get_global(cx).minimap;
21072            if self.minimap_visibility != MinimapVisibility::Disabled {
21073                if self.minimap_visibility.settings_visibility()
21074                    != minimap_settings.minimap_enabled()
21075                {
21076                    self.set_minimap_visibility(
21077                        MinimapVisibility::for_mode(self.mode(), cx),
21078                        window,
21079                        cx,
21080                    );
21081                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21082                    minimap_entity.update(cx, |minimap_editor, cx| {
21083                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21084                    })
21085                }
21086            }
21087        }
21088
21089        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21090            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21091        }) {
21092            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21093                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21094            }
21095            self.refresh_colors(false, None, window, cx);
21096        }
21097
21098        cx.notify();
21099    }
21100
21101    pub fn set_searchable(&mut self, searchable: bool) {
21102        self.searchable = searchable;
21103    }
21104
21105    pub fn searchable(&self) -> bool {
21106        self.searchable
21107    }
21108
21109    fn open_proposed_changes_editor(
21110        &mut self,
21111        _: &OpenProposedChangesEditor,
21112        window: &mut Window,
21113        cx: &mut Context<Self>,
21114    ) {
21115        let Some(workspace) = self.workspace() else {
21116            cx.propagate();
21117            return;
21118        };
21119
21120        let selections = self.selections.all::<usize>(cx);
21121        let multi_buffer = self.buffer.read(cx);
21122        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21123        let mut new_selections_by_buffer = HashMap::default();
21124        for selection in selections {
21125            for (buffer, range, _) in
21126                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21127            {
21128                let mut range = range.to_point(buffer);
21129                range.start.column = 0;
21130                range.end.column = buffer.line_len(range.end.row);
21131                new_selections_by_buffer
21132                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21133                    .or_insert(Vec::new())
21134                    .push(range)
21135            }
21136        }
21137
21138        let proposed_changes_buffers = new_selections_by_buffer
21139            .into_iter()
21140            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21141            .collect::<Vec<_>>();
21142        let proposed_changes_editor = cx.new(|cx| {
21143            ProposedChangesEditor::new(
21144                "Proposed changes",
21145                proposed_changes_buffers,
21146                self.project.clone(),
21147                window,
21148                cx,
21149            )
21150        });
21151
21152        window.defer(cx, move |window, cx| {
21153            workspace.update(cx, |workspace, cx| {
21154                workspace.active_pane().update(cx, |pane, cx| {
21155                    pane.add_item(
21156                        Box::new(proposed_changes_editor),
21157                        true,
21158                        true,
21159                        None,
21160                        window,
21161                        cx,
21162                    );
21163                });
21164            });
21165        });
21166    }
21167
21168    pub fn open_excerpts_in_split(
21169        &mut self,
21170        _: &OpenExcerptsSplit,
21171        window: &mut Window,
21172        cx: &mut Context<Self>,
21173    ) {
21174        self.open_excerpts_common(None, true, window, cx)
21175    }
21176
21177    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21178        self.open_excerpts_common(None, false, window, cx)
21179    }
21180
21181    fn open_excerpts_common(
21182        &mut self,
21183        jump_data: Option<JumpData>,
21184        split: bool,
21185        window: &mut Window,
21186        cx: &mut Context<Self>,
21187    ) {
21188        let Some(workspace) = self.workspace() else {
21189            cx.propagate();
21190            return;
21191        };
21192
21193        if self.buffer.read(cx).is_singleton() {
21194            cx.propagate();
21195            return;
21196        }
21197
21198        let mut new_selections_by_buffer = HashMap::default();
21199        match &jump_data {
21200            Some(JumpData::MultiBufferPoint {
21201                excerpt_id,
21202                position,
21203                anchor,
21204                line_offset_from_top,
21205            }) => {
21206                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21207                if let Some(buffer) = multi_buffer_snapshot
21208                    .buffer_id_for_excerpt(*excerpt_id)
21209                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21210                {
21211                    let buffer_snapshot = buffer.read(cx).snapshot();
21212                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21213                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21214                    } else {
21215                        buffer_snapshot.clip_point(*position, Bias::Left)
21216                    };
21217                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21218                    new_selections_by_buffer.insert(
21219                        buffer,
21220                        (
21221                            vec![jump_to_offset..jump_to_offset],
21222                            Some(*line_offset_from_top),
21223                        ),
21224                    );
21225                }
21226            }
21227            Some(JumpData::MultiBufferRow {
21228                row,
21229                line_offset_from_top,
21230            }) => {
21231                let point = MultiBufferPoint::new(row.0, 0);
21232                if let Some((buffer, buffer_point, _)) =
21233                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21234                {
21235                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21236                    new_selections_by_buffer
21237                        .entry(buffer)
21238                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21239                        .0
21240                        .push(buffer_offset..buffer_offset)
21241                }
21242            }
21243            None => {
21244                let selections = self.selections.all::<usize>(cx);
21245                let multi_buffer = self.buffer.read(cx);
21246                for selection in selections {
21247                    for (snapshot, range, _, anchor) in multi_buffer
21248                        .snapshot(cx)
21249                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21250                    {
21251                        if let Some(anchor) = anchor {
21252                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21253                            else {
21254                                continue;
21255                            };
21256                            let offset = text::ToOffset::to_offset(
21257                                &anchor.text_anchor,
21258                                &buffer_handle.read(cx).snapshot(),
21259                            );
21260                            let range = offset..offset;
21261                            new_selections_by_buffer
21262                                .entry(buffer_handle)
21263                                .or_insert((Vec::new(), None))
21264                                .0
21265                                .push(range)
21266                        } else {
21267                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21268                            else {
21269                                continue;
21270                            };
21271                            new_selections_by_buffer
21272                                .entry(buffer_handle)
21273                                .or_insert((Vec::new(), None))
21274                                .0
21275                                .push(range)
21276                        }
21277                    }
21278                }
21279            }
21280        }
21281
21282        new_selections_by_buffer
21283            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21284
21285        if new_selections_by_buffer.is_empty() {
21286            return;
21287        }
21288
21289        // We defer the pane interaction because we ourselves are a workspace item
21290        // and activating a new item causes the pane to call a method on us reentrantly,
21291        // which panics if we're on the stack.
21292        window.defer(cx, move |window, cx| {
21293            workspace.update(cx, |workspace, cx| {
21294                let pane = if split {
21295                    workspace.adjacent_pane(window, cx)
21296                } else {
21297                    workspace.active_pane().clone()
21298                };
21299
21300                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21301                    let editor = buffer
21302                        .read(cx)
21303                        .file()
21304                        .is_none()
21305                        .then(|| {
21306                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21307                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21308                            // Instead, we try to activate the existing editor in the pane first.
21309                            let (editor, pane_item_index) =
21310                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21311                                    let editor = item.downcast::<Editor>()?;
21312                                    let singleton_buffer =
21313                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21314                                    if singleton_buffer == buffer {
21315                                        Some((editor, i))
21316                                    } else {
21317                                        None
21318                                    }
21319                                })?;
21320                            pane.update(cx, |pane, cx| {
21321                                pane.activate_item(pane_item_index, true, true, window, cx)
21322                            });
21323                            Some(editor)
21324                        })
21325                        .flatten()
21326                        .unwrap_or_else(|| {
21327                            workspace.open_project_item::<Self>(
21328                                pane.clone(),
21329                                buffer,
21330                                true,
21331                                true,
21332                                window,
21333                                cx,
21334                            )
21335                        });
21336
21337                    editor.update(cx, |editor, cx| {
21338                        let autoscroll = match scroll_offset {
21339                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21340                            None => Autoscroll::newest(),
21341                        };
21342                        let nav_history = editor.nav_history.take();
21343                        editor.change_selections(
21344                            SelectionEffects::scroll(autoscroll),
21345                            window,
21346                            cx,
21347                            |s| {
21348                                s.select_ranges(ranges);
21349                            },
21350                        );
21351                        editor.nav_history = nav_history;
21352                    });
21353                }
21354            })
21355        });
21356    }
21357
21358    // For now, don't allow opening excerpts in buffers that aren't backed by
21359    // regular project files.
21360    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21361        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21362    }
21363
21364    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21365        let snapshot = self.buffer.read(cx).read(cx);
21366        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21367        Some(
21368            ranges
21369                .iter()
21370                .map(move |range| {
21371                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21372                })
21373                .collect(),
21374        )
21375    }
21376
21377    fn selection_replacement_ranges(
21378        &self,
21379        range: Range<OffsetUtf16>,
21380        cx: &mut App,
21381    ) -> Vec<Range<OffsetUtf16>> {
21382        let selections = self.selections.all::<OffsetUtf16>(cx);
21383        let newest_selection = selections
21384            .iter()
21385            .max_by_key(|selection| selection.id)
21386            .unwrap();
21387        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21388        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21389        let snapshot = self.buffer.read(cx).read(cx);
21390        selections
21391            .into_iter()
21392            .map(|mut selection| {
21393                selection.start.0 =
21394                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21395                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21396                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21397                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21398            })
21399            .collect()
21400    }
21401
21402    fn report_editor_event(
21403        &self,
21404        reported_event: ReportEditorEvent,
21405        file_extension: Option<String>,
21406        cx: &App,
21407    ) {
21408        if cfg!(any(test, feature = "test-support")) {
21409            return;
21410        }
21411
21412        let Some(project) = &self.project else { return };
21413
21414        // If None, we are in a file without an extension
21415        let file = self
21416            .buffer
21417            .read(cx)
21418            .as_singleton()
21419            .and_then(|b| b.read(cx).file());
21420        let file_extension = file_extension.or(file
21421            .as_ref()
21422            .and_then(|file| Path::new(file.file_name(cx)).extension())
21423            .and_then(|e| e.to_str())
21424            .map(|a| a.to_string()));
21425
21426        let vim_mode = vim_enabled(cx);
21427
21428        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21429        let copilot_enabled = edit_predictions_provider
21430            == language::language_settings::EditPredictionProvider::Copilot;
21431        let copilot_enabled_for_language = self
21432            .buffer
21433            .read(cx)
21434            .language_settings(cx)
21435            .show_edit_predictions;
21436
21437        let project = project.read(cx);
21438        let event_type = reported_event.event_type();
21439
21440        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21441            telemetry::event!(
21442                event_type,
21443                type = if auto_saved {"autosave"} else {"manual"},
21444                file_extension,
21445                vim_mode,
21446                copilot_enabled,
21447                copilot_enabled_for_language,
21448                edit_predictions_provider,
21449                is_via_ssh = project.is_via_remote_server(),
21450            );
21451        } else {
21452            telemetry::event!(
21453                event_type,
21454                file_extension,
21455                vim_mode,
21456                copilot_enabled,
21457                copilot_enabled_for_language,
21458                edit_predictions_provider,
21459                is_via_ssh = project.is_via_remote_server(),
21460            );
21461        };
21462    }
21463
21464    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21465    /// with each line being an array of {text, highlight} objects.
21466    fn copy_highlight_json(
21467        &mut self,
21468        _: &CopyHighlightJson,
21469        window: &mut Window,
21470        cx: &mut Context<Self>,
21471    ) {
21472        #[derive(Serialize)]
21473        struct Chunk<'a> {
21474            text: String,
21475            highlight: Option<&'a str>,
21476        }
21477
21478        let snapshot = self.buffer.read(cx).snapshot(cx);
21479        let range = self
21480            .selected_text_range(false, window, cx)
21481            .and_then(|selection| {
21482                if selection.range.is_empty() {
21483                    None
21484                } else {
21485                    Some(selection.range)
21486                }
21487            })
21488            .unwrap_or_else(|| 0..snapshot.len());
21489
21490        let chunks = snapshot.chunks(range, true);
21491        let mut lines = Vec::new();
21492        let mut line: VecDeque<Chunk> = VecDeque::new();
21493
21494        let Some(style) = self.style.as_ref() else {
21495            return;
21496        };
21497
21498        for chunk in chunks {
21499            let highlight = chunk
21500                .syntax_highlight_id
21501                .and_then(|id| id.name(&style.syntax));
21502            let mut chunk_lines = chunk.text.split('\n').peekable();
21503            while let Some(text) = chunk_lines.next() {
21504                let mut merged_with_last_token = false;
21505                if let Some(last_token) = line.back_mut()
21506                    && last_token.highlight == highlight
21507                {
21508                    last_token.text.push_str(text);
21509                    merged_with_last_token = true;
21510                }
21511
21512                if !merged_with_last_token {
21513                    line.push_back(Chunk {
21514                        text: text.into(),
21515                        highlight,
21516                    });
21517                }
21518
21519                if chunk_lines.peek().is_some() {
21520                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21521                        line.pop_front();
21522                    }
21523                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21524                        line.pop_back();
21525                    }
21526
21527                    lines.push(mem::take(&mut line));
21528                }
21529            }
21530        }
21531
21532        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21533            return;
21534        };
21535        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21536    }
21537
21538    pub fn open_context_menu(
21539        &mut self,
21540        _: &OpenContextMenu,
21541        window: &mut Window,
21542        cx: &mut Context<Self>,
21543    ) {
21544        self.request_autoscroll(Autoscroll::newest(), cx);
21545        let position = self.selections.newest_display(cx).start;
21546        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21547    }
21548
21549    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21550        &self.inlay_hint_cache
21551    }
21552
21553    pub fn replay_insert_event(
21554        &mut self,
21555        text: &str,
21556        relative_utf16_range: Option<Range<isize>>,
21557        window: &mut Window,
21558        cx: &mut Context<Self>,
21559    ) {
21560        if !self.input_enabled {
21561            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21562            return;
21563        }
21564        if let Some(relative_utf16_range) = relative_utf16_range {
21565            let selections = self.selections.all::<OffsetUtf16>(cx);
21566            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21567                let new_ranges = selections.into_iter().map(|range| {
21568                    let start = OffsetUtf16(
21569                        range
21570                            .head()
21571                            .0
21572                            .saturating_add_signed(relative_utf16_range.start),
21573                    );
21574                    let end = OffsetUtf16(
21575                        range
21576                            .head()
21577                            .0
21578                            .saturating_add_signed(relative_utf16_range.end),
21579                    );
21580                    start..end
21581                });
21582                s.select_ranges(new_ranges);
21583            });
21584        }
21585
21586        self.handle_input(text, window, cx);
21587    }
21588
21589    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21590        let Some(provider) = self.semantics_provider.as_ref() else {
21591            return false;
21592        };
21593
21594        let mut supports = false;
21595        self.buffer().update(cx, |this, cx| {
21596            this.for_each_buffer(|buffer| {
21597                supports |= provider.supports_inlay_hints(buffer, cx);
21598            });
21599        });
21600
21601        supports
21602    }
21603
21604    pub fn is_focused(&self, window: &Window) -> bool {
21605        self.focus_handle.is_focused(window)
21606    }
21607
21608    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21609        cx.emit(EditorEvent::Focused);
21610
21611        if let Some(descendant) = self
21612            .last_focused_descendant
21613            .take()
21614            .and_then(|descendant| descendant.upgrade())
21615        {
21616            window.focus(&descendant);
21617        } else {
21618            if let Some(blame) = self.blame.as_ref() {
21619                blame.update(cx, GitBlame::focus)
21620            }
21621
21622            self.blink_manager.update(cx, BlinkManager::enable);
21623            self.show_cursor_names(window, cx);
21624            self.buffer.update(cx, |buffer, cx| {
21625                buffer.finalize_last_transaction(cx);
21626                if self.leader_id.is_none() {
21627                    buffer.set_active_selections(
21628                        &self.selections.disjoint_anchors_arc(),
21629                        self.selections.line_mode(),
21630                        self.cursor_shape,
21631                        cx,
21632                    );
21633                }
21634            });
21635        }
21636    }
21637
21638    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21639        cx.emit(EditorEvent::FocusedIn)
21640    }
21641
21642    fn handle_focus_out(
21643        &mut self,
21644        event: FocusOutEvent,
21645        _window: &mut Window,
21646        cx: &mut Context<Self>,
21647    ) {
21648        if event.blurred != self.focus_handle {
21649            self.last_focused_descendant = Some(event.blurred);
21650        }
21651        self.selection_drag_state = SelectionDragState::None;
21652        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21653    }
21654
21655    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21656        self.blink_manager.update(cx, BlinkManager::disable);
21657        self.buffer
21658            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21659
21660        if let Some(blame) = self.blame.as_ref() {
21661            blame.update(cx, GitBlame::blur)
21662        }
21663        if !self.hover_state.focused(window, cx) {
21664            hide_hover(self, cx);
21665        }
21666        if !self
21667            .context_menu
21668            .borrow()
21669            .as_ref()
21670            .is_some_and(|context_menu| context_menu.focused(window, cx))
21671        {
21672            self.hide_context_menu(window, cx);
21673        }
21674        self.take_active_edit_prediction(cx);
21675        cx.emit(EditorEvent::Blurred);
21676        cx.notify();
21677    }
21678
21679    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21680        let mut pending: String = window
21681            .pending_input_keystrokes()
21682            .into_iter()
21683            .flatten()
21684            .filter_map(|keystroke| {
21685                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21686                    keystroke.key_char.clone()
21687                } else {
21688                    None
21689                }
21690            })
21691            .collect();
21692
21693        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21694            pending = "".to_string();
21695        }
21696
21697        let existing_pending = self
21698            .text_highlights::<PendingInput>(cx)
21699            .map(|(_, ranges)| ranges.to_vec());
21700        if existing_pending.is_none() && pending.is_empty() {
21701            return;
21702        }
21703        let transaction =
21704            self.transact(window, cx, |this, window, cx| {
21705                let selections = this.selections.all::<usize>(cx);
21706                let edits = selections
21707                    .iter()
21708                    .map(|selection| (selection.end..selection.end, pending.clone()));
21709                this.edit(edits, cx);
21710                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21711                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21712                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21713                    }));
21714                });
21715                if let Some(existing_ranges) = existing_pending {
21716                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21717                    this.edit(edits, cx);
21718                }
21719            });
21720
21721        let snapshot = self.snapshot(window, cx);
21722        let ranges = self
21723            .selections
21724            .all::<usize>(cx)
21725            .into_iter()
21726            .map(|selection| {
21727                snapshot.buffer_snapshot().anchor_after(selection.end)
21728                    ..snapshot
21729                        .buffer_snapshot()
21730                        .anchor_before(selection.end + pending.len())
21731            })
21732            .collect();
21733
21734        if pending.is_empty() {
21735            self.clear_highlights::<PendingInput>(cx);
21736        } else {
21737            self.highlight_text::<PendingInput>(
21738                ranges,
21739                HighlightStyle {
21740                    underline: Some(UnderlineStyle {
21741                        thickness: px(1.),
21742                        color: None,
21743                        wavy: false,
21744                    }),
21745                    ..Default::default()
21746                },
21747                cx,
21748            );
21749        }
21750
21751        self.ime_transaction = self.ime_transaction.or(transaction);
21752        if let Some(transaction) = self.ime_transaction {
21753            self.buffer.update(cx, |buffer, cx| {
21754                buffer.group_until_transaction(transaction, cx);
21755            });
21756        }
21757
21758        if self.text_highlights::<PendingInput>(cx).is_none() {
21759            self.ime_transaction.take();
21760        }
21761    }
21762
21763    pub fn register_action_renderer(
21764        &mut self,
21765        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21766    ) -> Subscription {
21767        let id = self.next_editor_action_id.post_inc();
21768        self.editor_actions
21769            .borrow_mut()
21770            .insert(id, Box::new(listener));
21771
21772        let editor_actions = self.editor_actions.clone();
21773        Subscription::new(move || {
21774            editor_actions.borrow_mut().remove(&id);
21775        })
21776    }
21777
21778    pub fn register_action<A: Action>(
21779        &mut self,
21780        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21781    ) -> Subscription {
21782        let id = self.next_editor_action_id.post_inc();
21783        let listener = Arc::new(listener);
21784        self.editor_actions.borrow_mut().insert(
21785            id,
21786            Box::new(move |_, window, _| {
21787                let listener = listener.clone();
21788                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21789                    let action = action.downcast_ref().unwrap();
21790                    if phase == DispatchPhase::Bubble {
21791                        listener(action, window, cx)
21792                    }
21793                })
21794            }),
21795        );
21796
21797        let editor_actions = self.editor_actions.clone();
21798        Subscription::new(move || {
21799            editor_actions.borrow_mut().remove(&id);
21800        })
21801    }
21802
21803    pub fn file_header_size(&self) -> u32 {
21804        FILE_HEADER_HEIGHT
21805    }
21806
21807    pub fn restore(
21808        &mut self,
21809        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21810        window: &mut Window,
21811        cx: &mut Context<Self>,
21812    ) {
21813        let workspace = self.workspace();
21814        let project = self.project();
21815        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21816            let mut tasks = Vec::new();
21817            for (buffer_id, changes) in revert_changes {
21818                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21819                    buffer.update(cx, |buffer, cx| {
21820                        buffer.edit(
21821                            changes
21822                                .into_iter()
21823                                .map(|(range, text)| (range, text.to_string())),
21824                            None,
21825                            cx,
21826                        );
21827                    });
21828
21829                    if let Some(project) =
21830                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21831                    {
21832                        project.update(cx, |project, cx| {
21833                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21834                        })
21835                    }
21836                }
21837            }
21838            tasks
21839        });
21840        cx.spawn_in(window, async move |_, cx| {
21841            for (buffer, task) in save_tasks {
21842                let result = task.await;
21843                if result.is_err() {
21844                    let Some(path) = buffer
21845                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21846                        .ok()
21847                    else {
21848                        continue;
21849                    };
21850                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21851                        let Some(task) = cx
21852                            .update_window_entity(workspace, |workspace, window, cx| {
21853                                workspace
21854                                    .open_path_preview(path, None, false, false, false, window, cx)
21855                            })
21856                            .ok()
21857                        else {
21858                            continue;
21859                        };
21860                        task.await.log_err();
21861                    }
21862                }
21863            }
21864        })
21865        .detach();
21866        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21867            selections.refresh()
21868        });
21869    }
21870
21871    pub fn to_pixel_point(
21872        &self,
21873        source: multi_buffer::Anchor,
21874        editor_snapshot: &EditorSnapshot,
21875        window: &mut Window,
21876    ) -> Option<gpui::Point<Pixels>> {
21877        let source_point = source.to_display_point(editor_snapshot);
21878        self.display_to_pixel_point(source_point, editor_snapshot, window)
21879    }
21880
21881    pub fn display_to_pixel_point(
21882        &self,
21883        source: DisplayPoint,
21884        editor_snapshot: &EditorSnapshot,
21885        window: &mut Window,
21886    ) -> Option<gpui::Point<Pixels>> {
21887        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21888        let text_layout_details = self.text_layout_details(window);
21889        let scroll_top = text_layout_details
21890            .scroll_anchor
21891            .scroll_position(editor_snapshot)
21892            .y;
21893
21894        if source.row().as_f64() < scroll_top.floor() {
21895            return None;
21896        }
21897        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21898        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21899        Some(gpui::Point::new(source_x, source_y))
21900    }
21901
21902    pub fn has_visible_completions_menu(&self) -> bool {
21903        !self.edit_prediction_preview_is_active()
21904            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21905                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21906            })
21907    }
21908
21909    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21910        if self.mode.is_minimap() {
21911            return;
21912        }
21913        self.addons
21914            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21915    }
21916
21917    pub fn unregister_addon<T: Addon>(&mut self) {
21918        self.addons.remove(&std::any::TypeId::of::<T>());
21919    }
21920
21921    pub fn addon<T: Addon>(&self) -> Option<&T> {
21922        let type_id = std::any::TypeId::of::<T>();
21923        self.addons
21924            .get(&type_id)
21925            .and_then(|item| item.to_any().downcast_ref::<T>())
21926    }
21927
21928    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21929        let type_id = std::any::TypeId::of::<T>();
21930        self.addons
21931            .get_mut(&type_id)
21932            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21933    }
21934
21935    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21936        let text_layout_details = self.text_layout_details(window);
21937        let style = &text_layout_details.editor_style;
21938        let font_id = window.text_system().resolve_font(&style.text.font());
21939        let font_size = style.text.font_size.to_pixels(window.rem_size());
21940        let line_height = style.text.line_height_in_pixels(window.rem_size());
21941        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21942        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21943
21944        CharacterDimensions {
21945            em_width,
21946            em_advance,
21947            line_height,
21948        }
21949    }
21950
21951    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21952        self.load_diff_task.clone()
21953    }
21954
21955    fn read_metadata_from_db(
21956        &mut self,
21957        item_id: u64,
21958        workspace_id: WorkspaceId,
21959        window: &mut Window,
21960        cx: &mut Context<Editor>,
21961    ) {
21962        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21963            && !self.mode.is_minimap()
21964            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21965        {
21966            let buffer_snapshot = OnceCell::new();
21967
21968            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21969                && !folds.is_empty()
21970            {
21971                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21972                self.fold_ranges(
21973                    folds
21974                        .into_iter()
21975                        .map(|(start, end)| {
21976                            snapshot.clip_offset(start, Bias::Left)
21977                                ..snapshot.clip_offset(end, Bias::Right)
21978                        })
21979                        .collect(),
21980                    false,
21981                    window,
21982                    cx,
21983                );
21984            }
21985
21986            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21987                && !selections.is_empty()
21988            {
21989                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21990                // skip adding the initial selection to selection history
21991                self.selection_history.mode = SelectionHistoryMode::Skipping;
21992                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21993                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21994                        snapshot.clip_offset(start, Bias::Left)
21995                            ..snapshot.clip_offset(end, Bias::Right)
21996                    }));
21997                });
21998                self.selection_history.mode = SelectionHistoryMode::Normal;
21999            };
22000        }
22001
22002        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22003    }
22004
22005    fn update_lsp_data(
22006        &mut self,
22007        ignore_cache: bool,
22008        for_buffer: Option<BufferId>,
22009        window: &mut Window,
22010        cx: &mut Context<'_, Self>,
22011    ) {
22012        self.pull_diagnostics(for_buffer, window, cx);
22013        self.refresh_colors(ignore_cache, for_buffer, window, cx);
22014    }
22015}
22016
22017fn edit_for_markdown_paste<'a>(
22018    buffer: &MultiBufferSnapshot,
22019    range: Range<usize>,
22020    to_insert: &'a str,
22021    url: Option<url::Url>,
22022) -> (Range<usize>, Cow<'a, str>) {
22023    if url.is_none() {
22024        return (range, Cow::Borrowed(to_insert));
22025    };
22026
22027    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22028
22029    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22030        Cow::Borrowed(to_insert)
22031    } else {
22032        Cow::Owned(format!("[{old_text}]({to_insert})"))
22033    };
22034    (range, new_text)
22035}
22036
22037fn vim_enabled(cx: &App) -> bool {
22038    vim_mode_setting::VimModeSetting::try_get(cx)
22039        .map(|vim_mode| vim_mode.0)
22040        .unwrap_or(false)
22041}
22042
22043fn process_completion_for_edit(
22044    completion: &Completion,
22045    intent: CompletionIntent,
22046    buffer: &Entity<Buffer>,
22047    cursor_position: &text::Anchor,
22048    cx: &mut Context<Editor>,
22049) -> CompletionEdit {
22050    let buffer = buffer.read(cx);
22051    let buffer_snapshot = buffer.snapshot();
22052    let (snippet, new_text) = if completion.is_snippet() {
22053        let mut snippet_source = completion.new_text.clone();
22054        // Workaround for typescript language server issues so that methods don't expand within
22055        // strings and functions with type expressions. The previous point is used because the query
22056        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22057        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22058        let previous_point = if previous_point.column > 0 {
22059            cursor_position.to_previous_offset(&buffer_snapshot)
22060        } else {
22061            cursor_position.to_offset(&buffer_snapshot)
22062        };
22063        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22064            && scope.prefers_label_for_snippet_in_completion()
22065            && let Some(label) = completion.label()
22066            && matches!(
22067                completion.kind(),
22068                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22069            )
22070        {
22071            snippet_source = label;
22072        }
22073        match Snippet::parse(&snippet_source).log_err() {
22074            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22075            None => (None, completion.new_text.clone()),
22076        }
22077    } else {
22078        (None, completion.new_text.clone())
22079    };
22080
22081    let mut range_to_replace = {
22082        let replace_range = &completion.replace_range;
22083        if let CompletionSource::Lsp {
22084            insert_range: Some(insert_range),
22085            ..
22086        } = &completion.source
22087        {
22088            debug_assert_eq!(
22089                insert_range.start, replace_range.start,
22090                "insert_range and replace_range should start at the same position"
22091            );
22092            debug_assert!(
22093                insert_range
22094                    .start
22095                    .cmp(cursor_position, &buffer_snapshot)
22096                    .is_le(),
22097                "insert_range should start before or at cursor position"
22098            );
22099            debug_assert!(
22100                replace_range
22101                    .start
22102                    .cmp(cursor_position, &buffer_snapshot)
22103                    .is_le(),
22104                "replace_range should start before or at cursor position"
22105            );
22106
22107            let should_replace = match intent {
22108                CompletionIntent::CompleteWithInsert => false,
22109                CompletionIntent::CompleteWithReplace => true,
22110                CompletionIntent::Complete | CompletionIntent::Compose => {
22111                    let insert_mode =
22112                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22113                            .completions
22114                            .lsp_insert_mode;
22115                    match insert_mode {
22116                        LspInsertMode::Insert => false,
22117                        LspInsertMode::Replace => true,
22118                        LspInsertMode::ReplaceSubsequence => {
22119                            let mut text_to_replace = buffer.chars_for_range(
22120                                buffer.anchor_before(replace_range.start)
22121                                    ..buffer.anchor_after(replace_range.end),
22122                            );
22123                            let mut current_needle = text_to_replace.next();
22124                            for haystack_ch in completion.label.text.chars() {
22125                                if let Some(needle_ch) = current_needle
22126                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22127                                {
22128                                    current_needle = text_to_replace.next();
22129                                }
22130                            }
22131                            current_needle.is_none()
22132                        }
22133                        LspInsertMode::ReplaceSuffix => {
22134                            if replace_range
22135                                .end
22136                                .cmp(cursor_position, &buffer_snapshot)
22137                                .is_gt()
22138                            {
22139                                let range_after_cursor = *cursor_position..replace_range.end;
22140                                let text_after_cursor = buffer
22141                                    .text_for_range(
22142                                        buffer.anchor_before(range_after_cursor.start)
22143                                            ..buffer.anchor_after(range_after_cursor.end),
22144                                    )
22145                                    .collect::<String>()
22146                                    .to_ascii_lowercase();
22147                                completion
22148                                    .label
22149                                    .text
22150                                    .to_ascii_lowercase()
22151                                    .ends_with(&text_after_cursor)
22152                            } else {
22153                                true
22154                            }
22155                        }
22156                    }
22157                }
22158            };
22159
22160            if should_replace {
22161                replace_range.clone()
22162            } else {
22163                insert_range.clone()
22164            }
22165        } else {
22166            replace_range.clone()
22167        }
22168    };
22169
22170    if range_to_replace
22171        .end
22172        .cmp(cursor_position, &buffer_snapshot)
22173        .is_lt()
22174    {
22175        range_to_replace.end = *cursor_position;
22176    }
22177
22178    CompletionEdit {
22179        new_text,
22180        replace_range: range_to_replace.to_offset(buffer),
22181        snippet,
22182    }
22183}
22184
22185struct CompletionEdit {
22186    new_text: String,
22187    replace_range: Range<usize>,
22188    snippet: Option<Snippet>,
22189}
22190
22191fn insert_extra_newline_brackets(
22192    buffer: &MultiBufferSnapshot,
22193    range: Range<usize>,
22194    language: &language::LanguageScope,
22195) -> bool {
22196    let leading_whitespace_len = buffer
22197        .reversed_chars_at(range.start)
22198        .take_while(|c| c.is_whitespace() && *c != '\n')
22199        .map(|c| c.len_utf8())
22200        .sum::<usize>();
22201    let trailing_whitespace_len = buffer
22202        .chars_at(range.end)
22203        .take_while(|c| c.is_whitespace() && *c != '\n')
22204        .map(|c| c.len_utf8())
22205        .sum::<usize>();
22206    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22207
22208    language.brackets().any(|(pair, enabled)| {
22209        let pair_start = pair.start.trim_end();
22210        let pair_end = pair.end.trim_start();
22211
22212        enabled
22213            && pair.newline
22214            && buffer.contains_str_at(range.end, pair_end)
22215            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22216    })
22217}
22218
22219fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22220    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22221        [(buffer, range, _)] => (*buffer, range.clone()),
22222        _ => return false,
22223    };
22224    let pair = {
22225        let mut result: Option<BracketMatch> = None;
22226
22227        for pair in buffer
22228            .all_bracket_ranges(range.clone())
22229            .filter(move |pair| {
22230                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22231            })
22232        {
22233            let len = pair.close_range.end - pair.open_range.start;
22234
22235            if let Some(existing) = &result {
22236                let existing_len = existing.close_range.end - existing.open_range.start;
22237                if len > existing_len {
22238                    continue;
22239                }
22240            }
22241
22242            result = Some(pair);
22243        }
22244
22245        result
22246    };
22247    let Some(pair) = pair else {
22248        return false;
22249    };
22250    pair.newline_only
22251        && buffer
22252            .chars_for_range(pair.open_range.end..range.start)
22253            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22254            .all(|c| c.is_whitespace() && c != '\n')
22255}
22256
22257fn update_uncommitted_diff_for_buffer(
22258    editor: Entity<Editor>,
22259    project: &Entity<Project>,
22260    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22261    buffer: Entity<MultiBuffer>,
22262    cx: &mut App,
22263) -> Task<()> {
22264    let mut tasks = Vec::new();
22265    project.update(cx, |project, cx| {
22266        for buffer in buffers {
22267            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22268                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22269            }
22270        }
22271    });
22272    cx.spawn(async move |cx| {
22273        let diffs = future::join_all(tasks).await;
22274        if editor
22275            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22276            .unwrap_or(false)
22277        {
22278            return;
22279        }
22280
22281        buffer
22282            .update(cx, |buffer, cx| {
22283                for diff in diffs.into_iter().flatten() {
22284                    buffer.add_diff(diff, cx);
22285                }
22286            })
22287            .ok();
22288    })
22289}
22290
22291fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22292    let tab_size = tab_size.get() as usize;
22293    let mut width = offset;
22294
22295    for ch in text.chars() {
22296        width += if ch == '\t' {
22297            tab_size - (width % tab_size)
22298        } else {
22299            1
22300        };
22301    }
22302
22303    width - offset
22304}
22305
22306#[cfg(test)]
22307mod tests {
22308    use super::*;
22309
22310    #[test]
22311    fn test_string_size_with_expanded_tabs() {
22312        let nz = |val| NonZeroU32::new(val).unwrap();
22313        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22314        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22315        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22316        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22317        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22318        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22319        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22320        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22321    }
22322}
22323
22324/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22325struct WordBreakingTokenizer<'a> {
22326    input: &'a str,
22327}
22328
22329impl<'a> WordBreakingTokenizer<'a> {
22330    fn new(input: &'a str) -> Self {
22331        Self { input }
22332    }
22333}
22334
22335fn is_char_ideographic(ch: char) -> bool {
22336    use unicode_script::Script::*;
22337    use unicode_script::UnicodeScript;
22338    matches!(ch.script(), Han | Tangut | Yi)
22339}
22340
22341fn is_grapheme_ideographic(text: &str) -> bool {
22342    text.chars().any(is_char_ideographic)
22343}
22344
22345fn is_grapheme_whitespace(text: &str) -> bool {
22346    text.chars().any(|x| x.is_whitespace())
22347}
22348
22349fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22350    text.chars()
22351        .next()
22352        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22353}
22354
22355#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22356enum WordBreakToken<'a> {
22357    Word { token: &'a str, grapheme_len: usize },
22358    InlineWhitespace { token: &'a str, grapheme_len: usize },
22359    Newline,
22360}
22361
22362impl<'a> Iterator for WordBreakingTokenizer<'a> {
22363    /// Yields a span, the count of graphemes in the token, and whether it was
22364    /// whitespace. Note that it also breaks at word boundaries.
22365    type Item = WordBreakToken<'a>;
22366
22367    fn next(&mut self) -> Option<Self::Item> {
22368        use unicode_segmentation::UnicodeSegmentation;
22369        if self.input.is_empty() {
22370            return None;
22371        }
22372
22373        let mut iter = self.input.graphemes(true).peekable();
22374        let mut offset = 0;
22375        let mut grapheme_len = 0;
22376        if let Some(first_grapheme) = iter.next() {
22377            let is_newline = first_grapheme == "\n";
22378            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22379            offset += first_grapheme.len();
22380            grapheme_len += 1;
22381            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22382                if let Some(grapheme) = iter.peek().copied()
22383                    && should_stay_with_preceding_ideograph(grapheme)
22384                {
22385                    offset += grapheme.len();
22386                    grapheme_len += 1;
22387                }
22388            } else {
22389                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22390                let mut next_word_bound = words.peek().copied();
22391                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22392                    next_word_bound = words.next();
22393                }
22394                while let Some(grapheme) = iter.peek().copied() {
22395                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22396                        break;
22397                    };
22398                    if is_grapheme_whitespace(grapheme) != is_whitespace
22399                        || (grapheme == "\n") != is_newline
22400                    {
22401                        break;
22402                    };
22403                    offset += grapheme.len();
22404                    grapheme_len += 1;
22405                    iter.next();
22406                }
22407            }
22408            let token = &self.input[..offset];
22409            self.input = &self.input[offset..];
22410            if token == "\n" {
22411                Some(WordBreakToken::Newline)
22412            } else if is_whitespace {
22413                Some(WordBreakToken::InlineWhitespace {
22414                    token,
22415                    grapheme_len,
22416                })
22417            } else {
22418                Some(WordBreakToken::Word {
22419                    token,
22420                    grapheme_len,
22421                })
22422            }
22423        } else {
22424            None
22425        }
22426    }
22427}
22428
22429#[test]
22430fn test_word_breaking_tokenizer() {
22431    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22432        ("", &[]),
22433        ("  ", &[whitespace("  ", 2)]),
22434        ("Ʒ", &[word("Ʒ", 1)]),
22435        ("Ǽ", &[word("Ǽ", 1)]),
22436        ("", &[word("", 1)]),
22437        ("⋑⋑", &[word("⋑⋑", 2)]),
22438        (
22439            "原理,进而",
22440            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22441        ),
22442        (
22443            "hello world",
22444            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22445        ),
22446        (
22447            "hello, world",
22448            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22449        ),
22450        (
22451            "  hello world",
22452            &[
22453                whitespace("  ", 2),
22454                word("hello", 5),
22455                whitespace(" ", 1),
22456                word("world", 5),
22457            ],
22458        ),
22459        (
22460            "这是什么 \n 钢笔",
22461            &[
22462                word("", 1),
22463                word("", 1),
22464                word("", 1),
22465                word("", 1),
22466                whitespace(" ", 1),
22467                newline(),
22468                whitespace(" ", 1),
22469                word("", 1),
22470                word("", 1),
22471            ],
22472        ),
22473        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22474    ];
22475
22476    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22477        WordBreakToken::Word {
22478            token,
22479            grapheme_len,
22480        }
22481    }
22482
22483    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22484        WordBreakToken::InlineWhitespace {
22485            token,
22486            grapheme_len,
22487        }
22488    }
22489
22490    fn newline() -> WordBreakToken<'static> {
22491        WordBreakToken::Newline
22492    }
22493
22494    for (input, result) in tests {
22495        assert_eq!(
22496            WordBreakingTokenizer::new(input)
22497                .collect::<Vec<_>>()
22498                .as_slice(),
22499            *result,
22500        );
22501    }
22502}
22503
22504fn wrap_with_prefix(
22505    first_line_prefix: String,
22506    subsequent_lines_prefix: String,
22507    unwrapped_text: String,
22508    wrap_column: usize,
22509    tab_size: NonZeroU32,
22510    preserve_existing_whitespace: bool,
22511) -> String {
22512    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22513    let subsequent_lines_prefix_len =
22514        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22515    let mut wrapped_text = String::new();
22516    let mut current_line = first_line_prefix;
22517    let mut is_first_line = true;
22518
22519    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22520    let mut current_line_len = first_line_prefix_len;
22521    let mut in_whitespace = false;
22522    for token in tokenizer {
22523        let have_preceding_whitespace = in_whitespace;
22524        match token {
22525            WordBreakToken::Word {
22526                token,
22527                grapheme_len,
22528            } => {
22529                in_whitespace = false;
22530                let current_prefix_len = if is_first_line {
22531                    first_line_prefix_len
22532                } else {
22533                    subsequent_lines_prefix_len
22534                };
22535                if current_line_len + grapheme_len > wrap_column
22536                    && current_line_len != current_prefix_len
22537                {
22538                    wrapped_text.push_str(current_line.trim_end());
22539                    wrapped_text.push('\n');
22540                    is_first_line = false;
22541                    current_line = subsequent_lines_prefix.clone();
22542                    current_line_len = subsequent_lines_prefix_len;
22543                }
22544                current_line.push_str(token);
22545                current_line_len += grapheme_len;
22546            }
22547            WordBreakToken::InlineWhitespace {
22548                mut token,
22549                mut grapheme_len,
22550            } => {
22551                in_whitespace = true;
22552                if have_preceding_whitespace && !preserve_existing_whitespace {
22553                    continue;
22554                }
22555                if !preserve_existing_whitespace {
22556                    // Keep a single whitespace grapheme as-is
22557                    if let Some(first) =
22558                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22559                    {
22560                        token = first;
22561                    } else {
22562                        token = " ";
22563                    }
22564                    grapheme_len = 1;
22565                }
22566                let current_prefix_len = if is_first_line {
22567                    first_line_prefix_len
22568                } else {
22569                    subsequent_lines_prefix_len
22570                };
22571                if current_line_len + grapheme_len > wrap_column {
22572                    wrapped_text.push_str(current_line.trim_end());
22573                    wrapped_text.push('\n');
22574                    is_first_line = false;
22575                    current_line = subsequent_lines_prefix.clone();
22576                    current_line_len = subsequent_lines_prefix_len;
22577                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22578                    current_line.push_str(token);
22579                    current_line_len += grapheme_len;
22580                }
22581            }
22582            WordBreakToken::Newline => {
22583                in_whitespace = true;
22584                let current_prefix_len = if is_first_line {
22585                    first_line_prefix_len
22586                } else {
22587                    subsequent_lines_prefix_len
22588                };
22589                if preserve_existing_whitespace {
22590                    wrapped_text.push_str(current_line.trim_end());
22591                    wrapped_text.push('\n');
22592                    is_first_line = false;
22593                    current_line = subsequent_lines_prefix.clone();
22594                    current_line_len = subsequent_lines_prefix_len;
22595                } else if have_preceding_whitespace {
22596                    continue;
22597                } else if current_line_len + 1 > wrap_column
22598                    && current_line_len != current_prefix_len
22599                {
22600                    wrapped_text.push_str(current_line.trim_end());
22601                    wrapped_text.push('\n');
22602                    is_first_line = false;
22603                    current_line = subsequent_lines_prefix.clone();
22604                    current_line_len = subsequent_lines_prefix_len;
22605                } else if current_line_len != current_prefix_len {
22606                    current_line.push(' ');
22607                    current_line_len += 1;
22608                }
22609            }
22610        }
22611    }
22612
22613    if !current_line.is_empty() {
22614        wrapped_text.push_str(&current_line);
22615    }
22616    wrapped_text
22617}
22618
22619#[test]
22620fn test_wrap_with_prefix() {
22621    assert_eq!(
22622        wrap_with_prefix(
22623            "# ".to_string(),
22624            "# ".to_string(),
22625            "abcdefg".to_string(),
22626            4,
22627            NonZeroU32::new(4).unwrap(),
22628            false,
22629        ),
22630        "# abcdefg"
22631    );
22632    assert_eq!(
22633        wrap_with_prefix(
22634            "".to_string(),
22635            "".to_string(),
22636            "\thello world".to_string(),
22637            8,
22638            NonZeroU32::new(4).unwrap(),
22639            false,
22640        ),
22641        "hello\nworld"
22642    );
22643    assert_eq!(
22644        wrap_with_prefix(
22645            "// ".to_string(),
22646            "// ".to_string(),
22647            "xx \nyy zz aa bb cc".to_string(),
22648            12,
22649            NonZeroU32::new(4).unwrap(),
22650            false,
22651        ),
22652        "// xx yy zz\n// aa bb cc"
22653    );
22654    assert_eq!(
22655        wrap_with_prefix(
22656            String::new(),
22657            String::new(),
22658            "这是什么 \n 钢笔".to_string(),
22659            3,
22660            NonZeroU32::new(4).unwrap(),
22661            false,
22662        ),
22663        "这是什\n么 钢\n"
22664    );
22665    assert_eq!(
22666        wrap_with_prefix(
22667            String::new(),
22668            String::new(),
22669            format!("foo{}bar", '\u{2009}'), // thin space
22670            80,
22671            NonZeroU32::new(4).unwrap(),
22672            false,
22673        ),
22674        format!("foo{}bar", '\u{2009}')
22675    );
22676}
22677
22678pub trait CollaborationHub {
22679    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22680    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22681    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22682}
22683
22684impl CollaborationHub for Entity<Project> {
22685    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22686        self.read(cx).collaborators()
22687    }
22688
22689    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22690        self.read(cx).user_store().read(cx).participant_indices()
22691    }
22692
22693    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22694        let this = self.read(cx);
22695        let user_ids = this.collaborators().values().map(|c| c.user_id);
22696        this.user_store().read(cx).participant_names(user_ids, cx)
22697    }
22698}
22699
22700pub trait SemanticsProvider {
22701    fn hover(
22702        &self,
22703        buffer: &Entity<Buffer>,
22704        position: text::Anchor,
22705        cx: &mut App,
22706    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22707
22708    fn inline_values(
22709        &self,
22710        buffer_handle: Entity<Buffer>,
22711        range: Range<text::Anchor>,
22712        cx: &mut App,
22713    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22714
22715    fn inlay_hints(
22716        &self,
22717        buffer_handle: Entity<Buffer>,
22718        range: Range<text::Anchor>,
22719        cx: &mut App,
22720    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22721
22722    fn resolve_inlay_hint(
22723        &self,
22724        hint: InlayHint,
22725        buffer_handle: Entity<Buffer>,
22726        server_id: LanguageServerId,
22727        cx: &mut App,
22728    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22729
22730    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22731
22732    fn document_highlights(
22733        &self,
22734        buffer: &Entity<Buffer>,
22735        position: text::Anchor,
22736        cx: &mut App,
22737    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22738
22739    fn definitions(
22740        &self,
22741        buffer: &Entity<Buffer>,
22742        position: text::Anchor,
22743        kind: GotoDefinitionKind,
22744        cx: &mut App,
22745    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22746
22747    fn range_for_rename(
22748        &self,
22749        buffer: &Entity<Buffer>,
22750        position: text::Anchor,
22751        cx: &mut App,
22752    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22753
22754    fn perform_rename(
22755        &self,
22756        buffer: &Entity<Buffer>,
22757        position: text::Anchor,
22758        new_name: String,
22759        cx: &mut App,
22760    ) -> Option<Task<Result<ProjectTransaction>>>;
22761}
22762
22763pub trait CompletionProvider {
22764    fn completions(
22765        &self,
22766        excerpt_id: ExcerptId,
22767        buffer: &Entity<Buffer>,
22768        buffer_position: text::Anchor,
22769        trigger: CompletionContext,
22770        window: &mut Window,
22771        cx: &mut Context<Editor>,
22772    ) -> Task<Result<Vec<CompletionResponse>>>;
22773
22774    fn resolve_completions(
22775        &self,
22776        _buffer: Entity<Buffer>,
22777        _completion_indices: Vec<usize>,
22778        _completions: Rc<RefCell<Box<[Completion]>>>,
22779        _cx: &mut Context<Editor>,
22780    ) -> Task<Result<bool>> {
22781        Task::ready(Ok(false))
22782    }
22783
22784    fn apply_additional_edits_for_completion(
22785        &self,
22786        _buffer: Entity<Buffer>,
22787        _completions: Rc<RefCell<Box<[Completion]>>>,
22788        _completion_index: usize,
22789        _push_to_history: bool,
22790        _cx: &mut Context<Editor>,
22791    ) -> Task<Result<Option<language::Transaction>>> {
22792        Task::ready(Ok(None))
22793    }
22794
22795    fn is_completion_trigger(
22796        &self,
22797        buffer: &Entity<Buffer>,
22798        position: language::Anchor,
22799        text: &str,
22800        trigger_in_words: bool,
22801        menu_is_open: bool,
22802        cx: &mut Context<Editor>,
22803    ) -> bool;
22804
22805    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22806
22807    fn sort_completions(&self) -> bool {
22808        true
22809    }
22810
22811    fn filter_completions(&self) -> bool {
22812        true
22813    }
22814}
22815
22816pub trait CodeActionProvider {
22817    fn id(&self) -> Arc<str>;
22818
22819    fn code_actions(
22820        &self,
22821        buffer: &Entity<Buffer>,
22822        range: Range<text::Anchor>,
22823        window: &mut Window,
22824        cx: &mut App,
22825    ) -> Task<Result<Vec<CodeAction>>>;
22826
22827    fn apply_code_action(
22828        &self,
22829        buffer_handle: Entity<Buffer>,
22830        action: CodeAction,
22831        excerpt_id: ExcerptId,
22832        push_to_history: bool,
22833        window: &mut Window,
22834        cx: &mut App,
22835    ) -> Task<Result<ProjectTransaction>>;
22836}
22837
22838impl CodeActionProvider for Entity<Project> {
22839    fn id(&self) -> Arc<str> {
22840        "project".into()
22841    }
22842
22843    fn code_actions(
22844        &self,
22845        buffer: &Entity<Buffer>,
22846        range: Range<text::Anchor>,
22847        _window: &mut Window,
22848        cx: &mut App,
22849    ) -> Task<Result<Vec<CodeAction>>> {
22850        self.update(cx, |project, cx| {
22851            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22852            let code_actions = project.code_actions(buffer, range, None, cx);
22853            cx.background_spawn(async move {
22854                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22855                Ok(code_lens_actions
22856                    .context("code lens fetch")?
22857                    .into_iter()
22858                    .flatten()
22859                    .chain(
22860                        code_actions
22861                            .context("code action fetch")?
22862                            .into_iter()
22863                            .flatten(),
22864                    )
22865                    .collect())
22866            })
22867        })
22868    }
22869
22870    fn apply_code_action(
22871        &self,
22872        buffer_handle: Entity<Buffer>,
22873        action: CodeAction,
22874        _excerpt_id: ExcerptId,
22875        push_to_history: bool,
22876        _window: &mut Window,
22877        cx: &mut App,
22878    ) -> Task<Result<ProjectTransaction>> {
22879        self.update(cx, |project, cx| {
22880            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22881        })
22882    }
22883}
22884
22885fn snippet_completions(
22886    project: &Project,
22887    buffer: &Entity<Buffer>,
22888    buffer_position: text::Anchor,
22889    cx: &mut App,
22890) -> Task<Result<CompletionResponse>> {
22891    let languages = buffer.read(cx).languages_at(buffer_position);
22892    let snippet_store = project.snippets().read(cx);
22893
22894    let scopes: Vec<_> = languages
22895        .iter()
22896        .filter_map(|language| {
22897            let language_name = language.lsp_id();
22898            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22899
22900            if snippets.is_empty() {
22901                None
22902            } else {
22903                Some((language.default_scope(), snippets))
22904            }
22905        })
22906        .collect();
22907
22908    if scopes.is_empty() {
22909        return Task::ready(Ok(CompletionResponse {
22910            completions: vec![],
22911            display_options: CompletionDisplayOptions::default(),
22912            is_incomplete: false,
22913        }));
22914    }
22915
22916    let snapshot = buffer.read(cx).text_snapshot();
22917    let executor = cx.background_executor().clone();
22918
22919    cx.background_spawn(async move {
22920        let mut is_incomplete = false;
22921        let mut completions: Vec<Completion> = Vec::new();
22922        for (scope, snippets) in scopes.into_iter() {
22923            let classifier =
22924                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22925
22926            const MAX_WORD_PREFIX_LEN: usize = 128;
22927            let last_word: String = snapshot
22928                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22929                .take(MAX_WORD_PREFIX_LEN)
22930                .take_while(|c| classifier.is_word(*c))
22931                .collect::<String>()
22932                .chars()
22933                .rev()
22934                .collect();
22935
22936            if last_word.is_empty() {
22937                return Ok(CompletionResponse {
22938                    completions: vec![],
22939                    display_options: CompletionDisplayOptions::default(),
22940                    is_incomplete: true,
22941                });
22942            }
22943
22944            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22945            let to_lsp = |point: &text::Anchor| {
22946                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22947                point_to_lsp(end)
22948            };
22949            let lsp_end = to_lsp(&buffer_position);
22950
22951            let candidates = snippets
22952                .iter()
22953                .enumerate()
22954                .flat_map(|(ix, snippet)| {
22955                    snippet
22956                        .prefix
22957                        .iter()
22958                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22959                })
22960                .collect::<Vec<StringMatchCandidate>>();
22961
22962            const MAX_RESULTS: usize = 100;
22963            let mut matches = fuzzy::match_strings(
22964                &candidates,
22965                &last_word,
22966                last_word.chars().any(|c| c.is_uppercase()),
22967                true,
22968                MAX_RESULTS,
22969                &Default::default(),
22970                executor.clone(),
22971            )
22972            .await;
22973
22974            if matches.len() >= MAX_RESULTS {
22975                is_incomplete = true;
22976            }
22977
22978            // Remove all candidates where the query's start does not match the start of any word in the candidate
22979            if let Some(query_start) = last_word.chars().next() {
22980                matches.retain(|string_match| {
22981                    split_words(&string_match.string).any(|word| {
22982                        // Check that the first codepoint of the word as lowercase matches the first
22983                        // codepoint of the query as lowercase
22984                        word.chars()
22985                            .flat_map(|codepoint| codepoint.to_lowercase())
22986                            .zip(query_start.to_lowercase())
22987                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22988                    })
22989                });
22990            }
22991
22992            let matched_strings = matches
22993                .into_iter()
22994                .map(|m| m.string)
22995                .collect::<HashSet<_>>();
22996
22997            completions.extend(snippets.iter().filter_map(|snippet| {
22998                let matching_prefix = snippet
22999                    .prefix
23000                    .iter()
23001                    .find(|prefix| matched_strings.contains(*prefix))?;
23002                let start = as_offset - last_word.len();
23003                let start = snapshot.anchor_before(start);
23004                let range = start..buffer_position;
23005                let lsp_start = to_lsp(&start);
23006                let lsp_range = lsp::Range {
23007                    start: lsp_start,
23008                    end: lsp_end,
23009                };
23010                Some(Completion {
23011                    replace_range: range,
23012                    new_text: snippet.body.clone(),
23013                    source: CompletionSource::Lsp {
23014                        insert_range: None,
23015                        server_id: LanguageServerId(usize::MAX),
23016                        resolved: true,
23017                        lsp_completion: Box::new(lsp::CompletionItem {
23018                            label: snippet.prefix.first().unwrap().clone(),
23019                            kind: Some(CompletionItemKind::SNIPPET),
23020                            label_details: snippet.description.as_ref().map(|description| {
23021                                lsp::CompletionItemLabelDetails {
23022                                    detail: Some(description.clone()),
23023                                    description: None,
23024                                }
23025                            }),
23026                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23027                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23028                                lsp::InsertReplaceEdit {
23029                                    new_text: snippet.body.clone(),
23030                                    insert: lsp_range,
23031                                    replace: lsp_range,
23032                                },
23033                            )),
23034                            filter_text: Some(snippet.body.clone()),
23035                            sort_text: Some(char::MAX.to_string()),
23036                            ..lsp::CompletionItem::default()
23037                        }),
23038                        lsp_defaults: None,
23039                    },
23040                    label: CodeLabel {
23041                        text: matching_prefix.clone(),
23042                        runs: Vec::new(),
23043                        filter_range: 0..matching_prefix.len(),
23044                    },
23045                    icon_path: None,
23046                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23047                        single_line: snippet.name.clone().into(),
23048                        plain_text: snippet
23049                            .description
23050                            .clone()
23051                            .map(|description| description.into()),
23052                    }),
23053                    insert_text_mode: None,
23054                    confirm: None,
23055                })
23056            }))
23057        }
23058
23059        Ok(CompletionResponse {
23060            completions,
23061            display_options: CompletionDisplayOptions::default(),
23062            is_incomplete,
23063        })
23064    })
23065}
23066
23067impl CompletionProvider for Entity<Project> {
23068    fn completions(
23069        &self,
23070        _excerpt_id: ExcerptId,
23071        buffer: &Entity<Buffer>,
23072        buffer_position: text::Anchor,
23073        options: CompletionContext,
23074        _window: &mut Window,
23075        cx: &mut Context<Editor>,
23076    ) -> Task<Result<Vec<CompletionResponse>>> {
23077        self.update(cx, |project, cx| {
23078            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23079            let project_completions = project.completions(buffer, buffer_position, options, cx);
23080            cx.background_spawn(async move {
23081                let mut responses = project_completions.await?;
23082                let snippets = snippets.await?;
23083                if !snippets.completions.is_empty() {
23084                    responses.push(snippets);
23085                }
23086                Ok(responses)
23087            })
23088        })
23089    }
23090
23091    fn resolve_completions(
23092        &self,
23093        buffer: Entity<Buffer>,
23094        completion_indices: Vec<usize>,
23095        completions: Rc<RefCell<Box<[Completion]>>>,
23096        cx: &mut Context<Editor>,
23097    ) -> Task<Result<bool>> {
23098        self.update(cx, |project, cx| {
23099            project.lsp_store().update(cx, |lsp_store, cx| {
23100                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23101            })
23102        })
23103    }
23104
23105    fn apply_additional_edits_for_completion(
23106        &self,
23107        buffer: Entity<Buffer>,
23108        completions: Rc<RefCell<Box<[Completion]>>>,
23109        completion_index: usize,
23110        push_to_history: bool,
23111        cx: &mut Context<Editor>,
23112    ) -> Task<Result<Option<language::Transaction>>> {
23113        self.update(cx, |project, cx| {
23114            project.lsp_store().update(cx, |lsp_store, cx| {
23115                lsp_store.apply_additional_edits_for_completion(
23116                    buffer,
23117                    completions,
23118                    completion_index,
23119                    push_to_history,
23120                    cx,
23121                )
23122            })
23123        })
23124    }
23125
23126    fn is_completion_trigger(
23127        &self,
23128        buffer: &Entity<Buffer>,
23129        position: language::Anchor,
23130        text: &str,
23131        trigger_in_words: bool,
23132        menu_is_open: bool,
23133        cx: &mut Context<Editor>,
23134    ) -> bool {
23135        let mut chars = text.chars();
23136        let char = if let Some(char) = chars.next() {
23137            char
23138        } else {
23139            return false;
23140        };
23141        if chars.next().is_some() {
23142            return false;
23143        }
23144
23145        let buffer = buffer.read(cx);
23146        let snapshot = buffer.snapshot();
23147        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23148            return false;
23149        }
23150        let classifier = snapshot
23151            .char_classifier_at(position)
23152            .scope_context(Some(CharScopeContext::Completion));
23153        if trigger_in_words && classifier.is_word(char) {
23154            return true;
23155        }
23156
23157        buffer.completion_triggers().contains(text)
23158    }
23159}
23160
23161impl SemanticsProvider for Entity<Project> {
23162    fn hover(
23163        &self,
23164        buffer: &Entity<Buffer>,
23165        position: text::Anchor,
23166        cx: &mut App,
23167    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23168        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23169    }
23170
23171    fn document_highlights(
23172        &self,
23173        buffer: &Entity<Buffer>,
23174        position: text::Anchor,
23175        cx: &mut App,
23176    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23177        Some(self.update(cx, |project, cx| {
23178            project.document_highlights(buffer, position, cx)
23179        }))
23180    }
23181
23182    fn definitions(
23183        &self,
23184        buffer: &Entity<Buffer>,
23185        position: text::Anchor,
23186        kind: GotoDefinitionKind,
23187        cx: &mut App,
23188    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23189        Some(self.update(cx, |project, cx| match kind {
23190            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23191            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23192            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23193            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23194        }))
23195    }
23196
23197    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23198        self.update(cx, |project, cx| {
23199            if project
23200                .active_debug_session(cx)
23201                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23202            {
23203                return true;
23204            }
23205
23206            buffer.update(cx, |buffer, cx| {
23207                project.any_language_server_supports_inlay_hints(buffer, cx)
23208            })
23209        })
23210    }
23211
23212    fn inline_values(
23213        &self,
23214        buffer_handle: Entity<Buffer>,
23215        range: Range<text::Anchor>,
23216        cx: &mut App,
23217    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23218        self.update(cx, |project, cx| {
23219            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23220
23221            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23222        })
23223    }
23224
23225    fn inlay_hints(
23226        &self,
23227        buffer_handle: Entity<Buffer>,
23228        range: Range<text::Anchor>,
23229        cx: &mut App,
23230    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23231        Some(self.update(cx, |project, cx| {
23232            project.inlay_hints(buffer_handle, range, cx)
23233        }))
23234    }
23235
23236    fn resolve_inlay_hint(
23237        &self,
23238        hint: InlayHint,
23239        buffer_handle: Entity<Buffer>,
23240        server_id: LanguageServerId,
23241        cx: &mut App,
23242    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23243        Some(self.update(cx, |project, cx| {
23244            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23245        }))
23246    }
23247
23248    fn range_for_rename(
23249        &self,
23250        buffer: &Entity<Buffer>,
23251        position: text::Anchor,
23252        cx: &mut App,
23253    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23254        Some(self.update(cx, |project, cx| {
23255            let buffer = buffer.clone();
23256            let task = project.prepare_rename(buffer.clone(), position, cx);
23257            cx.spawn(async move |_, cx| {
23258                Ok(match task.await? {
23259                    PrepareRenameResponse::Success(range) => Some(range),
23260                    PrepareRenameResponse::InvalidPosition => None,
23261                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23262                        // Fallback on using TreeSitter info to determine identifier range
23263                        buffer.read_with(cx, |buffer, _| {
23264                            let snapshot = buffer.snapshot();
23265                            let (range, kind) = snapshot.surrounding_word(position, None);
23266                            if kind != Some(CharKind::Word) {
23267                                return None;
23268                            }
23269                            Some(
23270                                snapshot.anchor_before(range.start)
23271                                    ..snapshot.anchor_after(range.end),
23272                            )
23273                        })?
23274                    }
23275                })
23276            })
23277        }))
23278    }
23279
23280    fn perform_rename(
23281        &self,
23282        buffer: &Entity<Buffer>,
23283        position: text::Anchor,
23284        new_name: String,
23285        cx: &mut App,
23286    ) -> Option<Task<Result<ProjectTransaction>>> {
23287        Some(self.update(cx, |project, cx| {
23288            project.perform_rename(buffer.clone(), position, new_name, cx)
23289        }))
23290    }
23291}
23292
23293fn inlay_hint_settings(
23294    location: Anchor,
23295    snapshot: &MultiBufferSnapshot,
23296    cx: &mut Context<Editor>,
23297) -> InlayHintSettings {
23298    let file = snapshot.file_at(location);
23299    let language = snapshot.language_at(location).map(|l| l.name());
23300    language_settings(language, file, cx).inlay_hints
23301}
23302
23303fn consume_contiguous_rows(
23304    contiguous_row_selections: &mut Vec<Selection<Point>>,
23305    selection: &Selection<Point>,
23306    display_map: &DisplaySnapshot,
23307    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23308) -> (MultiBufferRow, MultiBufferRow) {
23309    contiguous_row_selections.push(selection.clone());
23310    let start_row = starting_row(selection, display_map);
23311    let mut end_row = ending_row(selection, display_map);
23312
23313    while let Some(next_selection) = selections.peek() {
23314        if next_selection.start.row <= end_row.0 {
23315            end_row = ending_row(next_selection, display_map);
23316            contiguous_row_selections.push(selections.next().unwrap().clone());
23317        } else {
23318            break;
23319        }
23320    }
23321    (start_row, end_row)
23322}
23323
23324fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23325    if selection.start.column > 0 {
23326        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23327    } else {
23328        MultiBufferRow(selection.start.row)
23329    }
23330}
23331
23332fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23333    if next_selection.end.column > 0 || next_selection.is_empty() {
23334        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23335    } else {
23336        MultiBufferRow(next_selection.end.row)
23337    }
23338}
23339
23340impl EditorSnapshot {
23341    pub fn remote_selections_in_range<'a>(
23342        &'a self,
23343        range: &'a Range<Anchor>,
23344        collaboration_hub: &dyn CollaborationHub,
23345        cx: &'a App,
23346    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23347        let participant_names = collaboration_hub.user_names(cx);
23348        let participant_indices = collaboration_hub.user_participant_indices(cx);
23349        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23350        let collaborators_by_replica_id = collaborators_by_peer_id
23351            .values()
23352            .map(|collaborator| (collaborator.replica_id, collaborator))
23353            .collect::<HashMap<_, _>>();
23354        self.buffer_snapshot()
23355            .selections_in_range(range, false)
23356            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23357                if replica_id == AGENT_REPLICA_ID {
23358                    Some(RemoteSelection {
23359                        replica_id,
23360                        selection,
23361                        cursor_shape,
23362                        line_mode,
23363                        collaborator_id: CollaboratorId::Agent,
23364                        user_name: Some("Agent".into()),
23365                        color: cx.theme().players().agent(),
23366                    })
23367                } else {
23368                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23369                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23370                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23371                    Some(RemoteSelection {
23372                        replica_id,
23373                        selection,
23374                        cursor_shape,
23375                        line_mode,
23376                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23377                        user_name,
23378                        color: if let Some(index) = participant_index {
23379                            cx.theme().players().color_for_participant(index.0)
23380                        } else {
23381                            cx.theme().players().absent()
23382                        },
23383                    })
23384                }
23385            })
23386    }
23387
23388    pub fn hunks_for_ranges(
23389        &self,
23390        ranges: impl IntoIterator<Item = Range<Point>>,
23391    ) -> Vec<MultiBufferDiffHunk> {
23392        let mut hunks = Vec::new();
23393        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23394            HashMap::default();
23395        for query_range in ranges {
23396            let query_rows =
23397                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23398            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23399                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23400            ) {
23401                // Include deleted hunks that are adjacent to the query range, because
23402                // otherwise they would be missed.
23403                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23404                if hunk.status().is_deleted() {
23405                    intersects_range |= hunk.row_range.start == query_rows.end;
23406                    intersects_range |= hunk.row_range.end == query_rows.start;
23407                }
23408                if intersects_range {
23409                    if !processed_buffer_rows
23410                        .entry(hunk.buffer_id)
23411                        .or_default()
23412                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23413                    {
23414                        continue;
23415                    }
23416                    hunks.push(hunk);
23417                }
23418            }
23419        }
23420
23421        hunks
23422    }
23423
23424    fn display_diff_hunks_for_rows<'a>(
23425        &'a self,
23426        display_rows: Range<DisplayRow>,
23427        folded_buffers: &'a HashSet<BufferId>,
23428    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23429        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23430        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23431
23432        self.buffer_snapshot()
23433            .diff_hunks_in_range(buffer_start..buffer_end)
23434            .filter_map(|hunk| {
23435                if folded_buffers.contains(&hunk.buffer_id) {
23436                    return None;
23437                }
23438
23439                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23440                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23441
23442                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23443                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23444
23445                let display_hunk = if hunk_display_start.column() != 0 {
23446                    DisplayDiffHunk::Folded {
23447                        display_row: hunk_display_start.row(),
23448                    }
23449                } else {
23450                    let mut end_row = hunk_display_end.row();
23451                    if hunk_display_end.column() > 0 {
23452                        end_row.0 += 1;
23453                    }
23454                    let is_created_file = hunk.is_created_file();
23455                    DisplayDiffHunk::Unfolded {
23456                        status: hunk.status(),
23457                        diff_base_byte_range: hunk.diff_base_byte_range,
23458                        display_row_range: hunk_display_start.row()..end_row,
23459                        multi_buffer_range: Anchor::range_in_buffer(
23460                            hunk.excerpt_id,
23461                            hunk.buffer_id,
23462                            hunk.buffer_range,
23463                        ),
23464                        is_created_file,
23465                    }
23466                };
23467
23468                Some(display_hunk)
23469            })
23470    }
23471
23472    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23473        self.display_snapshot
23474            .buffer_snapshot()
23475            .language_at(position)
23476    }
23477
23478    pub fn is_focused(&self) -> bool {
23479        self.is_focused
23480    }
23481
23482    pub fn placeholder_text(&self) -> Option<String> {
23483        self.placeholder_display_snapshot
23484            .as_ref()
23485            .map(|display_map| display_map.text())
23486    }
23487
23488    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23489        self.scroll_anchor.scroll_position(&self.display_snapshot)
23490    }
23491
23492    fn gutter_dimensions(
23493        &self,
23494        font_id: FontId,
23495        font_size: Pixels,
23496        max_line_number_width: Pixels,
23497        cx: &App,
23498    ) -> Option<GutterDimensions> {
23499        if !self.show_gutter {
23500            return None;
23501        }
23502
23503        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23504        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23505
23506        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23507            matches!(
23508                ProjectSettings::get_global(cx).git.git_gutter,
23509                GitGutterSetting::TrackedFiles
23510            )
23511        });
23512        let gutter_settings = EditorSettings::get_global(cx).gutter;
23513        let show_line_numbers = self
23514            .show_line_numbers
23515            .unwrap_or(gutter_settings.line_numbers);
23516        let line_gutter_width = if show_line_numbers {
23517            // Avoid flicker-like gutter resizes when the line number gains another digit by
23518            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23519            let min_width_for_number_on_gutter =
23520                ch_advance * gutter_settings.min_line_number_digits as f32;
23521            max_line_number_width.max(min_width_for_number_on_gutter)
23522        } else {
23523            0.0.into()
23524        };
23525
23526        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23527        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23528
23529        let git_blame_entries_width =
23530            self.git_blame_gutter_max_author_length
23531                .map(|max_author_length| {
23532                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23533                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23534
23535                    /// The number of characters to dedicate to gaps and margins.
23536                    const SPACING_WIDTH: usize = 4;
23537
23538                    let max_char_count = max_author_length.min(renderer.max_author_length())
23539                        + ::git::SHORT_SHA_LENGTH
23540                        + MAX_RELATIVE_TIMESTAMP.len()
23541                        + SPACING_WIDTH;
23542
23543                    ch_advance * max_char_count
23544                });
23545
23546        let is_singleton = self.buffer_snapshot().is_singleton();
23547
23548        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23549        left_padding += if !is_singleton {
23550            ch_width * 4.0
23551        } else if show_runnables || show_breakpoints {
23552            ch_width * 3.0
23553        } else if show_git_gutter && show_line_numbers {
23554            ch_width * 2.0
23555        } else if show_git_gutter || show_line_numbers {
23556            ch_width
23557        } else {
23558            px(0.)
23559        };
23560
23561        let shows_folds = is_singleton && gutter_settings.folds;
23562
23563        let right_padding = if shows_folds && show_line_numbers {
23564            ch_width * 4.0
23565        } else if shows_folds || (!is_singleton && show_line_numbers) {
23566            ch_width * 3.0
23567        } else if show_line_numbers {
23568            ch_width
23569        } else {
23570            px(0.)
23571        };
23572
23573        Some(GutterDimensions {
23574            left_padding,
23575            right_padding,
23576            width: line_gutter_width + left_padding + right_padding,
23577            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23578            git_blame_entries_width,
23579        })
23580    }
23581
23582    pub fn render_crease_toggle(
23583        &self,
23584        buffer_row: MultiBufferRow,
23585        row_contains_cursor: bool,
23586        editor: Entity<Editor>,
23587        window: &mut Window,
23588        cx: &mut App,
23589    ) -> Option<AnyElement> {
23590        let folded = self.is_line_folded(buffer_row);
23591        let mut is_foldable = false;
23592
23593        if let Some(crease) = self
23594            .crease_snapshot
23595            .query_row(buffer_row, self.buffer_snapshot())
23596        {
23597            is_foldable = true;
23598            match crease {
23599                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23600                    if let Some(render_toggle) = render_toggle {
23601                        let toggle_callback =
23602                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23603                                if folded {
23604                                    editor.update(cx, |editor, cx| {
23605                                        editor.fold_at(buffer_row, window, cx)
23606                                    });
23607                                } else {
23608                                    editor.update(cx, |editor, cx| {
23609                                        editor.unfold_at(buffer_row, window, cx)
23610                                    });
23611                                }
23612                            });
23613                        return Some((render_toggle)(
23614                            buffer_row,
23615                            folded,
23616                            toggle_callback,
23617                            window,
23618                            cx,
23619                        ));
23620                    }
23621                }
23622            }
23623        }
23624
23625        is_foldable |= self.starts_indent(buffer_row);
23626
23627        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23628            Some(
23629                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23630                    .toggle_state(folded)
23631                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23632                        if folded {
23633                            this.unfold_at(buffer_row, window, cx);
23634                        } else {
23635                            this.fold_at(buffer_row, window, cx);
23636                        }
23637                    }))
23638                    .into_any_element(),
23639            )
23640        } else {
23641            None
23642        }
23643    }
23644
23645    pub fn render_crease_trailer(
23646        &self,
23647        buffer_row: MultiBufferRow,
23648        window: &mut Window,
23649        cx: &mut App,
23650    ) -> Option<AnyElement> {
23651        let folded = self.is_line_folded(buffer_row);
23652        if let Crease::Inline { render_trailer, .. } = self
23653            .crease_snapshot
23654            .query_row(buffer_row, self.buffer_snapshot())?
23655        {
23656            let render_trailer = render_trailer.as_ref()?;
23657            Some(render_trailer(buffer_row, folded, window, cx))
23658        } else {
23659            None
23660        }
23661    }
23662}
23663
23664impl Deref for EditorSnapshot {
23665    type Target = DisplaySnapshot;
23666
23667    fn deref(&self) -> &Self::Target {
23668        &self.display_snapshot
23669    }
23670}
23671
23672#[derive(Clone, Debug, PartialEq, Eq)]
23673pub enum EditorEvent {
23674    InputIgnored {
23675        text: Arc<str>,
23676    },
23677    InputHandled {
23678        utf16_range_to_replace: Option<Range<isize>>,
23679        text: Arc<str>,
23680    },
23681    ExcerptsAdded {
23682        buffer: Entity<Buffer>,
23683        predecessor: ExcerptId,
23684        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23685    },
23686    ExcerptsRemoved {
23687        ids: Vec<ExcerptId>,
23688        removed_buffer_ids: Vec<BufferId>,
23689    },
23690    BufferFoldToggled {
23691        ids: Vec<ExcerptId>,
23692        folded: bool,
23693    },
23694    ExcerptsEdited {
23695        ids: Vec<ExcerptId>,
23696    },
23697    ExcerptsExpanded {
23698        ids: Vec<ExcerptId>,
23699    },
23700    BufferEdited,
23701    Edited {
23702        transaction_id: clock::Lamport,
23703    },
23704    Reparsed(BufferId),
23705    Focused,
23706    FocusedIn,
23707    Blurred,
23708    DirtyChanged,
23709    Saved,
23710    TitleChanged,
23711    SelectionsChanged {
23712        local: bool,
23713    },
23714    ScrollPositionChanged {
23715        local: bool,
23716        autoscroll: bool,
23717    },
23718    TransactionUndone {
23719        transaction_id: clock::Lamport,
23720    },
23721    TransactionBegun {
23722        transaction_id: clock::Lamport,
23723    },
23724    CursorShapeChanged,
23725    BreadcrumbsChanged,
23726    PushedToNavHistory {
23727        anchor: Anchor,
23728        is_deactivate: bool,
23729    },
23730}
23731
23732impl EventEmitter<EditorEvent> for Editor {}
23733
23734impl Focusable for Editor {
23735    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23736        self.focus_handle.clone()
23737    }
23738}
23739
23740impl Render for Editor {
23741    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23742        let settings = ThemeSettings::get_global(cx);
23743
23744        let mut text_style = match self.mode {
23745            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23746                color: cx.theme().colors().editor_foreground,
23747                font_family: settings.ui_font.family.clone(),
23748                font_features: settings.ui_font.features.clone(),
23749                font_fallbacks: settings.ui_font.fallbacks.clone(),
23750                font_size: rems(0.875).into(),
23751                font_weight: settings.ui_font.weight,
23752                line_height: relative(settings.buffer_line_height.value()),
23753                ..Default::default()
23754            },
23755            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23756                color: cx.theme().colors().editor_foreground,
23757                font_family: settings.buffer_font.family.clone(),
23758                font_features: settings.buffer_font.features.clone(),
23759                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23760                font_size: settings.buffer_font_size(cx).into(),
23761                font_weight: settings.buffer_font.weight,
23762                line_height: relative(settings.buffer_line_height.value()),
23763                ..Default::default()
23764            },
23765        };
23766        if let Some(text_style_refinement) = &self.text_style_refinement {
23767            text_style.refine(text_style_refinement)
23768        }
23769
23770        let background = match self.mode {
23771            EditorMode::SingleLine => cx.theme().system().transparent,
23772            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23773            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23774            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23775        };
23776
23777        EditorElement::new(
23778            &cx.entity(),
23779            EditorStyle {
23780                background,
23781                border: cx.theme().colors().border,
23782                local_player: cx.theme().players().local(),
23783                text: text_style,
23784                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23785                syntax: cx.theme().syntax().clone(),
23786                status: cx.theme().status().clone(),
23787                inlay_hints_style: make_inlay_hints_style(cx),
23788                edit_prediction_styles: make_suggestion_styles(cx),
23789                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23790                show_underlines: self.diagnostics_enabled(),
23791            },
23792        )
23793    }
23794}
23795
23796impl EntityInputHandler for Editor {
23797    fn text_for_range(
23798        &mut self,
23799        range_utf16: Range<usize>,
23800        adjusted_range: &mut Option<Range<usize>>,
23801        _: &mut Window,
23802        cx: &mut Context<Self>,
23803    ) -> Option<String> {
23804        let snapshot = self.buffer.read(cx).read(cx);
23805        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23806        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23807        if (start.0..end.0) != range_utf16 {
23808            adjusted_range.replace(start.0..end.0);
23809        }
23810        Some(snapshot.text_for_range(start..end).collect())
23811    }
23812
23813    fn selected_text_range(
23814        &mut self,
23815        ignore_disabled_input: bool,
23816        _: &mut Window,
23817        cx: &mut Context<Self>,
23818    ) -> Option<UTF16Selection> {
23819        // Prevent the IME menu from appearing when holding down an alphabetic key
23820        // while input is disabled.
23821        if !ignore_disabled_input && !self.input_enabled {
23822            return None;
23823        }
23824
23825        let selection = self.selections.newest::<OffsetUtf16>(cx);
23826        let range = selection.range();
23827
23828        Some(UTF16Selection {
23829            range: range.start.0..range.end.0,
23830            reversed: selection.reversed,
23831        })
23832    }
23833
23834    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23835        let snapshot = self.buffer.read(cx).read(cx);
23836        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23837        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23838    }
23839
23840    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23841        self.clear_highlights::<InputComposition>(cx);
23842        self.ime_transaction.take();
23843    }
23844
23845    fn replace_text_in_range(
23846        &mut self,
23847        range_utf16: Option<Range<usize>>,
23848        text: &str,
23849        window: &mut Window,
23850        cx: &mut Context<Self>,
23851    ) {
23852        if !self.input_enabled {
23853            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23854            return;
23855        }
23856
23857        self.transact(window, cx, |this, window, cx| {
23858            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23859                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23860                Some(this.selection_replacement_ranges(range_utf16, cx))
23861            } else {
23862                this.marked_text_ranges(cx)
23863            };
23864
23865            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23866                let newest_selection_id = this.selections.newest_anchor().id;
23867                this.selections
23868                    .all::<OffsetUtf16>(cx)
23869                    .iter()
23870                    .zip(ranges_to_replace.iter())
23871                    .find_map(|(selection, range)| {
23872                        if selection.id == newest_selection_id {
23873                            Some(
23874                                (range.start.0 as isize - selection.head().0 as isize)
23875                                    ..(range.end.0 as isize - selection.head().0 as isize),
23876                            )
23877                        } else {
23878                            None
23879                        }
23880                    })
23881            });
23882
23883            cx.emit(EditorEvent::InputHandled {
23884                utf16_range_to_replace: range_to_replace,
23885                text: text.into(),
23886            });
23887
23888            if let Some(new_selected_ranges) = new_selected_ranges {
23889                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23890                    selections.select_ranges(new_selected_ranges)
23891                });
23892                this.backspace(&Default::default(), window, cx);
23893            }
23894
23895            this.handle_input(text, window, cx);
23896        });
23897
23898        if let Some(transaction) = self.ime_transaction {
23899            self.buffer.update(cx, |buffer, cx| {
23900                buffer.group_until_transaction(transaction, cx);
23901            });
23902        }
23903
23904        self.unmark_text(window, cx);
23905    }
23906
23907    fn replace_and_mark_text_in_range(
23908        &mut self,
23909        range_utf16: Option<Range<usize>>,
23910        text: &str,
23911        new_selected_range_utf16: Option<Range<usize>>,
23912        window: &mut Window,
23913        cx: &mut Context<Self>,
23914    ) {
23915        if !self.input_enabled {
23916            return;
23917        }
23918
23919        let transaction = self.transact(window, cx, |this, window, cx| {
23920            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23921                let snapshot = this.buffer.read(cx).read(cx);
23922                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23923                    for marked_range in &mut marked_ranges {
23924                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23925                        marked_range.start.0 += relative_range_utf16.start;
23926                        marked_range.start =
23927                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23928                        marked_range.end =
23929                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23930                    }
23931                }
23932                Some(marked_ranges)
23933            } else if let Some(range_utf16) = range_utf16 {
23934                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23935                Some(this.selection_replacement_ranges(range_utf16, cx))
23936            } else {
23937                None
23938            };
23939
23940            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23941                let newest_selection_id = this.selections.newest_anchor().id;
23942                this.selections
23943                    .all::<OffsetUtf16>(cx)
23944                    .iter()
23945                    .zip(ranges_to_replace.iter())
23946                    .find_map(|(selection, range)| {
23947                        if selection.id == newest_selection_id {
23948                            Some(
23949                                (range.start.0 as isize - selection.head().0 as isize)
23950                                    ..(range.end.0 as isize - selection.head().0 as isize),
23951                            )
23952                        } else {
23953                            None
23954                        }
23955                    })
23956            });
23957
23958            cx.emit(EditorEvent::InputHandled {
23959                utf16_range_to_replace: range_to_replace,
23960                text: text.into(),
23961            });
23962
23963            if let Some(ranges) = ranges_to_replace {
23964                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23965                    s.select_ranges(ranges)
23966                });
23967            }
23968
23969            let marked_ranges = {
23970                let snapshot = this.buffer.read(cx).read(cx);
23971                this.selections
23972                    .disjoint_anchors_arc()
23973                    .iter()
23974                    .map(|selection| {
23975                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23976                    })
23977                    .collect::<Vec<_>>()
23978            };
23979
23980            if text.is_empty() {
23981                this.unmark_text(window, cx);
23982            } else {
23983                this.highlight_text::<InputComposition>(
23984                    marked_ranges.clone(),
23985                    HighlightStyle {
23986                        underline: Some(UnderlineStyle {
23987                            thickness: px(1.),
23988                            color: None,
23989                            wavy: false,
23990                        }),
23991                        ..Default::default()
23992                    },
23993                    cx,
23994                );
23995            }
23996
23997            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23998            let use_autoclose = this.use_autoclose;
23999            let use_auto_surround = this.use_auto_surround;
24000            this.set_use_autoclose(false);
24001            this.set_use_auto_surround(false);
24002            this.handle_input(text, window, cx);
24003            this.set_use_autoclose(use_autoclose);
24004            this.set_use_auto_surround(use_auto_surround);
24005
24006            if let Some(new_selected_range) = new_selected_range_utf16 {
24007                let snapshot = this.buffer.read(cx).read(cx);
24008                let new_selected_ranges = marked_ranges
24009                    .into_iter()
24010                    .map(|marked_range| {
24011                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24012                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24013                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24014                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24015                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24016                    })
24017                    .collect::<Vec<_>>();
24018
24019                drop(snapshot);
24020                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24021                    selections.select_ranges(new_selected_ranges)
24022                });
24023            }
24024        });
24025
24026        self.ime_transaction = self.ime_transaction.or(transaction);
24027        if let Some(transaction) = self.ime_transaction {
24028            self.buffer.update(cx, |buffer, cx| {
24029                buffer.group_until_transaction(transaction, cx);
24030            });
24031        }
24032
24033        if self.text_highlights::<InputComposition>(cx).is_none() {
24034            self.ime_transaction.take();
24035        }
24036    }
24037
24038    fn bounds_for_range(
24039        &mut self,
24040        range_utf16: Range<usize>,
24041        element_bounds: gpui::Bounds<Pixels>,
24042        window: &mut Window,
24043        cx: &mut Context<Self>,
24044    ) -> Option<gpui::Bounds<Pixels>> {
24045        let text_layout_details = self.text_layout_details(window);
24046        let CharacterDimensions {
24047            em_width,
24048            em_advance,
24049            line_height,
24050        } = self.character_dimensions(window);
24051
24052        let snapshot = self.snapshot(window, cx);
24053        let scroll_position = snapshot.scroll_position();
24054        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24055
24056        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24057        let x = Pixels::from(
24058            ScrollOffset::from(
24059                snapshot.x_for_display_point(start, &text_layout_details)
24060                    + self.gutter_dimensions.full_width(),
24061            ) - scroll_left,
24062        );
24063        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24064
24065        Some(Bounds {
24066            origin: element_bounds.origin + point(x, y),
24067            size: size(em_width, line_height),
24068        })
24069    }
24070
24071    fn character_index_for_point(
24072        &mut self,
24073        point: gpui::Point<Pixels>,
24074        _window: &mut Window,
24075        _cx: &mut Context<Self>,
24076    ) -> Option<usize> {
24077        let position_map = self.last_position_map.as_ref()?;
24078        if !position_map.text_hitbox.contains(&point) {
24079            return None;
24080        }
24081        let display_point = position_map.point_for_position(point).previous_valid;
24082        let anchor = position_map
24083            .snapshot
24084            .display_point_to_anchor(display_point, Bias::Left);
24085        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24086        Some(utf16_offset.0)
24087    }
24088}
24089
24090trait SelectionExt {
24091    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24092    fn spanned_rows(
24093        &self,
24094        include_end_if_at_line_start: bool,
24095        map: &DisplaySnapshot,
24096    ) -> Range<MultiBufferRow>;
24097}
24098
24099impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24100    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24101        let start = self
24102            .start
24103            .to_point(map.buffer_snapshot())
24104            .to_display_point(map);
24105        let end = self
24106            .end
24107            .to_point(map.buffer_snapshot())
24108            .to_display_point(map);
24109        if self.reversed {
24110            end..start
24111        } else {
24112            start..end
24113        }
24114    }
24115
24116    fn spanned_rows(
24117        &self,
24118        include_end_if_at_line_start: bool,
24119        map: &DisplaySnapshot,
24120    ) -> Range<MultiBufferRow> {
24121        let start = self.start.to_point(map.buffer_snapshot());
24122        let mut end = self.end.to_point(map.buffer_snapshot());
24123        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24124            end.row -= 1;
24125        }
24126
24127        let buffer_start = map.prev_line_boundary(start).0;
24128        let buffer_end = map.next_line_boundary(end).0;
24129        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24130    }
24131}
24132
24133impl<T: InvalidationRegion> InvalidationStack<T> {
24134    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24135    where
24136        S: Clone + ToOffset,
24137    {
24138        while let Some(region) = self.last() {
24139            let all_selections_inside_invalidation_ranges =
24140                if selections.len() == region.ranges().len() {
24141                    selections
24142                        .iter()
24143                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24144                        .all(|(selection, invalidation_range)| {
24145                            let head = selection.head().to_offset(buffer);
24146                            invalidation_range.start <= head && invalidation_range.end >= head
24147                        })
24148                } else {
24149                    false
24150                };
24151
24152            if all_selections_inside_invalidation_ranges {
24153                break;
24154            } else {
24155                self.pop();
24156            }
24157        }
24158    }
24159}
24160
24161impl<T> Default for InvalidationStack<T> {
24162    fn default() -> Self {
24163        Self(Default::default())
24164    }
24165}
24166
24167impl<T> Deref for InvalidationStack<T> {
24168    type Target = Vec<T>;
24169
24170    fn deref(&self) -> &Self::Target {
24171        &self.0
24172    }
24173}
24174
24175impl<T> DerefMut for InvalidationStack<T> {
24176    fn deref_mut(&mut self) -> &mut Self::Target {
24177        &mut self.0
24178    }
24179}
24180
24181impl InvalidationRegion for SnippetState {
24182    fn ranges(&self) -> &[Range<Anchor>] {
24183        &self.ranges[self.active_index]
24184    }
24185}
24186
24187fn edit_prediction_edit_text(
24188    current_snapshot: &BufferSnapshot,
24189    edits: &[(Range<Anchor>, String)],
24190    edit_preview: &EditPreview,
24191    include_deletions: bool,
24192    cx: &App,
24193) -> HighlightedText {
24194    let edits = edits
24195        .iter()
24196        .map(|(anchor, text)| {
24197            (
24198                anchor.start.text_anchor..anchor.end.text_anchor,
24199                text.clone(),
24200            )
24201        })
24202        .collect::<Vec<_>>();
24203
24204    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24205}
24206
24207fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24208    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24209    // Just show the raw edit text with basic styling
24210    let mut text = String::new();
24211    let mut highlights = Vec::new();
24212
24213    let insertion_highlight_style = HighlightStyle {
24214        color: Some(cx.theme().colors().text),
24215        ..Default::default()
24216    };
24217
24218    for (_, edit_text) in edits {
24219        let start_offset = text.len();
24220        text.push_str(edit_text);
24221        let end_offset = text.len();
24222
24223        if start_offset < end_offset {
24224            highlights.push((start_offset..end_offset, insertion_highlight_style));
24225        }
24226    }
24227
24228    HighlightedText {
24229        text: text.into(),
24230        highlights,
24231    }
24232}
24233
24234pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24235    match severity {
24236        lsp::DiagnosticSeverity::ERROR => colors.error,
24237        lsp::DiagnosticSeverity::WARNING => colors.warning,
24238        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24239        lsp::DiagnosticSeverity::HINT => colors.info,
24240        _ => colors.ignored,
24241    }
24242}
24243
24244pub fn styled_runs_for_code_label<'a>(
24245    label: &'a CodeLabel,
24246    syntax_theme: &'a theme::SyntaxTheme,
24247) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24248    let fade_out = HighlightStyle {
24249        fade_out: Some(0.35),
24250        ..Default::default()
24251    };
24252
24253    let mut prev_end = label.filter_range.end;
24254    label
24255        .runs
24256        .iter()
24257        .enumerate()
24258        .flat_map(move |(ix, (range, highlight_id))| {
24259            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24260                style
24261            } else {
24262                return Default::default();
24263            };
24264            let muted_style = style.highlight(fade_out);
24265
24266            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24267            if range.start >= label.filter_range.end {
24268                if range.start > prev_end {
24269                    runs.push((prev_end..range.start, fade_out));
24270                }
24271                runs.push((range.clone(), muted_style));
24272            } else if range.end <= label.filter_range.end {
24273                runs.push((range.clone(), style));
24274            } else {
24275                runs.push((range.start..label.filter_range.end, style));
24276                runs.push((label.filter_range.end..range.end, muted_style));
24277            }
24278            prev_end = cmp::max(prev_end, range.end);
24279
24280            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24281                runs.push((prev_end..label.text.len(), fade_out));
24282            }
24283
24284            runs
24285        })
24286}
24287
24288pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24289    let mut prev_index = 0;
24290    let mut prev_codepoint: Option<char> = None;
24291    text.char_indices()
24292        .chain([(text.len(), '\0')])
24293        .filter_map(move |(index, codepoint)| {
24294            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24295            let is_boundary = index == text.len()
24296                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24297                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24298            if is_boundary {
24299                let chunk = &text[prev_index..index];
24300                prev_index = index;
24301                Some(chunk)
24302            } else {
24303                None
24304            }
24305        })
24306}
24307
24308pub trait RangeToAnchorExt: Sized {
24309    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24310
24311    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24312        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24313        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24314    }
24315}
24316
24317impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24318    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24319        let start_offset = self.start.to_offset(snapshot);
24320        let end_offset = self.end.to_offset(snapshot);
24321        if start_offset == end_offset {
24322            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24323        } else {
24324            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24325        }
24326    }
24327}
24328
24329pub trait RowExt {
24330    fn as_f64(&self) -> f64;
24331
24332    fn next_row(&self) -> Self;
24333
24334    fn previous_row(&self) -> Self;
24335
24336    fn minus(&self, other: Self) -> u32;
24337}
24338
24339impl RowExt for DisplayRow {
24340    fn as_f64(&self) -> f64 {
24341        self.0 as _
24342    }
24343
24344    fn next_row(&self) -> Self {
24345        Self(self.0 + 1)
24346    }
24347
24348    fn previous_row(&self) -> Self {
24349        Self(self.0.saturating_sub(1))
24350    }
24351
24352    fn minus(&self, other: Self) -> u32 {
24353        self.0 - other.0
24354    }
24355}
24356
24357impl RowExt for MultiBufferRow {
24358    fn as_f64(&self) -> f64 {
24359        self.0 as _
24360    }
24361
24362    fn next_row(&self) -> Self {
24363        Self(self.0 + 1)
24364    }
24365
24366    fn previous_row(&self) -> Self {
24367        Self(self.0.saturating_sub(1))
24368    }
24369
24370    fn minus(&self, other: Self) -> u32 {
24371        self.0 - other.0
24372    }
24373}
24374
24375trait RowRangeExt {
24376    type Row;
24377
24378    fn len(&self) -> usize;
24379
24380    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24381}
24382
24383impl RowRangeExt for Range<MultiBufferRow> {
24384    type Row = MultiBufferRow;
24385
24386    fn len(&self) -> usize {
24387        (self.end.0 - self.start.0) as usize
24388    }
24389
24390    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24391        (self.start.0..self.end.0).map(MultiBufferRow)
24392    }
24393}
24394
24395impl RowRangeExt for Range<DisplayRow> {
24396    type Row = DisplayRow;
24397
24398    fn len(&self) -> usize {
24399        (self.end.0 - self.start.0) as usize
24400    }
24401
24402    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24403        (self.start.0..self.end.0).map(DisplayRow)
24404    }
24405}
24406
24407/// If select range has more than one line, we
24408/// just point the cursor to range.start.
24409fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24410    if range.start.row == range.end.row {
24411        range
24412    } else {
24413        range.start..range.start
24414    }
24415}
24416pub struct KillRing(ClipboardItem);
24417impl Global for KillRing {}
24418
24419const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24420
24421enum BreakpointPromptEditAction {
24422    Log,
24423    Condition,
24424    HitCondition,
24425}
24426
24427struct BreakpointPromptEditor {
24428    pub(crate) prompt: Entity<Editor>,
24429    editor: WeakEntity<Editor>,
24430    breakpoint_anchor: Anchor,
24431    breakpoint: Breakpoint,
24432    edit_action: BreakpointPromptEditAction,
24433    block_ids: HashSet<CustomBlockId>,
24434    editor_margins: Arc<Mutex<EditorMargins>>,
24435    _subscriptions: Vec<Subscription>,
24436}
24437
24438impl BreakpointPromptEditor {
24439    const MAX_LINES: u8 = 4;
24440
24441    fn new(
24442        editor: WeakEntity<Editor>,
24443        breakpoint_anchor: Anchor,
24444        breakpoint: Breakpoint,
24445        edit_action: BreakpointPromptEditAction,
24446        window: &mut Window,
24447        cx: &mut Context<Self>,
24448    ) -> Self {
24449        let base_text = match edit_action {
24450            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24451            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24452            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24453        }
24454        .map(|msg| msg.to_string())
24455        .unwrap_or_default();
24456
24457        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24458        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24459
24460        let prompt = cx.new(|cx| {
24461            let mut prompt = Editor::new(
24462                EditorMode::AutoHeight {
24463                    min_lines: 1,
24464                    max_lines: Some(Self::MAX_LINES as usize),
24465                },
24466                buffer,
24467                None,
24468                window,
24469                cx,
24470            );
24471            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24472            prompt.set_show_cursor_when_unfocused(false, cx);
24473            prompt.set_placeholder_text(
24474                match edit_action {
24475                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24476                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24477                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24478                },
24479                window,
24480                cx,
24481            );
24482
24483            prompt
24484        });
24485
24486        Self {
24487            prompt,
24488            editor,
24489            breakpoint_anchor,
24490            breakpoint,
24491            edit_action,
24492            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24493            block_ids: Default::default(),
24494            _subscriptions: vec![],
24495        }
24496    }
24497
24498    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24499        self.block_ids.extend(block_ids)
24500    }
24501
24502    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24503        if let Some(editor) = self.editor.upgrade() {
24504            let message = self
24505                .prompt
24506                .read(cx)
24507                .buffer
24508                .read(cx)
24509                .as_singleton()
24510                .expect("A multi buffer in breakpoint prompt isn't possible")
24511                .read(cx)
24512                .as_rope()
24513                .to_string();
24514
24515            editor.update(cx, |editor, cx| {
24516                editor.edit_breakpoint_at_anchor(
24517                    self.breakpoint_anchor,
24518                    self.breakpoint.clone(),
24519                    match self.edit_action {
24520                        BreakpointPromptEditAction::Log => {
24521                            BreakpointEditAction::EditLogMessage(message.into())
24522                        }
24523                        BreakpointPromptEditAction::Condition => {
24524                            BreakpointEditAction::EditCondition(message.into())
24525                        }
24526                        BreakpointPromptEditAction::HitCondition => {
24527                            BreakpointEditAction::EditHitCondition(message.into())
24528                        }
24529                    },
24530                    cx,
24531                );
24532
24533                editor.remove_blocks(self.block_ids.clone(), None, cx);
24534                cx.focus_self(window);
24535            });
24536        }
24537    }
24538
24539    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24540        self.editor
24541            .update(cx, |editor, cx| {
24542                editor.remove_blocks(self.block_ids.clone(), None, cx);
24543                window.focus(&editor.focus_handle);
24544            })
24545            .log_err();
24546    }
24547
24548    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24549        let settings = ThemeSettings::get_global(cx);
24550        let text_style = TextStyle {
24551            color: if self.prompt.read(cx).read_only(cx) {
24552                cx.theme().colors().text_disabled
24553            } else {
24554                cx.theme().colors().text
24555            },
24556            font_family: settings.buffer_font.family.clone(),
24557            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24558            font_size: settings.buffer_font_size(cx).into(),
24559            font_weight: settings.buffer_font.weight,
24560            line_height: relative(settings.buffer_line_height.value()),
24561            ..Default::default()
24562        };
24563        EditorElement::new(
24564            &self.prompt,
24565            EditorStyle {
24566                background: cx.theme().colors().editor_background,
24567                local_player: cx.theme().players().local(),
24568                text: text_style,
24569                ..Default::default()
24570            },
24571        )
24572    }
24573}
24574
24575impl Render for BreakpointPromptEditor {
24576    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24577        let editor_margins = *self.editor_margins.lock();
24578        let gutter_dimensions = editor_margins.gutter;
24579        h_flex()
24580            .key_context("Editor")
24581            .bg(cx.theme().colors().editor_background)
24582            .border_y_1()
24583            .border_color(cx.theme().status().info_border)
24584            .size_full()
24585            .py(window.line_height() / 2.5)
24586            .on_action(cx.listener(Self::confirm))
24587            .on_action(cx.listener(Self::cancel))
24588            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24589            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24590    }
24591}
24592
24593impl Focusable for BreakpointPromptEditor {
24594    fn focus_handle(&self, cx: &App) -> FocusHandle {
24595        self.prompt.focus_handle(cx)
24596    }
24597}
24598
24599fn all_edits_insertions_or_deletions(
24600    edits: &Vec<(Range<Anchor>, String)>,
24601    snapshot: &MultiBufferSnapshot,
24602) -> bool {
24603    let mut all_insertions = true;
24604    let mut all_deletions = true;
24605
24606    for (range, new_text) in edits.iter() {
24607        let range_is_empty = range.to_offset(snapshot).is_empty();
24608        let text_is_empty = new_text.is_empty();
24609
24610        if range_is_empty != text_is_empty {
24611            if range_is_empty {
24612                all_deletions = false;
24613            } else {
24614                all_insertions = false;
24615            }
24616        } else {
24617            return false;
24618        }
24619
24620        if !all_insertions && !all_deletions {
24621            return false;
24622        }
24623    }
24624    all_insertions || all_deletions
24625}
24626
24627struct MissingEditPredictionKeybindingTooltip;
24628
24629impl Render for MissingEditPredictionKeybindingTooltip {
24630    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24631        ui::tooltip_container(cx, |container, cx| {
24632            container
24633                .flex_shrink_0()
24634                .max_w_80()
24635                .min_h(rems_from_px(124.))
24636                .justify_between()
24637                .child(
24638                    v_flex()
24639                        .flex_1()
24640                        .text_ui_sm(cx)
24641                        .child(Label::new("Conflict with Accept Keybinding"))
24642                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24643                )
24644                .child(
24645                    h_flex()
24646                        .pb_1()
24647                        .gap_1()
24648                        .items_end()
24649                        .w_full()
24650                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24651                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24652                        }))
24653                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24654                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24655                        })),
24656                )
24657        })
24658    }
24659}
24660
24661#[derive(Debug, Clone, Copy, PartialEq)]
24662pub struct LineHighlight {
24663    pub background: Background,
24664    pub border: Option<gpui::Hsla>,
24665    pub include_gutter: bool,
24666    pub type_id: Option<TypeId>,
24667}
24668
24669struct LineManipulationResult {
24670    pub new_text: String,
24671    pub line_count_before: usize,
24672    pub line_count_after: usize,
24673}
24674
24675fn render_diff_hunk_controls(
24676    row: u32,
24677    status: &DiffHunkStatus,
24678    hunk_range: Range<Anchor>,
24679    is_created_file: bool,
24680    line_height: Pixels,
24681    editor: &Entity<Editor>,
24682    _window: &mut Window,
24683    cx: &mut App,
24684) -> AnyElement {
24685    h_flex()
24686        .h(line_height)
24687        .mr_1()
24688        .gap_1()
24689        .px_0p5()
24690        .pb_1()
24691        .border_x_1()
24692        .border_b_1()
24693        .border_color(cx.theme().colors().border_variant)
24694        .rounded_b_lg()
24695        .bg(cx.theme().colors().editor_background)
24696        .gap_1()
24697        .block_mouse_except_scroll()
24698        .shadow_md()
24699        .child(if status.has_secondary_hunk() {
24700            Button::new(("stage", row as u64), "Stage")
24701                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24702                .tooltip({
24703                    let focus_handle = editor.focus_handle(cx);
24704                    move |window, cx| {
24705                        Tooltip::for_action_in(
24706                            "Stage Hunk",
24707                            &::git::ToggleStaged,
24708                            &focus_handle,
24709                            window,
24710                            cx,
24711                        )
24712                    }
24713                })
24714                .on_click({
24715                    let editor = editor.clone();
24716                    move |_event, _window, cx| {
24717                        editor.update(cx, |editor, cx| {
24718                            editor.stage_or_unstage_diff_hunks(
24719                                true,
24720                                vec![hunk_range.start..hunk_range.start],
24721                                cx,
24722                            );
24723                        });
24724                    }
24725                })
24726        } else {
24727            Button::new(("unstage", row as u64), "Unstage")
24728                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24729                .tooltip({
24730                    let focus_handle = editor.focus_handle(cx);
24731                    move |window, cx| {
24732                        Tooltip::for_action_in(
24733                            "Unstage Hunk",
24734                            &::git::ToggleStaged,
24735                            &focus_handle,
24736                            window,
24737                            cx,
24738                        )
24739                    }
24740                })
24741                .on_click({
24742                    let editor = editor.clone();
24743                    move |_event, _window, cx| {
24744                        editor.update(cx, |editor, cx| {
24745                            editor.stage_or_unstage_diff_hunks(
24746                                false,
24747                                vec![hunk_range.start..hunk_range.start],
24748                                cx,
24749                            );
24750                        });
24751                    }
24752                })
24753        })
24754        .child(
24755            Button::new(("restore", row as u64), "Restore")
24756                .tooltip({
24757                    let focus_handle = editor.focus_handle(cx);
24758                    move |window, cx| {
24759                        Tooltip::for_action_in(
24760                            "Restore Hunk",
24761                            &::git::Restore,
24762                            &focus_handle,
24763                            window,
24764                            cx,
24765                        )
24766                    }
24767                })
24768                .on_click({
24769                    let editor = editor.clone();
24770                    move |_event, window, cx| {
24771                        editor.update(cx, |editor, cx| {
24772                            let snapshot = editor.snapshot(window, cx);
24773                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24774                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24775                        });
24776                    }
24777                })
24778                .disabled(is_created_file),
24779        )
24780        .when(
24781            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24782            |el| {
24783                el.child(
24784                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24785                        .shape(IconButtonShape::Square)
24786                        .icon_size(IconSize::Small)
24787                        // .disabled(!has_multiple_hunks)
24788                        .tooltip({
24789                            let focus_handle = editor.focus_handle(cx);
24790                            move |window, cx| {
24791                                Tooltip::for_action_in(
24792                                    "Next Hunk",
24793                                    &GoToHunk,
24794                                    &focus_handle,
24795                                    window,
24796                                    cx,
24797                                )
24798                            }
24799                        })
24800                        .on_click({
24801                            let editor = editor.clone();
24802                            move |_event, window, cx| {
24803                                editor.update(cx, |editor, cx| {
24804                                    let snapshot = editor.snapshot(window, cx);
24805                                    let position =
24806                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24807                                    editor.go_to_hunk_before_or_after_position(
24808                                        &snapshot,
24809                                        position,
24810                                        Direction::Next,
24811                                        window,
24812                                        cx,
24813                                    );
24814                                    editor.expand_selected_diff_hunks(cx);
24815                                });
24816                            }
24817                        }),
24818                )
24819                .child(
24820                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24821                        .shape(IconButtonShape::Square)
24822                        .icon_size(IconSize::Small)
24823                        // .disabled(!has_multiple_hunks)
24824                        .tooltip({
24825                            let focus_handle = editor.focus_handle(cx);
24826                            move |window, cx| {
24827                                Tooltip::for_action_in(
24828                                    "Previous Hunk",
24829                                    &GoToPreviousHunk,
24830                                    &focus_handle,
24831                                    window,
24832                                    cx,
24833                                )
24834                            }
24835                        })
24836                        .on_click({
24837                            let editor = editor.clone();
24838                            move |_event, window, cx| {
24839                                editor.update(cx, |editor, cx| {
24840                                    let snapshot = editor.snapshot(window, cx);
24841                                    let point =
24842                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24843                                    editor.go_to_hunk_before_or_after_position(
24844                                        &snapshot,
24845                                        point,
24846                                        Direction::Prev,
24847                                        window,
24848                                        cx,
24849                                    );
24850                                    editor.expand_selected_diff_hunks(cx);
24851                                });
24852                            }
24853                        }),
24854                )
24855            },
24856        )
24857        .into_any_element()
24858}
24859
24860pub fn multibuffer_context_lines(cx: &App) -> u32 {
24861    EditorSettings::try_get(cx)
24862        .map(|settings| settings.excerpt_context_lines)
24863        .unwrap_or(2)
24864        .min(32)
24865}