editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{
  164        DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
  165    },
  166};
  167use rand::{seq::SliceRandom, thread_rng};
  168use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  169use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  170use selections_collection::{
  171    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  172};
  173use serde::{Deserialize, Serialize};
  174use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::TypeId,
  179    borrow::Cow,
  180    cell::OnceCell,
  181    cell::RefCell,
  182    cmp::{self, Ordering, Reverse},
  183    iter::Peekable,
  184    mem,
  185    num::NonZeroU32,
  186    ops::Not,
  187    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  188    path::{Path, PathBuf},
  189    rc::Rc,
  190    sync::Arc,
  191    time::{Duration, Instant},
  192};
  193use sum_tree::TreeMap;
  194use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  196use theme::{
  197    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::SearchEvent,
  212};
  213
  214use crate::{
  215    code_context_menus::CompletionsMenuSource,
  216    editor_settings::MultiCursorModifier,
  217    hover_links::{find_url, find_url_from_range},
  218    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  219};
  220
  221pub const FILE_HEADER_HEIGHT: u32 = 2;
  222pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  223pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  224const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  225const MAX_LINE_LEN: usize = 1024;
  226const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  227const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  228pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  229#[doc(hidden)]
  230pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  231const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  232
  233pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  235pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  236
  237pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  238pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  239pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  240
  241pub type RenderDiffHunkControlsFn = Arc<
  242    dyn Fn(
  243        u32,
  244        &DiffHunkStatus,
  245        Range<Anchor>,
  246        bool,
  247        Pixels,
  248        &Entity<Editor>,
  249        &mut Window,
  250        &mut App,
  251    ) -> AnyElement,
  252>;
  253
  254enum ReportEditorEvent {
  255    Saved { auto_saved: bool },
  256    EditorOpened,
  257    Closed,
  258}
  259
  260impl ReportEditorEvent {
  261    pub fn event_type(&self) -> &'static str {
  262        match self {
  263            Self::Saved { .. } => "Editor Saved",
  264            Self::EditorOpened => "Editor Opened",
  265            Self::Closed => "Editor Closed",
  266        }
  267    }
  268}
  269
  270struct InlineValueCache {
  271    enabled: bool,
  272    inlays: Vec<InlayId>,
  273    refresh_task: Task<Option<()>>,
  274}
  275
  276impl InlineValueCache {
  277    fn new(enabled: bool) -> Self {
  278        Self {
  279            enabled,
  280            inlays: Vec::new(),
  281            refresh_task: Task::ready(None),
  282        }
  283    }
  284}
  285
  286#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  287pub enum InlayId {
  288    EditPrediction(usize),
  289    DebuggerValue(usize),
  290    // LSP
  291    Hint(usize),
  292    Color(usize),
  293}
  294
  295impl InlayId {
  296    fn id(&self) -> usize {
  297        match self {
  298            Self::EditPrediction(id) => *id,
  299            Self::DebuggerValue(id) => *id,
  300            Self::Hint(id) => *id,
  301            Self::Color(id) => *id,
  302        }
  303    }
  304}
  305
  306pub enum ActiveDebugLine {}
  307pub enum DebugStackFrameLine {}
  308enum DocumentHighlightRead {}
  309enum DocumentHighlightWrite {}
  310enum InputComposition {}
  311pub enum PendingInput {}
  312enum SelectedTextHighlight {}
  313
  314pub enum ConflictsOuter {}
  315pub enum ConflictsOurs {}
  316pub enum ConflictsTheirs {}
  317pub enum ConflictsOursMarker {}
  318pub enum ConflictsTheirsMarker {}
  319
  320#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  321pub enum Navigated {
  322    Yes,
  323    No,
  324}
  325
  326impl Navigated {
  327    pub fn from_bool(yes: bool) -> Navigated {
  328        if yes { Navigated::Yes } else { Navigated::No }
  329    }
  330}
  331
  332#[derive(Debug, Clone, PartialEq, Eq)]
  333enum DisplayDiffHunk {
  334    Folded {
  335        display_row: DisplayRow,
  336    },
  337    Unfolded {
  338        is_created_file: bool,
  339        diff_base_byte_range: Range<usize>,
  340        display_row_range: Range<DisplayRow>,
  341        multi_buffer_range: Range<Anchor>,
  342        status: DiffHunkStatus,
  343    },
  344}
  345
  346pub enum HideMouseCursorOrigin {
  347    TypingAction,
  348    MovementAction,
  349}
  350
  351pub fn init_settings(cx: &mut App) {
  352    EditorSettings::register(cx);
  353}
  354
  355pub fn init(cx: &mut App) {
  356    init_settings(cx);
  357
  358    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  359
  360    workspace::register_project_item::<Editor>(cx);
  361    workspace::FollowableViewRegistry::register::<Editor>(cx);
  362    workspace::register_serializable_item::<Editor>(cx);
  363
  364    cx.observe_new(
  365        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  366            workspace.register_action(Editor::new_file);
  367            workspace.register_action(Editor::new_file_vertical);
  368            workspace.register_action(Editor::new_file_horizontal);
  369            workspace.register_action(Editor::cancel_language_server_work);
  370            workspace.register_action(Editor::toggle_focus);
  371        },
  372    )
  373    .detach();
  374
  375    cx.on_action(move |_: &workspace::NewFile, cx| {
  376        let app_state = workspace::AppState::global(cx);
  377        if let Some(app_state) = app_state.upgrade() {
  378            workspace::open_new(
  379                Default::default(),
  380                app_state,
  381                cx,
  382                |workspace, window, cx| {
  383                    Editor::new_file(workspace, &Default::default(), window, cx)
  384                },
  385            )
  386            .detach();
  387        }
  388    });
  389    cx.on_action(move |_: &workspace::NewWindow, cx| {
  390        let app_state = workspace::AppState::global(cx);
  391        if let Some(app_state) = app_state.upgrade() {
  392            workspace::open_new(
  393                Default::default(),
  394                app_state,
  395                cx,
  396                |workspace, window, cx| {
  397                    cx.activate(true);
  398                    Editor::new_file(workspace, &Default::default(), window, cx)
  399                },
  400            )
  401            .detach();
  402        }
  403    });
  404}
  405
  406pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  407    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  408}
  409
  410pub trait DiagnosticRenderer {
  411    fn render_group(
  412        &self,
  413        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  414        buffer_id: BufferId,
  415        snapshot: EditorSnapshot,
  416        editor: WeakEntity<Editor>,
  417        cx: &mut App,
  418    ) -> Vec<BlockProperties<Anchor>>;
  419
  420    fn render_hover(
  421        &self,
  422        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  423        range: Range<Point>,
  424        buffer_id: BufferId,
  425        cx: &mut App,
  426    ) -> Option<Entity<markdown::Markdown>>;
  427
  428    fn open_link(
  429        &self,
  430        editor: &mut Editor,
  431        link: SharedString,
  432        window: &mut Window,
  433        cx: &mut Context<Editor>,
  434    );
  435}
  436
  437pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  438
  439impl GlobalDiagnosticRenderer {
  440    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  441        cx.try_global::<Self>().map(|g| g.0.clone())
  442    }
  443}
  444
  445impl gpui::Global for GlobalDiagnosticRenderer {}
  446pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  447    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  448}
  449
  450pub struct SearchWithinRange;
  451
  452trait InvalidationRegion {
  453    fn ranges(&self) -> &[Range<Anchor>];
  454}
  455
  456#[derive(Clone, Debug, PartialEq)]
  457pub enum SelectPhase {
  458    Begin {
  459        position: DisplayPoint,
  460        add: bool,
  461        click_count: usize,
  462    },
  463    BeginColumnar {
  464        position: DisplayPoint,
  465        reset: bool,
  466        mode: ColumnarMode,
  467        goal_column: u32,
  468    },
  469    Extend {
  470        position: DisplayPoint,
  471        click_count: usize,
  472    },
  473    Update {
  474        position: DisplayPoint,
  475        goal_column: u32,
  476        scroll_delta: gpui::Point<f32>,
  477    },
  478    End,
  479}
  480
  481#[derive(Clone, Debug, PartialEq)]
  482pub enum ColumnarMode {
  483    FromMouse,
  484    FromSelection,
  485}
  486
  487#[derive(Clone, Debug)]
  488pub enum SelectMode {
  489    Character,
  490    Word(Range<Anchor>),
  491    Line(Range<Anchor>),
  492    All,
  493}
  494
  495#[derive(Clone, PartialEq, Eq, Debug)]
  496pub enum EditorMode {
  497    SingleLine,
  498    AutoHeight {
  499        min_lines: usize,
  500        max_lines: Option<usize>,
  501    },
  502    Full {
  503        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  504        scale_ui_elements_with_buffer_font_size: bool,
  505        /// When set to `true`, the editor will render a background for the active line.
  506        show_active_line_background: bool,
  507        /// When set to `true`, the editor's height will be determined by its content.
  508        sized_by_content: bool,
  509    },
  510    Minimap {
  511        parent: WeakEntity<Editor>,
  512    },
  513}
  514
  515impl EditorMode {
  516    pub fn full() -> Self {
  517        Self::Full {
  518            scale_ui_elements_with_buffer_font_size: true,
  519            show_active_line_background: true,
  520            sized_by_content: false,
  521        }
  522    }
  523
  524    #[inline]
  525    pub fn is_full(&self) -> bool {
  526        matches!(self, Self::Full { .. })
  527    }
  528
  529    #[inline]
  530    pub fn is_single_line(&self) -> bool {
  531        matches!(self, Self::SingleLine { .. })
  532    }
  533
  534    #[inline]
  535    fn is_minimap(&self) -> bool {
  536        matches!(self, Self::Minimap { .. })
  537    }
  538}
  539
  540#[derive(Copy, Clone, Debug)]
  541pub enum SoftWrap {
  542    /// Prefer not to wrap at all.
  543    ///
  544    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  545    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  546    GitDiff,
  547    /// Prefer a single line generally, unless an overly long line is encountered.
  548    None,
  549    /// Soft wrap lines that exceed the editor width.
  550    EditorWidth,
  551    /// Soft wrap lines at the preferred line length.
  552    Column(u32),
  553    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  554    Bounded(u32),
  555}
  556
  557#[derive(Clone)]
  558pub struct EditorStyle {
  559    pub background: Hsla,
  560    pub border: Hsla,
  561    pub local_player: PlayerColor,
  562    pub text: TextStyle,
  563    pub scrollbar_width: Pixels,
  564    pub syntax: Arc<SyntaxTheme>,
  565    pub status: StatusColors,
  566    pub inlay_hints_style: HighlightStyle,
  567    pub edit_prediction_styles: EditPredictionStyles,
  568    pub unnecessary_code_fade: f32,
  569    pub show_underlines: bool,
  570}
  571
  572impl Default for EditorStyle {
  573    fn default() -> Self {
  574        Self {
  575            background: Hsla::default(),
  576            border: Hsla::default(),
  577            local_player: PlayerColor::default(),
  578            text: TextStyle::default(),
  579            scrollbar_width: Pixels::default(),
  580            syntax: Default::default(),
  581            // HACK: Status colors don't have a real default.
  582            // We should look into removing the status colors from the editor
  583            // style and retrieve them directly from the theme.
  584            status: StatusColors::dark(),
  585            inlay_hints_style: HighlightStyle::default(),
  586            edit_prediction_styles: EditPredictionStyles {
  587                insertion: HighlightStyle::default(),
  588                whitespace: HighlightStyle::default(),
  589            },
  590            unnecessary_code_fade: Default::default(),
  591            show_underlines: true,
  592        }
  593    }
  594}
  595
  596pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  597    let show_background = language_settings::language_settings(None, None, cx)
  598        .inlay_hints
  599        .show_background;
  600
  601    HighlightStyle {
  602        color: Some(cx.theme().status().hint),
  603        background_color: show_background.then(|| cx.theme().status().hint_background),
  604        ..HighlightStyle::default()
  605    }
  606}
  607
  608pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  609    EditPredictionStyles {
  610        insertion: HighlightStyle {
  611            color: Some(cx.theme().status().predictive),
  612            ..HighlightStyle::default()
  613        },
  614        whitespace: HighlightStyle {
  615            background_color: Some(cx.theme().status().created_background),
  616            ..HighlightStyle::default()
  617        },
  618    }
  619}
  620
  621type CompletionId = usize;
  622
  623pub(crate) enum EditDisplayMode {
  624    TabAccept,
  625    DiffPopover,
  626    Inline,
  627}
  628
  629enum EditPrediction {
  630    Edit {
  631        edits: Vec<(Range<Anchor>, String)>,
  632        edit_preview: Option<EditPreview>,
  633        display_mode: EditDisplayMode,
  634        snapshot: BufferSnapshot,
  635    },
  636    Move {
  637        target: Anchor,
  638        snapshot: BufferSnapshot,
  639    },
  640}
  641
  642struct EditPredictionState {
  643    inlay_ids: Vec<InlayId>,
  644    completion: EditPrediction,
  645    completion_id: Option<SharedString>,
  646    invalidation_range: Range<Anchor>,
  647}
  648
  649enum EditPredictionSettings {
  650    Disabled,
  651    Enabled {
  652        show_in_menu: bool,
  653        preview_requires_modifier: bool,
  654    },
  655}
  656
  657enum EditPredictionHighlight {}
  658
  659#[derive(Debug, Clone)]
  660struct InlineDiagnostic {
  661    message: SharedString,
  662    group_id: usize,
  663    is_primary: bool,
  664    start: Point,
  665    severity: lsp::DiagnosticSeverity,
  666}
  667
  668pub enum MenuEditPredictionsPolicy {
  669    Never,
  670    ByProvider,
  671}
  672
  673pub enum EditPredictionPreview {
  674    /// Modifier is not pressed
  675    Inactive { released_too_fast: bool },
  676    /// Modifier pressed
  677    Active {
  678        since: Instant,
  679        previous_scroll_position: Option<ScrollAnchor>,
  680    },
  681}
  682
  683impl EditPredictionPreview {
  684    pub fn released_too_fast(&self) -> bool {
  685        match self {
  686            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  687            EditPredictionPreview::Active { .. } => false,
  688        }
  689    }
  690
  691    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  692        if let EditPredictionPreview::Active {
  693            previous_scroll_position,
  694            ..
  695        } = self
  696        {
  697            *previous_scroll_position = scroll_position;
  698        }
  699    }
  700}
  701
  702pub struct ContextMenuOptions {
  703    pub min_entries_visible: usize,
  704    pub max_entries_visible: usize,
  705    pub placement: Option<ContextMenuPlacement>,
  706}
  707
  708#[derive(Debug, Clone, PartialEq, Eq)]
  709pub enum ContextMenuPlacement {
  710    Above,
  711    Below,
  712}
  713
  714#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  715struct EditorActionId(usize);
  716
  717impl EditorActionId {
  718    pub fn post_inc(&mut self) -> Self {
  719        let answer = self.0;
  720
  721        *self = Self(answer + 1);
  722
  723        Self(answer)
  724    }
  725}
  726
  727// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  728// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  729
  730type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  731type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  732
  733#[derive(Default)]
  734struct ScrollbarMarkerState {
  735    scrollbar_size: Size<Pixels>,
  736    dirty: bool,
  737    markers: Arc<[PaintQuad]>,
  738    pending_refresh: Option<Task<Result<()>>>,
  739}
  740
  741impl ScrollbarMarkerState {
  742    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  743        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  744    }
  745}
  746
  747#[derive(Clone, Copy, PartialEq, Eq)]
  748pub enum MinimapVisibility {
  749    Disabled,
  750    Enabled {
  751        /// The configuration currently present in the users settings.
  752        setting_configuration: bool,
  753        /// Whether to override the currently set visibility from the users setting.
  754        toggle_override: bool,
  755    },
  756}
  757
  758impl MinimapVisibility {
  759    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  760        if mode.is_full() {
  761            Self::Enabled {
  762                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  763                toggle_override: false,
  764            }
  765        } else {
  766            Self::Disabled
  767        }
  768    }
  769
  770    fn hidden(&self) -> Self {
  771        match *self {
  772            Self::Enabled {
  773                setting_configuration,
  774                ..
  775            } => Self::Enabled {
  776                setting_configuration,
  777                toggle_override: setting_configuration,
  778            },
  779            Self::Disabled => Self::Disabled,
  780        }
  781    }
  782
  783    fn disabled(&self) -> bool {
  784        matches!(*self, Self::Disabled)
  785    }
  786
  787    fn settings_visibility(&self) -> bool {
  788        match *self {
  789            Self::Enabled {
  790                setting_configuration,
  791                ..
  792            } => setting_configuration,
  793            _ => false,
  794        }
  795    }
  796
  797    fn visible(&self) -> bool {
  798        match *self {
  799            Self::Enabled {
  800                setting_configuration,
  801                toggle_override,
  802            } => setting_configuration ^ toggle_override,
  803            _ => false,
  804        }
  805    }
  806
  807    fn toggle_visibility(&self) -> Self {
  808        match *self {
  809            Self::Enabled {
  810                toggle_override,
  811                setting_configuration,
  812            } => Self::Enabled {
  813                setting_configuration,
  814                toggle_override: !toggle_override,
  815            },
  816            Self::Disabled => Self::Disabled,
  817        }
  818    }
  819}
  820
  821#[derive(Clone, Debug)]
  822struct RunnableTasks {
  823    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  824    offset: multi_buffer::Anchor,
  825    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  826    column: u32,
  827    // Values of all named captures, including those starting with '_'
  828    extra_variables: HashMap<String, String>,
  829    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  830    context_range: Range<BufferOffset>,
  831}
  832
  833impl RunnableTasks {
  834    fn resolve<'a>(
  835        &'a self,
  836        cx: &'a task::TaskContext,
  837    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  838        self.templates.iter().filter_map(|(kind, template)| {
  839            template
  840                .resolve_task(&kind.to_id_base(), cx)
  841                .map(|task| (kind.clone(), task))
  842        })
  843    }
  844}
  845
  846#[derive(Clone)]
  847pub struct ResolvedTasks {
  848    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  849    position: Anchor,
  850}
  851
  852#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  853struct BufferOffset(usize);
  854
  855// Addons allow storing per-editor state in other crates (e.g. Vim)
  856pub trait Addon: 'static {
  857    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  858
  859    fn render_buffer_header_controls(
  860        &self,
  861        _: &ExcerptInfo,
  862        _: &Window,
  863        _: &App,
  864    ) -> Option<AnyElement> {
  865        None
  866    }
  867
  868    fn to_any(&self) -> &dyn std::any::Any;
  869
  870    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  871        None
  872    }
  873}
  874
  875struct ChangeLocation {
  876    current: Option<Vec<Anchor>>,
  877    original: Vec<Anchor>,
  878}
  879impl ChangeLocation {
  880    fn locations(&self) -> &[Anchor] {
  881        self.current.as_ref().unwrap_or(&self.original)
  882    }
  883}
  884
  885/// A set of caret positions, registered when the editor was edited.
  886pub struct ChangeList {
  887    changes: Vec<ChangeLocation>,
  888    /// Currently "selected" change.
  889    position: Option<usize>,
  890}
  891
  892impl ChangeList {
  893    pub fn new() -> Self {
  894        Self {
  895            changes: Vec::new(),
  896            position: None,
  897        }
  898    }
  899
  900    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  901    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  902    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  903        if self.changes.is_empty() {
  904            return None;
  905        }
  906
  907        let prev = self.position.unwrap_or(self.changes.len());
  908        let next = if direction == Direction::Prev {
  909            prev.saturating_sub(count)
  910        } else {
  911            (prev + count).min(self.changes.len() - 1)
  912        };
  913        self.position = Some(next);
  914        self.changes.get(next).map(|change| change.locations())
  915    }
  916
  917    /// Adds a new change to the list, resetting the change list position.
  918    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  919        self.position.take();
  920        if let Some(last) = self.changes.last_mut()
  921            && group
  922        {
  923            last.current = Some(new_positions)
  924        } else {
  925            self.changes.push(ChangeLocation {
  926                original: new_positions,
  927                current: None,
  928            });
  929        }
  930    }
  931
  932    pub fn last(&self) -> Option<&[Anchor]> {
  933        self.changes.last().map(|change| change.locations())
  934    }
  935
  936    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  937        self.changes.last().map(|change| change.original.as_slice())
  938    }
  939
  940    pub fn invert_last_group(&mut self) {
  941        if let Some(last) = self.changes.last_mut()
  942            && let Some(current) = last.current.as_mut()
  943        {
  944            mem::swap(&mut last.original, current);
  945        }
  946    }
  947}
  948
  949#[derive(Clone)]
  950struct InlineBlamePopoverState {
  951    scroll_handle: ScrollHandle,
  952    commit_message: Option<ParsedCommitMessage>,
  953    markdown: Entity<Markdown>,
  954}
  955
  956struct InlineBlamePopover {
  957    position: gpui::Point<Pixels>,
  958    hide_task: Option<Task<()>>,
  959    popover_bounds: Option<Bounds<Pixels>>,
  960    popover_state: InlineBlamePopoverState,
  961    keyboard_grace: bool,
  962}
  963
  964enum SelectionDragState {
  965    /// State when no drag related activity is detected.
  966    None,
  967    /// State when the mouse is down on a selection that is about to be dragged.
  968    ReadyToDrag {
  969        selection: Selection<Anchor>,
  970        click_position: gpui::Point<Pixels>,
  971        mouse_down_time: Instant,
  972    },
  973    /// State when the mouse is dragging the selection in the editor.
  974    Dragging {
  975        selection: Selection<Anchor>,
  976        drop_cursor: Selection<Anchor>,
  977        hide_drop_cursor: bool,
  978    },
  979}
  980
  981enum ColumnarSelectionState {
  982    FromMouse {
  983        selection_tail: Anchor,
  984        display_point: Option<DisplayPoint>,
  985    },
  986    FromSelection {
  987        selection_tail: Anchor,
  988    },
  989}
  990
  991/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  992/// a breakpoint on them.
  993#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  994struct PhantomBreakpointIndicator {
  995    display_row: DisplayRow,
  996    /// There's a small debounce between hovering over the line and showing the indicator.
  997    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  998    is_active: bool,
  999    collides_with_existing_breakpoint: bool,
 1000}
 1001
 1002/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1003///
 1004/// See the [module level documentation](self) for more information.
 1005pub struct Editor {
 1006    focus_handle: FocusHandle,
 1007    last_focused_descendant: Option<WeakFocusHandle>,
 1008    /// The text buffer being edited
 1009    buffer: Entity<MultiBuffer>,
 1010    /// Map of how text in the buffer should be displayed.
 1011    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1012    pub display_map: Entity<DisplayMap>,
 1013    pub selections: SelectionsCollection,
 1014    pub scroll_manager: ScrollManager,
 1015    /// When inline assist editors are linked, they all render cursors because
 1016    /// typing enters text into each of them, even the ones that aren't focused.
 1017    pub(crate) show_cursor_when_unfocused: bool,
 1018    columnar_selection_state: Option<ColumnarSelectionState>,
 1019    add_selections_state: Option<AddSelectionsState>,
 1020    select_next_state: Option<SelectNextState>,
 1021    select_prev_state: Option<SelectNextState>,
 1022    selection_history: SelectionHistory,
 1023    defer_selection_effects: bool,
 1024    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1025    autoclose_regions: Vec<AutocloseRegion>,
 1026    snippet_stack: InvalidationStack<SnippetState>,
 1027    select_syntax_node_history: SelectSyntaxNodeHistory,
 1028    ime_transaction: Option<TransactionId>,
 1029    pub diagnostics_max_severity: DiagnosticSeverity,
 1030    active_diagnostics: ActiveDiagnostic,
 1031    show_inline_diagnostics: bool,
 1032    inline_diagnostics_update: Task<()>,
 1033    inline_diagnostics_enabled: bool,
 1034    diagnostics_enabled: bool,
 1035    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1036    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1037    hard_wrap: Option<usize>,
 1038    project: Option<Entity<Project>>,
 1039    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1040    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1041    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1042    blink_manager: Entity<BlinkManager>,
 1043    show_cursor_names: bool,
 1044    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1045    pub show_local_selections: bool,
 1046    mode: EditorMode,
 1047    show_breadcrumbs: bool,
 1048    show_gutter: bool,
 1049    show_scrollbars: ScrollbarAxes,
 1050    minimap_visibility: MinimapVisibility,
 1051    offset_content: bool,
 1052    disable_expand_excerpt_buttons: bool,
 1053    show_line_numbers: Option<bool>,
 1054    use_relative_line_numbers: Option<bool>,
 1055    show_git_diff_gutter: Option<bool>,
 1056    show_code_actions: Option<bool>,
 1057    show_runnables: Option<bool>,
 1058    show_breakpoints: Option<bool>,
 1059    show_wrap_guides: Option<bool>,
 1060    show_indent_guides: Option<bool>,
 1061    placeholder_text: Option<Arc<str>>,
 1062    highlight_order: usize,
 1063    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1064    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1065    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1066    scrollbar_marker_state: ScrollbarMarkerState,
 1067    active_indent_guides_state: ActiveIndentGuidesState,
 1068    nav_history: Option<ItemNavHistory>,
 1069    context_menu: RefCell<Option<CodeContextMenu>>,
 1070    context_menu_options: Option<ContextMenuOptions>,
 1071    mouse_context_menu: Option<MouseContextMenu>,
 1072    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1073    inline_blame_popover: Option<InlineBlamePopover>,
 1074    inline_blame_popover_show_task: Option<Task<()>>,
 1075    signature_help_state: SignatureHelpState,
 1076    auto_signature_help: Option<bool>,
 1077    find_all_references_task_sources: Vec<Anchor>,
 1078    next_completion_id: CompletionId,
 1079    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1080    code_actions_task: Option<Task<Result<()>>>,
 1081    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1082    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1083    document_highlights_task: Option<Task<()>>,
 1084    linked_editing_range_task: Option<Task<Option<()>>>,
 1085    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1086    pending_rename: Option<RenameState>,
 1087    searchable: bool,
 1088    cursor_shape: CursorShape,
 1089    current_line_highlight: Option<CurrentLineHighlight>,
 1090    collapse_matches: bool,
 1091    autoindent_mode: Option<AutoindentMode>,
 1092    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1093    input_enabled: bool,
 1094    use_modal_editing: bool,
 1095    read_only: bool,
 1096    leader_id: Option<CollaboratorId>,
 1097    remote_id: Option<ViewId>,
 1098    pub hover_state: HoverState,
 1099    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1100    gutter_hovered: bool,
 1101    hovered_link_state: Option<HoveredLinkState>,
 1102    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1103    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1104    active_edit_prediction: Option<EditPredictionState>,
 1105    /// Used to prevent flickering as the user types while the menu is open
 1106    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1107    edit_prediction_settings: EditPredictionSettings,
 1108    edit_predictions_hidden_for_vim_mode: bool,
 1109    show_edit_predictions_override: Option<bool>,
 1110    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1111    edit_prediction_preview: EditPredictionPreview,
 1112    edit_prediction_indent_conflict: bool,
 1113    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1114    inlay_hint_cache: InlayHintCache,
 1115    next_inlay_id: usize,
 1116    _subscriptions: Vec<Subscription>,
 1117    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1118    gutter_dimensions: GutterDimensions,
 1119    style: Option<EditorStyle>,
 1120    text_style_refinement: Option<TextStyleRefinement>,
 1121    next_editor_action_id: EditorActionId,
 1122    editor_actions: Rc<
 1123        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1124    >,
 1125    use_autoclose: bool,
 1126    use_auto_surround: bool,
 1127    auto_replace_emoji_shortcode: bool,
 1128    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1129    show_git_blame_gutter: bool,
 1130    show_git_blame_inline: bool,
 1131    show_git_blame_inline_delay_task: Option<Task<()>>,
 1132    git_blame_inline_enabled: bool,
 1133    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1134    serialize_dirty_buffers: bool,
 1135    show_selection_menu: Option<bool>,
 1136    blame: Option<Entity<GitBlame>>,
 1137    blame_subscription: Option<Subscription>,
 1138    custom_context_menu: Option<
 1139        Box<
 1140            dyn 'static
 1141                + Fn(
 1142                    &mut Self,
 1143                    DisplayPoint,
 1144                    &mut Window,
 1145                    &mut Context<Self>,
 1146                ) -> Option<Entity<ui::ContextMenu>>,
 1147        >,
 1148    >,
 1149    last_bounds: Option<Bounds<Pixels>>,
 1150    last_position_map: Option<Rc<PositionMap>>,
 1151    expect_bounds_change: Option<Bounds<Pixels>>,
 1152    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1153    tasks_update_task: Option<Task<()>>,
 1154    breakpoint_store: Option<Entity<BreakpointStore>>,
 1155    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1156    hovered_diff_hunk_row: Option<DisplayRow>,
 1157    pull_diagnostics_task: Task<()>,
 1158    in_project_search: bool,
 1159    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1160    breadcrumb_header: Option<String>,
 1161    focused_block: Option<FocusedBlock>,
 1162    next_scroll_position: NextScrollCursorCenterTopBottom,
 1163    addons: HashMap<TypeId, Box<dyn Addon>>,
 1164    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1165    load_diff_task: Option<Shared<Task<()>>>,
 1166    /// Whether we are temporarily displaying a diff other than git's
 1167    temporary_diff_override: bool,
 1168    selection_mark_mode: bool,
 1169    toggle_fold_multiple_buffers: Task<()>,
 1170    _scroll_cursor_center_top_bottom_task: Task<()>,
 1171    serialize_selections: Task<()>,
 1172    serialize_folds: Task<()>,
 1173    mouse_cursor_hidden: bool,
 1174    minimap: Option<Entity<Self>>,
 1175    hide_mouse_mode: HideMouseMode,
 1176    pub change_list: ChangeList,
 1177    inline_value_cache: InlineValueCache,
 1178    selection_drag_state: SelectionDragState,
 1179    next_color_inlay_id: usize,
 1180    colors: Option<LspColorData>,
 1181    folding_newlines: Task<()>,
 1182}
 1183
 1184#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1185enum NextScrollCursorCenterTopBottom {
 1186    #[default]
 1187    Center,
 1188    Top,
 1189    Bottom,
 1190}
 1191
 1192impl NextScrollCursorCenterTopBottom {
 1193    fn next(&self) -> Self {
 1194        match self {
 1195            Self::Center => Self::Top,
 1196            Self::Top => Self::Bottom,
 1197            Self::Bottom => Self::Center,
 1198        }
 1199    }
 1200}
 1201
 1202#[derive(Clone)]
 1203pub struct EditorSnapshot {
 1204    pub mode: EditorMode,
 1205    show_gutter: bool,
 1206    show_line_numbers: Option<bool>,
 1207    show_git_diff_gutter: Option<bool>,
 1208    show_code_actions: Option<bool>,
 1209    show_runnables: Option<bool>,
 1210    show_breakpoints: Option<bool>,
 1211    git_blame_gutter_max_author_length: Option<usize>,
 1212    pub display_snapshot: DisplaySnapshot,
 1213    pub placeholder_text: Option<Arc<str>>,
 1214    is_focused: bool,
 1215    scroll_anchor: ScrollAnchor,
 1216    ongoing_scroll: OngoingScroll,
 1217    current_line_highlight: CurrentLineHighlight,
 1218    gutter_hovered: bool,
 1219}
 1220
 1221#[derive(Default, Debug, Clone, Copy)]
 1222pub struct GutterDimensions {
 1223    pub left_padding: Pixels,
 1224    pub right_padding: Pixels,
 1225    pub width: Pixels,
 1226    pub margin: Pixels,
 1227    pub git_blame_entries_width: Option<Pixels>,
 1228}
 1229
 1230impl GutterDimensions {
 1231    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1232        Self {
 1233            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1234            ..Default::default()
 1235        }
 1236    }
 1237
 1238    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1239        -cx.text_system().descent(font_id, font_size)
 1240    }
 1241    /// The full width of the space taken up by the gutter.
 1242    pub fn full_width(&self) -> Pixels {
 1243        self.margin + self.width
 1244    }
 1245
 1246    /// The width of the space reserved for the fold indicators,
 1247    /// use alongside 'justify_end' and `gutter_width` to
 1248    /// right align content with the line numbers
 1249    pub fn fold_area_width(&self) -> Pixels {
 1250        self.margin + self.right_padding
 1251    }
 1252}
 1253
 1254struct CharacterDimensions {
 1255    em_width: Pixels,
 1256    em_advance: Pixels,
 1257    line_height: Pixels,
 1258}
 1259
 1260#[derive(Debug)]
 1261pub struct RemoteSelection {
 1262    pub replica_id: ReplicaId,
 1263    pub selection: Selection<Anchor>,
 1264    pub cursor_shape: CursorShape,
 1265    pub collaborator_id: CollaboratorId,
 1266    pub line_mode: bool,
 1267    pub user_name: Option<SharedString>,
 1268    pub color: PlayerColor,
 1269}
 1270
 1271#[derive(Clone, Debug)]
 1272struct SelectionHistoryEntry {
 1273    selections: Arc<[Selection<Anchor>]>,
 1274    select_next_state: Option<SelectNextState>,
 1275    select_prev_state: Option<SelectNextState>,
 1276    add_selections_state: Option<AddSelectionsState>,
 1277}
 1278
 1279#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1280enum SelectionHistoryMode {
 1281    Normal,
 1282    Undoing,
 1283    Redoing,
 1284    Skipping,
 1285}
 1286
 1287#[derive(Clone, PartialEq, Eq, Hash)]
 1288struct HoveredCursor {
 1289    replica_id: u16,
 1290    selection_id: usize,
 1291}
 1292
 1293impl Default for SelectionHistoryMode {
 1294    fn default() -> Self {
 1295        Self::Normal
 1296    }
 1297}
 1298
 1299#[derive(Debug)]
 1300/// SelectionEffects controls the side-effects of updating the selection.
 1301///
 1302/// The default behaviour does "what you mostly want":
 1303/// - it pushes to the nav history if the cursor moved by >10 lines
 1304/// - it re-triggers completion requests
 1305/// - it scrolls to fit
 1306///
 1307/// You might want to modify these behaviours. For example when doing a "jump"
 1308/// like go to definition, we always want to add to nav history; but when scrolling
 1309/// in vim mode we never do.
 1310///
 1311/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1312/// move.
 1313#[derive(Clone)]
 1314pub struct SelectionEffects {
 1315    nav_history: Option<bool>,
 1316    completions: bool,
 1317    scroll: Option<Autoscroll>,
 1318}
 1319
 1320impl Default for SelectionEffects {
 1321    fn default() -> Self {
 1322        Self {
 1323            nav_history: None,
 1324            completions: true,
 1325            scroll: Some(Autoscroll::fit()),
 1326        }
 1327    }
 1328}
 1329impl SelectionEffects {
 1330    pub fn scroll(scroll: Autoscroll) -> Self {
 1331        Self {
 1332            scroll: Some(scroll),
 1333            ..Default::default()
 1334        }
 1335    }
 1336
 1337    pub fn no_scroll() -> Self {
 1338        Self {
 1339            scroll: None,
 1340            ..Default::default()
 1341        }
 1342    }
 1343
 1344    pub fn completions(self, completions: bool) -> Self {
 1345        Self {
 1346            completions,
 1347            ..self
 1348        }
 1349    }
 1350
 1351    pub fn nav_history(self, nav_history: bool) -> Self {
 1352        Self {
 1353            nav_history: Some(nav_history),
 1354            ..self
 1355        }
 1356    }
 1357}
 1358
 1359struct DeferredSelectionEffectsState {
 1360    changed: bool,
 1361    effects: SelectionEffects,
 1362    old_cursor_position: Anchor,
 1363    history_entry: SelectionHistoryEntry,
 1364}
 1365
 1366#[derive(Default)]
 1367struct SelectionHistory {
 1368    #[allow(clippy::type_complexity)]
 1369    selections_by_transaction:
 1370        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1371    mode: SelectionHistoryMode,
 1372    undo_stack: VecDeque<SelectionHistoryEntry>,
 1373    redo_stack: VecDeque<SelectionHistoryEntry>,
 1374}
 1375
 1376impl SelectionHistory {
 1377    #[track_caller]
 1378    fn insert_transaction(
 1379        &mut self,
 1380        transaction_id: TransactionId,
 1381        selections: Arc<[Selection<Anchor>]>,
 1382    ) {
 1383        if selections.is_empty() {
 1384            log::error!(
 1385                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1386                std::panic::Location::caller()
 1387            );
 1388            return;
 1389        }
 1390        self.selections_by_transaction
 1391            .insert(transaction_id, (selections, None));
 1392    }
 1393
 1394    #[allow(clippy::type_complexity)]
 1395    fn transaction(
 1396        &self,
 1397        transaction_id: TransactionId,
 1398    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1399        self.selections_by_transaction.get(&transaction_id)
 1400    }
 1401
 1402    #[allow(clippy::type_complexity)]
 1403    fn transaction_mut(
 1404        &mut self,
 1405        transaction_id: TransactionId,
 1406    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1407        self.selections_by_transaction.get_mut(&transaction_id)
 1408    }
 1409
 1410    fn push(&mut self, entry: SelectionHistoryEntry) {
 1411        if !entry.selections.is_empty() {
 1412            match self.mode {
 1413                SelectionHistoryMode::Normal => {
 1414                    self.push_undo(entry);
 1415                    self.redo_stack.clear();
 1416                }
 1417                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1418                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1419                SelectionHistoryMode::Skipping => {}
 1420            }
 1421        }
 1422    }
 1423
 1424    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1425        if self
 1426            .undo_stack
 1427            .back()
 1428            .is_none_or(|e| e.selections != entry.selections)
 1429        {
 1430            self.undo_stack.push_back(entry);
 1431            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1432                self.undo_stack.pop_front();
 1433            }
 1434        }
 1435    }
 1436
 1437    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1438        if self
 1439            .redo_stack
 1440            .back()
 1441            .is_none_or(|e| e.selections != entry.selections)
 1442        {
 1443            self.redo_stack.push_back(entry);
 1444            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1445                self.redo_stack.pop_front();
 1446            }
 1447        }
 1448    }
 1449}
 1450
 1451#[derive(Clone, Copy)]
 1452pub struct RowHighlightOptions {
 1453    pub autoscroll: bool,
 1454    pub include_gutter: bool,
 1455}
 1456
 1457impl Default for RowHighlightOptions {
 1458    fn default() -> Self {
 1459        Self {
 1460            autoscroll: Default::default(),
 1461            include_gutter: true,
 1462        }
 1463    }
 1464}
 1465
 1466struct RowHighlight {
 1467    index: usize,
 1468    range: Range<Anchor>,
 1469    color: Hsla,
 1470    options: RowHighlightOptions,
 1471    type_id: TypeId,
 1472}
 1473
 1474#[derive(Clone, Debug)]
 1475struct AddSelectionsState {
 1476    groups: Vec<AddSelectionsGroup>,
 1477}
 1478
 1479#[derive(Clone, Debug)]
 1480struct AddSelectionsGroup {
 1481    above: bool,
 1482    stack: Vec<usize>,
 1483}
 1484
 1485#[derive(Clone)]
 1486struct SelectNextState {
 1487    query: AhoCorasick,
 1488    wordwise: bool,
 1489    done: bool,
 1490}
 1491
 1492impl std::fmt::Debug for SelectNextState {
 1493    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1494        f.debug_struct(std::any::type_name::<Self>())
 1495            .field("wordwise", &self.wordwise)
 1496            .field("done", &self.done)
 1497            .finish()
 1498    }
 1499}
 1500
 1501#[derive(Debug)]
 1502struct AutocloseRegion {
 1503    selection_id: usize,
 1504    range: Range<Anchor>,
 1505    pair: BracketPair,
 1506}
 1507
 1508#[derive(Debug)]
 1509struct SnippetState {
 1510    ranges: Vec<Vec<Range<Anchor>>>,
 1511    active_index: usize,
 1512    choices: Vec<Option<Vec<String>>>,
 1513}
 1514
 1515#[doc(hidden)]
 1516pub struct RenameState {
 1517    pub range: Range<Anchor>,
 1518    pub old_name: Arc<str>,
 1519    pub editor: Entity<Editor>,
 1520    block_id: CustomBlockId,
 1521}
 1522
 1523struct InvalidationStack<T>(Vec<T>);
 1524
 1525struct RegisteredEditPredictionProvider {
 1526    provider: Arc<dyn EditPredictionProviderHandle>,
 1527    _subscription: Subscription,
 1528}
 1529
 1530#[derive(Debug, PartialEq, Eq)]
 1531pub struct ActiveDiagnosticGroup {
 1532    pub active_range: Range<Anchor>,
 1533    pub active_message: String,
 1534    pub group_id: usize,
 1535    pub blocks: HashSet<CustomBlockId>,
 1536}
 1537
 1538#[derive(Debug, PartialEq, Eq)]
 1539
 1540pub(crate) enum ActiveDiagnostic {
 1541    None,
 1542    All,
 1543    Group(ActiveDiagnosticGroup),
 1544}
 1545
 1546#[derive(Serialize, Deserialize, Clone, Debug)]
 1547pub struct ClipboardSelection {
 1548    /// The number of bytes in this selection.
 1549    pub len: usize,
 1550    /// Whether this was a full-line selection.
 1551    pub is_entire_line: bool,
 1552    /// The indentation of the first line when this content was originally copied.
 1553    pub first_line_indent: u32,
 1554}
 1555
 1556// selections, scroll behavior, was newest selection reversed
 1557type SelectSyntaxNodeHistoryState = (
 1558    Box<[Selection<usize>]>,
 1559    SelectSyntaxNodeScrollBehavior,
 1560    bool,
 1561);
 1562
 1563#[derive(Default)]
 1564struct SelectSyntaxNodeHistory {
 1565    stack: Vec<SelectSyntaxNodeHistoryState>,
 1566    // disable temporarily to allow changing selections without losing the stack
 1567    pub disable_clearing: bool,
 1568}
 1569
 1570impl SelectSyntaxNodeHistory {
 1571    pub fn try_clear(&mut self) {
 1572        if !self.disable_clearing {
 1573            self.stack.clear();
 1574        }
 1575    }
 1576
 1577    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1578        self.stack.push(selection);
 1579    }
 1580
 1581    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1582        self.stack.pop()
 1583    }
 1584}
 1585
 1586enum SelectSyntaxNodeScrollBehavior {
 1587    CursorTop,
 1588    FitSelection,
 1589    CursorBottom,
 1590}
 1591
 1592#[derive(Debug)]
 1593pub(crate) struct NavigationData {
 1594    cursor_anchor: Anchor,
 1595    cursor_position: Point,
 1596    scroll_anchor: ScrollAnchor,
 1597    scroll_top_row: u32,
 1598}
 1599
 1600#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1601pub enum GotoDefinitionKind {
 1602    Symbol,
 1603    Declaration,
 1604    Type,
 1605    Implementation,
 1606}
 1607
 1608#[derive(Debug, Clone)]
 1609enum InlayHintRefreshReason {
 1610    ModifiersChanged(bool),
 1611    Toggle(bool),
 1612    SettingsChange(InlayHintSettings),
 1613    NewLinesShown,
 1614    BufferEdited(HashSet<Arc<Language>>),
 1615    RefreshRequested,
 1616    ExcerptsRemoved(Vec<ExcerptId>),
 1617}
 1618
 1619impl InlayHintRefreshReason {
 1620    fn description(&self) -> &'static str {
 1621        match self {
 1622            Self::ModifiersChanged(_) => "modifiers changed",
 1623            Self::Toggle(_) => "toggle",
 1624            Self::SettingsChange(_) => "settings change",
 1625            Self::NewLinesShown => "new lines shown",
 1626            Self::BufferEdited(_) => "buffer edited",
 1627            Self::RefreshRequested => "refresh requested",
 1628            Self::ExcerptsRemoved(_) => "excerpts removed",
 1629        }
 1630    }
 1631}
 1632
 1633pub enum FormatTarget {
 1634    Buffers(HashSet<Entity<Buffer>>),
 1635    Ranges(Vec<Range<MultiBufferPoint>>),
 1636}
 1637
 1638pub(crate) struct FocusedBlock {
 1639    id: BlockId,
 1640    focus_handle: WeakFocusHandle,
 1641}
 1642
 1643#[derive(Clone)]
 1644enum JumpData {
 1645    MultiBufferRow {
 1646        row: MultiBufferRow,
 1647        line_offset_from_top: u32,
 1648    },
 1649    MultiBufferPoint {
 1650        excerpt_id: ExcerptId,
 1651        position: Point,
 1652        anchor: text::Anchor,
 1653        line_offset_from_top: u32,
 1654    },
 1655}
 1656
 1657pub enum MultibufferSelectionMode {
 1658    First,
 1659    All,
 1660}
 1661
 1662#[derive(Clone, Copy, Debug, Default)]
 1663pub struct RewrapOptions {
 1664    pub override_language_settings: bool,
 1665    pub preserve_existing_whitespace: bool,
 1666}
 1667
 1668impl Editor {
 1669    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1673    }
 1674
 1675    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1676        let buffer = cx.new(|cx| Buffer::local("", cx));
 1677        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1678        Self::new(EditorMode::full(), buffer, None, window, cx)
 1679    }
 1680
 1681    pub fn auto_height(
 1682        min_lines: usize,
 1683        max_lines: usize,
 1684        window: &mut Window,
 1685        cx: &mut Context<Self>,
 1686    ) -> Self {
 1687        let buffer = cx.new(|cx| Buffer::local("", cx));
 1688        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1689        Self::new(
 1690            EditorMode::AutoHeight {
 1691                min_lines,
 1692                max_lines: Some(max_lines),
 1693            },
 1694            buffer,
 1695            None,
 1696            window,
 1697            cx,
 1698        )
 1699    }
 1700
 1701    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1702    /// The editor grows as tall as needed to fit its content.
 1703    pub fn auto_height_unbounded(
 1704        min_lines: usize,
 1705        window: &mut Window,
 1706        cx: &mut Context<Self>,
 1707    ) -> Self {
 1708        let buffer = cx.new(|cx| Buffer::local("", cx));
 1709        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1710        Self::new(
 1711            EditorMode::AutoHeight {
 1712                min_lines,
 1713                max_lines: None,
 1714            },
 1715            buffer,
 1716            None,
 1717            window,
 1718            cx,
 1719        )
 1720    }
 1721
 1722    pub fn for_buffer(
 1723        buffer: Entity<Buffer>,
 1724        project: Option<Entity<Project>>,
 1725        window: &mut Window,
 1726        cx: &mut Context<Self>,
 1727    ) -> Self {
 1728        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1729        Self::new(EditorMode::full(), buffer, project, window, cx)
 1730    }
 1731
 1732    pub fn for_multibuffer(
 1733        buffer: Entity<MultiBuffer>,
 1734        project: Option<Entity<Project>>,
 1735        window: &mut Window,
 1736        cx: &mut Context<Self>,
 1737    ) -> Self {
 1738        Self::new(EditorMode::full(), buffer, project, window, cx)
 1739    }
 1740
 1741    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1742        let mut clone = Self::new(
 1743            self.mode.clone(),
 1744            self.buffer.clone(),
 1745            self.project.clone(),
 1746            window,
 1747            cx,
 1748        );
 1749        self.display_map.update(cx, |display_map, cx| {
 1750            let snapshot = display_map.snapshot(cx);
 1751            clone.display_map.update(cx, |display_map, cx| {
 1752                display_map.set_state(&snapshot, cx);
 1753            });
 1754        });
 1755        clone.folds_did_change(cx);
 1756        clone.selections.clone_state(&self.selections);
 1757        clone.scroll_manager.clone_state(&self.scroll_manager);
 1758        clone.searchable = self.searchable;
 1759        clone.read_only = self.read_only;
 1760        clone
 1761    }
 1762
 1763    pub fn new(
 1764        mode: EditorMode,
 1765        buffer: Entity<MultiBuffer>,
 1766        project: Option<Entity<Project>>,
 1767        window: &mut Window,
 1768        cx: &mut Context<Self>,
 1769    ) -> Self {
 1770        Editor::new_internal(mode, buffer, project, None, window, cx)
 1771    }
 1772
 1773    fn new_internal(
 1774        mode: EditorMode,
 1775        buffer: Entity<MultiBuffer>,
 1776        project: Option<Entity<Project>>,
 1777        display_map: Option<Entity<DisplayMap>>,
 1778        window: &mut Window,
 1779        cx: &mut Context<Self>,
 1780    ) -> Self {
 1781        debug_assert!(
 1782            display_map.is_none() || mode.is_minimap(),
 1783            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1784        );
 1785
 1786        let full_mode = mode.is_full();
 1787        let is_minimap = mode.is_minimap();
 1788        let diagnostics_max_severity = if full_mode {
 1789            EditorSettings::get_global(cx)
 1790                .diagnostics_max_severity
 1791                .unwrap_or(DiagnosticSeverity::Hint)
 1792        } else {
 1793            DiagnosticSeverity::Off
 1794        };
 1795        let style = window.text_style();
 1796        let font_size = style.font_size.to_pixels(window.rem_size());
 1797        let editor = cx.entity().downgrade();
 1798        let fold_placeholder = FoldPlaceholder {
 1799            constrain_width: true,
 1800            render: Arc::new(move |fold_id, fold_range, cx| {
 1801                let editor = editor.clone();
 1802                div()
 1803                    .id(fold_id)
 1804                    .bg(cx.theme().colors().ghost_element_background)
 1805                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1806                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1807                    .rounded_xs()
 1808                    .size_full()
 1809                    .cursor_pointer()
 1810                    .child("")
 1811                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1812                    .on_click(move |_, _window, cx| {
 1813                        editor
 1814                            .update(cx, |editor, cx| {
 1815                                editor.unfold_ranges(
 1816                                    &[fold_range.start..fold_range.end],
 1817                                    true,
 1818                                    false,
 1819                                    cx,
 1820                                );
 1821                                cx.stop_propagation();
 1822                            })
 1823                            .ok();
 1824                    })
 1825                    .into_any()
 1826            }),
 1827            merge_adjacent: true,
 1828            ..FoldPlaceholder::default()
 1829        };
 1830        let display_map = display_map.unwrap_or_else(|| {
 1831            cx.new(|cx| {
 1832                DisplayMap::new(
 1833                    buffer.clone(),
 1834                    style.font(),
 1835                    font_size,
 1836                    None,
 1837                    FILE_HEADER_HEIGHT,
 1838                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1839                    fold_placeholder,
 1840                    diagnostics_max_severity,
 1841                    cx,
 1842                )
 1843            })
 1844        });
 1845
 1846        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1847
 1848        let blink_manager = cx.new(|cx| {
 1849            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1850            if is_minimap {
 1851                blink_manager.disable(cx);
 1852            }
 1853            blink_manager
 1854        });
 1855
 1856        let soft_wrap_mode_override =
 1857            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1858
 1859        let mut project_subscriptions = Vec::new();
 1860        if full_mode && let Some(project) = project.as_ref() {
 1861            project_subscriptions.push(cx.subscribe_in(
 1862                project,
 1863                window,
 1864                |editor, _, event, window, cx| match event {
 1865                    project::Event::RefreshCodeLens => {
 1866                        // we always query lens with actions, without storing them, always refreshing them
 1867                    }
 1868                    project::Event::RefreshInlayHints => {
 1869                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1870                    }
 1871                    project::Event::LanguageServerAdded(..)
 1872                    | project::Event::LanguageServerRemoved(..) => {
 1873                        if editor.tasks_update_task.is_none() {
 1874                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1875                        }
 1876                    }
 1877                    project::Event::SnippetEdit(id, snippet_edits) => {
 1878                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1879                            let focus_handle = editor.focus_handle(cx);
 1880                            if focus_handle.is_focused(window) {
 1881                                let snapshot = buffer.read(cx).snapshot();
 1882                                for (range, snippet) in snippet_edits {
 1883                                    let editor_range =
 1884                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1885                                    editor
 1886                                        .insert_snippet(
 1887                                            &[editor_range],
 1888                                            snippet.clone(),
 1889                                            window,
 1890                                            cx,
 1891                                        )
 1892                                        .ok();
 1893                                }
 1894                            }
 1895                        }
 1896                    }
 1897                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1898                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1899                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1900                        }
 1901                    }
 1902
 1903                    project::Event::EntryRenamed(transaction) => {
 1904                        let Some(workspace) = editor.workspace() else {
 1905                            return;
 1906                        };
 1907                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1908                        else {
 1909                            return;
 1910                        };
 1911                        if active_editor.entity_id() == cx.entity_id() {
 1912                            let edited_buffers_already_open = {
 1913                                let other_editors: Vec<Entity<Editor>> = workspace
 1914                                    .read(cx)
 1915                                    .panes()
 1916                                    .iter()
 1917                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1918                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1919                                    .collect();
 1920
 1921                                transaction.0.keys().all(|buffer| {
 1922                                    other_editors.iter().any(|editor| {
 1923                                        let multi_buffer = editor.read(cx).buffer();
 1924                                        multi_buffer.read(cx).is_singleton()
 1925                                            && multi_buffer.read(cx).as_singleton().map_or(
 1926                                                false,
 1927                                                |singleton| {
 1928                                                    singleton.entity_id() == buffer.entity_id()
 1929                                                },
 1930                                            )
 1931                                    })
 1932                                })
 1933                            };
 1934
 1935                            if !edited_buffers_already_open {
 1936                                let workspace = workspace.downgrade();
 1937                                let transaction = transaction.clone();
 1938                                cx.defer_in(window, move |_, window, cx| {
 1939                                    cx.spawn_in(window, async move |editor, cx| {
 1940                                        Self::open_project_transaction(
 1941                                            &editor,
 1942                                            workspace,
 1943                                            transaction,
 1944                                            "Rename".to_string(),
 1945                                            cx,
 1946                                        )
 1947                                        .await
 1948                                        .ok()
 1949                                    })
 1950                                    .detach();
 1951                                });
 1952                            }
 1953                        }
 1954                    }
 1955
 1956                    _ => {}
 1957                },
 1958            ));
 1959            if let Some(task_inventory) = project
 1960                .read(cx)
 1961                .task_store()
 1962                .read(cx)
 1963                .task_inventory()
 1964                .cloned()
 1965            {
 1966                project_subscriptions.push(cx.observe_in(
 1967                    &task_inventory,
 1968                    window,
 1969                    |editor, _, window, cx| {
 1970                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1971                    },
 1972                ));
 1973            };
 1974
 1975            project_subscriptions.push(cx.subscribe_in(
 1976                &project.read(cx).breakpoint_store(),
 1977                window,
 1978                |editor, _, event, window, cx| match event {
 1979                    BreakpointStoreEvent::ClearDebugLines => {
 1980                        editor.clear_row_highlights::<ActiveDebugLine>();
 1981                        editor.refresh_inline_values(cx);
 1982                    }
 1983                    BreakpointStoreEvent::SetDebugLine => {
 1984                        if editor.go_to_active_debug_line(window, cx) {
 1985                            cx.stop_propagation();
 1986                        }
 1987
 1988                        editor.refresh_inline_values(cx);
 1989                    }
 1990                    _ => {}
 1991                },
 1992            ));
 1993            let git_store = project.read(cx).git_store().clone();
 1994            let project = project.clone();
 1995            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1996                if let GitStoreEvent::RepositoryUpdated(
 1997                    _,
 1998                    RepositoryEvent::Updated {
 1999                        new_instance: true, ..
 2000                    },
 2001                    _,
 2002                ) = event
 2003                {
 2004                    this.load_diff_task = Some(
 2005                        update_uncommitted_diff_for_buffer(
 2006                            cx.entity(),
 2007                            &project,
 2008                            this.buffer.read(cx).all_buffers(),
 2009                            this.buffer.clone(),
 2010                            cx,
 2011                        )
 2012                        .shared(),
 2013                    );
 2014                }
 2015            }));
 2016        }
 2017
 2018        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2019
 2020        let inlay_hint_settings =
 2021            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2022        let focus_handle = cx.focus_handle();
 2023        if !is_minimap {
 2024            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2025                .detach();
 2026            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2027                .detach();
 2028            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2029                .detach();
 2030            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2031                .detach();
 2032            cx.observe_pending_input(window, Self::observe_pending_input)
 2033                .detach();
 2034        }
 2035
 2036        let show_indent_guides =
 2037            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2038                Some(false)
 2039            } else {
 2040                None
 2041            };
 2042
 2043        let breakpoint_store = match (&mode, project.as_ref()) {
 2044            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2045            _ => None,
 2046        };
 2047
 2048        let mut code_action_providers = Vec::new();
 2049        let mut load_uncommitted_diff = None;
 2050        if let Some(project) = project.clone() {
 2051            load_uncommitted_diff = Some(
 2052                update_uncommitted_diff_for_buffer(
 2053                    cx.entity(),
 2054                    &project,
 2055                    buffer.read(cx).all_buffers(),
 2056                    buffer.clone(),
 2057                    cx,
 2058                )
 2059                .shared(),
 2060            );
 2061            code_action_providers.push(Rc::new(project) as Rc<_>);
 2062        }
 2063
 2064        let mut editor = Self {
 2065            focus_handle,
 2066            show_cursor_when_unfocused: false,
 2067            last_focused_descendant: None,
 2068            buffer: buffer.clone(),
 2069            display_map: display_map.clone(),
 2070            selections,
 2071            scroll_manager: ScrollManager::new(cx),
 2072            columnar_selection_state: None,
 2073            add_selections_state: None,
 2074            select_next_state: None,
 2075            select_prev_state: None,
 2076            selection_history: SelectionHistory::default(),
 2077            defer_selection_effects: false,
 2078            deferred_selection_effects_state: None,
 2079            autoclose_regions: Vec::new(),
 2080            snippet_stack: InvalidationStack::default(),
 2081            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2082            ime_transaction: None,
 2083            active_diagnostics: ActiveDiagnostic::None,
 2084            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2085            inline_diagnostics_update: Task::ready(()),
 2086            inline_diagnostics: Vec::new(),
 2087            soft_wrap_mode_override,
 2088            diagnostics_max_severity,
 2089            hard_wrap: None,
 2090            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2092            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2093            project,
 2094            blink_manager: blink_manager.clone(),
 2095            show_local_selections: true,
 2096            show_scrollbars: ScrollbarAxes {
 2097                horizontal: full_mode,
 2098                vertical: full_mode,
 2099            },
 2100            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2101            offset_content: !matches!(mode, EditorMode::SingleLine),
 2102            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2103            show_gutter: full_mode,
 2104            show_line_numbers: (!full_mode).then_some(false),
 2105            use_relative_line_numbers: None,
 2106            disable_expand_excerpt_buttons: !full_mode,
 2107            show_git_diff_gutter: None,
 2108            show_code_actions: None,
 2109            show_runnables: None,
 2110            show_breakpoints: None,
 2111            show_wrap_guides: None,
 2112            show_indent_guides,
 2113            placeholder_text: None,
 2114            highlight_order: 0,
 2115            highlighted_rows: HashMap::default(),
 2116            background_highlights: TreeMap::default(),
 2117            gutter_highlights: TreeMap::default(),
 2118            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2119            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2120            nav_history: None,
 2121            context_menu: RefCell::new(None),
 2122            context_menu_options: None,
 2123            mouse_context_menu: None,
 2124            completion_tasks: Vec::new(),
 2125            inline_blame_popover: None,
 2126            inline_blame_popover_show_task: None,
 2127            signature_help_state: SignatureHelpState::default(),
 2128            auto_signature_help: None,
 2129            find_all_references_task_sources: Vec::new(),
 2130            next_completion_id: 0,
 2131            next_inlay_id: 0,
 2132            code_action_providers,
 2133            available_code_actions: None,
 2134            code_actions_task: None,
 2135            quick_selection_highlight_task: None,
 2136            debounced_selection_highlight_task: None,
 2137            document_highlights_task: None,
 2138            linked_editing_range_task: None,
 2139            pending_rename: None,
 2140            searchable: !is_minimap,
 2141            cursor_shape: EditorSettings::get_global(cx)
 2142                .cursor_shape
 2143                .unwrap_or_default(),
 2144            current_line_highlight: None,
 2145            autoindent_mode: Some(AutoindentMode::EachLine),
 2146            collapse_matches: false,
 2147            workspace: None,
 2148            input_enabled: !is_minimap,
 2149            use_modal_editing: full_mode,
 2150            read_only: is_minimap,
 2151            use_autoclose: true,
 2152            use_auto_surround: true,
 2153            auto_replace_emoji_shortcode: false,
 2154            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2155            leader_id: None,
 2156            remote_id: None,
 2157            hover_state: HoverState::default(),
 2158            pending_mouse_down: None,
 2159            hovered_link_state: None,
 2160            edit_prediction_provider: None,
 2161            active_edit_prediction: None,
 2162            stale_edit_prediction_in_menu: None,
 2163            edit_prediction_preview: EditPredictionPreview::Inactive {
 2164                released_too_fast: false,
 2165            },
 2166            inline_diagnostics_enabled: full_mode,
 2167            diagnostics_enabled: full_mode,
 2168            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2169            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2170            gutter_hovered: false,
 2171            pixel_position_of_newest_cursor: None,
 2172            last_bounds: None,
 2173            last_position_map: None,
 2174            expect_bounds_change: None,
 2175            gutter_dimensions: GutterDimensions::default(),
 2176            style: None,
 2177            show_cursor_names: false,
 2178            hovered_cursors: HashMap::default(),
 2179            next_editor_action_id: EditorActionId::default(),
 2180            editor_actions: Rc::default(),
 2181            edit_predictions_hidden_for_vim_mode: false,
 2182            show_edit_predictions_override: None,
 2183            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2184            edit_prediction_settings: EditPredictionSettings::Disabled,
 2185            edit_prediction_indent_conflict: false,
 2186            edit_prediction_requires_modifier_in_indent_conflict: true,
 2187            custom_context_menu: None,
 2188            show_git_blame_gutter: false,
 2189            show_git_blame_inline: false,
 2190            show_selection_menu: None,
 2191            show_git_blame_inline_delay_task: None,
 2192            git_blame_inline_enabled: full_mode
 2193                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2194            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2195            serialize_dirty_buffers: !is_minimap
 2196                && ProjectSettings::get_global(cx)
 2197                    .session
 2198                    .restore_unsaved_buffers,
 2199            blame: None,
 2200            blame_subscription: None,
 2201            tasks: BTreeMap::default(),
 2202
 2203            breakpoint_store,
 2204            gutter_breakpoint_indicator: (None, None),
 2205            hovered_diff_hunk_row: None,
 2206            _subscriptions: (!is_minimap)
 2207                .then(|| {
 2208                    vec![
 2209                        cx.observe(&buffer, Self::on_buffer_changed),
 2210                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2211                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2212                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2213                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2214                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2215                        cx.observe_window_activation(window, |editor, window, cx| {
 2216                            let active = window.is_window_active();
 2217                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2218                                if active {
 2219                                    blink_manager.enable(cx);
 2220                                } else {
 2221                                    blink_manager.disable(cx);
 2222                                }
 2223                            });
 2224                            if active {
 2225                                editor.show_mouse_cursor(cx);
 2226                            }
 2227                        }),
 2228                    ]
 2229                })
 2230                .unwrap_or_default(),
 2231            tasks_update_task: None,
 2232            pull_diagnostics_task: Task::ready(()),
 2233            colors: None,
 2234            next_color_inlay_id: 0,
 2235            linked_edit_ranges: Default::default(),
 2236            in_project_search: false,
 2237            previous_search_ranges: None,
 2238            breadcrumb_header: None,
 2239            focused_block: None,
 2240            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2241            addons: HashMap::default(),
 2242            registered_buffers: HashMap::default(),
 2243            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2244            selection_mark_mode: false,
 2245            toggle_fold_multiple_buffers: Task::ready(()),
 2246            serialize_selections: Task::ready(()),
 2247            serialize_folds: Task::ready(()),
 2248            text_style_refinement: None,
 2249            load_diff_task: load_uncommitted_diff,
 2250            temporary_diff_override: false,
 2251            mouse_cursor_hidden: false,
 2252            minimap: None,
 2253            hide_mouse_mode: EditorSettings::get_global(cx)
 2254                .hide_mouse
 2255                .unwrap_or_default(),
 2256            change_list: ChangeList::new(),
 2257            mode,
 2258            selection_drag_state: SelectionDragState::None,
 2259            folding_newlines: Task::ready(()),
 2260        };
 2261
 2262        if is_minimap {
 2263            return editor;
 2264        }
 2265
 2266        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2267            editor
 2268                ._subscriptions
 2269                .push(cx.observe(breakpoints, |_, _, cx| {
 2270                    cx.notify();
 2271                }));
 2272        }
 2273        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2274        editor._subscriptions.extend(project_subscriptions);
 2275
 2276        editor._subscriptions.push(cx.subscribe_in(
 2277            &cx.entity(),
 2278            window,
 2279            |editor, _, e: &EditorEvent, window, cx| match e {
 2280                EditorEvent::ScrollPositionChanged { local, .. } => {
 2281                    if *local {
 2282                        let new_anchor = editor.scroll_manager.anchor();
 2283                        let snapshot = editor.snapshot(window, cx);
 2284                        editor.update_restoration_data(cx, move |data| {
 2285                            data.scroll_position = (
 2286                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2287                                new_anchor.offset,
 2288                            );
 2289                        });
 2290                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2291                        editor.inline_blame_popover.take();
 2292                    }
 2293                }
 2294                EditorEvent::Edited { .. } => {
 2295                    if !vim_enabled(cx) {
 2296                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2297                        let pop_state = editor
 2298                            .change_list
 2299                            .last()
 2300                            .map(|previous| {
 2301                                previous.len() == selections.len()
 2302                                    && previous.iter().enumerate().all(|(ix, p)| {
 2303                                        p.to_display_point(&map).row()
 2304                                            == selections[ix].head().row()
 2305                                    })
 2306                            })
 2307                            .unwrap_or(false);
 2308                        let new_positions = selections
 2309                            .into_iter()
 2310                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2311                            .collect();
 2312                        editor
 2313                            .change_list
 2314                            .push_to_change_list(pop_state, new_positions);
 2315                    }
 2316                }
 2317                _ => (),
 2318            },
 2319        ));
 2320
 2321        if let Some(dap_store) = editor
 2322            .project
 2323            .as_ref()
 2324            .map(|project| project.read(cx).dap_store())
 2325        {
 2326            let weak_editor = cx.weak_entity();
 2327
 2328            editor
 2329                ._subscriptions
 2330                .push(
 2331                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2332                        let session_entity = cx.entity();
 2333                        weak_editor
 2334                            .update(cx, |editor, cx| {
 2335                                editor._subscriptions.push(
 2336                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2337                                );
 2338                            })
 2339                            .ok();
 2340                    }),
 2341                );
 2342
 2343            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2344                editor
 2345                    ._subscriptions
 2346                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2347            }
 2348        }
 2349
 2350        // skip adding the initial selection to selection history
 2351        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2352        editor.end_selection(window, cx);
 2353        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2354
 2355        editor.scroll_manager.show_scrollbars(window, cx);
 2356        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2357
 2358        if full_mode {
 2359            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2360            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2361
 2362            if editor.git_blame_inline_enabled {
 2363                editor.start_git_blame_inline(false, window, cx);
 2364            }
 2365
 2366            editor.go_to_active_debug_line(window, cx);
 2367
 2368            if let Some(buffer) = buffer.read(cx).as_singleton()
 2369                && let Some(project) = editor.project()
 2370            {
 2371                let handle = project.update(cx, |project, cx| {
 2372                    project.register_buffer_with_language_servers(&buffer, cx)
 2373                });
 2374                editor
 2375                    .registered_buffers
 2376                    .insert(buffer.read(cx).remote_id(), handle);
 2377            }
 2378
 2379            editor.minimap =
 2380                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2381            editor.colors = Some(LspColorData::new(cx));
 2382            editor.update_lsp_data(false, None, window, cx);
 2383        }
 2384
 2385        if editor.mode.is_full() {
 2386            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2387        }
 2388
 2389        editor
 2390    }
 2391
 2392    pub fn deploy_mouse_context_menu(
 2393        &mut self,
 2394        position: gpui::Point<Pixels>,
 2395        context_menu: Entity<ContextMenu>,
 2396        window: &mut Window,
 2397        cx: &mut Context<Self>,
 2398    ) {
 2399        self.mouse_context_menu = Some(MouseContextMenu::new(
 2400            self,
 2401            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2402            context_menu,
 2403            window,
 2404            cx,
 2405        ));
 2406    }
 2407
 2408    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2409        self.mouse_context_menu
 2410            .as_ref()
 2411            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2412    }
 2413
 2414    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2415        if self
 2416            .selections
 2417            .pending
 2418            .as_ref()
 2419            .is_some_and(|pending_selection| {
 2420                let snapshot = self.buffer().read(cx).snapshot(cx);
 2421                pending_selection
 2422                    .selection
 2423                    .range()
 2424                    .includes(range, &snapshot)
 2425            })
 2426        {
 2427            return true;
 2428        }
 2429
 2430        self.selections
 2431            .disjoint_in_range::<usize>(range.clone(), cx)
 2432            .into_iter()
 2433            .any(|selection| {
 2434                // This is needed to cover a corner case, if we just check for an existing
 2435                // selection in the fold range, having a cursor at the start of the fold
 2436                // marks it as selected. Non-empty selections don't cause this.
 2437                let length = selection.end - selection.start;
 2438                length > 0
 2439            })
 2440    }
 2441
 2442    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2443        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2444    }
 2445
 2446    fn key_context_internal(
 2447        &self,
 2448        has_active_edit_prediction: bool,
 2449        window: &Window,
 2450        cx: &App,
 2451    ) -> KeyContext {
 2452        let mut key_context = KeyContext::new_with_defaults();
 2453        key_context.add("Editor");
 2454        let mode = match self.mode {
 2455            EditorMode::SingleLine => "single_line",
 2456            EditorMode::AutoHeight { .. } => "auto_height",
 2457            EditorMode::Minimap { .. } => "minimap",
 2458            EditorMode::Full { .. } => "full",
 2459        };
 2460
 2461        if EditorSettings::jupyter_enabled(cx) {
 2462            key_context.add("jupyter");
 2463        }
 2464
 2465        key_context.set("mode", mode);
 2466        if self.pending_rename.is_some() {
 2467            key_context.add("renaming");
 2468        }
 2469
 2470        match self.context_menu.borrow().as_ref() {
 2471            Some(CodeContextMenu::Completions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_completions");
 2475                }
 2476            }
 2477            Some(CodeContextMenu::CodeActions(menu)) => {
 2478                if menu.visible() {
 2479                    key_context.add("menu");
 2480                    key_context.add("showing_code_actions")
 2481                }
 2482            }
 2483            None => {}
 2484        }
 2485
 2486        if self.signature_help_state.has_multiple_signatures() {
 2487            key_context.add("showing_signature_help");
 2488        }
 2489
 2490        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2491        if !self.focus_handle(cx).contains_focused(window, cx)
 2492            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2493        {
 2494            for addon in self.addons.values() {
 2495                addon.extend_key_context(&mut key_context, cx)
 2496            }
 2497        }
 2498
 2499        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2500            if let Some(extension) = singleton_buffer
 2501                .read(cx)
 2502                .file()
 2503                .and_then(|file| file.path().extension()?.to_str())
 2504            {
 2505                key_context.set("extension", extension.to_string());
 2506            }
 2507        } else {
 2508            key_context.add("multibuffer");
 2509        }
 2510
 2511        if has_active_edit_prediction {
 2512            if self.edit_prediction_in_conflict() {
 2513                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2514            } else {
 2515                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2516                key_context.add("copilot_suggestion");
 2517            }
 2518        }
 2519
 2520        if self.selection_mark_mode {
 2521            key_context.add("selection_mode");
 2522        }
 2523
 2524        key_context
 2525    }
 2526
 2527    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2528        if self.mouse_cursor_hidden {
 2529            self.mouse_cursor_hidden = false;
 2530            cx.notify();
 2531        }
 2532    }
 2533
 2534    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2535        let hide_mouse_cursor = match origin {
 2536            HideMouseCursorOrigin::TypingAction => {
 2537                matches!(
 2538                    self.hide_mouse_mode,
 2539                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2540                )
 2541            }
 2542            HideMouseCursorOrigin::MovementAction => {
 2543                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2544            }
 2545        };
 2546        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2547            self.mouse_cursor_hidden = hide_mouse_cursor;
 2548            cx.notify();
 2549        }
 2550    }
 2551
 2552    pub fn edit_prediction_in_conflict(&self) -> bool {
 2553        if !self.show_edit_predictions_in_menu() {
 2554            return false;
 2555        }
 2556
 2557        let showing_completions = self
 2558            .context_menu
 2559            .borrow()
 2560            .as_ref()
 2561            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2562
 2563        showing_completions
 2564            || self.edit_prediction_requires_modifier()
 2565            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2566            // bindings to insert tab characters.
 2567            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2568    }
 2569
 2570    pub fn accept_edit_prediction_keybind(
 2571        &self,
 2572        accept_partial: bool,
 2573        window: &Window,
 2574        cx: &App,
 2575    ) -> AcceptEditPredictionBinding {
 2576        let key_context = self.key_context_internal(true, window, cx);
 2577        let in_conflict = self.edit_prediction_in_conflict();
 2578
 2579        let bindings = if accept_partial {
 2580            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2581        } else {
 2582            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2583        };
 2584
 2585        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2586        // just the first one.
 2587        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2588            !in_conflict
 2589                || binding
 2590                    .keystrokes()
 2591                    .first()
 2592                    .is_some_and(|keystroke| keystroke.display_modifiers.modified())
 2593        }))
 2594    }
 2595
 2596    pub fn new_file(
 2597        workspace: &mut Workspace,
 2598        _: &workspace::NewFile,
 2599        window: &mut Window,
 2600        cx: &mut Context<Workspace>,
 2601    ) {
 2602        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2603            "Failed to create buffer",
 2604            window,
 2605            cx,
 2606            |e, _, _| match e.error_code() {
 2607                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2608                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2609                e.error_tag("required").unwrap_or("the latest version")
 2610            )),
 2611                _ => None,
 2612            },
 2613        );
 2614    }
 2615
 2616    pub fn new_in_workspace(
 2617        workspace: &mut Workspace,
 2618        window: &mut Window,
 2619        cx: &mut Context<Workspace>,
 2620    ) -> Task<Result<Entity<Editor>>> {
 2621        let project = workspace.project().clone();
 2622        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2623
 2624        cx.spawn_in(window, async move |workspace, cx| {
 2625            let buffer = create.await?;
 2626            workspace.update_in(cx, |workspace, window, cx| {
 2627                let editor =
 2628                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2629                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2630                editor
 2631            })
 2632        })
 2633    }
 2634
 2635    fn new_file_vertical(
 2636        workspace: &mut Workspace,
 2637        _: &workspace::NewFileSplitVertical,
 2638        window: &mut Window,
 2639        cx: &mut Context<Workspace>,
 2640    ) {
 2641        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2642    }
 2643
 2644    fn new_file_horizontal(
 2645        workspace: &mut Workspace,
 2646        _: &workspace::NewFileSplitHorizontal,
 2647        window: &mut Window,
 2648        cx: &mut Context<Workspace>,
 2649    ) {
 2650        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2651    }
 2652
 2653    fn new_file_in_direction(
 2654        workspace: &mut Workspace,
 2655        direction: SplitDirection,
 2656        window: &mut Window,
 2657        cx: &mut Context<Workspace>,
 2658    ) {
 2659        let project = workspace.project().clone();
 2660        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2661
 2662        cx.spawn_in(window, async move |workspace, cx| {
 2663            let buffer = create.await?;
 2664            workspace.update_in(cx, move |workspace, window, cx| {
 2665                workspace.split_item(
 2666                    direction,
 2667                    Box::new(
 2668                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2669                    ),
 2670                    window,
 2671                    cx,
 2672                )
 2673            })?;
 2674            anyhow::Ok(())
 2675        })
 2676        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2677            match e.error_code() {
 2678                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2679                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2680                e.error_tag("required").unwrap_or("the latest version")
 2681            )),
 2682                _ => None,
 2683            }
 2684        });
 2685    }
 2686
 2687    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2688        self.leader_id
 2689    }
 2690
 2691    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2692        &self.buffer
 2693    }
 2694
 2695    pub fn project(&self) -> Option<&Entity<Project>> {
 2696        self.project.as_ref()
 2697    }
 2698
 2699    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2700        self.workspace.as_ref()?.0.upgrade()
 2701    }
 2702
 2703    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2704        self.buffer().read(cx).title(cx)
 2705    }
 2706
 2707    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2708        let git_blame_gutter_max_author_length = self
 2709            .render_git_blame_gutter(cx)
 2710            .then(|| {
 2711                if let Some(blame) = self.blame.as_ref() {
 2712                    let max_author_length =
 2713                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2714                    Some(max_author_length)
 2715                } else {
 2716                    None
 2717                }
 2718            })
 2719            .flatten();
 2720
 2721        EditorSnapshot {
 2722            mode: self.mode.clone(),
 2723            show_gutter: self.show_gutter,
 2724            show_line_numbers: self.show_line_numbers,
 2725            show_git_diff_gutter: self.show_git_diff_gutter,
 2726            show_code_actions: self.show_code_actions,
 2727            show_runnables: self.show_runnables,
 2728            show_breakpoints: self.show_breakpoints,
 2729            git_blame_gutter_max_author_length,
 2730            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2731            scroll_anchor: self.scroll_manager.anchor(),
 2732            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2733            placeholder_text: self.placeholder_text.clone(),
 2734            is_focused: self.focus_handle.is_focused(window),
 2735            current_line_highlight: self
 2736                .current_line_highlight
 2737                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2738            gutter_hovered: self.gutter_hovered,
 2739        }
 2740    }
 2741
 2742    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2743        self.buffer.read(cx).language_at(point, cx)
 2744    }
 2745
 2746    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2747        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2748    }
 2749
 2750    pub fn active_excerpt(
 2751        &self,
 2752        cx: &App,
 2753    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2754        self.buffer
 2755            .read(cx)
 2756            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2757    }
 2758
 2759    pub fn mode(&self) -> &EditorMode {
 2760        &self.mode
 2761    }
 2762
 2763    pub fn set_mode(&mut self, mode: EditorMode) {
 2764        self.mode = mode;
 2765    }
 2766
 2767    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2768        self.collaboration_hub.as_deref()
 2769    }
 2770
 2771    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2772        self.collaboration_hub = Some(hub);
 2773    }
 2774
 2775    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2776        self.in_project_search = in_project_search;
 2777    }
 2778
 2779    pub fn set_custom_context_menu(
 2780        &mut self,
 2781        f: impl 'static
 2782        + Fn(
 2783            &mut Self,
 2784            DisplayPoint,
 2785            &mut Window,
 2786            &mut Context<Self>,
 2787        ) -> Option<Entity<ui::ContextMenu>>,
 2788    ) {
 2789        self.custom_context_menu = Some(Box::new(f))
 2790    }
 2791
 2792    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2793        self.completion_provider = provider;
 2794    }
 2795
 2796    #[cfg(any(test, feature = "test-support"))]
 2797    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2798        self.completion_provider.clone()
 2799    }
 2800
 2801    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2802        self.semantics_provider.clone()
 2803    }
 2804
 2805    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2806        self.semantics_provider = provider;
 2807    }
 2808
 2809    pub fn set_edit_prediction_provider<T>(
 2810        &mut self,
 2811        provider: Option<Entity<T>>,
 2812        window: &mut Window,
 2813        cx: &mut Context<Self>,
 2814    ) where
 2815        T: EditPredictionProvider,
 2816    {
 2817        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2818            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2819                if this.focus_handle.is_focused(window) {
 2820                    this.update_visible_edit_prediction(window, cx);
 2821                }
 2822            }),
 2823            provider: Arc::new(provider),
 2824        });
 2825        self.update_edit_prediction_settings(cx);
 2826        self.refresh_edit_prediction(false, false, window, cx);
 2827    }
 2828
 2829    pub fn placeholder_text(&self) -> Option<&str> {
 2830        self.placeholder_text.as_deref()
 2831    }
 2832
 2833    pub fn set_placeholder_text(
 2834        &mut self,
 2835        placeholder_text: impl Into<Arc<str>>,
 2836        cx: &mut Context<Self>,
 2837    ) {
 2838        let placeholder_text = Some(placeholder_text.into());
 2839        if self.placeholder_text != placeholder_text {
 2840            self.placeholder_text = placeholder_text;
 2841            cx.notify();
 2842        }
 2843    }
 2844
 2845    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2846        self.cursor_shape = cursor_shape;
 2847
 2848        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2849        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2850
 2851        cx.notify();
 2852    }
 2853
 2854    pub fn set_current_line_highlight(
 2855        &mut self,
 2856        current_line_highlight: Option<CurrentLineHighlight>,
 2857    ) {
 2858        self.current_line_highlight = current_line_highlight;
 2859    }
 2860
 2861    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2862        self.collapse_matches = collapse_matches;
 2863    }
 2864
 2865    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2866        let buffers = self.buffer.read(cx).all_buffers();
 2867        let Some(project) = self.project.as_ref() else {
 2868            return;
 2869        };
 2870        project.update(cx, |project, cx| {
 2871            for buffer in buffers {
 2872                self.registered_buffers
 2873                    .entry(buffer.read(cx).remote_id())
 2874                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2875            }
 2876        })
 2877    }
 2878
 2879    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2880        if self.collapse_matches {
 2881            return range.start..range.start;
 2882        }
 2883        range.clone()
 2884    }
 2885
 2886    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2887        if self.display_map.read(cx).clip_at_line_ends != clip {
 2888            self.display_map
 2889                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2890        }
 2891    }
 2892
 2893    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2894        self.input_enabled = input_enabled;
 2895    }
 2896
 2897    pub fn set_edit_predictions_hidden_for_vim_mode(
 2898        &mut self,
 2899        hidden: bool,
 2900        window: &mut Window,
 2901        cx: &mut Context<Self>,
 2902    ) {
 2903        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2904            self.edit_predictions_hidden_for_vim_mode = hidden;
 2905            if hidden {
 2906                self.update_visible_edit_prediction(window, cx);
 2907            } else {
 2908                self.refresh_edit_prediction(true, false, window, cx);
 2909            }
 2910        }
 2911    }
 2912
 2913    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2914        self.menu_edit_predictions_policy = value;
 2915    }
 2916
 2917    pub fn set_autoindent(&mut self, autoindent: bool) {
 2918        if autoindent {
 2919            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2920        } else {
 2921            self.autoindent_mode = None;
 2922        }
 2923    }
 2924
 2925    pub fn read_only(&self, cx: &App) -> bool {
 2926        self.read_only || self.buffer.read(cx).read_only()
 2927    }
 2928
 2929    pub fn set_read_only(&mut self, read_only: bool) {
 2930        self.read_only = read_only;
 2931    }
 2932
 2933    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2934        self.use_autoclose = autoclose;
 2935    }
 2936
 2937    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2938        self.use_auto_surround = auto_surround;
 2939    }
 2940
 2941    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2942        self.auto_replace_emoji_shortcode = auto_replace;
 2943    }
 2944
 2945    pub fn toggle_edit_predictions(
 2946        &mut self,
 2947        _: &ToggleEditPrediction,
 2948        window: &mut Window,
 2949        cx: &mut Context<Self>,
 2950    ) {
 2951        if self.show_edit_predictions_override.is_some() {
 2952            self.set_show_edit_predictions(None, window, cx);
 2953        } else {
 2954            let show_edit_predictions = !self.edit_predictions_enabled();
 2955            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2956        }
 2957    }
 2958
 2959    pub fn set_show_edit_predictions(
 2960        &mut self,
 2961        show_edit_predictions: Option<bool>,
 2962        window: &mut Window,
 2963        cx: &mut Context<Self>,
 2964    ) {
 2965        self.show_edit_predictions_override = show_edit_predictions;
 2966        self.update_edit_prediction_settings(cx);
 2967
 2968        if let Some(false) = show_edit_predictions {
 2969            self.discard_edit_prediction(false, cx);
 2970        } else {
 2971            self.refresh_edit_prediction(false, true, window, cx);
 2972        }
 2973    }
 2974
 2975    fn edit_predictions_disabled_in_scope(
 2976        &self,
 2977        buffer: &Entity<Buffer>,
 2978        buffer_position: language::Anchor,
 2979        cx: &App,
 2980    ) -> bool {
 2981        let snapshot = buffer.read(cx).snapshot();
 2982        let settings = snapshot.settings_at(buffer_position, cx);
 2983
 2984        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2985            return false;
 2986        };
 2987
 2988        scope.override_name().is_some_and(|scope_name| {
 2989            settings
 2990                .edit_predictions_disabled_in
 2991                .iter()
 2992                .any(|s| s == scope_name)
 2993        })
 2994    }
 2995
 2996    pub fn set_use_modal_editing(&mut self, to: bool) {
 2997        self.use_modal_editing = to;
 2998    }
 2999
 3000    pub fn use_modal_editing(&self) -> bool {
 3001        self.use_modal_editing
 3002    }
 3003
 3004    fn selections_did_change(
 3005        &mut self,
 3006        local: bool,
 3007        old_cursor_position: &Anchor,
 3008        effects: SelectionEffects,
 3009        window: &mut Window,
 3010        cx: &mut Context<Self>,
 3011    ) {
 3012        window.invalidate_character_coordinates();
 3013
 3014        // Copy selections to primary selection buffer
 3015        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3016        if local {
 3017            let selections = self.selections.all::<usize>(cx);
 3018            let buffer_handle = self.buffer.read(cx).read(cx);
 3019
 3020            let mut text = String::new();
 3021            for (index, selection) in selections.iter().enumerate() {
 3022                let text_for_selection = buffer_handle
 3023                    .text_for_range(selection.start..selection.end)
 3024                    .collect::<String>();
 3025
 3026                text.push_str(&text_for_selection);
 3027                if index != selections.len() - 1 {
 3028                    text.push('\n');
 3029                }
 3030            }
 3031
 3032            if !text.is_empty() {
 3033                cx.write_to_primary(ClipboardItem::new_string(text));
 3034            }
 3035        }
 3036
 3037        let selection_anchors = self.selections.disjoint_anchors();
 3038
 3039        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3040            self.buffer.update(cx, |buffer, cx| {
 3041                buffer.set_active_selections(
 3042                    &selection_anchors,
 3043                    self.selections.line_mode,
 3044                    self.cursor_shape,
 3045                    cx,
 3046                )
 3047            });
 3048        }
 3049        let display_map = self
 3050            .display_map
 3051            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3052        let buffer = &display_map.buffer_snapshot;
 3053        if self.selections.count() == 1 {
 3054            self.add_selections_state = None;
 3055        }
 3056        self.select_next_state = None;
 3057        self.select_prev_state = None;
 3058        self.select_syntax_node_history.try_clear();
 3059        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3060        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3061        self.take_rename(false, window, cx);
 3062
 3063        let newest_selection = self.selections.newest_anchor();
 3064        let new_cursor_position = newest_selection.head();
 3065        let selection_start = newest_selection.start;
 3066
 3067        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3068            self.push_to_nav_history(
 3069                *old_cursor_position,
 3070                Some(new_cursor_position.to_point(buffer)),
 3071                false,
 3072                effects.nav_history == Some(true),
 3073                cx,
 3074            );
 3075        }
 3076
 3077        if local {
 3078            if let Some(buffer_id) = new_cursor_position.buffer_id
 3079                && !self.registered_buffers.contains_key(&buffer_id)
 3080                && let Some(project) = self.project.as_ref()
 3081            {
 3082                project.update(cx, |project, cx| {
 3083                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3084                        return;
 3085                    };
 3086                    self.registered_buffers.insert(
 3087                        buffer_id,
 3088                        project.register_buffer_with_language_servers(&buffer, cx),
 3089                    );
 3090                })
 3091            }
 3092
 3093            let mut context_menu = self.context_menu.borrow_mut();
 3094            let completion_menu = match context_menu.as_ref() {
 3095                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3096                Some(CodeContextMenu::CodeActions(_)) => {
 3097                    *context_menu = None;
 3098                    None
 3099                }
 3100                None => None,
 3101            };
 3102            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3103            drop(context_menu);
 3104
 3105            if effects.completions
 3106                && let Some(completion_position) = completion_position
 3107            {
 3108                let start_offset = selection_start.to_offset(buffer);
 3109                let position_matches = start_offset == completion_position.to_offset(buffer);
 3110                let continue_showing = if position_matches {
 3111                    if self.snippet_stack.is_empty() {
 3112                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3113                    } else {
 3114                        // Snippet choices can be shown even when the cursor is in whitespace.
 3115                        // Dismissing the menu with actions like backspace is handled by
 3116                        // invalidation regions.
 3117                        true
 3118                    }
 3119                } else {
 3120                    false
 3121                };
 3122
 3123                if continue_showing {
 3124                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3125                } else {
 3126                    self.hide_context_menu(window, cx);
 3127                }
 3128            }
 3129
 3130            hide_hover(self, cx);
 3131
 3132            if old_cursor_position.to_display_point(&display_map).row()
 3133                != new_cursor_position.to_display_point(&display_map).row()
 3134            {
 3135                self.available_code_actions.take();
 3136            }
 3137            self.refresh_code_actions(window, cx);
 3138            self.refresh_document_highlights(cx);
 3139            self.refresh_selected_text_highlights(false, window, cx);
 3140            refresh_matching_bracket_highlights(self, window, cx);
 3141            self.update_visible_edit_prediction(window, cx);
 3142            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3143            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3144            self.inline_blame_popover.take();
 3145            if self.git_blame_inline_enabled {
 3146                self.start_inline_blame_timer(window, cx);
 3147            }
 3148        }
 3149
 3150        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3151        cx.emit(EditorEvent::SelectionsChanged { local });
 3152
 3153        let selections = &self.selections.disjoint;
 3154        if selections.len() == 1 {
 3155            cx.emit(SearchEvent::ActiveMatchChanged)
 3156        }
 3157        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3158            let inmemory_selections = selections
 3159                .iter()
 3160                .map(|s| {
 3161                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3162                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3163                })
 3164                .collect();
 3165            self.update_restoration_data(cx, |data| {
 3166                data.selections = inmemory_selections;
 3167            });
 3168
 3169            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3170                && let Some(workspace_id) =
 3171                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3172            {
 3173                let snapshot = self.buffer().read(cx).snapshot(cx);
 3174                let selections = selections.clone();
 3175                let background_executor = cx.background_executor().clone();
 3176                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3177                self.serialize_selections = cx.background_spawn(async move {
 3178                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3179                            let db_selections = selections
 3180                                .iter()
 3181                                .map(|selection| {
 3182                                    (
 3183                                        selection.start.to_offset(&snapshot),
 3184                                        selection.end.to_offset(&snapshot),
 3185                                    )
 3186                                })
 3187                                .collect();
 3188
 3189                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3190                                .await
 3191                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3192                                .log_err();
 3193                        });
 3194            }
 3195        }
 3196
 3197        cx.notify();
 3198    }
 3199
 3200    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3201        use text::ToOffset as _;
 3202        use text::ToPoint as _;
 3203
 3204        if self.mode.is_minimap()
 3205            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3206        {
 3207            return;
 3208        }
 3209
 3210        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3211            return;
 3212        };
 3213
 3214        let snapshot = singleton.read(cx).snapshot();
 3215        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3216            let display_snapshot = display_map.snapshot(cx);
 3217
 3218            display_snapshot
 3219                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3220                .map(|fold| {
 3221                    fold.range.start.text_anchor.to_point(&snapshot)
 3222                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3223                })
 3224                .collect()
 3225        });
 3226        self.update_restoration_data(cx, |data| {
 3227            data.folds = inmemory_folds;
 3228        });
 3229
 3230        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3231            return;
 3232        };
 3233        let background_executor = cx.background_executor().clone();
 3234        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3235        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3236            display_map
 3237                .snapshot(cx)
 3238                .folds_in_range(0..snapshot.len())
 3239                .map(|fold| {
 3240                    (
 3241                        fold.range.start.text_anchor.to_offset(&snapshot),
 3242                        fold.range.end.text_anchor.to_offset(&snapshot),
 3243                    )
 3244                })
 3245                .collect()
 3246        });
 3247        self.serialize_folds = cx.background_spawn(async move {
 3248            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3249            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3250                .await
 3251                .with_context(|| {
 3252                    format!(
 3253                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3254                    )
 3255                })
 3256                .log_err();
 3257        });
 3258    }
 3259
 3260    pub fn sync_selections(
 3261        &mut self,
 3262        other: Entity<Editor>,
 3263        cx: &mut Context<Self>,
 3264    ) -> gpui::Subscription {
 3265        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3266        self.selections.change_with(cx, |selections| {
 3267            selections.select_anchors(other_selections);
 3268        });
 3269
 3270        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3271            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3272                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3273                if other_selections.is_empty() {
 3274                    return;
 3275                }
 3276                this.selections.change_with(cx, |selections| {
 3277                    selections.select_anchors(other_selections);
 3278                });
 3279            }
 3280        });
 3281
 3282        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3283            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3284                let these_selections = this.selections.disjoint.to_vec();
 3285                if these_selections.is_empty() {
 3286                    return;
 3287                }
 3288                other.update(cx, |other_editor, cx| {
 3289                    other_editor.selections.change_with(cx, |selections| {
 3290                        selections.select_anchors(these_selections);
 3291                    })
 3292                });
 3293            }
 3294        });
 3295
 3296        Subscription::join(other_subscription, this_subscription)
 3297    }
 3298
 3299    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3300    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3301    /// effects of selection change occur at the end of the transaction.
 3302    pub fn change_selections<R>(
 3303        &mut self,
 3304        effects: SelectionEffects,
 3305        window: &mut Window,
 3306        cx: &mut Context<Self>,
 3307        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3308    ) -> R {
 3309        if let Some(state) = &mut self.deferred_selection_effects_state {
 3310            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3311            state.effects.completions = effects.completions;
 3312            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3313            let (changed, result) = self.selections.change_with(cx, change);
 3314            state.changed |= changed;
 3315            return result;
 3316        }
 3317        let mut state = DeferredSelectionEffectsState {
 3318            changed: false,
 3319            effects,
 3320            old_cursor_position: self.selections.newest_anchor().head(),
 3321            history_entry: SelectionHistoryEntry {
 3322                selections: self.selections.disjoint_anchors(),
 3323                select_next_state: self.select_next_state.clone(),
 3324                select_prev_state: self.select_prev_state.clone(),
 3325                add_selections_state: self.add_selections_state.clone(),
 3326            },
 3327        };
 3328        let (changed, result) = self.selections.change_with(cx, change);
 3329        state.changed = state.changed || changed;
 3330        if self.defer_selection_effects {
 3331            self.deferred_selection_effects_state = Some(state);
 3332        } else {
 3333            self.apply_selection_effects(state, window, cx);
 3334        }
 3335        result
 3336    }
 3337
 3338    /// Defers the effects of selection change, so that the effects of multiple calls to
 3339    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3340    /// to selection history and the state of popovers based on selection position aren't
 3341    /// erroneously updated.
 3342    pub fn with_selection_effects_deferred<R>(
 3343        &mut self,
 3344        window: &mut Window,
 3345        cx: &mut Context<Self>,
 3346        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3347    ) -> R {
 3348        let already_deferred = self.defer_selection_effects;
 3349        self.defer_selection_effects = true;
 3350        let result = update(self, window, cx);
 3351        if !already_deferred {
 3352            self.defer_selection_effects = false;
 3353            if let Some(state) = self.deferred_selection_effects_state.take() {
 3354                self.apply_selection_effects(state, window, cx);
 3355            }
 3356        }
 3357        result
 3358    }
 3359
 3360    fn apply_selection_effects(
 3361        &mut self,
 3362        state: DeferredSelectionEffectsState,
 3363        window: &mut Window,
 3364        cx: &mut Context<Self>,
 3365    ) {
 3366        if state.changed {
 3367            self.selection_history.push(state.history_entry);
 3368
 3369            if let Some(autoscroll) = state.effects.scroll {
 3370                self.request_autoscroll(autoscroll, cx);
 3371            }
 3372
 3373            let old_cursor_position = &state.old_cursor_position;
 3374
 3375            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3376
 3377            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3378                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3379            }
 3380        }
 3381    }
 3382
 3383    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3384    where
 3385        I: IntoIterator<Item = (Range<S>, T)>,
 3386        S: ToOffset,
 3387        T: Into<Arc<str>>,
 3388    {
 3389        if self.read_only(cx) {
 3390            return;
 3391        }
 3392
 3393        self.buffer
 3394            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3395    }
 3396
 3397    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3398    where
 3399        I: IntoIterator<Item = (Range<S>, T)>,
 3400        S: ToOffset,
 3401        T: Into<Arc<str>>,
 3402    {
 3403        if self.read_only(cx) {
 3404            return;
 3405        }
 3406
 3407        self.buffer.update(cx, |buffer, cx| {
 3408            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3409        });
 3410    }
 3411
 3412    pub fn edit_with_block_indent<I, S, T>(
 3413        &mut self,
 3414        edits: I,
 3415        original_indent_columns: Vec<Option<u32>>,
 3416        cx: &mut Context<Self>,
 3417    ) where
 3418        I: IntoIterator<Item = (Range<S>, T)>,
 3419        S: ToOffset,
 3420        T: Into<Arc<str>>,
 3421    {
 3422        if self.read_only(cx) {
 3423            return;
 3424        }
 3425
 3426        self.buffer.update(cx, |buffer, cx| {
 3427            buffer.edit(
 3428                edits,
 3429                Some(AutoindentMode::Block {
 3430                    original_indent_columns,
 3431                }),
 3432                cx,
 3433            )
 3434        });
 3435    }
 3436
 3437    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3438        self.hide_context_menu(window, cx);
 3439
 3440        match phase {
 3441            SelectPhase::Begin {
 3442                position,
 3443                add,
 3444                click_count,
 3445            } => self.begin_selection(position, add, click_count, window, cx),
 3446            SelectPhase::BeginColumnar {
 3447                position,
 3448                goal_column,
 3449                reset,
 3450                mode,
 3451            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3452            SelectPhase::Extend {
 3453                position,
 3454                click_count,
 3455            } => self.extend_selection(position, click_count, window, cx),
 3456            SelectPhase::Update {
 3457                position,
 3458                goal_column,
 3459                scroll_delta,
 3460            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3461            SelectPhase::End => self.end_selection(window, cx),
 3462        }
 3463    }
 3464
 3465    fn extend_selection(
 3466        &mut self,
 3467        position: DisplayPoint,
 3468        click_count: usize,
 3469        window: &mut Window,
 3470        cx: &mut Context<Self>,
 3471    ) {
 3472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3473        let tail = self.selections.newest::<usize>(cx).tail();
 3474        self.begin_selection(position, false, click_count, window, cx);
 3475
 3476        let position = position.to_offset(&display_map, Bias::Left);
 3477        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3478
 3479        let mut pending_selection = self
 3480            .selections
 3481            .pending_anchor()
 3482            .expect("extend_selection not called with pending selection");
 3483        if position >= tail {
 3484            pending_selection.start = tail_anchor;
 3485        } else {
 3486            pending_selection.end = tail_anchor;
 3487            pending_selection.reversed = true;
 3488        }
 3489
 3490        let mut pending_mode = self.selections.pending_mode().unwrap();
 3491        match &mut pending_mode {
 3492            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3493            _ => {}
 3494        }
 3495
 3496        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3497            SelectionEffects::scroll(Autoscroll::fit())
 3498        } else {
 3499            SelectionEffects::no_scroll()
 3500        };
 3501
 3502        self.change_selections(effects, window, cx, |s| {
 3503            s.set_pending(pending_selection, pending_mode)
 3504        });
 3505    }
 3506
 3507    fn begin_selection(
 3508        &mut self,
 3509        position: DisplayPoint,
 3510        add: bool,
 3511        click_count: usize,
 3512        window: &mut Window,
 3513        cx: &mut Context<Self>,
 3514    ) {
 3515        if !self.focus_handle.is_focused(window) {
 3516            self.last_focused_descendant = None;
 3517            window.focus(&self.focus_handle);
 3518        }
 3519
 3520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3521        let buffer = &display_map.buffer_snapshot;
 3522        let position = display_map.clip_point(position, Bias::Left);
 3523
 3524        let start;
 3525        let end;
 3526        let mode;
 3527        let mut auto_scroll;
 3528        match click_count {
 3529            1 => {
 3530                start = buffer.anchor_before(position.to_point(&display_map));
 3531                end = start;
 3532                mode = SelectMode::Character;
 3533                auto_scroll = true;
 3534            }
 3535            2 => {
 3536                let position = display_map
 3537                    .clip_point(position, Bias::Left)
 3538                    .to_offset(&display_map, Bias::Left);
 3539                let (range, _) = buffer.surrounding_word(position, false);
 3540                start = buffer.anchor_before(range.start);
 3541                end = buffer.anchor_before(range.end);
 3542                mode = SelectMode::Word(start..end);
 3543                auto_scroll = true;
 3544            }
 3545            3 => {
 3546                let position = display_map
 3547                    .clip_point(position, Bias::Left)
 3548                    .to_point(&display_map);
 3549                let line_start = display_map.prev_line_boundary(position).0;
 3550                let next_line_start = buffer.clip_point(
 3551                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3552                    Bias::Left,
 3553                );
 3554                start = buffer.anchor_before(line_start);
 3555                end = buffer.anchor_before(next_line_start);
 3556                mode = SelectMode::Line(start..end);
 3557                auto_scroll = true;
 3558            }
 3559            _ => {
 3560                start = buffer.anchor_before(0);
 3561                end = buffer.anchor_before(buffer.len());
 3562                mode = SelectMode::All;
 3563                auto_scroll = false;
 3564            }
 3565        }
 3566        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3567
 3568        let point_to_delete: Option<usize> = {
 3569            let selected_points: Vec<Selection<Point>> =
 3570                self.selections.disjoint_in_range(start..end, cx);
 3571
 3572            if !add || click_count > 1 {
 3573                None
 3574            } else if !selected_points.is_empty() {
 3575                Some(selected_points[0].id)
 3576            } else {
 3577                let clicked_point_already_selected =
 3578                    self.selections.disjoint.iter().find(|selection| {
 3579                        selection.start.to_point(buffer) == start.to_point(buffer)
 3580                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3581                    });
 3582
 3583                clicked_point_already_selected.map(|selection| selection.id)
 3584            }
 3585        };
 3586
 3587        let selections_count = self.selections.count();
 3588        let effects = if auto_scroll {
 3589            SelectionEffects::default()
 3590        } else {
 3591            SelectionEffects::no_scroll()
 3592        };
 3593
 3594        self.change_selections(effects, window, cx, |s| {
 3595            if let Some(point_to_delete) = point_to_delete {
 3596                s.delete(point_to_delete);
 3597
 3598                if selections_count == 1 {
 3599                    s.set_pending_anchor_range(start..end, mode);
 3600                }
 3601            } else {
 3602                if !add {
 3603                    s.clear_disjoint();
 3604                }
 3605
 3606                s.set_pending_anchor_range(start..end, mode);
 3607            }
 3608        });
 3609    }
 3610
 3611    fn begin_columnar_selection(
 3612        &mut self,
 3613        position: DisplayPoint,
 3614        goal_column: u32,
 3615        reset: bool,
 3616        mode: ColumnarMode,
 3617        window: &mut Window,
 3618        cx: &mut Context<Self>,
 3619    ) {
 3620        if !self.focus_handle.is_focused(window) {
 3621            self.last_focused_descendant = None;
 3622            window.focus(&self.focus_handle);
 3623        }
 3624
 3625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3626
 3627        if reset {
 3628            let pointer_position = display_map
 3629                .buffer_snapshot
 3630                .anchor_before(position.to_point(&display_map));
 3631
 3632            self.change_selections(
 3633                SelectionEffects::scroll(Autoscroll::newest()),
 3634                window,
 3635                cx,
 3636                |s| {
 3637                    s.clear_disjoint();
 3638                    s.set_pending_anchor_range(
 3639                        pointer_position..pointer_position,
 3640                        SelectMode::Character,
 3641                    );
 3642                },
 3643            );
 3644        };
 3645
 3646        let tail = self.selections.newest::<Point>(cx).tail();
 3647        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3648        self.columnar_selection_state = match mode {
 3649            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3650                selection_tail: selection_anchor,
 3651                display_point: if reset {
 3652                    if position.column() != goal_column {
 3653                        Some(DisplayPoint::new(position.row(), goal_column))
 3654                    } else {
 3655                        None
 3656                    }
 3657                } else {
 3658                    None
 3659                },
 3660            }),
 3661            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3662                selection_tail: selection_anchor,
 3663            }),
 3664        };
 3665
 3666        if !reset {
 3667            self.select_columns(position, goal_column, &display_map, window, cx);
 3668        }
 3669    }
 3670
 3671    fn update_selection(
 3672        &mut self,
 3673        position: DisplayPoint,
 3674        goal_column: u32,
 3675        scroll_delta: gpui::Point<f32>,
 3676        window: &mut Window,
 3677        cx: &mut Context<Self>,
 3678    ) {
 3679        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3680
 3681        if self.columnar_selection_state.is_some() {
 3682            self.select_columns(position, goal_column, &display_map, window, cx);
 3683        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3684            let buffer = &display_map.buffer_snapshot;
 3685            let head;
 3686            let tail;
 3687            let mode = self.selections.pending_mode().unwrap();
 3688            match &mode {
 3689                SelectMode::Character => {
 3690                    head = position.to_point(&display_map);
 3691                    tail = pending.tail().to_point(buffer);
 3692                }
 3693                SelectMode::Word(original_range) => {
 3694                    let offset = display_map
 3695                        .clip_point(position, Bias::Left)
 3696                        .to_offset(&display_map, Bias::Left);
 3697                    let original_range = original_range.to_offset(buffer);
 3698
 3699                    let head_offset = if buffer.is_inside_word(offset, false)
 3700                        || original_range.contains(&offset)
 3701                    {
 3702                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3703                        if word_range.start < original_range.start {
 3704                            word_range.start
 3705                        } else {
 3706                            word_range.end
 3707                        }
 3708                    } else {
 3709                        offset
 3710                    };
 3711
 3712                    head = head_offset.to_point(buffer);
 3713                    if head_offset <= original_range.start {
 3714                        tail = original_range.end.to_point(buffer);
 3715                    } else {
 3716                        tail = original_range.start.to_point(buffer);
 3717                    }
 3718                }
 3719                SelectMode::Line(original_range) => {
 3720                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3721
 3722                    let position = display_map
 3723                        .clip_point(position, Bias::Left)
 3724                        .to_point(&display_map);
 3725                    let line_start = display_map.prev_line_boundary(position).0;
 3726                    let next_line_start = buffer.clip_point(
 3727                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3728                        Bias::Left,
 3729                    );
 3730
 3731                    if line_start < original_range.start {
 3732                        head = line_start
 3733                    } else {
 3734                        head = next_line_start
 3735                    }
 3736
 3737                    if head <= original_range.start {
 3738                        tail = original_range.end;
 3739                    } else {
 3740                        tail = original_range.start;
 3741                    }
 3742                }
 3743                SelectMode::All => {
 3744                    return;
 3745                }
 3746            };
 3747
 3748            if head < tail {
 3749                pending.start = buffer.anchor_before(head);
 3750                pending.end = buffer.anchor_before(tail);
 3751                pending.reversed = true;
 3752            } else {
 3753                pending.start = buffer.anchor_before(tail);
 3754                pending.end = buffer.anchor_before(head);
 3755                pending.reversed = false;
 3756            }
 3757
 3758            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3759                s.set_pending(pending, mode);
 3760            });
 3761        } else {
 3762            log::error!("update_selection dispatched with no pending selection");
 3763            return;
 3764        }
 3765
 3766        self.apply_scroll_delta(scroll_delta, window, cx);
 3767        cx.notify();
 3768    }
 3769
 3770    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3771        self.columnar_selection_state.take();
 3772        if self.selections.pending_anchor().is_some() {
 3773            let selections = self.selections.all::<usize>(cx);
 3774            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3775                s.select(selections);
 3776                s.clear_pending();
 3777            });
 3778        }
 3779    }
 3780
 3781    fn select_columns(
 3782        &mut self,
 3783        head: DisplayPoint,
 3784        goal_column: u32,
 3785        display_map: &DisplaySnapshot,
 3786        window: &mut Window,
 3787        cx: &mut Context<Self>,
 3788    ) {
 3789        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3790            return;
 3791        };
 3792
 3793        let tail = match columnar_state {
 3794            ColumnarSelectionState::FromMouse {
 3795                selection_tail,
 3796                display_point,
 3797            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3798            ColumnarSelectionState::FromSelection { selection_tail } => {
 3799                selection_tail.to_display_point(display_map)
 3800            }
 3801        };
 3802
 3803        let start_row = cmp::min(tail.row(), head.row());
 3804        let end_row = cmp::max(tail.row(), head.row());
 3805        let start_column = cmp::min(tail.column(), goal_column);
 3806        let end_column = cmp::max(tail.column(), goal_column);
 3807        let reversed = start_column < tail.column();
 3808
 3809        let selection_ranges = (start_row.0..=end_row.0)
 3810            .map(DisplayRow)
 3811            .filter_map(|row| {
 3812                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3813                    || start_column <= display_map.line_len(row))
 3814                    && !display_map.is_block_line(row)
 3815                {
 3816                    let start = display_map
 3817                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3818                        .to_point(display_map);
 3819                    let end = display_map
 3820                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3821                        .to_point(display_map);
 3822                    if reversed {
 3823                        Some(end..start)
 3824                    } else {
 3825                        Some(start..end)
 3826                    }
 3827                } else {
 3828                    None
 3829                }
 3830            })
 3831            .collect::<Vec<_>>();
 3832
 3833        let ranges = match columnar_state {
 3834            ColumnarSelectionState::FromMouse { .. } => {
 3835                let mut non_empty_ranges = selection_ranges
 3836                    .iter()
 3837                    .filter(|selection_range| selection_range.start != selection_range.end)
 3838                    .peekable();
 3839                if non_empty_ranges.peek().is_some() {
 3840                    non_empty_ranges.cloned().collect()
 3841                } else {
 3842                    selection_ranges
 3843                }
 3844            }
 3845            _ => selection_ranges,
 3846        };
 3847
 3848        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3849            s.select_ranges(ranges);
 3850        });
 3851        cx.notify();
 3852    }
 3853
 3854    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3855        self.selections
 3856            .all_adjusted(cx)
 3857            .iter()
 3858            .any(|selection| !selection.is_empty())
 3859    }
 3860
 3861    pub fn has_pending_nonempty_selection(&self) -> bool {
 3862        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3863            Some(Selection { start, end, .. }) => start != end,
 3864            None => false,
 3865        };
 3866
 3867        pending_nonempty_selection
 3868            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3869    }
 3870
 3871    pub fn has_pending_selection(&self) -> bool {
 3872        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3873    }
 3874
 3875    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3876        self.selection_mark_mode = false;
 3877        self.selection_drag_state = SelectionDragState::None;
 3878
 3879        if self.clear_expanded_diff_hunks(cx) {
 3880            cx.notify();
 3881            return;
 3882        }
 3883        if self.dismiss_menus_and_popups(true, window, cx) {
 3884            return;
 3885        }
 3886
 3887        if self.mode.is_full()
 3888            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3889        {
 3890            return;
 3891        }
 3892
 3893        cx.propagate();
 3894    }
 3895
 3896    pub fn dismiss_menus_and_popups(
 3897        &mut self,
 3898        is_user_requested: bool,
 3899        window: &mut Window,
 3900        cx: &mut Context<Self>,
 3901    ) -> bool {
 3902        if self.take_rename(false, window, cx).is_some() {
 3903            return true;
 3904        }
 3905
 3906        if hide_hover(self, cx) {
 3907            return true;
 3908        }
 3909
 3910        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3911            return true;
 3912        }
 3913
 3914        if self.hide_context_menu(window, cx).is_some() {
 3915            return true;
 3916        }
 3917
 3918        if self.mouse_context_menu.take().is_some() {
 3919            return true;
 3920        }
 3921
 3922        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3923            return true;
 3924        }
 3925
 3926        if self.snippet_stack.pop().is_some() {
 3927            return true;
 3928        }
 3929
 3930        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3931            self.dismiss_diagnostics(cx);
 3932            return true;
 3933        }
 3934
 3935        false
 3936    }
 3937
 3938    fn linked_editing_ranges_for(
 3939        &self,
 3940        selection: Range<text::Anchor>,
 3941        cx: &App,
 3942    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3943        if self.linked_edit_ranges.is_empty() {
 3944            return None;
 3945        }
 3946        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3947            selection.end.buffer_id.and_then(|end_buffer_id| {
 3948                if selection.start.buffer_id != Some(end_buffer_id) {
 3949                    return None;
 3950                }
 3951                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3952                let snapshot = buffer.read(cx).snapshot();
 3953                self.linked_edit_ranges
 3954                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3955                    .map(|ranges| (ranges, snapshot, buffer))
 3956            })?;
 3957        use text::ToOffset as TO;
 3958        // find offset from the start of current range to current cursor position
 3959        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3960
 3961        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3962        let start_difference = start_offset - start_byte_offset;
 3963        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3964        let end_difference = end_offset - start_byte_offset;
 3965        // Current range has associated linked ranges.
 3966        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3967        for range in linked_ranges.iter() {
 3968            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3969            let end_offset = start_offset + end_difference;
 3970            let start_offset = start_offset + start_difference;
 3971            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3972                continue;
 3973            }
 3974            if self.selections.disjoint_anchor_ranges().any(|s| {
 3975                if s.start.buffer_id != selection.start.buffer_id
 3976                    || s.end.buffer_id != selection.end.buffer_id
 3977                {
 3978                    return false;
 3979                }
 3980                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3981                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3982            }) {
 3983                continue;
 3984            }
 3985            let start = buffer_snapshot.anchor_after(start_offset);
 3986            let end = buffer_snapshot.anchor_after(end_offset);
 3987            linked_edits
 3988                .entry(buffer.clone())
 3989                .or_default()
 3990                .push(start..end);
 3991        }
 3992        Some(linked_edits)
 3993    }
 3994
 3995    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3996        let text: Arc<str> = text.into();
 3997
 3998        if self.read_only(cx) {
 3999            return;
 4000        }
 4001
 4002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4003
 4004        let selections = self.selections.all_adjusted(cx);
 4005        let mut bracket_inserted = false;
 4006        let mut edits = Vec::new();
 4007        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4008        let mut new_selections = Vec::with_capacity(selections.len());
 4009        let mut new_autoclose_regions = Vec::new();
 4010        let snapshot = self.buffer.read(cx).read(cx);
 4011        let mut clear_linked_edit_ranges = false;
 4012
 4013        for (selection, autoclose_region) in
 4014            self.selections_with_autoclose_regions(selections, &snapshot)
 4015        {
 4016            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4017                // Determine if the inserted text matches the opening or closing
 4018                // bracket of any of this language's bracket pairs.
 4019                let mut bracket_pair = None;
 4020                let mut is_bracket_pair_start = false;
 4021                let mut is_bracket_pair_end = false;
 4022                if !text.is_empty() {
 4023                    let mut bracket_pair_matching_end = None;
 4024                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4025                    //  and they are removing the character that triggered IME popup.
 4026                    for (pair, enabled) in scope.brackets() {
 4027                        if !pair.close && !pair.surround {
 4028                            continue;
 4029                        }
 4030
 4031                        if enabled && pair.start.ends_with(text.as_ref()) {
 4032                            let prefix_len = pair.start.len() - text.len();
 4033                            let preceding_text_matches_prefix = prefix_len == 0
 4034                                || (selection.start.column >= (prefix_len as u32)
 4035                                    && snapshot.contains_str_at(
 4036                                        Point::new(
 4037                                            selection.start.row,
 4038                                            selection.start.column - (prefix_len as u32),
 4039                                        ),
 4040                                        &pair.start[..prefix_len],
 4041                                    ));
 4042                            if preceding_text_matches_prefix {
 4043                                bracket_pair = Some(pair.clone());
 4044                                is_bracket_pair_start = true;
 4045                                break;
 4046                            }
 4047                        }
 4048                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4049                        {
 4050                            // take first bracket pair matching end, but don't break in case a later bracket
 4051                            // pair matches start
 4052                            bracket_pair_matching_end = Some(pair.clone());
 4053                        }
 4054                    }
 4055                    if let Some(end) = bracket_pair_matching_end
 4056                        && bracket_pair.is_none()
 4057                    {
 4058                        bracket_pair = Some(end);
 4059                        is_bracket_pair_end = true;
 4060                    }
 4061                }
 4062
 4063                if let Some(bracket_pair) = bracket_pair {
 4064                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4065                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4066                    let auto_surround =
 4067                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4068                    if selection.is_empty() {
 4069                        if is_bracket_pair_start {
 4070                            // If the inserted text is a suffix of an opening bracket and the
 4071                            // selection is preceded by the rest of the opening bracket, then
 4072                            // insert the closing bracket.
 4073                            let following_text_allows_autoclose = snapshot
 4074                                .chars_at(selection.start)
 4075                                .next()
 4076                                .is_none_or(|c| scope.should_autoclose_before(c));
 4077
 4078                            let preceding_text_allows_autoclose = selection.start.column == 0
 4079                                || snapshot
 4080                                    .reversed_chars_at(selection.start)
 4081                                    .next()
 4082                                    .is_none_or(|c| {
 4083                                        bracket_pair.start != bracket_pair.end
 4084                                            || !snapshot
 4085                                                .char_classifier_at(selection.start)
 4086                                                .is_word(c)
 4087                                    });
 4088
 4089                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4090                                && bracket_pair.start.len() == 1
 4091                            {
 4092                                let target = bracket_pair.start.chars().next().unwrap();
 4093                                let current_line_count = snapshot
 4094                                    .reversed_chars_at(selection.start)
 4095                                    .take_while(|&c| c != '\n')
 4096                                    .filter(|&c| c == target)
 4097                                    .count();
 4098                                current_line_count % 2 == 1
 4099                            } else {
 4100                                false
 4101                            };
 4102
 4103                            if autoclose
 4104                                && bracket_pair.close
 4105                                && following_text_allows_autoclose
 4106                                && preceding_text_allows_autoclose
 4107                                && !is_closing_quote
 4108                            {
 4109                                let anchor = snapshot.anchor_before(selection.end);
 4110                                new_selections.push((selection.map(|_| anchor), text.len()));
 4111                                new_autoclose_regions.push((
 4112                                    anchor,
 4113                                    text.len(),
 4114                                    selection.id,
 4115                                    bracket_pair.clone(),
 4116                                ));
 4117                                edits.push((
 4118                                    selection.range(),
 4119                                    format!("{}{}", text, bracket_pair.end).into(),
 4120                                ));
 4121                                bracket_inserted = true;
 4122                                continue;
 4123                            }
 4124                        }
 4125
 4126                        if let Some(region) = autoclose_region {
 4127                            // If the selection is followed by an auto-inserted closing bracket,
 4128                            // then don't insert that closing bracket again; just move the selection
 4129                            // past the closing bracket.
 4130                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4131                                && text.as_ref() == region.pair.end.as_str()
 4132                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4133                            if should_skip {
 4134                                let anchor = snapshot.anchor_after(selection.end);
 4135                                new_selections
 4136                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4137                                continue;
 4138                            }
 4139                        }
 4140
 4141                        let always_treat_brackets_as_autoclosed = snapshot
 4142                            .language_settings_at(selection.start, cx)
 4143                            .always_treat_brackets_as_autoclosed;
 4144                        if always_treat_brackets_as_autoclosed
 4145                            && is_bracket_pair_end
 4146                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4147                        {
 4148                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4149                            // and the inserted text is a closing bracket and the selection is followed
 4150                            // by the closing bracket then move the selection past the closing bracket.
 4151                            let anchor = snapshot.anchor_after(selection.end);
 4152                            new_selections.push((selection.map(|_| anchor), text.len()));
 4153                            continue;
 4154                        }
 4155                    }
 4156                    // If an opening bracket is 1 character long and is typed while
 4157                    // text is selected, then surround that text with the bracket pair.
 4158                    else if auto_surround
 4159                        && bracket_pair.surround
 4160                        && is_bracket_pair_start
 4161                        && bracket_pair.start.chars().count() == 1
 4162                    {
 4163                        edits.push((selection.start..selection.start, text.clone()));
 4164                        edits.push((
 4165                            selection.end..selection.end,
 4166                            bracket_pair.end.as_str().into(),
 4167                        ));
 4168                        bracket_inserted = true;
 4169                        new_selections.push((
 4170                            Selection {
 4171                                id: selection.id,
 4172                                start: snapshot.anchor_after(selection.start),
 4173                                end: snapshot.anchor_before(selection.end),
 4174                                reversed: selection.reversed,
 4175                                goal: selection.goal,
 4176                            },
 4177                            0,
 4178                        ));
 4179                        continue;
 4180                    }
 4181                }
 4182            }
 4183
 4184            if self.auto_replace_emoji_shortcode
 4185                && selection.is_empty()
 4186                && text.as_ref().ends_with(':')
 4187                && let Some(possible_emoji_short_code) =
 4188                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4189                && !possible_emoji_short_code.is_empty()
 4190                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4191            {
 4192                let emoji_shortcode_start = Point::new(
 4193                    selection.start.row,
 4194                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4195                );
 4196
 4197                // Remove shortcode from buffer
 4198                edits.push((
 4199                    emoji_shortcode_start..selection.start,
 4200                    "".to_string().into(),
 4201                ));
 4202                new_selections.push((
 4203                    Selection {
 4204                        id: selection.id,
 4205                        start: snapshot.anchor_after(emoji_shortcode_start),
 4206                        end: snapshot.anchor_before(selection.start),
 4207                        reversed: selection.reversed,
 4208                        goal: selection.goal,
 4209                    },
 4210                    0,
 4211                ));
 4212
 4213                // Insert emoji
 4214                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4215                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4216                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4217
 4218                continue;
 4219            }
 4220
 4221            // If not handling any auto-close operation, then just replace the selected
 4222            // text with the given input and move the selection to the end of the
 4223            // newly inserted text.
 4224            let anchor = snapshot.anchor_after(selection.end);
 4225            if !self.linked_edit_ranges.is_empty() {
 4226                let start_anchor = snapshot.anchor_before(selection.start);
 4227
 4228                let is_word_char = text.chars().next().is_none_or(|char| {
 4229                    let classifier = snapshot
 4230                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4231                        .ignore_punctuation(true);
 4232                    classifier.is_word(char)
 4233                });
 4234
 4235                if is_word_char {
 4236                    if let Some(ranges) = self
 4237                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4238                    {
 4239                        for (buffer, edits) in ranges {
 4240                            linked_edits
 4241                                .entry(buffer.clone())
 4242                                .or_default()
 4243                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4244                        }
 4245                    }
 4246                } else {
 4247                    clear_linked_edit_ranges = true;
 4248                }
 4249            }
 4250
 4251            new_selections.push((selection.map(|_| anchor), 0));
 4252            edits.push((selection.start..selection.end, text.clone()));
 4253        }
 4254
 4255        drop(snapshot);
 4256
 4257        self.transact(window, cx, |this, window, cx| {
 4258            if clear_linked_edit_ranges {
 4259                this.linked_edit_ranges.clear();
 4260            }
 4261            let initial_buffer_versions =
 4262                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4263
 4264            this.buffer.update(cx, |buffer, cx| {
 4265                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4266            });
 4267            for (buffer, edits) in linked_edits {
 4268                buffer.update(cx, |buffer, cx| {
 4269                    let snapshot = buffer.snapshot();
 4270                    let edits = edits
 4271                        .into_iter()
 4272                        .map(|(range, text)| {
 4273                            use text::ToPoint as TP;
 4274                            let end_point = TP::to_point(&range.end, &snapshot);
 4275                            let start_point = TP::to_point(&range.start, &snapshot);
 4276                            (start_point..end_point, text)
 4277                        })
 4278                        .sorted_by_key(|(range, _)| range.start);
 4279                    buffer.edit(edits, None, cx);
 4280                })
 4281            }
 4282            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4283            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4284            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4285            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4286                .zip(new_selection_deltas)
 4287                .map(|(selection, delta)| Selection {
 4288                    id: selection.id,
 4289                    start: selection.start + delta,
 4290                    end: selection.end + delta,
 4291                    reversed: selection.reversed,
 4292                    goal: SelectionGoal::None,
 4293                })
 4294                .collect::<Vec<_>>();
 4295
 4296            let mut i = 0;
 4297            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4298                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4299                let start = map.buffer_snapshot.anchor_before(position);
 4300                let end = map.buffer_snapshot.anchor_after(position);
 4301                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4302                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4303                        Ordering::Less => i += 1,
 4304                        Ordering::Greater => break,
 4305                        Ordering::Equal => {
 4306                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4307                                Ordering::Less => i += 1,
 4308                                Ordering::Equal => break,
 4309                                Ordering::Greater => break,
 4310                            }
 4311                        }
 4312                    }
 4313                }
 4314                this.autoclose_regions.insert(
 4315                    i,
 4316                    AutocloseRegion {
 4317                        selection_id,
 4318                        range: start..end,
 4319                        pair,
 4320                    },
 4321                );
 4322            }
 4323
 4324            let had_active_edit_prediction = this.has_active_edit_prediction();
 4325            this.change_selections(
 4326                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4327                window,
 4328                cx,
 4329                |s| s.select(new_selections),
 4330            );
 4331
 4332            if !bracket_inserted
 4333                && let Some(on_type_format_task) =
 4334                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4335            {
 4336                on_type_format_task.detach_and_log_err(cx);
 4337            }
 4338
 4339            let editor_settings = EditorSettings::get_global(cx);
 4340            if bracket_inserted
 4341                && (editor_settings.auto_signature_help
 4342                    || editor_settings.show_signature_help_after_edits)
 4343            {
 4344                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4345            }
 4346
 4347            let trigger_in_words =
 4348                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4349            if this.hard_wrap.is_some() {
 4350                let latest: Range<Point> = this.selections.newest(cx).range();
 4351                if latest.is_empty()
 4352                    && this
 4353                        .buffer()
 4354                        .read(cx)
 4355                        .snapshot(cx)
 4356                        .line_len(MultiBufferRow(latest.start.row))
 4357                        == latest.start.column
 4358                {
 4359                    this.rewrap_impl(
 4360                        RewrapOptions {
 4361                            override_language_settings: true,
 4362                            preserve_existing_whitespace: true,
 4363                        },
 4364                        cx,
 4365                    )
 4366                }
 4367            }
 4368            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4369            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4370            this.refresh_edit_prediction(true, false, window, cx);
 4371            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4372        });
 4373    }
 4374
 4375    fn find_possible_emoji_shortcode_at_position(
 4376        snapshot: &MultiBufferSnapshot,
 4377        position: Point,
 4378    ) -> Option<String> {
 4379        let mut chars = Vec::new();
 4380        let mut found_colon = false;
 4381        for char in snapshot.reversed_chars_at(position).take(100) {
 4382            // Found a possible emoji shortcode in the middle of the buffer
 4383            if found_colon {
 4384                if char.is_whitespace() {
 4385                    chars.reverse();
 4386                    return Some(chars.iter().collect());
 4387                }
 4388                // If the previous character is not a whitespace, we are in the middle of a word
 4389                // and we only want to complete the shortcode if the word is made up of other emojis
 4390                let mut containing_word = String::new();
 4391                for ch in snapshot
 4392                    .reversed_chars_at(position)
 4393                    .skip(chars.len() + 1)
 4394                    .take(100)
 4395                {
 4396                    if ch.is_whitespace() {
 4397                        break;
 4398                    }
 4399                    containing_word.push(ch);
 4400                }
 4401                let containing_word = containing_word.chars().rev().collect::<String>();
 4402                if util::word_consists_of_emojis(containing_word.as_str()) {
 4403                    chars.reverse();
 4404                    return Some(chars.iter().collect());
 4405                }
 4406            }
 4407
 4408            if char.is_whitespace() || !char.is_ascii() {
 4409                return None;
 4410            }
 4411            if char == ':' {
 4412                found_colon = true;
 4413            } else {
 4414                chars.push(char);
 4415            }
 4416        }
 4417        // Found a possible emoji shortcode at the beginning of the buffer
 4418        chars.reverse();
 4419        Some(chars.iter().collect())
 4420    }
 4421
 4422    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4423        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4424        self.transact(window, cx, |this, window, cx| {
 4425            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4426                let selections = this.selections.all::<usize>(cx);
 4427                let multi_buffer = this.buffer.read(cx);
 4428                let buffer = multi_buffer.snapshot(cx);
 4429                selections
 4430                    .iter()
 4431                    .map(|selection| {
 4432                        let start_point = selection.start.to_point(&buffer);
 4433                        let mut existing_indent =
 4434                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4435                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4436                        let start = selection.start;
 4437                        let end = selection.end;
 4438                        let selection_is_empty = start == end;
 4439                        let language_scope = buffer.language_scope_at(start);
 4440                        let (
 4441                            comment_delimiter,
 4442                            doc_delimiter,
 4443                            insert_extra_newline,
 4444                            indent_on_newline,
 4445                            indent_on_extra_newline,
 4446                        ) = if let Some(language) = &language_scope {
 4447                            let mut insert_extra_newline =
 4448                                insert_extra_newline_brackets(&buffer, start..end, language)
 4449                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4450
 4451                            // Comment extension on newline is allowed only for cursor selections
 4452                            let comment_delimiter = maybe!({
 4453                                if !selection_is_empty {
 4454                                    return None;
 4455                                }
 4456
 4457                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4458                                    return None;
 4459                                }
 4460
 4461                                let delimiters = language.line_comment_prefixes();
 4462                                let max_len_of_delimiter =
 4463                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4464                                let (snapshot, range) =
 4465                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4466
 4467                                let num_of_whitespaces = snapshot
 4468                                    .chars_for_range(range.clone())
 4469                                    .take_while(|c| c.is_whitespace())
 4470                                    .count();
 4471                                let comment_candidate = snapshot
 4472                                    .chars_for_range(range.clone())
 4473                                    .skip(num_of_whitespaces)
 4474                                    .take(max_len_of_delimiter)
 4475                                    .collect::<String>();
 4476                                let (delimiter, trimmed_len) = delimiters
 4477                                    .iter()
 4478                                    .filter_map(|delimiter| {
 4479                                        let prefix = delimiter.trim_end();
 4480                                        if comment_candidate.starts_with(prefix) {
 4481                                            Some((delimiter, prefix.len()))
 4482                                        } else {
 4483                                            None
 4484                                        }
 4485                                    })
 4486                                    .max_by_key(|(_, len)| *len)?;
 4487
 4488                                if let Some(BlockCommentConfig {
 4489                                    start: block_start, ..
 4490                                }) = language.block_comment()
 4491                                {
 4492                                    let block_start_trimmed = block_start.trim_end();
 4493                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4494                                        let line_content = snapshot
 4495                                            .chars_for_range(range)
 4496                                            .skip(num_of_whitespaces)
 4497                                            .take(block_start_trimmed.len())
 4498                                            .collect::<String>();
 4499
 4500                                        if line_content.starts_with(block_start_trimmed) {
 4501                                            return None;
 4502                                        }
 4503                                    }
 4504                                }
 4505
 4506                                let cursor_is_placed_after_comment_marker =
 4507                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4508                                if cursor_is_placed_after_comment_marker {
 4509                                    Some(delimiter.clone())
 4510                                } else {
 4511                                    None
 4512                                }
 4513                            });
 4514
 4515                            let mut indent_on_newline = IndentSize::spaces(0);
 4516                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4517
 4518                            let doc_delimiter = maybe!({
 4519                                if !selection_is_empty {
 4520                                    return None;
 4521                                }
 4522
 4523                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4524                                    return None;
 4525                                }
 4526
 4527                                let BlockCommentConfig {
 4528                                    start: start_tag,
 4529                                    end: end_tag,
 4530                                    prefix: delimiter,
 4531                                    tab_size: len,
 4532                                } = language.documentation_comment()?;
 4533                                let is_within_block_comment = buffer
 4534                                    .language_scope_at(start_point)
 4535                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4536                                if !is_within_block_comment {
 4537                                    return None;
 4538                                }
 4539
 4540                                let (snapshot, range) =
 4541                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4542
 4543                                let num_of_whitespaces = snapshot
 4544                                    .chars_for_range(range.clone())
 4545                                    .take_while(|c| c.is_whitespace())
 4546                                    .count();
 4547
 4548                                // 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.
 4549                                let column = start_point.column;
 4550                                let cursor_is_after_start_tag = {
 4551                                    let start_tag_len = start_tag.len();
 4552                                    let start_tag_line = snapshot
 4553                                        .chars_for_range(range.clone())
 4554                                        .skip(num_of_whitespaces)
 4555                                        .take(start_tag_len)
 4556                                        .collect::<String>();
 4557                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4558                                        num_of_whitespaces + start_tag_len <= column as usize
 4559                                    } else {
 4560                                        false
 4561                                    }
 4562                                };
 4563
 4564                                let cursor_is_after_delimiter = {
 4565                                    let delimiter_trim = delimiter.trim_end();
 4566                                    let delimiter_line = snapshot
 4567                                        .chars_for_range(range.clone())
 4568                                        .skip(num_of_whitespaces)
 4569                                        .take(delimiter_trim.len())
 4570                                        .collect::<String>();
 4571                                    if delimiter_line.starts_with(delimiter_trim) {
 4572                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4573                                    } else {
 4574                                        false
 4575                                    }
 4576                                };
 4577
 4578                                let cursor_is_before_end_tag_if_exists = {
 4579                                    let mut char_position = 0u32;
 4580                                    let mut end_tag_offset = None;
 4581
 4582                                    'outer: for chunk in snapshot.text_for_range(range) {
 4583                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4584                                            let chars_before_match =
 4585                                                chunk[..byte_pos].chars().count() as u32;
 4586                                            end_tag_offset =
 4587                                                Some(char_position + chars_before_match);
 4588                                            break 'outer;
 4589                                        }
 4590                                        char_position += chunk.chars().count() as u32;
 4591                                    }
 4592
 4593                                    if let Some(end_tag_offset) = end_tag_offset {
 4594                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4595                                        if cursor_is_after_start_tag {
 4596                                            if cursor_is_before_end_tag {
 4597                                                insert_extra_newline = true;
 4598                                            }
 4599                                            let cursor_is_at_start_of_end_tag =
 4600                                                column == end_tag_offset;
 4601                                            if cursor_is_at_start_of_end_tag {
 4602                                                indent_on_extra_newline.len = *len;
 4603                                            }
 4604                                        }
 4605                                        cursor_is_before_end_tag
 4606                                    } else {
 4607                                        true
 4608                                    }
 4609                                };
 4610
 4611                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4612                                    && cursor_is_before_end_tag_if_exists
 4613                                {
 4614                                    if cursor_is_after_start_tag {
 4615                                        indent_on_newline.len = *len;
 4616                                    }
 4617                                    Some(delimiter.clone())
 4618                                } else {
 4619                                    None
 4620                                }
 4621                            });
 4622
 4623                            (
 4624                                comment_delimiter,
 4625                                doc_delimiter,
 4626                                insert_extra_newline,
 4627                                indent_on_newline,
 4628                                indent_on_extra_newline,
 4629                            )
 4630                        } else {
 4631                            (
 4632                                None,
 4633                                None,
 4634                                false,
 4635                                IndentSize::default(),
 4636                                IndentSize::default(),
 4637                            )
 4638                        };
 4639
 4640                        let prevent_auto_indent = doc_delimiter.is_some();
 4641                        let delimiter = comment_delimiter.or(doc_delimiter);
 4642
 4643                        let capacity_for_delimiter =
 4644                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4645                        let mut new_text = String::with_capacity(
 4646                            1 + capacity_for_delimiter
 4647                                + existing_indent.len as usize
 4648                                + indent_on_newline.len as usize
 4649                                + indent_on_extra_newline.len as usize,
 4650                        );
 4651                        new_text.push('\n');
 4652                        new_text.extend(existing_indent.chars());
 4653                        new_text.extend(indent_on_newline.chars());
 4654
 4655                        if let Some(delimiter) = &delimiter {
 4656                            new_text.push_str(delimiter);
 4657                        }
 4658
 4659                        if insert_extra_newline {
 4660                            new_text.push('\n');
 4661                            new_text.extend(existing_indent.chars());
 4662                            new_text.extend(indent_on_extra_newline.chars());
 4663                        }
 4664
 4665                        let anchor = buffer.anchor_after(end);
 4666                        let new_selection = selection.map(|_| anchor);
 4667                        (
 4668                            ((start..end, new_text), prevent_auto_indent),
 4669                            (insert_extra_newline, new_selection),
 4670                        )
 4671                    })
 4672                    .unzip()
 4673            };
 4674
 4675            let mut auto_indent_edits = Vec::new();
 4676            let mut edits = Vec::new();
 4677            for (edit, prevent_auto_indent) in edits_with_flags {
 4678                if prevent_auto_indent {
 4679                    edits.push(edit);
 4680                } else {
 4681                    auto_indent_edits.push(edit);
 4682                }
 4683            }
 4684            if !edits.is_empty() {
 4685                this.edit(edits, cx);
 4686            }
 4687            if !auto_indent_edits.is_empty() {
 4688                this.edit_with_autoindent(auto_indent_edits, cx);
 4689            }
 4690
 4691            let buffer = this.buffer.read(cx).snapshot(cx);
 4692            let new_selections = selection_info
 4693                .into_iter()
 4694                .map(|(extra_newline_inserted, new_selection)| {
 4695                    let mut cursor = new_selection.end.to_point(&buffer);
 4696                    if extra_newline_inserted {
 4697                        cursor.row -= 1;
 4698                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4699                    }
 4700                    new_selection.map(|_| cursor)
 4701                })
 4702                .collect();
 4703
 4704            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4705            this.refresh_edit_prediction(true, false, window, cx);
 4706        });
 4707    }
 4708
 4709    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4710        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4711
 4712        let buffer = self.buffer.read(cx);
 4713        let snapshot = buffer.snapshot(cx);
 4714
 4715        let mut edits = Vec::new();
 4716        let mut rows = Vec::new();
 4717
 4718        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4719            let cursor = selection.head();
 4720            let row = cursor.row;
 4721
 4722            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4723
 4724            let newline = "\n".to_string();
 4725            edits.push((start_of_line..start_of_line, newline));
 4726
 4727            rows.push(row + rows_inserted as u32);
 4728        }
 4729
 4730        self.transact(window, cx, |editor, window, cx| {
 4731            editor.edit(edits, cx);
 4732
 4733            editor.change_selections(Default::default(), window, cx, |s| {
 4734                let mut index = 0;
 4735                s.move_cursors_with(|map, _, _| {
 4736                    let row = rows[index];
 4737                    index += 1;
 4738
 4739                    let point = Point::new(row, 0);
 4740                    let boundary = map.next_line_boundary(point).1;
 4741                    let clipped = map.clip_point(boundary, Bias::Left);
 4742
 4743                    (clipped, SelectionGoal::None)
 4744                });
 4745            });
 4746
 4747            let mut indent_edits = Vec::new();
 4748            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4749            for row in rows {
 4750                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4751                for (row, indent) in indents {
 4752                    if indent.len == 0 {
 4753                        continue;
 4754                    }
 4755
 4756                    let text = match indent.kind {
 4757                        IndentKind::Space => " ".repeat(indent.len as usize),
 4758                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4759                    };
 4760                    let point = Point::new(row.0, 0);
 4761                    indent_edits.push((point..point, text));
 4762                }
 4763            }
 4764            editor.edit(indent_edits, cx);
 4765        });
 4766    }
 4767
 4768    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4770
 4771        let buffer = self.buffer.read(cx);
 4772        let snapshot = buffer.snapshot(cx);
 4773
 4774        let mut edits = Vec::new();
 4775        let mut rows = Vec::new();
 4776        let mut rows_inserted = 0;
 4777
 4778        for selection in self.selections.all_adjusted(cx) {
 4779            let cursor = selection.head();
 4780            let row = cursor.row;
 4781
 4782            let point = Point::new(row + 1, 0);
 4783            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4784
 4785            let newline = "\n".to_string();
 4786            edits.push((start_of_line..start_of_line, newline));
 4787
 4788            rows_inserted += 1;
 4789            rows.push(row + rows_inserted);
 4790        }
 4791
 4792        self.transact(window, cx, |editor, window, cx| {
 4793            editor.edit(edits, cx);
 4794
 4795            editor.change_selections(Default::default(), window, cx, |s| {
 4796                let mut index = 0;
 4797                s.move_cursors_with(|map, _, _| {
 4798                    let row = rows[index];
 4799                    index += 1;
 4800
 4801                    let point = Point::new(row, 0);
 4802                    let boundary = map.next_line_boundary(point).1;
 4803                    let clipped = map.clip_point(boundary, Bias::Left);
 4804
 4805                    (clipped, SelectionGoal::None)
 4806                });
 4807            });
 4808
 4809            let mut indent_edits = Vec::new();
 4810            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4811            for row in rows {
 4812                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4813                for (row, indent) in indents {
 4814                    if indent.len == 0 {
 4815                        continue;
 4816                    }
 4817
 4818                    let text = match indent.kind {
 4819                        IndentKind::Space => " ".repeat(indent.len as usize),
 4820                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4821                    };
 4822                    let point = Point::new(row.0, 0);
 4823                    indent_edits.push((point..point, text));
 4824                }
 4825            }
 4826            editor.edit(indent_edits, cx);
 4827        });
 4828    }
 4829
 4830    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4831        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4832            original_indent_columns: Vec::new(),
 4833        });
 4834        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4835    }
 4836
 4837    fn insert_with_autoindent_mode(
 4838        &mut self,
 4839        text: &str,
 4840        autoindent_mode: Option<AutoindentMode>,
 4841        window: &mut Window,
 4842        cx: &mut Context<Self>,
 4843    ) {
 4844        if self.read_only(cx) {
 4845            return;
 4846        }
 4847
 4848        let text: Arc<str> = text.into();
 4849        self.transact(window, cx, |this, window, cx| {
 4850            let old_selections = this.selections.all_adjusted(cx);
 4851            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4852                let anchors = {
 4853                    let snapshot = buffer.read(cx);
 4854                    old_selections
 4855                        .iter()
 4856                        .map(|s| {
 4857                            let anchor = snapshot.anchor_after(s.head());
 4858                            s.map(|_| anchor)
 4859                        })
 4860                        .collect::<Vec<_>>()
 4861                };
 4862                buffer.edit(
 4863                    old_selections
 4864                        .iter()
 4865                        .map(|s| (s.start..s.end, text.clone())),
 4866                    autoindent_mode,
 4867                    cx,
 4868                );
 4869                anchors
 4870            });
 4871
 4872            this.change_selections(Default::default(), window, cx, |s| {
 4873                s.select_anchors(selection_anchors);
 4874            });
 4875
 4876            cx.notify();
 4877        });
 4878    }
 4879
 4880    fn trigger_completion_on_input(
 4881        &mut self,
 4882        text: &str,
 4883        trigger_in_words: bool,
 4884        window: &mut Window,
 4885        cx: &mut Context<Self>,
 4886    ) {
 4887        let completions_source = self
 4888            .context_menu
 4889            .borrow()
 4890            .as_ref()
 4891            .and_then(|menu| match menu {
 4892                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4893                CodeContextMenu::CodeActions(_) => None,
 4894            });
 4895
 4896        match completions_source {
 4897            Some(CompletionsMenuSource::Words) => {
 4898                self.show_word_completions(&ShowWordCompletions, window, cx)
 4899            }
 4900            Some(CompletionsMenuSource::Normal)
 4901            | Some(CompletionsMenuSource::SnippetChoices)
 4902            | None
 4903                if self.is_completion_trigger(
 4904                    text,
 4905                    trigger_in_words,
 4906                    completions_source.is_some(),
 4907                    cx,
 4908                ) =>
 4909            {
 4910                self.show_completions(
 4911                    &ShowCompletions {
 4912                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4913                    },
 4914                    window,
 4915                    cx,
 4916                )
 4917            }
 4918            _ => {
 4919                self.hide_context_menu(window, cx);
 4920            }
 4921        }
 4922    }
 4923
 4924    fn is_completion_trigger(
 4925        &self,
 4926        text: &str,
 4927        trigger_in_words: bool,
 4928        menu_is_open: bool,
 4929        cx: &mut Context<Self>,
 4930    ) -> bool {
 4931        let position = self.selections.newest_anchor().head();
 4932        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4933            return false;
 4934        };
 4935
 4936        if let Some(completion_provider) = &self.completion_provider {
 4937            completion_provider.is_completion_trigger(
 4938                &buffer,
 4939                position.text_anchor,
 4940                text,
 4941                trigger_in_words,
 4942                menu_is_open,
 4943                cx,
 4944            )
 4945        } else {
 4946            false
 4947        }
 4948    }
 4949
 4950    /// If any empty selections is touching the start of its innermost containing autoclose
 4951    /// region, expand it to select the brackets.
 4952    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4953        let selections = self.selections.all::<usize>(cx);
 4954        let buffer = self.buffer.read(cx).read(cx);
 4955        let new_selections = self
 4956            .selections_with_autoclose_regions(selections, &buffer)
 4957            .map(|(mut selection, region)| {
 4958                if !selection.is_empty() {
 4959                    return selection;
 4960                }
 4961
 4962                if let Some(region) = region {
 4963                    let mut range = region.range.to_offset(&buffer);
 4964                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4965                        range.start -= region.pair.start.len();
 4966                        if buffer.contains_str_at(range.start, &region.pair.start)
 4967                            && buffer.contains_str_at(range.end, &region.pair.end)
 4968                        {
 4969                            range.end += region.pair.end.len();
 4970                            selection.start = range.start;
 4971                            selection.end = range.end;
 4972
 4973                            return selection;
 4974                        }
 4975                    }
 4976                }
 4977
 4978                let always_treat_brackets_as_autoclosed = buffer
 4979                    .language_settings_at(selection.start, cx)
 4980                    .always_treat_brackets_as_autoclosed;
 4981
 4982                if !always_treat_brackets_as_autoclosed {
 4983                    return selection;
 4984                }
 4985
 4986                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4987                    for (pair, enabled) in scope.brackets() {
 4988                        if !enabled || !pair.close {
 4989                            continue;
 4990                        }
 4991
 4992                        if buffer.contains_str_at(selection.start, &pair.end) {
 4993                            let pair_start_len = pair.start.len();
 4994                            if buffer.contains_str_at(
 4995                                selection.start.saturating_sub(pair_start_len),
 4996                                &pair.start,
 4997                            ) {
 4998                                selection.start -= pair_start_len;
 4999                                selection.end += pair.end.len();
 5000
 5001                                return selection;
 5002                            }
 5003                        }
 5004                    }
 5005                }
 5006
 5007                selection
 5008            })
 5009            .collect();
 5010
 5011        drop(buffer);
 5012        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5013            selections.select(new_selections)
 5014        });
 5015    }
 5016
 5017    /// Iterate the given selections, and for each one, find the smallest surrounding
 5018    /// autoclose region. This uses the ordering of the selections and the autoclose
 5019    /// regions to avoid repeated comparisons.
 5020    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5021        &'a self,
 5022        selections: impl IntoIterator<Item = Selection<D>>,
 5023        buffer: &'a MultiBufferSnapshot,
 5024    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5025        let mut i = 0;
 5026        let mut regions = self.autoclose_regions.as_slice();
 5027        selections.into_iter().map(move |selection| {
 5028            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5029
 5030            let mut enclosing = None;
 5031            while let Some(pair_state) = regions.get(i) {
 5032                if pair_state.range.end.to_offset(buffer) < range.start {
 5033                    regions = &regions[i + 1..];
 5034                    i = 0;
 5035                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5036                    break;
 5037                } else {
 5038                    if pair_state.selection_id == selection.id {
 5039                        enclosing = Some(pair_state);
 5040                    }
 5041                    i += 1;
 5042                }
 5043            }
 5044
 5045            (selection, enclosing)
 5046        })
 5047    }
 5048
 5049    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5050    fn invalidate_autoclose_regions(
 5051        &mut self,
 5052        mut selections: &[Selection<Anchor>],
 5053        buffer: &MultiBufferSnapshot,
 5054    ) {
 5055        self.autoclose_regions.retain(|state| {
 5056            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5057                return false;
 5058            }
 5059
 5060            let mut i = 0;
 5061            while let Some(selection) = selections.get(i) {
 5062                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5063                    selections = &selections[1..];
 5064                    continue;
 5065                }
 5066                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5067                    break;
 5068                }
 5069                if selection.id == state.selection_id {
 5070                    return true;
 5071                } else {
 5072                    i += 1;
 5073                }
 5074            }
 5075            false
 5076        });
 5077    }
 5078
 5079    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5080        let offset = position.to_offset(buffer);
 5081        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5082        if offset > word_range.start && kind == Some(CharKind::Word) {
 5083            Some(
 5084                buffer
 5085                    .text_for_range(word_range.start..offset)
 5086                    .collect::<String>(),
 5087            )
 5088        } else {
 5089            None
 5090        }
 5091    }
 5092
 5093    pub fn toggle_inline_values(
 5094        &mut self,
 5095        _: &ToggleInlineValues,
 5096        _: &mut Window,
 5097        cx: &mut Context<Self>,
 5098    ) {
 5099        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5100
 5101        self.refresh_inline_values(cx);
 5102    }
 5103
 5104    pub fn toggle_inlay_hints(
 5105        &mut self,
 5106        _: &ToggleInlayHints,
 5107        _: &mut Window,
 5108        cx: &mut Context<Self>,
 5109    ) {
 5110        self.refresh_inlay_hints(
 5111            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5112            cx,
 5113        );
 5114    }
 5115
 5116    pub fn inlay_hints_enabled(&self) -> bool {
 5117        self.inlay_hint_cache.enabled
 5118    }
 5119
 5120    pub fn inline_values_enabled(&self) -> bool {
 5121        self.inline_value_cache.enabled
 5122    }
 5123
 5124    #[cfg(any(test, feature = "test-support"))]
 5125    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5126        self.display_map
 5127            .read(cx)
 5128            .current_inlays()
 5129            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5130            .cloned()
 5131            .collect()
 5132    }
 5133
 5134    #[cfg(any(test, feature = "test-support"))]
 5135    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5136        self.display_map
 5137            .read(cx)
 5138            .current_inlays()
 5139            .cloned()
 5140            .collect()
 5141    }
 5142
 5143    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5144        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5145            return;
 5146        }
 5147
 5148        let reason_description = reason.description();
 5149        let ignore_debounce = matches!(
 5150            reason,
 5151            InlayHintRefreshReason::SettingsChange(_)
 5152                | InlayHintRefreshReason::Toggle(_)
 5153                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5154                | InlayHintRefreshReason::ModifiersChanged(_)
 5155        );
 5156        let (invalidate_cache, required_languages) = match reason {
 5157            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5158                match self.inlay_hint_cache.modifiers_override(enabled) {
 5159                    Some(enabled) => {
 5160                        if enabled {
 5161                            (InvalidationStrategy::RefreshRequested, None)
 5162                        } else {
 5163                            self.splice_inlays(
 5164                                &self
 5165                                    .visible_inlay_hints(cx)
 5166                                    .iter()
 5167                                    .map(|inlay| inlay.id)
 5168                                    .collect::<Vec<InlayId>>(),
 5169                                Vec::new(),
 5170                                cx,
 5171                            );
 5172                            return;
 5173                        }
 5174                    }
 5175                    None => return,
 5176                }
 5177            }
 5178            InlayHintRefreshReason::Toggle(enabled) => {
 5179                if self.inlay_hint_cache.toggle(enabled) {
 5180                    if enabled {
 5181                        (InvalidationStrategy::RefreshRequested, None)
 5182                    } else {
 5183                        self.splice_inlays(
 5184                            &self
 5185                                .visible_inlay_hints(cx)
 5186                                .iter()
 5187                                .map(|inlay| inlay.id)
 5188                                .collect::<Vec<InlayId>>(),
 5189                            Vec::new(),
 5190                            cx,
 5191                        );
 5192                        return;
 5193                    }
 5194                } else {
 5195                    return;
 5196                }
 5197            }
 5198            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5199                match self.inlay_hint_cache.update_settings(
 5200                    &self.buffer,
 5201                    new_settings,
 5202                    self.visible_inlay_hints(cx),
 5203                    cx,
 5204                ) {
 5205                    ControlFlow::Break(Some(InlaySplice {
 5206                        to_remove,
 5207                        to_insert,
 5208                    })) => {
 5209                        self.splice_inlays(&to_remove, to_insert, cx);
 5210                        return;
 5211                    }
 5212                    ControlFlow::Break(None) => return,
 5213                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5214                }
 5215            }
 5216            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5217                if let Some(InlaySplice {
 5218                    to_remove,
 5219                    to_insert,
 5220                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5221                {
 5222                    self.splice_inlays(&to_remove, to_insert, cx);
 5223                }
 5224                self.display_map.update(cx, |display_map, _| {
 5225                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5226                });
 5227                return;
 5228            }
 5229            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5230            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5231                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5232            }
 5233            InlayHintRefreshReason::RefreshRequested => {
 5234                (InvalidationStrategy::RefreshRequested, None)
 5235            }
 5236        };
 5237
 5238        if let Some(InlaySplice {
 5239            to_remove,
 5240            to_insert,
 5241        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5242            reason_description,
 5243            self.visible_excerpts(required_languages.as_ref(), cx),
 5244            invalidate_cache,
 5245            ignore_debounce,
 5246            cx,
 5247        ) {
 5248            self.splice_inlays(&to_remove, to_insert, cx);
 5249        }
 5250    }
 5251
 5252    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5253        self.display_map
 5254            .read(cx)
 5255            .current_inlays()
 5256            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5257            .cloned()
 5258            .collect()
 5259    }
 5260
 5261    pub fn visible_excerpts(
 5262        &self,
 5263        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5264        cx: &mut Context<Editor>,
 5265    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5266        let Some(project) = self.project() else {
 5267            return HashMap::default();
 5268        };
 5269        let project = project.read(cx);
 5270        let multi_buffer = self.buffer().read(cx);
 5271        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5272        let multi_buffer_visible_start = self
 5273            .scroll_manager
 5274            .anchor()
 5275            .anchor
 5276            .to_point(&multi_buffer_snapshot);
 5277        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5278            multi_buffer_visible_start
 5279                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5280            Bias::Left,
 5281        );
 5282        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5283        multi_buffer_snapshot
 5284            .range_to_buffer_ranges(multi_buffer_visible_range)
 5285            .into_iter()
 5286            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5287            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5288                let buffer_file = project::File::from_dyn(buffer.file())?;
 5289                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5290                let worktree_entry = buffer_worktree
 5291                    .read(cx)
 5292                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5293                if worktree_entry.is_ignored {
 5294                    return None;
 5295                }
 5296
 5297                let language = buffer.language()?;
 5298                if let Some(restrict_to_languages) = restrict_to_languages
 5299                    && !restrict_to_languages.contains(language)
 5300                {
 5301                    return None;
 5302                }
 5303                Some((
 5304                    excerpt_id,
 5305                    (
 5306                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5307                        buffer.version().clone(),
 5308                        excerpt_visible_range,
 5309                    ),
 5310                ))
 5311            })
 5312            .collect()
 5313    }
 5314
 5315    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5316        TextLayoutDetails {
 5317            text_system: window.text_system().clone(),
 5318            editor_style: self.style.clone().unwrap(),
 5319            rem_size: window.rem_size(),
 5320            scroll_anchor: self.scroll_manager.anchor(),
 5321            visible_rows: self.visible_line_count(),
 5322            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5323        }
 5324    }
 5325
 5326    pub fn splice_inlays(
 5327        &self,
 5328        to_remove: &[InlayId],
 5329        to_insert: Vec<Inlay>,
 5330        cx: &mut Context<Self>,
 5331    ) {
 5332        self.display_map.update(cx, |display_map, cx| {
 5333            display_map.splice_inlays(to_remove, to_insert, cx)
 5334        });
 5335        cx.notify();
 5336    }
 5337
 5338    fn trigger_on_type_formatting(
 5339        &self,
 5340        input: String,
 5341        window: &mut Window,
 5342        cx: &mut Context<Self>,
 5343    ) -> Option<Task<Result<()>>> {
 5344        if input.len() != 1 {
 5345            return None;
 5346        }
 5347
 5348        let project = self.project()?;
 5349        let position = self.selections.newest_anchor().head();
 5350        let (buffer, buffer_position) = self
 5351            .buffer
 5352            .read(cx)
 5353            .text_anchor_for_position(position, cx)?;
 5354
 5355        let settings = language_settings::language_settings(
 5356            buffer
 5357                .read(cx)
 5358                .language_at(buffer_position)
 5359                .map(|l| l.name()),
 5360            buffer.read(cx).file(),
 5361            cx,
 5362        );
 5363        if !settings.use_on_type_format {
 5364            return None;
 5365        }
 5366
 5367        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5368        // hence we do LSP request & edit on host side only — add formats to host's history.
 5369        let push_to_lsp_host_history = true;
 5370        // If this is not the host, append its history with new edits.
 5371        let push_to_client_history = project.read(cx).is_via_collab();
 5372
 5373        let on_type_formatting = project.update(cx, |project, cx| {
 5374            project.on_type_format(
 5375                buffer.clone(),
 5376                buffer_position,
 5377                input,
 5378                push_to_lsp_host_history,
 5379                cx,
 5380            )
 5381        });
 5382        Some(cx.spawn_in(window, async move |editor, cx| {
 5383            if let Some(transaction) = on_type_formatting.await? {
 5384                if push_to_client_history {
 5385                    buffer
 5386                        .update(cx, |buffer, _| {
 5387                            buffer.push_transaction(transaction, Instant::now());
 5388                            buffer.finalize_last_transaction();
 5389                        })
 5390                        .ok();
 5391                }
 5392                editor.update(cx, |editor, cx| {
 5393                    editor.refresh_document_highlights(cx);
 5394                })?;
 5395            }
 5396            Ok(())
 5397        }))
 5398    }
 5399
 5400    pub fn show_word_completions(
 5401        &mut self,
 5402        _: &ShowWordCompletions,
 5403        window: &mut Window,
 5404        cx: &mut Context<Self>,
 5405    ) {
 5406        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5407    }
 5408
 5409    pub fn show_completions(
 5410        &mut self,
 5411        options: &ShowCompletions,
 5412        window: &mut Window,
 5413        cx: &mut Context<Self>,
 5414    ) {
 5415        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5416    }
 5417
 5418    fn open_or_update_completions_menu(
 5419        &mut self,
 5420        requested_source: Option<CompletionsMenuSource>,
 5421        trigger: Option<&str>,
 5422        window: &mut Window,
 5423        cx: &mut Context<Self>,
 5424    ) {
 5425        if self.pending_rename.is_some() {
 5426            return;
 5427        }
 5428
 5429        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5430
 5431        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5432        // inserted and selected. To handle that case, the start of the selection is used so that
 5433        // the menu starts with all choices.
 5434        let position = self
 5435            .selections
 5436            .newest_anchor()
 5437            .start
 5438            .bias_right(&multibuffer_snapshot);
 5439        if position.diff_base_anchor.is_some() {
 5440            return;
 5441        }
 5442        let (buffer, buffer_position) =
 5443            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5444                output
 5445            } else {
 5446                return;
 5447            };
 5448        let buffer_snapshot = buffer.read(cx).snapshot();
 5449
 5450        let query: Option<Arc<String>> =
 5451            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5452
 5453        drop(multibuffer_snapshot);
 5454
 5455        let provider = match requested_source {
 5456            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5457            Some(CompletionsMenuSource::Words) => None,
 5458            Some(CompletionsMenuSource::SnippetChoices) => {
 5459                log::error!("bug: SnippetChoices requested_source is not handled");
 5460                None
 5461            }
 5462        };
 5463
 5464        let sort_completions = provider
 5465            .as_ref()
 5466            .is_some_and(|provider| provider.sort_completions());
 5467
 5468        let filter_completions = provider
 5469            .as_ref()
 5470            .is_none_or(|provider| provider.filter_completions());
 5471
 5472        let trigger_kind = match trigger {
 5473            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5474                CompletionTriggerKind::TRIGGER_CHARACTER
 5475            }
 5476            _ => CompletionTriggerKind::INVOKED,
 5477        };
 5478        let completion_context = CompletionContext {
 5479            trigger_character: trigger.and_then(|trigger| {
 5480                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5481                    Some(String::from(trigger))
 5482                } else {
 5483                    None
 5484                }
 5485            }),
 5486            trigger_kind,
 5487        };
 5488
 5489        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5490        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5491        // involve trigger chars, so this is skipped in that case.
 5492        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5493        {
 5494            let menu_is_open = matches!(
 5495                self.context_menu.borrow().as_ref(),
 5496                Some(CodeContextMenu::Completions(_))
 5497            );
 5498            if menu_is_open {
 5499                self.hide_context_menu(window, cx);
 5500            }
 5501        }
 5502
 5503        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5504            if filter_completions {
 5505                menu.filter(query.clone(), provider.clone(), window, cx);
 5506            }
 5507            // When `is_incomplete` is false, no need to re-query completions when the current query
 5508            // is a suffix of the initial query.
 5509            if !menu.is_incomplete {
 5510                // If the new query is a suffix of the old query (typing more characters) and
 5511                // the previous result was complete, the existing completions can be filtered.
 5512                //
 5513                // Note that this is always true for snippet completions.
 5514                let query_matches = match (&menu.initial_query, &query) {
 5515                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5516                    (None, _) => true,
 5517                    _ => false,
 5518                };
 5519                if query_matches {
 5520                    let position_matches = if menu.initial_position == position {
 5521                        true
 5522                    } else {
 5523                        let snapshot = self.buffer.read(cx).read(cx);
 5524                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5525                    };
 5526                    if position_matches {
 5527                        return;
 5528                    }
 5529                }
 5530            }
 5531        };
 5532
 5533        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5534            buffer_snapshot.surrounding_word(buffer_position, false)
 5535        {
 5536            let word_to_exclude = buffer_snapshot
 5537                .text_for_range(word_range.clone())
 5538                .collect::<String>();
 5539            (
 5540                buffer_snapshot.anchor_before(word_range.start)
 5541                    ..buffer_snapshot.anchor_after(buffer_position),
 5542                Some(word_to_exclude),
 5543            )
 5544        } else {
 5545            (buffer_position..buffer_position, None)
 5546        };
 5547
 5548        let language = buffer_snapshot
 5549            .language_at(buffer_position)
 5550            .map(|language| language.name());
 5551
 5552        let completion_settings =
 5553            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5554
 5555        let show_completion_documentation = buffer_snapshot
 5556            .settings_at(buffer_position, cx)
 5557            .show_completion_documentation;
 5558
 5559        // The document can be large, so stay in reasonable bounds when searching for words,
 5560        // otherwise completion pop-up might be slow to appear.
 5561        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5562        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5563        let min_word_search = buffer_snapshot.clip_point(
 5564            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5565            Bias::Left,
 5566        );
 5567        let max_word_search = buffer_snapshot.clip_point(
 5568            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5569            Bias::Right,
 5570        );
 5571        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5572            ..buffer_snapshot.point_to_offset(max_word_search);
 5573
 5574        let skip_digits = query
 5575            .as_ref()
 5576            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5577
 5578        let omit_word_completions = match &query {
 5579            Some(query) => query.chars().count() < completion_settings.words_min_length,
 5580            None => completion_settings.words_min_length != 0,
 5581        };
 5582
 5583        let (mut words, provider_responses) = match &provider {
 5584            Some(provider) => {
 5585                let provider_responses = provider.completions(
 5586                    position.excerpt_id,
 5587                    &buffer,
 5588                    buffer_position,
 5589                    completion_context,
 5590                    window,
 5591                    cx,
 5592                );
 5593
 5594                let words = match (omit_word_completions, completion_settings.words) {
 5595                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5596                        Task::ready(BTreeMap::default())
 5597                    }
 5598                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5599                        .background_spawn(async move {
 5600                            buffer_snapshot.words_in_range(WordsQuery {
 5601                                fuzzy_contents: None,
 5602                                range: word_search_range,
 5603                                skip_digits,
 5604                            })
 5605                        }),
 5606                };
 5607
 5608                (words, provider_responses)
 5609            }
 5610            None => {
 5611                let words = if omit_word_completions {
 5612                    Task::ready(BTreeMap::default())
 5613                } else {
 5614                    cx.background_spawn(async move {
 5615                        buffer_snapshot.words_in_range(WordsQuery {
 5616                            fuzzy_contents: None,
 5617                            range: word_search_range,
 5618                            skip_digits,
 5619                        })
 5620                    })
 5621                };
 5622                (words, Task::ready(Ok(Vec::new())))
 5623            }
 5624        };
 5625
 5626        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5627
 5628        let id = post_inc(&mut self.next_completion_id);
 5629        let task = cx.spawn_in(window, async move |editor, cx| {
 5630            let Ok(()) = editor.update(cx, |this, _| {
 5631                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5632            }) else {
 5633                return;
 5634            };
 5635
 5636            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5637            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5638            let mut completions = Vec::new();
 5639            let mut is_incomplete = false;
 5640            let mut display_options: Option<CompletionDisplayOptions> = None;
 5641            if let Some(provider_responses) = provider_responses.await.log_err()
 5642                && !provider_responses.is_empty()
 5643            {
 5644                for response in provider_responses {
 5645                    completions.extend(response.completions);
 5646                    is_incomplete = is_incomplete || response.is_incomplete;
 5647                    match display_options.as_mut() {
 5648                        None => {
 5649                            display_options = Some(response.display_options);
 5650                        }
 5651                        Some(options) => options.merge(&response.display_options),
 5652                    }
 5653                }
 5654                if completion_settings.words == WordsCompletionMode::Fallback {
 5655                    words = Task::ready(BTreeMap::default());
 5656                }
 5657            }
 5658            let display_options = display_options.unwrap_or_default();
 5659
 5660            let mut words = words.await;
 5661            if let Some(word_to_exclude) = &word_to_exclude {
 5662                words.remove(word_to_exclude);
 5663            }
 5664            for lsp_completion in &completions {
 5665                words.remove(&lsp_completion.new_text);
 5666            }
 5667            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5668                replace_range: word_replace_range.clone(),
 5669                new_text: word.clone(),
 5670                label: CodeLabel::plain(word, None),
 5671                icon_path: None,
 5672                documentation: None,
 5673                source: CompletionSource::BufferWord {
 5674                    word_range,
 5675                    resolved: false,
 5676                },
 5677                insert_text_mode: Some(InsertTextMode::AS_IS),
 5678                confirm: None,
 5679            }));
 5680
 5681            let menu = if completions.is_empty() {
 5682                None
 5683            } else {
 5684                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5685                    let languages = editor
 5686                        .workspace
 5687                        .as_ref()
 5688                        .and_then(|(workspace, _)| workspace.upgrade())
 5689                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5690                    let menu = CompletionsMenu::new(
 5691                        id,
 5692                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5693                        sort_completions,
 5694                        show_completion_documentation,
 5695                        position,
 5696                        query.clone(),
 5697                        is_incomplete,
 5698                        buffer.clone(),
 5699                        completions.into(),
 5700                        display_options,
 5701                        snippet_sort_order,
 5702                        languages,
 5703                        language,
 5704                        cx,
 5705                    );
 5706
 5707                    let query = if filter_completions { query } else { None };
 5708                    let matches_task = if let Some(query) = query {
 5709                        menu.do_async_filtering(query, cx)
 5710                    } else {
 5711                        Task::ready(menu.unfiltered_matches())
 5712                    };
 5713                    (menu, matches_task)
 5714                }) else {
 5715                    return;
 5716                };
 5717
 5718                let matches = matches_task.await;
 5719
 5720                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5721                    // Newer menu already set, so exit.
 5722                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5723                        editor.context_menu.borrow().as_ref()
 5724                        && prev_menu.id > id
 5725                    {
 5726                        return;
 5727                    };
 5728
 5729                    // Only valid to take prev_menu because it the new menu is immediately set
 5730                    // below, or the menu is hidden.
 5731                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5732                        editor.context_menu.borrow_mut().take()
 5733                    {
 5734                        let position_matches =
 5735                            if prev_menu.initial_position == menu.initial_position {
 5736                                true
 5737                            } else {
 5738                                let snapshot = editor.buffer.read(cx).read(cx);
 5739                                prev_menu.initial_position.to_offset(&snapshot)
 5740                                    == menu.initial_position.to_offset(&snapshot)
 5741                            };
 5742                        if position_matches {
 5743                            // Preserve markdown cache before `set_filter_results` because it will
 5744                            // try to populate the documentation cache.
 5745                            menu.preserve_markdown_cache(prev_menu);
 5746                        }
 5747                    };
 5748
 5749                    menu.set_filter_results(matches, provider, window, cx);
 5750                }) else {
 5751                    return;
 5752                };
 5753
 5754                menu.visible().then_some(menu)
 5755            };
 5756
 5757            editor
 5758                .update_in(cx, |editor, window, cx| {
 5759                    if editor.focus_handle.is_focused(window)
 5760                        && let Some(menu) = menu
 5761                    {
 5762                        *editor.context_menu.borrow_mut() =
 5763                            Some(CodeContextMenu::Completions(menu));
 5764
 5765                        crate::hover_popover::hide_hover(editor, cx);
 5766                        if editor.show_edit_predictions_in_menu() {
 5767                            editor.update_visible_edit_prediction(window, cx);
 5768                        } else {
 5769                            editor.discard_edit_prediction(false, cx);
 5770                        }
 5771
 5772                        cx.notify();
 5773                        return;
 5774                    }
 5775
 5776                    if editor.completion_tasks.len() <= 1 {
 5777                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5778                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5779                        // If it was already hidden and we don't show edit predictions in the menu,
 5780                        // we should also show the edit prediction when available.
 5781                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5782                            editor.update_visible_edit_prediction(window, cx);
 5783                        }
 5784                    }
 5785                })
 5786                .ok();
 5787        });
 5788
 5789        self.completion_tasks.push((id, task));
 5790    }
 5791
 5792    #[cfg(feature = "test-support")]
 5793    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5794        let menu = self.context_menu.borrow();
 5795        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5796            let completions = menu.completions.borrow();
 5797            Some(completions.to_vec())
 5798        } else {
 5799            None
 5800        }
 5801    }
 5802
 5803    pub fn with_completions_menu_matching_id<R>(
 5804        &self,
 5805        id: CompletionId,
 5806        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5807    ) -> R {
 5808        let mut context_menu = self.context_menu.borrow_mut();
 5809        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5810            return f(None);
 5811        };
 5812        if completions_menu.id != id {
 5813            return f(None);
 5814        }
 5815        f(Some(completions_menu))
 5816    }
 5817
 5818    pub fn confirm_completion(
 5819        &mut self,
 5820        action: &ConfirmCompletion,
 5821        window: &mut Window,
 5822        cx: &mut Context<Self>,
 5823    ) -> Option<Task<Result<()>>> {
 5824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5825        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5826    }
 5827
 5828    pub fn confirm_completion_insert(
 5829        &mut self,
 5830        _: &ConfirmCompletionInsert,
 5831        window: &mut Window,
 5832        cx: &mut Context<Self>,
 5833    ) -> Option<Task<Result<()>>> {
 5834        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5835        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5836    }
 5837
 5838    pub fn confirm_completion_replace(
 5839        &mut self,
 5840        _: &ConfirmCompletionReplace,
 5841        window: &mut Window,
 5842        cx: &mut Context<Self>,
 5843    ) -> Option<Task<Result<()>>> {
 5844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5845        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5846    }
 5847
 5848    pub fn compose_completion(
 5849        &mut self,
 5850        action: &ComposeCompletion,
 5851        window: &mut Window,
 5852        cx: &mut Context<Self>,
 5853    ) -> Option<Task<Result<()>>> {
 5854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5855        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5856    }
 5857
 5858    fn do_completion(
 5859        &mut self,
 5860        item_ix: Option<usize>,
 5861        intent: CompletionIntent,
 5862        window: &mut Window,
 5863        cx: &mut Context<Editor>,
 5864    ) -> Option<Task<Result<()>>> {
 5865        use language::ToOffset as _;
 5866
 5867        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5868        else {
 5869            return None;
 5870        };
 5871
 5872        let candidate_id = {
 5873            let entries = completions_menu.entries.borrow();
 5874            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5875            if self.show_edit_predictions_in_menu() {
 5876                self.discard_edit_prediction(true, cx);
 5877            }
 5878            mat.candidate_id
 5879        };
 5880
 5881        let completion = completions_menu
 5882            .completions
 5883            .borrow()
 5884            .get(candidate_id)?
 5885            .clone();
 5886        cx.stop_propagation();
 5887
 5888        let buffer_handle = completions_menu.buffer.clone();
 5889
 5890        let CompletionEdit {
 5891            new_text,
 5892            snippet,
 5893            replace_range,
 5894        } = process_completion_for_edit(
 5895            &completion,
 5896            intent,
 5897            &buffer_handle,
 5898            &completions_menu.initial_position.text_anchor,
 5899            cx,
 5900        );
 5901
 5902        let buffer = buffer_handle.read(cx);
 5903        let snapshot = self.buffer.read(cx).snapshot(cx);
 5904        let newest_anchor = self.selections.newest_anchor();
 5905        let replace_range_multibuffer = {
 5906            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5907            let multibuffer_anchor = snapshot
 5908                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5909                .unwrap()
 5910                ..snapshot
 5911                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5912                    .unwrap();
 5913            multibuffer_anchor.start.to_offset(&snapshot)
 5914                ..multibuffer_anchor.end.to_offset(&snapshot)
 5915        };
 5916        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5917            return None;
 5918        }
 5919
 5920        let old_text = buffer
 5921            .text_for_range(replace_range.clone())
 5922            .collect::<String>();
 5923        let lookbehind = newest_anchor
 5924            .start
 5925            .text_anchor
 5926            .to_offset(buffer)
 5927            .saturating_sub(replace_range.start);
 5928        let lookahead = replace_range
 5929            .end
 5930            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5931        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5932        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5933
 5934        let selections = self.selections.all::<usize>(cx);
 5935        let mut ranges = Vec::new();
 5936        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5937
 5938        for selection in &selections {
 5939            let range = if selection.id == newest_anchor.id {
 5940                replace_range_multibuffer.clone()
 5941            } else {
 5942                let mut range = selection.range();
 5943
 5944                // if prefix is present, don't duplicate it
 5945                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5946                    range.start = range.start.saturating_sub(lookbehind);
 5947
 5948                    // if suffix is also present, mimic the newest cursor and replace it
 5949                    if selection.id != newest_anchor.id
 5950                        && snapshot.contains_str_at(range.end, suffix)
 5951                    {
 5952                        range.end += lookahead;
 5953                    }
 5954                }
 5955                range
 5956            };
 5957
 5958            ranges.push(range.clone());
 5959
 5960            if !self.linked_edit_ranges.is_empty() {
 5961                let start_anchor = snapshot.anchor_before(range.start);
 5962                let end_anchor = snapshot.anchor_after(range.end);
 5963                if let Some(ranges) = self
 5964                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5965                {
 5966                    for (buffer, edits) in ranges {
 5967                        linked_edits
 5968                            .entry(buffer.clone())
 5969                            .or_default()
 5970                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5971                    }
 5972                }
 5973            }
 5974        }
 5975
 5976        let common_prefix_len = old_text
 5977            .chars()
 5978            .zip(new_text.chars())
 5979            .take_while(|(a, b)| a == b)
 5980            .map(|(a, _)| a.len_utf8())
 5981            .sum::<usize>();
 5982
 5983        cx.emit(EditorEvent::InputHandled {
 5984            utf16_range_to_replace: None,
 5985            text: new_text[common_prefix_len..].into(),
 5986        });
 5987
 5988        self.transact(window, cx, |editor, window, cx| {
 5989            if let Some(mut snippet) = snippet {
 5990                snippet.text = new_text.to_string();
 5991                editor
 5992                    .insert_snippet(&ranges, snippet, window, cx)
 5993                    .log_err();
 5994            } else {
 5995                editor.buffer.update(cx, |multi_buffer, cx| {
 5996                    let auto_indent = match completion.insert_text_mode {
 5997                        Some(InsertTextMode::AS_IS) => None,
 5998                        _ => editor.autoindent_mode.clone(),
 5999                    };
 6000                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6001                    multi_buffer.edit(edits, auto_indent, cx);
 6002                });
 6003            }
 6004            for (buffer, edits) in linked_edits {
 6005                buffer.update(cx, |buffer, cx| {
 6006                    let snapshot = buffer.snapshot();
 6007                    let edits = edits
 6008                        .into_iter()
 6009                        .map(|(range, text)| {
 6010                            use text::ToPoint as TP;
 6011                            let end_point = TP::to_point(&range.end, &snapshot);
 6012                            let start_point = TP::to_point(&range.start, &snapshot);
 6013                            (start_point..end_point, text)
 6014                        })
 6015                        .sorted_by_key(|(range, _)| range.start);
 6016                    buffer.edit(edits, None, cx);
 6017                })
 6018            }
 6019
 6020            editor.refresh_edit_prediction(true, false, window, cx);
 6021        });
 6022        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6023
 6024        let show_new_completions_on_confirm = completion
 6025            .confirm
 6026            .as_ref()
 6027            .is_some_and(|confirm| confirm(intent, window, cx));
 6028        if show_new_completions_on_confirm {
 6029            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6030        }
 6031
 6032        let provider = self.completion_provider.as_ref()?;
 6033        drop(completion);
 6034        let apply_edits = provider.apply_additional_edits_for_completion(
 6035            buffer_handle,
 6036            completions_menu.completions.clone(),
 6037            candidate_id,
 6038            true,
 6039            cx,
 6040        );
 6041
 6042        let editor_settings = EditorSettings::get_global(cx);
 6043        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6044            // After the code completion is finished, users often want to know what signatures are needed.
 6045            // so we should automatically call signature_help
 6046            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6047        }
 6048
 6049        Some(cx.foreground_executor().spawn(async move {
 6050            apply_edits.await?;
 6051            Ok(())
 6052        }))
 6053    }
 6054
 6055    pub fn toggle_code_actions(
 6056        &mut self,
 6057        action: &ToggleCodeActions,
 6058        window: &mut Window,
 6059        cx: &mut Context<Self>,
 6060    ) {
 6061        let quick_launch = action.quick_launch;
 6062        let mut context_menu = self.context_menu.borrow_mut();
 6063        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6064            if code_actions.deployed_from == action.deployed_from {
 6065                // Toggle if we're selecting the same one
 6066                *context_menu = None;
 6067                cx.notify();
 6068                return;
 6069            } else {
 6070                // Otherwise, clear it and start a new one
 6071                *context_menu = None;
 6072                cx.notify();
 6073            }
 6074        }
 6075        drop(context_menu);
 6076        let snapshot = self.snapshot(window, cx);
 6077        let deployed_from = action.deployed_from.clone();
 6078        let action = action.clone();
 6079        self.completion_tasks.clear();
 6080        self.discard_edit_prediction(false, cx);
 6081
 6082        let multibuffer_point = match &action.deployed_from {
 6083            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6084                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6085            }
 6086            _ => self.selections.newest::<Point>(cx).head(),
 6087        };
 6088        let Some((buffer, buffer_row)) = snapshot
 6089            .buffer_snapshot
 6090            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6091            .and_then(|(buffer_snapshot, range)| {
 6092                self.buffer()
 6093                    .read(cx)
 6094                    .buffer(buffer_snapshot.remote_id())
 6095                    .map(|buffer| (buffer, range.start.row))
 6096            })
 6097        else {
 6098            return;
 6099        };
 6100        let buffer_id = buffer.read(cx).remote_id();
 6101        let tasks = self
 6102            .tasks
 6103            .get(&(buffer_id, buffer_row))
 6104            .map(|t| Arc::new(t.to_owned()));
 6105
 6106        if !self.focus_handle.is_focused(window) {
 6107            return;
 6108        }
 6109        let project = self.project.clone();
 6110
 6111        let code_actions_task = match deployed_from {
 6112            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6113            _ => self.code_actions(buffer_row, window, cx),
 6114        };
 6115
 6116        let runnable_task = match deployed_from {
 6117            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6118            _ => {
 6119                let mut task_context_task = Task::ready(None);
 6120                if let Some(tasks) = &tasks
 6121                    && let Some(project) = project
 6122                {
 6123                    task_context_task =
 6124                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6125                }
 6126
 6127                cx.spawn_in(window, {
 6128                    let buffer = buffer.clone();
 6129                    async move |editor, cx| {
 6130                        let task_context = task_context_task.await;
 6131
 6132                        let resolved_tasks =
 6133                            tasks
 6134                                .zip(task_context.clone())
 6135                                .map(|(tasks, task_context)| ResolvedTasks {
 6136                                    templates: tasks.resolve(&task_context).collect(),
 6137                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6138                                        multibuffer_point.row,
 6139                                        tasks.column,
 6140                                    )),
 6141                                });
 6142                        let debug_scenarios = editor
 6143                            .update(cx, |editor, cx| {
 6144                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6145                            })?
 6146                            .await;
 6147                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6148                    }
 6149                })
 6150            }
 6151        };
 6152
 6153        cx.spawn_in(window, async move |editor, cx| {
 6154            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6155            let code_actions = code_actions_task.await;
 6156            let spawn_straight_away = quick_launch
 6157                && resolved_tasks
 6158                    .as_ref()
 6159                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6160                && code_actions
 6161                    .as_ref()
 6162                    .is_none_or(|actions| actions.is_empty())
 6163                && debug_scenarios.is_empty();
 6164
 6165            editor.update_in(cx, |editor, window, cx| {
 6166                crate::hover_popover::hide_hover(editor, cx);
 6167                let actions = CodeActionContents::new(
 6168                    resolved_tasks,
 6169                    code_actions,
 6170                    debug_scenarios,
 6171                    task_context.unwrap_or_default(),
 6172                );
 6173
 6174                // Don't show the menu if there are no actions available
 6175                if actions.is_empty() {
 6176                    cx.notify();
 6177                    return Task::ready(Ok(()));
 6178                }
 6179
 6180                *editor.context_menu.borrow_mut() =
 6181                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6182                        buffer,
 6183                        actions,
 6184                        selected_item: Default::default(),
 6185                        scroll_handle: UniformListScrollHandle::default(),
 6186                        deployed_from,
 6187                    }));
 6188                cx.notify();
 6189                if spawn_straight_away
 6190                    && let Some(task) = editor.confirm_code_action(
 6191                        &ConfirmCodeAction { item_ix: Some(0) },
 6192                        window,
 6193                        cx,
 6194                    )
 6195                {
 6196                    return task;
 6197                }
 6198
 6199                Task::ready(Ok(()))
 6200            })
 6201        })
 6202        .detach_and_log_err(cx);
 6203    }
 6204
 6205    fn debug_scenarios(
 6206        &mut self,
 6207        resolved_tasks: &Option<ResolvedTasks>,
 6208        buffer: &Entity<Buffer>,
 6209        cx: &mut App,
 6210    ) -> Task<Vec<task::DebugScenario>> {
 6211        maybe!({
 6212            let project = self.project()?;
 6213            let dap_store = project.read(cx).dap_store();
 6214            let mut scenarios = vec![];
 6215            let resolved_tasks = resolved_tasks.as_ref()?;
 6216            let buffer = buffer.read(cx);
 6217            let language = buffer.language()?;
 6218            let file = buffer.file();
 6219            let debug_adapter = language_settings(language.name().into(), file, cx)
 6220                .debuggers
 6221                .first()
 6222                .map(SharedString::from)
 6223                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6224
 6225            dap_store.update(cx, |dap_store, cx| {
 6226                for (_, task) in &resolved_tasks.templates {
 6227                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6228                        task.original_task().clone(),
 6229                        debug_adapter.clone().into(),
 6230                        task.display_label().to_owned().into(),
 6231                        cx,
 6232                    );
 6233                    scenarios.push(maybe_scenario);
 6234                }
 6235            });
 6236            Some(cx.background_spawn(async move {
 6237                futures::future::join_all(scenarios)
 6238                    .await
 6239                    .into_iter()
 6240                    .flatten()
 6241                    .collect::<Vec<_>>()
 6242            }))
 6243        })
 6244        .unwrap_or_else(|| Task::ready(vec![]))
 6245    }
 6246
 6247    fn code_actions(
 6248        &mut self,
 6249        buffer_row: u32,
 6250        window: &mut Window,
 6251        cx: &mut Context<Self>,
 6252    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6253        let mut task = self.code_actions_task.take();
 6254        cx.spawn_in(window, async move |editor, cx| {
 6255            while let Some(prev_task) = task {
 6256                prev_task.await.log_err();
 6257                task = editor
 6258                    .update(cx, |this, _| this.code_actions_task.take())
 6259                    .ok()?;
 6260            }
 6261
 6262            editor
 6263                .update(cx, |editor, cx| {
 6264                    editor
 6265                        .available_code_actions
 6266                        .clone()
 6267                        .and_then(|(location, code_actions)| {
 6268                            let snapshot = location.buffer.read(cx).snapshot();
 6269                            let point_range = location.range.to_point(&snapshot);
 6270                            let point_range = point_range.start.row..=point_range.end.row;
 6271                            if point_range.contains(&buffer_row) {
 6272                                Some(code_actions)
 6273                            } else {
 6274                                None
 6275                            }
 6276                        })
 6277                })
 6278                .ok()
 6279                .flatten()
 6280        })
 6281    }
 6282
 6283    pub fn confirm_code_action(
 6284        &mut self,
 6285        action: &ConfirmCodeAction,
 6286        window: &mut Window,
 6287        cx: &mut Context<Self>,
 6288    ) -> Option<Task<Result<()>>> {
 6289        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6290
 6291        let actions_menu =
 6292            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6293                menu
 6294            } else {
 6295                return None;
 6296            };
 6297
 6298        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6299        let action = actions_menu.actions.get(action_ix)?;
 6300        let title = action.label();
 6301        let buffer = actions_menu.buffer;
 6302        let workspace = self.workspace()?;
 6303
 6304        match action {
 6305            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6306                workspace.update(cx, |workspace, cx| {
 6307                    workspace.schedule_resolved_task(
 6308                        task_source_kind,
 6309                        resolved_task,
 6310                        false,
 6311                        window,
 6312                        cx,
 6313                    );
 6314
 6315                    Some(Task::ready(Ok(())))
 6316                })
 6317            }
 6318            CodeActionsItem::CodeAction {
 6319                excerpt_id,
 6320                action,
 6321                provider,
 6322            } => {
 6323                let apply_code_action =
 6324                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6325                let workspace = workspace.downgrade();
 6326                Some(cx.spawn_in(window, async move |editor, cx| {
 6327                    let project_transaction = apply_code_action.await?;
 6328                    Self::open_project_transaction(
 6329                        &editor,
 6330                        workspace,
 6331                        project_transaction,
 6332                        title,
 6333                        cx,
 6334                    )
 6335                    .await
 6336                }))
 6337            }
 6338            CodeActionsItem::DebugScenario(scenario) => {
 6339                let context = actions_menu.actions.context;
 6340
 6341                workspace.update(cx, |workspace, cx| {
 6342                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6343                    workspace.start_debug_session(
 6344                        scenario,
 6345                        context,
 6346                        Some(buffer),
 6347                        None,
 6348                        window,
 6349                        cx,
 6350                    );
 6351                });
 6352                Some(Task::ready(Ok(())))
 6353            }
 6354        }
 6355    }
 6356
 6357    pub async fn open_project_transaction(
 6358        editor: &WeakEntity<Editor>,
 6359        workspace: WeakEntity<Workspace>,
 6360        transaction: ProjectTransaction,
 6361        title: String,
 6362        cx: &mut AsyncWindowContext,
 6363    ) -> Result<()> {
 6364        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6365        cx.update(|_, cx| {
 6366            entries.sort_unstable_by_key(|(buffer, _)| {
 6367                buffer.read(cx).file().map(|f| f.path().clone())
 6368            });
 6369        })?;
 6370
 6371        // If the project transaction's edits are all contained within this editor, then
 6372        // avoid opening a new editor to display them.
 6373
 6374        if let Some((buffer, transaction)) = entries.first() {
 6375            if entries.len() == 1 {
 6376                let excerpt = editor.update(cx, |editor, cx| {
 6377                    editor
 6378                        .buffer()
 6379                        .read(cx)
 6380                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6381                })?;
 6382                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6383                    && excerpted_buffer == *buffer
 6384                {
 6385                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6386                        let excerpt_range = excerpt_range.to_offset(buffer);
 6387                        buffer
 6388                            .edited_ranges_for_transaction::<usize>(transaction)
 6389                            .all(|range| {
 6390                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6391                            })
 6392                    })?;
 6393
 6394                    if all_edits_within_excerpt {
 6395                        return Ok(());
 6396                    }
 6397                }
 6398            }
 6399        } else {
 6400            return Ok(());
 6401        }
 6402
 6403        let mut ranges_to_highlight = Vec::new();
 6404        let excerpt_buffer = cx.new(|cx| {
 6405            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6406            for (buffer_handle, transaction) in &entries {
 6407                let edited_ranges = buffer_handle
 6408                    .read(cx)
 6409                    .edited_ranges_for_transaction::<Point>(transaction)
 6410                    .collect::<Vec<_>>();
 6411                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6412                    PathKey::for_buffer(buffer_handle, cx),
 6413                    buffer_handle.clone(),
 6414                    edited_ranges,
 6415                    DEFAULT_MULTIBUFFER_CONTEXT,
 6416                    cx,
 6417                );
 6418
 6419                ranges_to_highlight.extend(ranges);
 6420            }
 6421            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6422            multibuffer
 6423        })?;
 6424
 6425        workspace.update_in(cx, |workspace, window, cx| {
 6426            let project = workspace.project().clone();
 6427            let editor =
 6428                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6429            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6430            editor.update(cx, |editor, cx| {
 6431                editor.highlight_background::<Self>(
 6432                    &ranges_to_highlight,
 6433                    |theme| theme.colors().editor_highlighted_line_background,
 6434                    cx,
 6435                );
 6436            });
 6437        })?;
 6438
 6439        Ok(())
 6440    }
 6441
 6442    pub fn clear_code_action_providers(&mut self) {
 6443        self.code_action_providers.clear();
 6444        self.available_code_actions.take();
 6445    }
 6446
 6447    pub fn add_code_action_provider(
 6448        &mut self,
 6449        provider: Rc<dyn CodeActionProvider>,
 6450        window: &mut Window,
 6451        cx: &mut Context<Self>,
 6452    ) {
 6453        if self
 6454            .code_action_providers
 6455            .iter()
 6456            .any(|existing_provider| existing_provider.id() == provider.id())
 6457        {
 6458            return;
 6459        }
 6460
 6461        self.code_action_providers.push(provider);
 6462        self.refresh_code_actions(window, cx);
 6463    }
 6464
 6465    pub fn remove_code_action_provider(
 6466        &mut self,
 6467        id: Arc<str>,
 6468        window: &mut Window,
 6469        cx: &mut Context<Self>,
 6470    ) {
 6471        self.code_action_providers
 6472            .retain(|provider| provider.id() != id);
 6473        self.refresh_code_actions(window, cx);
 6474    }
 6475
 6476    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6477        !self.code_action_providers.is_empty()
 6478            && EditorSettings::get_global(cx).toolbar.code_actions
 6479    }
 6480
 6481    pub fn has_available_code_actions(&self) -> bool {
 6482        self.available_code_actions
 6483            .as_ref()
 6484            .is_some_and(|(_, actions)| !actions.is_empty())
 6485    }
 6486
 6487    fn render_inline_code_actions(
 6488        &self,
 6489        icon_size: ui::IconSize,
 6490        display_row: DisplayRow,
 6491        is_active: bool,
 6492        cx: &mut Context<Self>,
 6493    ) -> AnyElement {
 6494        let show_tooltip = !self.context_menu_visible();
 6495        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6496            .icon_size(icon_size)
 6497            .shape(ui::IconButtonShape::Square)
 6498            .icon_color(ui::Color::Hidden)
 6499            .toggle_state(is_active)
 6500            .when(show_tooltip, |this| {
 6501                this.tooltip({
 6502                    let focus_handle = self.focus_handle.clone();
 6503                    move |window, cx| {
 6504                        Tooltip::for_action_in(
 6505                            "Toggle Code Actions",
 6506                            &ToggleCodeActions {
 6507                                deployed_from: None,
 6508                                quick_launch: false,
 6509                            },
 6510                            &focus_handle,
 6511                            window,
 6512                            cx,
 6513                        )
 6514                    }
 6515                })
 6516            })
 6517            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6518                window.focus(&editor.focus_handle(cx));
 6519                editor.toggle_code_actions(
 6520                    &crate::actions::ToggleCodeActions {
 6521                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6522                            display_row,
 6523                        )),
 6524                        quick_launch: false,
 6525                    },
 6526                    window,
 6527                    cx,
 6528                );
 6529            }))
 6530            .into_any_element()
 6531    }
 6532
 6533    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6534        &self.context_menu
 6535    }
 6536
 6537    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6538        let newest_selection = self.selections.newest_anchor().clone();
 6539        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6540        let buffer = self.buffer.read(cx);
 6541        if newest_selection.head().diff_base_anchor.is_some() {
 6542            return None;
 6543        }
 6544        let (start_buffer, start) =
 6545            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6546        let (end_buffer, end) =
 6547            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6548        if start_buffer != end_buffer {
 6549            return None;
 6550        }
 6551
 6552        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6553            cx.background_executor()
 6554                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6555                .await;
 6556
 6557            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6558                let providers = this.code_action_providers.clone();
 6559                let tasks = this
 6560                    .code_action_providers
 6561                    .iter()
 6562                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6563                    .collect::<Vec<_>>();
 6564                (providers, tasks)
 6565            })?;
 6566
 6567            let mut actions = Vec::new();
 6568            for (provider, provider_actions) in
 6569                providers.into_iter().zip(future::join_all(tasks).await)
 6570            {
 6571                if let Some(provider_actions) = provider_actions.log_err() {
 6572                    actions.extend(provider_actions.into_iter().map(|action| {
 6573                        AvailableCodeAction {
 6574                            excerpt_id: newest_selection.start.excerpt_id,
 6575                            action,
 6576                            provider: provider.clone(),
 6577                        }
 6578                    }));
 6579                }
 6580            }
 6581
 6582            this.update(cx, |this, cx| {
 6583                this.available_code_actions = if actions.is_empty() {
 6584                    None
 6585                } else {
 6586                    Some((
 6587                        Location {
 6588                            buffer: start_buffer,
 6589                            range: start..end,
 6590                        },
 6591                        actions.into(),
 6592                    ))
 6593                };
 6594                cx.notify();
 6595            })
 6596        }));
 6597        None
 6598    }
 6599
 6600    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6601        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6602            self.show_git_blame_inline = false;
 6603
 6604            self.show_git_blame_inline_delay_task =
 6605                Some(cx.spawn_in(window, async move |this, cx| {
 6606                    cx.background_executor().timer(delay).await;
 6607
 6608                    this.update(cx, |this, cx| {
 6609                        this.show_git_blame_inline = true;
 6610                        cx.notify();
 6611                    })
 6612                    .log_err();
 6613                }));
 6614        }
 6615    }
 6616
 6617    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6618        let snapshot = self.snapshot(window, cx);
 6619        let cursor = self.selections.newest::<Point>(cx).head();
 6620        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6621        else {
 6622            return;
 6623        };
 6624
 6625        let Some(blame) = self.blame.as_ref() else {
 6626            return;
 6627        };
 6628
 6629        let row_info = RowInfo {
 6630            buffer_id: Some(buffer.remote_id()),
 6631            buffer_row: Some(point.row),
 6632            ..Default::default()
 6633        };
 6634        let Some(blame_entry) = blame
 6635            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6636            .flatten()
 6637        else {
 6638            return;
 6639        };
 6640
 6641        let anchor = self.selections.newest_anchor().head();
 6642        let position = self.to_pixel_point(anchor, &snapshot, window);
 6643        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6644            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6645        };
 6646    }
 6647
 6648    fn show_blame_popover(
 6649        &mut self,
 6650        blame_entry: &BlameEntry,
 6651        position: gpui::Point<Pixels>,
 6652        ignore_timeout: bool,
 6653        cx: &mut Context<Self>,
 6654    ) {
 6655        if let Some(state) = &mut self.inline_blame_popover {
 6656            state.hide_task.take();
 6657        } else {
 6658            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6659            let blame_entry = blame_entry.clone();
 6660            let show_task = cx.spawn(async move |editor, cx| {
 6661                if !ignore_timeout {
 6662                    cx.background_executor()
 6663                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6664                        .await;
 6665                }
 6666                editor
 6667                    .update(cx, |editor, cx| {
 6668                        editor.inline_blame_popover_show_task.take();
 6669                        let Some(blame) = editor.blame.as_ref() else {
 6670                            return;
 6671                        };
 6672                        let blame = blame.read(cx);
 6673                        let details = blame.details_for_entry(&blame_entry);
 6674                        let markdown = cx.new(|cx| {
 6675                            Markdown::new(
 6676                                details
 6677                                    .as_ref()
 6678                                    .map(|message| message.message.clone())
 6679                                    .unwrap_or_default(),
 6680                                None,
 6681                                None,
 6682                                cx,
 6683                            )
 6684                        });
 6685                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6686                            position,
 6687                            hide_task: None,
 6688                            popover_bounds: None,
 6689                            popover_state: InlineBlamePopoverState {
 6690                                scroll_handle: ScrollHandle::new(),
 6691                                commit_message: details,
 6692                                markdown,
 6693                            },
 6694                            keyboard_grace: ignore_timeout,
 6695                        });
 6696                        cx.notify();
 6697                    })
 6698                    .ok();
 6699            });
 6700            self.inline_blame_popover_show_task = Some(show_task);
 6701        }
 6702    }
 6703
 6704    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6705        self.inline_blame_popover_show_task.take();
 6706        if let Some(state) = &mut self.inline_blame_popover {
 6707            let hide_task = cx.spawn(async move |editor, cx| {
 6708                cx.background_executor()
 6709                    .timer(std::time::Duration::from_millis(100))
 6710                    .await;
 6711                editor
 6712                    .update(cx, |editor, cx| {
 6713                        editor.inline_blame_popover.take();
 6714                        cx.notify();
 6715                    })
 6716                    .ok();
 6717            });
 6718            state.hide_task = Some(hide_task);
 6719        }
 6720    }
 6721
 6722    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6723        if self.pending_rename.is_some() {
 6724            return None;
 6725        }
 6726
 6727        let provider = self.semantics_provider.clone()?;
 6728        let buffer = self.buffer.read(cx);
 6729        let newest_selection = self.selections.newest_anchor().clone();
 6730        let cursor_position = newest_selection.head();
 6731        let (cursor_buffer, cursor_buffer_position) =
 6732            buffer.text_anchor_for_position(cursor_position, cx)?;
 6733        let (tail_buffer, tail_buffer_position) =
 6734            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6735        if cursor_buffer != tail_buffer {
 6736            return None;
 6737        }
 6738
 6739        let snapshot = cursor_buffer.read(cx).snapshot();
 6740        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6741        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6742        if start_word_range != end_word_range {
 6743            self.document_highlights_task.take();
 6744            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6745            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6746            return None;
 6747        }
 6748
 6749        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6750        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6751            cx.background_executor()
 6752                .timer(Duration::from_millis(debounce))
 6753                .await;
 6754
 6755            let highlights = if let Some(highlights) = cx
 6756                .update(|cx| {
 6757                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6758                })
 6759                .ok()
 6760                .flatten()
 6761            {
 6762                highlights.await.log_err()
 6763            } else {
 6764                None
 6765            };
 6766
 6767            if let Some(highlights) = highlights {
 6768                this.update(cx, |this, cx| {
 6769                    if this.pending_rename.is_some() {
 6770                        return;
 6771                    }
 6772
 6773                    let buffer = this.buffer.read(cx);
 6774                    if buffer
 6775                        .text_anchor_for_position(cursor_position, cx)
 6776                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6777                    {
 6778                        return;
 6779                    }
 6780
 6781                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6782                    let mut write_ranges = Vec::new();
 6783                    let mut read_ranges = Vec::new();
 6784                    for highlight in highlights {
 6785                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6786                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6787                        {
 6788                            let start = highlight
 6789                                .range
 6790                                .start
 6791                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6792                            let end = highlight
 6793                                .range
 6794                                .end
 6795                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6796                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6797                                continue;
 6798                            }
 6799
 6800                            let range = Anchor {
 6801                                buffer_id: Some(buffer_id),
 6802                                excerpt_id,
 6803                                text_anchor: start,
 6804                                diff_base_anchor: None,
 6805                            }..Anchor {
 6806                                buffer_id: Some(buffer_id),
 6807                                excerpt_id,
 6808                                text_anchor: end,
 6809                                diff_base_anchor: None,
 6810                            };
 6811                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6812                                write_ranges.push(range);
 6813                            } else {
 6814                                read_ranges.push(range);
 6815                            }
 6816                        }
 6817                    }
 6818
 6819                    this.highlight_background::<DocumentHighlightRead>(
 6820                        &read_ranges,
 6821                        |theme| theme.colors().editor_document_highlight_read_background,
 6822                        cx,
 6823                    );
 6824                    this.highlight_background::<DocumentHighlightWrite>(
 6825                        &write_ranges,
 6826                        |theme| theme.colors().editor_document_highlight_write_background,
 6827                        cx,
 6828                    );
 6829                    cx.notify();
 6830                })
 6831                .log_err();
 6832            }
 6833        }));
 6834        None
 6835    }
 6836
 6837    fn prepare_highlight_query_from_selection(
 6838        &mut self,
 6839        cx: &mut Context<Editor>,
 6840    ) -> Option<(String, Range<Anchor>)> {
 6841        if matches!(self.mode, EditorMode::SingleLine) {
 6842            return None;
 6843        }
 6844        if !EditorSettings::get_global(cx).selection_highlight {
 6845            return None;
 6846        }
 6847        if self.selections.count() != 1 || self.selections.line_mode {
 6848            return None;
 6849        }
 6850        let selection = self.selections.newest::<Point>(cx);
 6851        if selection.is_empty() || selection.start.row != selection.end.row {
 6852            return None;
 6853        }
 6854        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6855        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6856        let query = multi_buffer_snapshot
 6857            .text_for_range(selection_anchor_range.clone())
 6858            .collect::<String>();
 6859        if query.trim().is_empty() {
 6860            return None;
 6861        }
 6862        Some((query, selection_anchor_range))
 6863    }
 6864
 6865    fn update_selection_occurrence_highlights(
 6866        &mut self,
 6867        query_text: String,
 6868        query_range: Range<Anchor>,
 6869        multi_buffer_range_to_query: Range<Point>,
 6870        use_debounce: bool,
 6871        window: &mut Window,
 6872        cx: &mut Context<Editor>,
 6873    ) -> Task<()> {
 6874        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6875        cx.spawn_in(window, async move |editor, cx| {
 6876            if use_debounce {
 6877                cx.background_executor()
 6878                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6879                    .await;
 6880            }
 6881            let match_task = cx.background_spawn(async move {
 6882                let buffer_ranges = multi_buffer_snapshot
 6883                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6884                    .into_iter()
 6885                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6886                let mut match_ranges = Vec::new();
 6887                let Ok(regex) = project::search::SearchQuery::text(
 6888                    query_text.clone(),
 6889                    false,
 6890                    false,
 6891                    false,
 6892                    Default::default(),
 6893                    Default::default(),
 6894                    false,
 6895                    None,
 6896                ) else {
 6897                    return Vec::default();
 6898                };
 6899                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6900                    match_ranges.extend(
 6901                        regex
 6902                            .search(buffer_snapshot, Some(search_range.clone()))
 6903                            .await
 6904                            .into_iter()
 6905                            .filter_map(|match_range| {
 6906                                let match_start = buffer_snapshot
 6907                                    .anchor_after(search_range.start + match_range.start);
 6908                                let match_end = buffer_snapshot
 6909                                    .anchor_before(search_range.start + match_range.end);
 6910                                let match_anchor_range = Anchor::range_in_buffer(
 6911                                    excerpt_id,
 6912                                    buffer_snapshot.remote_id(),
 6913                                    match_start..match_end,
 6914                                );
 6915                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6916                            }),
 6917                    );
 6918                }
 6919                match_ranges
 6920            });
 6921            let match_ranges = match_task.await;
 6922            editor
 6923                .update_in(cx, |editor, _, cx| {
 6924                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6925                    if !match_ranges.is_empty() {
 6926                        editor.highlight_background::<SelectedTextHighlight>(
 6927                            &match_ranges,
 6928                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6929                            cx,
 6930                        )
 6931                    }
 6932                })
 6933                .log_err();
 6934        })
 6935    }
 6936
 6937    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6938        struct NewlineFold;
 6939        let type_id = std::any::TypeId::of::<NewlineFold>();
 6940        if !self.mode.is_single_line() {
 6941            return;
 6942        }
 6943        let snapshot = self.snapshot(window, cx);
 6944        if snapshot.buffer_snapshot.max_point().row == 0 {
 6945            return;
 6946        }
 6947        let task = cx.background_spawn(async move {
 6948            let new_newlines = snapshot
 6949                .buffer_chars_at(0)
 6950                .filter_map(|(c, i)| {
 6951                    if c == '\n' {
 6952                        Some(
 6953                            snapshot.buffer_snapshot.anchor_after(i)
 6954                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6955                        )
 6956                    } else {
 6957                        None
 6958                    }
 6959                })
 6960                .collect::<Vec<_>>();
 6961            let existing_newlines = snapshot
 6962                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6963                .filter_map(|fold| {
 6964                    if fold.placeholder.type_tag == Some(type_id) {
 6965                        Some(fold.range.start..fold.range.end)
 6966                    } else {
 6967                        None
 6968                    }
 6969                })
 6970                .collect::<Vec<_>>();
 6971
 6972            (new_newlines, existing_newlines)
 6973        });
 6974        self.folding_newlines = cx.spawn(async move |this, cx| {
 6975            let (new_newlines, existing_newlines) = task.await;
 6976            if new_newlines == existing_newlines {
 6977                return;
 6978            }
 6979            let placeholder = FoldPlaceholder {
 6980                render: Arc::new(move |_, _, cx| {
 6981                    div()
 6982                        .bg(cx.theme().status().hint_background)
 6983                        .border_b_1()
 6984                        .size_full()
 6985                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6986                        .border_color(cx.theme().status().hint)
 6987                        .child("\\n")
 6988                        .into_any()
 6989                }),
 6990                constrain_width: false,
 6991                merge_adjacent: false,
 6992                type_tag: Some(type_id),
 6993            };
 6994            let creases = new_newlines
 6995                .into_iter()
 6996                .map(|range| Crease::simple(range, placeholder.clone()))
 6997                .collect();
 6998            this.update(cx, |this, cx| {
 6999                this.display_map.update(cx, |display_map, cx| {
 7000                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7001                    display_map.fold(creases, cx);
 7002                });
 7003            })
 7004            .ok();
 7005        });
 7006    }
 7007
 7008    fn refresh_selected_text_highlights(
 7009        &mut self,
 7010        on_buffer_edit: bool,
 7011        window: &mut Window,
 7012        cx: &mut Context<Editor>,
 7013    ) {
 7014        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7015        else {
 7016            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7017            self.quick_selection_highlight_task.take();
 7018            self.debounced_selection_highlight_task.take();
 7019            return;
 7020        };
 7021        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7022        if on_buffer_edit
 7023            || self
 7024                .quick_selection_highlight_task
 7025                .as_ref()
 7026                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7027        {
 7028            let multi_buffer_visible_start = self
 7029                .scroll_manager
 7030                .anchor()
 7031                .anchor
 7032                .to_point(&multi_buffer_snapshot);
 7033            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7034                multi_buffer_visible_start
 7035                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7036                Bias::Left,
 7037            );
 7038            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7039            self.quick_selection_highlight_task = Some((
 7040                query_range.clone(),
 7041                self.update_selection_occurrence_highlights(
 7042                    query_text.clone(),
 7043                    query_range.clone(),
 7044                    multi_buffer_visible_range,
 7045                    false,
 7046                    window,
 7047                    cx,
 7048                ),
 7049            ));
 7050        }
 7051        if on_buffer_edit
 7052            || self
 7053                .debounced_selection_highlight_task
 7054                .as_ref()
 7055                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7056        {
 7057            let multi_buffer_start = multi_buffer_snapshot
 7058                .anchor_before(0)
 7059                .to_point(&multi_buffer_snapshot);
 7060            let multi_buffer_end = multi_buffer_snapshot
 7061                .anchor_after(multi_buffer_snapshot.len())
 7062                .to_point(&multi_buffer_snapshot);
 7063            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7064            self.debounced_selection_highlight_task = Some((
 7065                query_range.clone(),
 7066                self.update_selection_occurrence_highlights(
 7067                    query_text,
 7068                    query_range,
 7069                    multi_buffer_full_range,
 7070                    true,
 7071                    window,
 7072                    cx,
 7073                ),
 7074            ));
 7075        }
 7076    }
 7077
 7078    pub fn refresh_edit_prediction(
 7079        &mut self,
 7080        debounce: bool,
 7081        user_requested: bool,
 7082        window: &mut Window,
 7083        cx: &mut Context<Self>,
 7084    ) -> Option<()> {
 7085        if DisableAiSettings::get_global(cx).disable_ai {
 7086            return None;
 7087        }
 7088
 7089        let provider = self.edit_prediction_provider()?;
 7090        let cursor = self.selections.newest_anchor().head();
 7091        let (buffer, cursor_buffer_position) =
 7092            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7093
 7094        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7095            self.discard_edit_prediction(false, cx);
 7096            return None;
 7097        }
 7098
 7099        if !user_requested
 7100            && (!self.should_show_edit_predictions()
 7101                || !self.is_focused(window)
 7102                || buffer.read(cx).is_empty())
 7103        {
 7104            self.discard_edit_prediction(false, cx);
 7105            return None;
 7106        }
 7107
 7108        self.update_visible_edit_prediction(window, cx);
 7109        provider.refresh(
 7110            self.project.clone(),
 7111            buffer,
 7112            cursor_buffer_position,
 7113            debounce,
 7114            cx,
 7115        );
 7116        Some(())
 7117    }
 7118
 7119    fn show_edit_predictions_in_menu(&self) -> bool {
 7120        match self.edit_prediction_settings {
 7121            EditPredictionSettings::Disabled => false,
 7122            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7123        }
 7124    }
 7125
 7126    pub fn edit_predictions_enabled(&self) -> bool {
 7127        match self.edit_prediction_settings {
 7128            EditPredictionSettings::Disabled => false,
 7129            EditPredictionSettings::Enabled { .. } => true,
 7130        }
 7131    }
 7132
 7133    fn edit_prediction_requires_modifier(&self) -> bool {
 7134        match self.edit_prediction_settings {
 7135            EditPredictionSettings::Disabled => false,
 7136            EditPredictionSettings::Enabled {
 7137                preview_requires_modifier,
 7138                ..
 7139            } => preview_requires_modifier,
 7140        }
 7141    }
 7142
 7143    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7144        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7145            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7146            self.discard_edit_prediction(false, cx);
 7147        } else {
 7148            let selection = self.selections.newest_anchor();
 7149            let cursor = selection.head();
 7150
 7151            if let Some((buffer, cursor_buffer_position)) =
 7152                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7153            {
 7154                self.edit_prediction_settings =
 7155                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7156            }
 7157        }
 7158    }
 7159
 7160    fn edit_prediction_settings_at_position(
 7161        &self,
 7162        buffer: &Entity<Buffer>,
 7163        buffer_position: language::Anchor,
 7164        cx: &App,
 7165    ) -> EditPredictionSettings {
 7166        if !self.mode.is_full()
 7167            || !self.show_edit_predictions_override.unwrap_or(true)
 7168            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7169        {
 7170            return EditPredictionSettings::Disabled;
 7171        }
 7172
 7173        let buffer = buffer.read(cx);
 7174
 7175        let file = buffer.file();
 7176
 7177        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7178            return EditPredictionSettings::Disabled;
 7179        };
 7180
 7181        let by_provider = matches!(
 7182            self.menu_edit_predictions_policy,
 7183            MenuEditPredictionsPolicy::ByProvider
 7184        );
 7185
 7186        let show_in_menu = by_provider
 7187            && self
 7188                .edit_prediction_provider
 7189                .as_ref()
 7190                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7191
 7192        let preview_requires_modifier =
 7193            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7194
 7195        EditPredictionSettings::Enabled {
 7196            show_in_menu,
 7197            preview_requires_modifier,
 7198        }
 7199    }
 7200
 7201    fn should_show_edit_predictions(&self) -> bool {
 7202        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7203    }
 7204
 7205    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7206        matches!(
 7207            self.edit_prediction_preview,
 7208            EditPredictionPreview::Active { .. }
 7209        )
 7210    }
 7211
 7212    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7213        let cursor = self.selections.newest_anchor().head();
 7214        if let Some((buffer, cursor_position)) =
 7215            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7216        {
 7217            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7218        } else {
 7219            false
 7220        }
 7221    }
 7222
 7223    pub fn supports_minimap(&self, cx: &App) -> bool {
 7224        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7225    }
 7226
 7227    fn edit_predictions_enabled_in_buffer(
 7228        &self,
 7229        buffer: &Entity<Buffer>,
 7230        buffer_position: language::Anchor,
 7231        cx: &App,
 7232    ) -> bool {
 7233        maybe!({
 7234            if self.read_only(cx) {
 7235                return Some(false);
 7236            }
 7237            let provider = self.edit_prediction_provider()?;
 7238            if !provider.is_enabled(buffer, buffer_position, cx) {
 7239                return Some(false);
 7240            }
 7241            let buffer = buffer.read(cx);
 7242            let Some(file) = buffer.file() else {
 7243                return Some(true);
 7244            };
 7245            let settings = all_language_settings(Some(file), cx);
 7246            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7247        })
 7248        .unwrap_or(false)
 7249    }
 7250
 7251    fn cycle_edit_prediction(
 7252        &mut self,
 7253        direction: Direction,
 7254        window: &mut Window,
 7255        cx: &mut Context<Self>,
 7256    ) -> Option<()> {
 7257        let provider = self.edit_prediction_provider()?;
 7258        let cursor = self.selections.newest_anchor().head();
 7259        let (buffer, cursor_buffer_position) =
 7260            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7261        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7262            return None;
 7263        }
 7264
 7265        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7266        self.update_visible_edit_prediction(window, cx);
 7267
 7268        Some(())
 7269    }
 7270
 7271    pub fn show_edit_prediction(
 7272        &mut self,
 7273        _: &ShowEditPrediction,
 7274        window: &mut Window,
 7275        cx: &mut Context<Self>,
 7276    ) {
 7277        if !self.has_active_edit_prediction() {
 7278            self.refresh_edit_prediction(false, true, window, cx);
 7279            return;
 7280        }
 7281
 7282        self.update_visible_edit_prediction(window, cx);
 7283    }
 7284
 7285    pub fn display_cursor_names(
 7286        &mut self,
 7287        _: &DisplayCursorNames,
 7288        window: &mut Window,
 7289        cx: &mut Context<Self>,
 7290    ) {
 7291        self.show_cursor_names(window, cx);
 7292    }
 7293
 7294    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7295        self.show_cursor_names = true;
 7296        cx.notify();
 7297        cx.spawn_in(window, async move |this, cx| {
 7298            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7299            this.update(cx, |this, cx| {
 7300                this.show_cursor_names = false;
 7301                cx.notify()
 7302            })
 7303            .ok()
 7304        })
 7305        .detach();
 7306    }
 7307
 7308    pub fn next_edit_prediction(
 7309        &mut self,
 7310        _: &NextEditPrediction,
 7311        window: &mut Window,
 7312        cx: &mut Context<Self>,
 7313    ) {
 7314        if self.has_active_edit_prediction() {
 7315            self.cycle_edit_prediction(Direction::Next, window, cx);
 7316        } else {
 7317            let is_copilot_disabled = self
 7318                .refresh_edit_prediction(false, true, window, cx)
 7319                .is_none();
 7320            if is_copilot_disabled {
 7321                cx.propagate();
 7322            }
 7323        }
 7324    }
 7325
 7326    pub fn previous_edit_prediction(
 7327        &mut self,
 7328        _: &PreviousEditPrediction,
 7329        window: &mut Window,
 7330        cx: &mut Context<Self>,
 7331    ) {
 7332        if self.has_active_edit_prediction() {
 7333            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7334        } else {
 7335            let is_copilot_disabled = self
 7336                .refresh_edit_prediction(false, true, window, cx)
 7337                .is_none();
 7338            if is_copilot_disabled {
 7339                cx.propagate();
 7340            }
 7341        }
 7342    }
 7343
 7344    pub fn accept_edit_prediction(
 7345        &mut self,
 7346        _: &AcceptEditPrediction,
 7347        window: &mut Window,
 7348        cx: &mut Context<Self>,
 7349    ) {
 7350        if self.show_edit_predictions_in_menu() {
 7351            self.hide_context_menu(window, cx);
 7352        }
 7353
 7354        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7355            return;
 7356        };
 7357
 7358        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7359
 7360        match &active_edit_prediction.completion {
 7361            EditPrediction::Move { target, .. } => {
 7362                let target = *target;
 7363
 7364                if let Some(position_map) = &self.last_position_map {
 7365                    if position_map
 7366                        .visible_row_range
 7367                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7368                        || !self.edit_prediction_requires_modifier()
 7369                    {
 7370                        self.unfold_ranges(&[target..target], true, false, cx);
 7371                        // Note that this is also done in vim's handler of the Tab action.
 7372                        self.change_selections(
 7373                            SelectionEffects::scroll(Autoscroll::newest()),
 7374                            window,
 7375                            cx,
 7376                            |selections| {
 7377                                selections.select_anchor_ranges([target..target]);
 7378                            },
 7379                        );
 7380                        self.clear_row_highlights::<EditPredictionPreview>();
 7381
 7382                        self.edit_prediction_preview
 7383                            .set_previous_scroll_position(None);
 7384                    } else {
 7385                        self.edit_prediction_preview
 7386                            .set_previous_scroll_position(Some(
 7387                                position_map.snapshot.scroll_anchor,
 7388                            ));
 7389
 7390                        self.highlight_rows::<EditPredictionPreview>(
 7391                            target..target,
 7392                            cx.theme().colors().editor_highlighted_line_background,
 7393                            RowHighlightOptions {
 7394                                autoscroll: true,
 7395                                ..Default::default()
 7396                            },
 7397                            cx,
 7398                        );
 7399                        self.request_autoscroll(Autoscroll::fit(), cx);
 7400                    }
 7401                }
 7402            }
 7403            EditPrediction::Edit { edits, .. } => {
 7404                if let Some(provider) = self.edit_prediction_provider() {
 7405                    provider.accept(cx);
 7406                }
 7407
 7408                // Store the transaction ID and selections before applying the edit
 7409                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7410
 7411                let snapshot = self.buffer.read(cx).snapshot(cx);
 7412                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7413
 7414                self.buffer.update(cx, |buffer, cx| {
 7415                    buffer.edit(edits.iter().cloned(), None, cx)
 7416                });
 7417
 7418                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7419                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7420                });
 7421
 7422                let selections = self.selections.disjoint_anchors();
 7423                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7424                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7425                    if has_new_transaction {
 7426                        self.selection_history
 7427                            .insert_transaction(transaction_id_now, selections);
 7428                    }
 7429                }
 7430
 7431                self.update_visible_edit_prediction(window, cx);
 7432                if self.active_edit_prediction.is_none() {
 7433                    self.refresh_edit_prediction(true, true, window, cx);
 7434                }
 7435
 7436                cx.notify();
 7437            }
 7438        }
 7439
 7440        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7441    }
 7442
 7443    pub fn accept_partial_edit_prediction(
 7444        &mut self,
 7445        _: &AcceptPartialEditPrediction,
 7446        window: &mut Window,
 7447        cx: &mut Context<Self>,
 7448    ) {
 7449        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7450            return;
 7451        };
 7452        if self.selections.count() != 1 {
 7453            return;
 7454        }
 7455
 7456        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7457
 7458        match &active_edit_prediction.completion {
 7459            EditPrediction::Move { target, .. } => {
 7460                let target = *target;
 7461                self.change_selections(
 7462                    SelectionEffects::scroll(Autoscroll::newest()),
 7463                    window,
 7464                    cx,
 7465                    |selections| {
 7466                        selections.select_anchor_ranges([target..target]);
 7467                    },
 7468                );
 7469            }
 7470            EditPrediction::Edit { edits, .. } => {
 7471                // Find an insertion that starts at the cursor position.
 7472                let snapshot = self.buffer.read(cx).snapshot(cx);
 7473                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7474                let insertion = edits.iter().find_map(|(range, text)| {
 7475                    let range = range.to_offset(&snapshot);
 7476                    if range.is_empty() && range.start == cursor_offset {
 7477                        Some(text)
 7478                    } else {
 7479                        None
 7480                    }
 7481                });
 7482
 7483                if let Some(text) = insertion {
 7484                    let mut partial_completion = text
 7485                        .chars()
 7486                        .by_ref()
 7487                        .take_while(|c| c.is_alphabetic())
 7488                        .collect::<String>();
 7489                    if partial_completion.is_empty() {
 7490                        partial_completion = text
 7491                            .chars()
 7492                            .by_ref()
 7493                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7494                            .collect::<String>();
 7495                    }
 7496
 7497                    cx.emit(EditorEvent::InputHandled {
 7498                        utf16_range_to_replace: None,
 7499                        text: partial_completion.clone().into(),
 7500                    });
 7501
 7502                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7503
 7504                    self.refresh_edit_prediction(true, true, window, cx);
 7505                    cx.notify();
 7506                } else {
 7507                    self.accept_edit_prediction(&Default::default(), window, cx);
 7508                }
 7509            }
 7510        }
 7511    }
 7512
 7513    fn discard_edit_prediction(
 7514        &mut self,
 7515        should_report_edit_prediction_event: bool,
 7516        cx: &mut Context<Self>,
 7517    ) -> bool {
 7518        if should_report_edit_prediction_event {
 7519            let completion_id = self
 7520                .active_edit_prediction
 7521                .as_ref()
 7522                .and_then(|active_completion| active_completion.completion_id.clone());
 7523
 7524            self.report_edit_prediction_event(completion_id, false, cx);
 7525        }
 7526
 7527        if let Some(provider) = self.edit_prediction_provider() {
 7528            provider.discard(cx);
 7529        }
 7530
 7531        self.take_active_edit_prediction(cx)
 7532    }
 7533
 7534    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7535        let Some(provider) = self.edit_prediction_provider() else {
 7536            return;
 7537        };
 7538
 7539        let Some((_, buffer, _)) = self
 7540            .buffer
 7541            .read(cx)
 7542            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7543        else {
 7544            return;
 7545        };
 7546
 7547        let extension = buffer
 7548            .read(cx)
 7549            .file()
 7550            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7551
 7552        let event_type = match accepted {
 7553            true => "Edit Prediction Accepted",
 7554            false => "Edit Prediction Discarded",
 7555        };
 7556        telemetry::event!(
 7557            event_type,
 7558            provider = provider.name(),
 7559            prediction_id = id,
 7560            suggestion_accepted = accepted,
 7561            file_extension = extension,
 7562        );
 7563    }
 7564
 7565    pub fn has_active_edit_prediction(&self) -> bool {
 7566        self.active_edit_prediction.is_some()
 7567    }
 7568
 7569    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7570        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7571            return false;
 7572        };
 7573
 7574        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7575        self.clear_highlights::<EditPredictionHighlight>(cx);
 7576        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7577        true
 7578    }
 7579
 7580    /// Returns true when we're displaying the edit prediction popover below the cursor
 7581    /// like we are not previewing and the LSP autocomplete menu is visible
 7582    /// or we are in `when_holding_modifier` mode.
 7583    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7584        if self.edit_prediction_preview_is_active()
 7585            || !self.show_edit_predictions_in_menu()
 7586            || !self.edit_predictions_enabled()
 7587        {
 7588            return false;
 7589        }
 7590
 7591        if self.has_visible_completions_menu() {
 7592            return true;
 7593        }
 7594
 7595        has_completion && self.edit_prediction_requires_modifier()
 7596    }
 7597
 7598    fn handle_modifiers_changed(
 7599        &mut self,
 7600        modifiers: Modifiers,
 7601        position_map: &PositionMap,
 7602        window: &mut Window,
 7603        cx: &mut Context<Self>,
 7604    ) {
 7605        if self.show_edit_predictions_in_menu() {
 7606            self.update_edit_prediction_preview(&modifiers, window, cx);
 7607        }
 7608
 7609        self.update_selection_mode(&modifiers, position_map, window, cx);
 7610
 7611        let mouse_position = window.mouse_position();
 7612        if !position_map.text_hitbox.is_hovered(window) {
 7613            return;
 7614        }
 7615
 7616        self.update_hovered_link(
 7617            position_map.point_for_position(mouse_position),
 7618            &position_map.snapshot,
 7619            modifiers,
 7620            window,
 7621            cx,
 7622        )
 7623    }
 7624
 7625    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7626        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7627        if invert {
 7628            match multi_cursor_setting {
 7629                MultiCursorModifier::Alt => modifiers.alt,
 7630                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7631            }
 7632        } else {
 7633            match multi_cursor_setting {
 7634                MultiCursorModifier::Alt => modifiers.secondary(),
 7635                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7636            }
 7637        }
 7638    }
 7639
 7640    fn columnar_selection_mode(
 7641        modifiers: &Modifiers,
 7642        cx: &mut Context<Self>,
 7643    ) -> Option<ColumnarMode> {
 7644        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7645            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7646                Some(ColumnarMode::FromMouse)
 7647            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7648                Some(ColumnarMode::FromSelection)
 7649            } else {
 7650                None
 7651            }
 7652        } else {
 7653            None
 7654        }
 7655    }
 7656
 7657    fn update_selection_mode(
 7658        &mut self,
 7659        modifiers: &Modifiers,
 7660        position_map: &PositionMap,
 7661        window: &mut Window,
 7662        cx: &mut Context<Self>,
 7663    ) {
 7664        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7665            return;
 7666        };
 7667        if self.selections.pending.is_none() {
 7668            return;
 7669        }
 7670
 7671        let mouse_position = window.mouse_position();
 7672        let point_for_position = position_map.point_for_position(mouse_position);
 7673        let position = point_for_position.previous_valid;
 7674
 7675        self.select(
 7676            SelectPhase::BeginColumnar {
 7677                position,
 7678                reset: false,
 7679                mode,
 7680                goal_column: point_for_position.exact_unclipped.column(),
 7681            },
 7682            window,
 7683            cx,
 7684        );
 7685    }
 7686
 7687    fn update_edit_prediction_preview(
 7688        &mut self,
 7689        modifiers: &Modifiers,
 7690        window: &mut Window,
 7691        cx: &mut Context<Self>,
 7692    ) {
 7693        let mut modifiers_held = false;
 7694        if let Some(accept_keystroke) = self
 7695            .accept_edit_prediction_keybind(false, window, cx)
 7696            .keystroke()
 7697        {
 7698            modifiers_held = modifiers_held
 7699                || (&accept_keystroke.display_modifiers == modifiers
 7700                    && accept_keystroke.display_modifiers.modified());
 7701        };
 7702        if let Some(accept_partial_keystroke) = self
 7703            .accept_edit_prediction_keybind(true, window, cx)
 7704            .keystroke()
 7705        {
 7706            modifiers_held = modifiers_held
 7707                || (&accept_partial_keystroke.display_modifiers == modifiers
 7708                    && accept_partial_keystroke.display_modifiers.modified());
 7709        }
 7710
 7711        if modifiers_held {
 7712            if matches!(
 7713                self.edit_prediction_preview,
 7714                EditPredictionPreview::Inactive { .. }
 7715            ) {
 7716                self.edit_prediction_preview = EditPredictionPreview::Active {
 7717                    previous_scroll_position: None,
 7718                    since: Instant::now(),
 7719                };
 7720
 7721                self.update_visible_edit_prediction(window, cx);
 7722                cx.notify();
 7723            }
 7724        } else if let EditPredictionPreview::Active {
 7725            previous_scroll_position,
 7726            since,
 7727        } = self.edit_prediction_preview
 7728        {
 7729            if let (Some(previous_scroll_position), Some(position_map)) =
 7730                (previous_scroll_position, self.last_position_map.as_ref())
 7731            {
 7732                self.set_scroll_position(
 7733                    previous_scroll_position
 7734                        .scroll_position(&position_map.snapshot.display_snapshot),
 7735                    window,
 7736                    cx,
 7737                );
 7738            }
 7739
 7740            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7741                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7742            };
 7743            self.clear_row_highlights::<EditPredictionPreview>();
 7744            self.update_visible_edit_prediction(window, cx);
 7745            cx.notify();
 7746        }
 7747    }
 7748
 7749    fn update_visible_edit_prediction(
 7750        &mut self,
 7751        _window: &mut Window,
 7752        cx: &mut Context<Self>,
 7753    ) -> Option<()> {
 7754        if DisableAiSettings::get_global(cx).disable_ai {
 7755            return None;
 7756        }
 7757
 7758        if self.ime_transaction.is_some() {
 7759            self.discard_edit_prediction(false, cx);
 7760            return None;
 7761        }
 7762
 7763        let selection = self.selections.newest_anchor();
 7764        let cursor = selection.head();
 7765        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7766        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7767        let excerpt_id = cursor.excerpt_id;
 7768
 7769        let show_in_menu = self.show_edit_predictions_in_menu();
 7770        let completions_menu_has_precedence = !show_in_menu
 7771            && (self.context_menu.borrow().is_some()
 7772                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7773
 7774        if completions_menu_has_precedence
 7775            || !offset_selection.is_empty()
 7776            || self
 7777                .active_edit_prediction
 7778                .as_ref()
 7779                .is_some_and(|completion| {
 7780                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7781                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7782                    !invalidation_range.contains(&offset_selection.head())
 7783                })
 7784        {
 7785            self.discard_edit_prediction(false, cx);
 7786            return None;
 7787        }
 7788
 7789        self.take_active_edit_prediction(cx);
 7790        let Some(provider) = self.edit_prediction_provider() else {
 7791            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7792            return None;
 7793        };
 7794
 7795        let (buffer, cursor_buffer_position) =
 7796            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7797
 7798        self.edit_prediction_settings =
 7799            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7800
 7801        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7802            self.discard_edit_prediction(false, cx);
 7803            return None;
 7804        };
 7805
 7806        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7807
 7808        if self.edit_prediction_indent_conflict {
 7809            let cursor_point = cursor.to_point(&multibuffer);
 7810
 7811            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7812
 7813            if let Some((_, indent)) = indents.iter().next()
 7814                && indent.len == cursor_point.column
 7815            {
 7816                self.edit_prediction_indent_conflict = false;
 7817            }
 7818        }
 7819
 7820        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7821        let edits = edit_prediction
 7822            .edits
 7823            .into_iter()
 7824            .flat_map(|(range, new_text)| {
 7825                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7826                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7827                Some((start..end, new_text))
 7828            })
 7829            .collect::<Vec<_>>();
 7830        if edits.is_empty() {
 7831            return None;
 7832        }
 7833
 7834        let first_edit_start = edits.first().unwrap().0.start;
 7835        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7836        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7837
 7838        let last_edit_end = edits.last().unwrap().0.end;
 7839        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7840        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7841
 7842        let cursor_row = cursor.to_point(&multibuffer).row;
 7843
 7844        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7845
 7846        let mut inlay_ids = Vec::new();
 7847        let invalidation_row_range;
 7848        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7849            Some(cursor_row..edit_end_row)
 7850        } else if cursor_row > edit_end_row {
 7851            Some(edit_start_row..cursor_row)
 7852        } else {
 7853            None
 7854        };
 7855        let supports_jump = self
 7856            .edit_prediction_provider
 7857            .as_ref()
 7858            .map(|provider| provider.provider.supports_jump_to_edit())
 7859            .unwrap_or(true);
 7860
 7861        let is_move = supports_jump
 7862            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7863        let completion = if is_move {
 7864            invalidation_row_range =
 7865                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7866            let target = first_edit_start;
 7867            EditPrediction::Move { target, snapshot }
 7868        } else {
 7869            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7870                && !self.edit_predictions_hidden_for_vim_mode;
 7871
 7872            if show_completions_in_buffer {
 7873                if edits
 7874                    .iter()
 7875                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7876                {
 7877                    let mut inlays = Vec::new();
 7878                    for (range, new_text) in &edits {
 7879                        let inlay = Inlay::edit_prediction(
 7880                            post_inc(&mut self.next_inlay_id),
 7881                            range.start,
 7882                            new_text.as_str(),
 7883                        );
 7884                        inlay_ids.push(inlay.id);
 7885                        inlays.push(inlay);
 7886                    }
 7887
 7888                    self.splice_inlays(&[], inlays, cx);
 7889                } else {
 7890                    let background_color = cx.theme().status().deleted_background;
 7891                    self.highlight_text::<EditPredictionHighlight>(
 7892                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7893                        HighlightStyle {
 7894                            background_color: Some(background_color),
 7895                            ..Default::default()
 7896                        },
 7897                        cx,
 7898                    );
 7899                }
 7900            }
 7901
 7902            invalidation_row_range = edit_start_row..edit_end_row;
 7903
 7904            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7905                if provider.show_tab_accept_marker() {
 7906                    EditDisplayMode::TabAccept
 7907                } else {
 7908                    EditDisplayMode::Inline
 7909                }
 7910            } else {
 7911                EditDisplayMode::DiffPopover
 7912            };
 7913
 7914            EditPrediction::Edit {
 7915                edits,
 7916                edit_preview: edit_prediction.edit_preview,
 7917                display_mode,
 7918                snapshot,
 7919            }
 7920        };
 7921
 7922        let invalidation_range = multibuffer
 7923            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7924            ..multibuffer.anchor_after(Point::new(
 7925                invalidation_row_range.end,
 7926                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7927            ));
 7928
 7929        self.stale_edit_prediction_in_menu = None;
 7930        self.active_edit_prediction = Some(EditPredictionState {
 7931            inlay_ids,
 7932            completion,
 7933            completion_id: edit_prediction.id,
 7934            invalidation_range,
 7935        });
 7936
 7937        cx.notify();
 7938
 7939        Some(())
 7940    }
 7941
 7942    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7943        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7944    }
 7945
 7946    fn clear_tasks(&mut self) {
 7947        self.tasks.clear()
 7948    }
 7949
 7950    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7951        if self.tasks.insert(key, value).is_some() {
 7952            // This case should hopefully be rare, but just in case...
 7953            log::error!(
 7954                "multiple different run targets found on a single line, only the last target will be rendered"
 7955            )
 7956        }
 7957    }
 7958
 7959    /// Get all display points of breakpoints that will be rendered within editor
 7960    ///
 7961    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7962    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7963    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7964    fn active_breakpoints(
 7965        &self,
 7966        range: Range<DisplayRow>,
 7967        window: &mut Window,
 7968        cx: &mut Context<Self>,
 7969    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7970        let mut breakpoint_display_points = HashMap::default();
 7971
 7972        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7973            return breakpoint_display_points;
 7974        };
 7975
 7976        let snapshot = self.snapshot(window, cx);
 7977
 7978        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7979        let Some(project) = self.project() else {
 7980            return breakpoint_display_points;
 7981        };
 7982
 7983        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7984            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7985
 7986        for (buffer_snapshot, range, excerpt_id) in
 7987            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7988        {
 7989            let Some(buffer) = project
 7990                .read(cx)
 7991                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7992            else {
 7993                continue;
 7994            };
 7995            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7996                &buffer,
 7997                Some(
 7998                    buffer_snapshot.anchor_before(range.start)
 7999                        ..buffer_snapshot.anchor_after(range.end),
 8000                ),
 8001                buffer_snapshot,
 8002                cx,
 8003            );
 8004            for (breakpoint, state) in breakpoints {
 8005                let multi_buffer_anchor =
 8006                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8007                let position = multi_buffer_anchor
 8008                    .to_point(multi_buffer_snapshot)
 8009                    .to_display_point(&snapshot);
 8010
 8011                breakpoint_display_points.insert(
 8012                    position.row(),
 8013                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8014                );
 8015            }
 8016        }
 8017
 8018        breakpoint_display_points
 8019    }
 8020
 8021    fn breakpoint_context_menu(
 8022        &self,
 8023        anchor: Anchor,
 8024        window: &mut Window,
 8025        cx: &mut Context<Self>,
 8026    ) -> Entity<ui::ContextMenu> {
 8027        let weak_editor = cx.weak_entity();
 8028        let focus_handle = self.focus_handle(cx);
 8029
 8030        let row = self
 8031            .buffer
 8032            .read(cx)
 8033            .snapshot(cx)
 8034            .summary_for_anchor::<Point>(&anchor)
 8035            .row;
 8036
 8037        let breakpoint = self
 8038            .breakpoint_at_row(row, window, cx)
 8039            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8040
 8041        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8042            "Edit Log Breakpoint"
 8043        } else {
 8044            "Set Log Breakpoint"
 8045        };
 8046
 8047        let condition_breakpoint_msg = if breakpoint
 8048            .as_ref()
 8049            .is_some_and(|bp| bp.1.condition.is_some())
 8050        {
 8051            "Edit Condition Breakpoint"
 8052        } else {
 8053            "Set Condition Breakpoint"
 8054        };
 8055
 8056        let hit_condition_breakpoint_msg = if breakpoint
 8057            .as_ref()
 8058            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8059        {
 8060            "Edit Hit Condition Breakpoint"
 8061        } else {
 8062            "Set Hit Condition Breakpoint"
 8063        };
 8064
 8065        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8066            "Unset Breakpoint"
 8067        } else {
 8068            "Set Breakpoint"
 8069        };
 8070
 8071        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8072
 8073        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8074            BreakpointState::Enabled => Some("Disable"),
 8075            BreakpointState::Disabled => Some("Enable"),
 8076        });
 8077
 8078        let (anchor, breakpoint) =
 8079            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8080
 8081        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8082            menu.on_blur_subscription(Subscription::new(|| {}))
 8083                .context(focus_handle)
 8084                .when(run_to_cursor, |this| {
 8085                    let weak_editor = weak_editor.clone();
 8086                    this.entry("Run to cursor", None, move |window, cx| {
 8087                        weak_editor
 8088                            .update(cx, |editor, cx| {
 8089                                editor.change_selections(
 8090                                    SelectionEffects::no_scroll(),
 8091                                    window,
 8092                                    cx,
 8093                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8094                                );
 8095                            })
 8096                            .ok();
 8097
 8098                        window.dispatch_action(Box::new(RunToCursor), cx);
 8099                    })
 8100                    .separator()
 8101                })
 8102                .when_some(toggle_state_msg, |this, msg| {
 8103                    this.entry(msg, None, {
 8104                        let weak_editor = weak_editor.clone();
 8105                        let breakpoint = breakpoint.clone();
 8106                        move |_window, cx| {
 8107                            weak_editor
 8108                                .update(cx, |this, cx| {
 8109                                    this.edit_breakpoint_at_anchor(
 8110                                        anchor,
 8111                                        breakpoint.as_ref().clone(),
 8112                                        BreakpointEditAction::InvertState,
 8113                                        cx,
 8114                                    );
 8115                                })
 8116                                .log_err();
 8117                        }
 8118                    })
 8119                })
 8120                .entry(set_breakpoint_msg, None, {
 8121                    let weak_editor = weak_editor.clone();
 8122                    let breakpoint = breakpoint.clone();
 8123                    move |_window, cx| {
 8124                        weak_editor
 8125                            .update(cx, |this, cx| {
 8126                                this.edit_breakpoint_at_anchor(
 8127                                    anchor,
 8128                                    breakpoint.as_ref().clone(),
 8129                                    BreakpointEditAction::Toggle,
 8130                                    cx,
 8131                                );
 8132                            })
 8133                            .log_err();
 8134                    }
 8135                })
 8136                .entry(log_breakpoint_msg, None, {
 8137                    let breakpoint = breakpoint.clone();
 8138                    let weak_editor = weak_editor.clone();
 8139                    move |window, cx| {
 8140                        weak_editor
 8141                            .update(cx, |this, cx| {
 8142                                this.add_edit_breakpoint_block(
 8143                                    anchor,
 8144                                    breakpoint.as_ref(),
 8145                                    BreakpointPromptEditAction::Log,
 8146                                    window,
 8147                                    cx,
 8148                                );
 8149                            })
 8150                            .log_err();
 8151                    }
 8152                })
 8153                .entry(condition_breakpoint_msg, None, {
 8154                    let breakpoint = breakpoint.clone();
 8155                    let weak_editor = weak_editor.clone();
 8156                    move |window, cx| {
 8157                        weak_editor
 8158                            .update(cx, |this, cx| {
 8159                                this.add_edit_breakpoint_block(
 8160                                    anchor,
 8161                                    breakpoint.as_ref(),
 8162                                    BreakpointPromptEditAction::Condition,
 8163                                    window,
 8164                                    cx,
 8165                                );
 8166                            })
 8167                            .log_err();
 8168                    }
 8169                })
 8170                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8171                    weak_editor
 8172                        .update(cx, |this, cx| {
 8173                            this.add_edit_breakpoint_block(
 8174                                anchor,
 8175                                breakpoint.as_ref(),
 8176                                BreakpointPromptEditAction::HitCondition,
 8177                                window,
 8178                                cx,
 8179                            );
 8180                        })
 8181                        .log_err();
 8182                })
 8183        })
 8184    }
 8185
 8186    fn render_breakpoint(
 8187        &self,
 8188        position: Anchor,
 8189        row: DisplayRow,
 8190        breakpoint: &Breakpoint,
 8191        state: Option<BreakpointSessionState>,
 8192        cx: &mut Context<Self>,
 8193    ) -> IconButton {
 8194        let is_rejected = state.is_some_and(|s| !s.verified);
 8195        // Is it a breakpoint that shows up when hovering over gutter?
 8196        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8197            (false, false),
 8198            |PhantomBreakpointIndicator {
 8199                 is_active,
 8200                 display_row,
 8201                 collides_with_existing_breakpoint,
 8202             }| {
 8203                (
 8204                    is_active && display_row == row,
 8205                    collides_with_existing_breakpoint,
 8206                )
 8207            },
 8208        );
 8209
 8210        let (color, icon) = {
 8211            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8212                (false, false) => ui::IconName::DebugBreakpoint,
 8213                (true, false) => ui::IconName::DebugLogBreakpoint,
 8214                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8215                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8216            };
 8217
 8218            let color = if is_phantom {
 8219                Color::Hint
 8220            } else if is_rejected {
 8221                Color::Disabled
 8222            } else {
 8223                Color::Debugger
 8224            };
 8225
 8226            (color, icon)
 8227        };
 8228
 8229        let breakpoint = Arc::from(breakpoint.clone());
 8230
 8231        let alt_as_text = gpui::Keystroke {
 8232            modifiers: Modifiers::secondary_key(),
 8233            ..Default::default()
 8234        };
 8235        let primary_action_text = if breakpoint.is_disabled() {
 8236            "Enable breakpoint"
 8237        } else if is_phantom && !collides_with_existing {
 8238            "Set breakpoint"
 8239        } else {
 8240            "Unset breakpoint"
 8241        };
 8242        let focus_handle = self.focus_handle.clone();
 8243
 8244        let meta = if is_rejected {
 8245            SharedString::from("No executable code is associated with this line.")
 8246        } else if collides_with_existing && !breakpoint.is_disabled() {
 8247            SharedString::from(format!(
 8248                "{alt_as_text}-click to disable,\nright-click for more options."
 8249            ))
 8250        } else {
 8251            SharedString::from("Right-click for more options.")
 8252        };
 8253        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8254            .icon_size(IconSize::XSmall)
 8255            .size(ui::ButtonSize::None)
 8256            .when(is_rejected, |this| {
 8257                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8258            })
 8259            .icon_color(color)
 8260            .style(ButtonStyle::Transparent)
 8261            .on_click(cx.listener({
 8262                move |editor, event: &ClickEvent, window, cx| {
 8263                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8264                        BreakpointEditAction::InvertState
 8265                    } else {
 8266                        BreakpointEditAction::Toggle
 8267                    };
 8268
 8269                    window.focus(&editor.focus_handle(cx));
 8270                    editor.edit_breakpoint_at_anchor(
 8271                        position,
 8272                        breakpoint.as_ref().clone(),
 8273                        edit_action,
 8274                        cx,
 8275                    );
 8276                }
 8277            }))
 8278            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8279                editor.set_breakpoint_context_menu(
 8280                    row,
 8281                    Some(position),
 8282                    event.position(),
 8283                    window,
 8284                    cx,
 8285                );
 8286            }))
 8287            .tooltip(move |window, cx| {
 8288                Tooltip::with_meta_in(
 8289                    primary_action_text,
 8290                    Some(&ToggleBreakpoint),
 8291                    meta.clone(),
 8292                    &focus_handle,
 8293                    window,
 8294                    cx,
 8295                )
 8296            })
 8297    }
 8298
 8299    fn build_tasks_context(
 8300        project: &Entity<Project>,
 8301        buffer: &Entity<Buffer>,
 8302        buffer_row: u32,
 8303        tasks: &Arc<RunnableTasks>,
 8304        cx: &mut Context<Self>,
 8305    ) -> Task<Option<task::TaskContext>> {
 8306        let position = Point::new(buffer_row, tasks.column);
 8307        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8308        let location = Location {
 8309            buffer: buffer.clone(),
 8310            range: range_start..range_start,
 8311        };
 8312        // Fill in the environmental variables from the tree-sitter captures
 8313        let mut captured_task_variables = TaskVariables::default();
 8314        for (capture_name, value) in tasks.extra_variables.clone() {
 8315            captured_task_variables.insert(
 8316                task::VariableName::Custom(capture_name.into()),
 8317                value.clone(),
 8318            );
 8319        }
 8320        project.update(cx, |project, cx| {
 8321            project.task_store().update(cx, |task_store, cx| {
 8322                task_store.task_context_for_location(captured_task_variables, location, cx)
 8323            })
 8324        })
 8325    }
 8326
 8327    pub fn spawn_nearest_task(
 8328        &mut self,
 8329        action: &SpawnNearestTask,
 8330        window: &mut Window,
 8331        cx: &mut Context<Self>,
 8332    ) {
 8333        let Some((workspace, _)) = self.workspace.clone() else {
 8334            return;
 8335        };
 8336        let Some(project) = self.project.clone() else {
 8337            return;
 8338        };
 8339
 8340        // Try to find a closest, enclosing node using tree-sitter that has a task
 8341        let Some((buffer, buffer_row, tasks)) = self
 8342            .find_enclosing_node_task(cx)
 8343            // Or find the task that's closest in row-distance.
 8344            .or_else(|| self.find_closest_task(cx))
 8345        else {
 8346            return;
 8347        };
 8348
 8349        let reveal_strategy = action.reveal;
 8350        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8351        cx.spawn_in(window, async move |_, cx| {
 8352            let context = task_context.await?;
 8353            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8354
 8355            let resolved = &mut resolved_task.resolved;
 8356            resolved.reveal = reveal_strategy;
 8357
 8358            workspace
 8359                .update_in(cx, |workspace, window, cx| {
 8360                    workspace.schedule_resolved_task(
 8361                        task_source_kind,
 8362                        resolved_task,
 8363                        false,
 8364                        window,
 8365                        cx,
 8366                    );
 8367                })
 8368                .ok()
 8369        })
 8370        .detach();
 8371    }
 8372
 8373    fn find_closest_task(
 8374        &mut self,
 8375        cx: &mut Context<Self>,
 8376    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8377        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8378
 8379        let ((buffer_id, row), tasks) = self
 8380            .tasks
 8381            .iter()
 8382            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8383
 8384        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8385        let tasks = Arc::new(tasks.to_owned());
 8386        Some((buffer, *row, tasks))
 8387    }
 8388
 8389    fn find_enclosing_node_task(
 8390        &mut self,
 8391        cx: &mut Context<Self>,
 8392    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8393        let snapshot = self.buffer.read(cx).snapshot(cx);
 8394        let offset = self.selections.newest::<usize>(cx).head();
 8395        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8396        let buffer_id = excerpt.buffer().remote_id();
 8397
 8398        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8399        let mut cursor = layer.node().walk();
 8400
 8401        while cursor.goto_first_child_for_byte(offset).is_some() {
 8402            if cursor.node().end_byte() == offset {
 8403                cursor.goto_next_sibling();
 8404            }
 8405        }
 8406
 8407        // Ascend to the smallest ancestor that contains the range and has a task.
 8408        loop {
 8409            let node = cursor.node();
 8410            let node_range = node.byte_range();
 8411            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8412
 8413            // Check if this node contains our offset
 8414            if node_range.start <= offset && node_range.end >= offset {
 8415                // If it contains offset, check for task
 8416                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8417                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8418                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8419                }
 8420            }
 8421
 8422            if !cursor.goto_parent() {
 8423                break;
 8424            }
 8425        }
 8426        None
 8427    }
 8428
 8429    fn render_run_indicator(
 8430        &self,
 8431        _style: &EditorStyle,
 8432        is_active: bool,
 8433        row: DisplayRow,
 8434        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8435        cx: &mut Context<Self>,
 8436    ) -> IconButton {
 8437        let color = Color::Muted;
 8438        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8439
 8440        IconButton::new(
 8441            ("run_indicator", row.0 as usize),
 8442            ui::IconName::PlayOutlined,
 8443        )
 8444        .shape(ui::IconButtonShape::Square)
 8445        .icon_size(IconSize::XSmall)
 8446        .icon_color(color)
 8447        .toggle_state(is_active)
 8448        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8449            let quick_launch = match e {
 8450                ClickEvent::Keyboard(_) => true,
 8451                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8452            };
 8453
 8454            window.focus(&editor.focus_handle(cx));
 8455            editor.toggle_code_actions(
 8456                &ToggleCodeActions {
 8457                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8458                    quick_launch,
 8459                },
 8460                window,
 8461                cx,
 8462            );
 8463        }))
 8464        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8465            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8466        }))
 8467    }
 8468
 8469    pub fn context_menu_visible(&self) -> bool {
 8470        !self.edit_prediction_preview_is_active()
 8471            && self
 8472                .context_menu
 8473                .borrow()
 8474                .as_ref()
 8475                .is_some_and(|menu| menu.visible())
 8476    }
 8477
 8478    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8479        self.context_menu
 8480            .borrow()
 8481            .as_ref()
 8482            .map(|menu| menu.origin())
 8483    }
 8484
 8485    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8486        self.context_menu_options = Some(options);
 8487    }
 8488
 8489    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8490    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8491
 8492    fn render_edit_prediction_popover(
 8493        &mut self,
 8494        text_bounds: &Bounds<Pixels>,
 8495        content_origin: gpui::Point<Pixels>,
 8496        right_margin: Pixels,
 8497        editor_snapshot: &EditorSnapshot,
 8498        visible_row_range: Range<DisplayRow>,
 8499        scroll_top: f32,
 8500        scroll_bottom: f32,
 8501        line_layouts: &[LineWithInvisibles],
 8502        line_height: Pixels,
 8503        scroll_pixel_position: gpui::Point<Pixels>,
 8504        newest_selection_head: Option<DisplayPoint>,
 8505        editor_width: Pixels,
 8506        style: &EditorStyle,
 8507        window: &mut Window,
 8508        cx: &mut App,
 8509    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8510        if self.mode().is_minimap() {
 8511            return None;
 8512        }
 8513        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8514
 8515        if self.edit_prediction_visible_in_cursor_popover(true) {
 8516            return None;
 8517        }
 8518
 8519        match &active_edit_prediction.completion {
 8520            EditPrediction::Move { target, .. } => {
 8521                let target_display_point = target.to_display_point(editor_snapshot);
 8522
 8523                if self.edit_prediction_requires_modifier() {
 8524                    if !self.edit_prediction_preview_is_active() {
 8525                        return None;
 8526                    }
 8527
 8528                    self.render_edit_prediction_modifier_jump_popover(
 8529                        text_bounds,
 8530                        content_origin,
 8531                        visible_row_range,
 8532                        line_layouts,
 8533                        line_height,
 8534                        scroll_pixel_position,
 8535                        newest_selection_head,
 8536                        target_display_point,
 8537                        window,
 8538                        cx,
 8539                    )
 8540                } else {
 8541                    self.render_edit_prediction_eager_jump_popover(
 8542                        text_bounds,
 8543                        content_origin,
 8544                        editor_snapshot,
 8545                        visible_row_range,
 8546                        scroll_top,
 8547                        scroll_bottom,
 8548                        line_height,
 8549                        scroll_pixel_position,
 8550                        target_display_point,
 8551                        editor_width,
 8552                        window,
 8553                        cx,
 8554                    )
 8555                }
 8556            }
 8557            EditPrediction::Edit {
 8558                display_mode: EditDisplayMode::Inline,
 8559                ..
 8560            } => None,
 8561            EditPrediction::Edit {
 8562                display_mode: EditDisplayMode::TabAccept,
 8563                edits,
 8564                ..
 8565            } => {
 8566                let range = &edits.first()?.0;
 8567                let target_display_point = range.end.to_display_point(editor_snapshot);
 8568
 8569                self.render_edit_prediction_end_of_line_popover(
 8570                    "Accept",
 8571                    editor_snapshot,
 8572                    visible_row_range,
 8573                    target_display_point,
 8574                    line_height,
 8575                    scroll_pixel_position,
 8576                    content_origin,
 8577                    editor_width,
 8578                    window,
 8579                    cx,
 8580                )
 8581            }
 8582            EditPrediction::Edit {
 8583                edits,
 8584                edit_preview,
 8585                display_mode: EditDisplayMode::DiffPopover,
 8586                snapshot,
 8587            } => self.render_edit_prediction_diff_popover(
 8588                text_bounds,
 8589                content_origin,
 8590                right_margin,
 8591                editor_snapshot,
 8592                visible_row_range,
 8593                line_layouts,
 8594                line_height,
 8595                scroll_pixel_position,
 8596                newest_selection_head,
 8597                editor_width,
 8598                style,
 8599                edits,
 8600                edit_preview,
 8601                snapshot,
 8602                window,
 8603                cx,
 8604            ),
 8605        }
 8606    }
 8607
 8608    fn render_edit_prediction_modifier_jump_popover(
 8609        &mut self,
 8610        text_bounds: &Bounds<Pixels>,
 8611        content_origin: gpui::Point<Pixels>,
 8612        visible_row_range: Range<DisplayRow>,
 8613        line_layouts: &[LineWithInvisibles],
 8614        line_height: Pixels,
 8615        scroll_pixel_position: gpui::Point<Pixels>,
 8616        newest_selection_head: Option<DisplayPoint>,
 8617        target_display_point: DisplayPoint,
 8618        window: &mut Window,
 8619        cx: &mut App,
 8620    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8621        let scrolled_content_origin =
 8622            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8623
 8624        const SCROLL_PADDING_Y: Pixels = px(12.);
 8625
 8626        if target_display_point.row() < visible_row_range.start {
 8627            return self.render_edit_prediction_scroll_popover(
 8628                |_| SCROLL_PADDING_Y,
 8629                IconName::ArrowUp,
 8630                visible_row_range,
 8631                line_layouts,
 8632                newest_selection_head,
 8633                scrolled_content_origin,
 8634                window,
 8635                cx,
 8636            );
 8637        } else if target_display_point.row() >= visible_row_range.end {
 8638            return self.render_edit_prediction_scroll_popover(
 8639                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8640                IconName::ArrowDown,
 8641                visible_row_range,
 8642                line_layouts,
 8643                newest_selection_head,
 8644                scrolled_content_origin,
 8645                window,
 8646                cx,
 8647            );
 8648        }
 8649
 8650        const POLE_WIDTH: Pixels = px(2.);
 8651
 8652        let line_layout =
 8653            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8654        let target_column = target_display_point.column() as usize;
 8655
 8656        let target_x = line_layout.x_for_index(target_column);
 8657        let target_y =
 8658            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8659
 8660        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8661
 8662        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8663        border_color.l += 0.001;
 8664
 8665        let mut element = v_flex()
 8666            .items_end()
 8667            .when(flag_on_right, |el| el.items_start())
 8668            .child(if flag_on_right {
 8669                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8670                    .rounded_bl(px(0.))
 8671                    .rounded_tl(px(0.))
 8672                    .border_l_2()
 8673                    .border_color(border_color)
 8674            } else {
 8675                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8676                    .rounded_br(px(0.))
 8677                    .rounded_tr(px(0.))
 8678                    .border_r_2()
 8679                    .border_color(border_color)
 8680            })
 8681            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8682            .into_any();
 8683
 8684        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8685
 8686        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8687            - point(
 8688                if flag_on_right {
 8689                    POLE_WIDTH
 8690                } else {
 8691                    size.width - POLE_WIDTH
 8692                },
 8693                size.height - line_height,
 8694            );
 8695
 8696        origin.x = origin.x.max(content_origin.x);
 8697
 8698        element.prepaint_at(origin, window, cx);
 8699
 8700        Some((element, origin))
 8701    }
 8702
 8703    fn render_edit_prediction_scroll_popover(
 8704        &mut self,
 8705        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8706        scroll_icon: IconName,
 8707        visible_row_range: Range<DisplayRow>,
 8708        line_layouts: &[LineWithInvisibles],
 8709        newest_selection_head: Option<DisplayPoint>,
 8710        scrolled_content_origin: gpui::Point<Pixels>,
 8711        window: &mut Window,
 8712        cx: &mut App,
 8713    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8714        let mut element = self
 8715            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8716            .into_any();
 8717
 8718        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8719
 8720        let cursor = newest_selection_head?;
 8721        let cursor_row_layout =
 8722            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8723        let cursor_column = cursor.column() as usize;
 8724
 8725        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8726
 8727        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8728
 8729        element.prepaint_at(origin, window, cx);
 8730        Some((element, origin))
 8731    }
 8732
 8733    fn render_edit_prediction_eager_jump_popover(
 8734        &mut self,
 8735        text_bounds: &Bounds<Pixels>,
 8736        content_origin: gpui::Point<Pixels>,
 8737        editor_snapshot: &EditorSnapshot,
 8738        visible_row_range: Range<DisplayRow>,
 8739        scroll_top: f32,
 8740        scroll_bottom: f32,
 8741        line_height: Pixels,
 8742        scroll_pixel_position: gpui::Point<Pixels>,
 8743        target_display_point: DisplayPoint,
 8744        editor_width: Pixels,
 8745        window: &mut Window,
 8746        cx: &mut App,
 8747    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8748        if target_display_point.row().as_f32() < scroll_top {
 8749            let mut element = self
 8750                .render_edit_prediction_line_popover(
 8751                    "Jump to Edit",
 8752                    Some(IconName::ArrowUp),
 8753                    window,
 8754                    cx,
 8755                )?
 8756                .into_any();
 8757
 8758            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8759            let offset = point(
 8760                (text_bounds.size.width - size.width) / 2.,
 8761                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8762            );
 8763
 8764            let origin = text_bounds.origin + offset;
 8765            element.prepaint_at(origin, window, cx);
 8766            Some((element, origin))
 8767        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8768            let mut element = self
 8769                .render_edit_prediction_line_popover(
 8770                    "Jump to Edit",
 8771                    Some(IconName::ArrowDown),
 8772                    window,
 8773                    cx,
 8774                )?
 8775                .into_any();
 8776
 8777            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8778            let offset = point(
 8779                (text_bounds.size.width - size.width) / 2.,
 8780                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8781            );
 8782
 8783            let origin = text_bounds.origin + offset;
 8784            element.prepaint_at(origin, window, cx);
 8785            Some((element, origin))
 8786        } else {
 8787            self.render_edit_prediction_end_of_line_popover(
 8788                "Jump to Edit",
 8789                editor_snapshot,
 8790                visible_row_range,
 8791                target_display_point,
 8792                line_height,
 8793                scroll_pixel_position,
 8794                content_origin,
 8795                editor_width,
 8796                window,
 8797                cx,
 8798            )
 8799        }
 8800    }
 8801
 8802    fn render_edit_prediction_end_of_line_popover(
 8803        self: &mut Editor,
 8804        label: &'static str,
 8805        editor_snapshot: &EditorSnapshot,
 8806        visible_row_range: Range<DisplayRow>,
 8807        target_display_point: DisplayPoint,
 8808        line_height: Pixels,
 8809        scroll_pixel_position: gpui::Point<Pixels>,
 8810        content_origin: gpui::Point<Pixels>,
 8811        editor_width: Pixels,
 8812        window: &mut Window,
 8813        cx: &mut App,
 8814    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8815        let target_line_end = DisplayPoint::new(
 8816            target_display_point.row(),
 8817            editor_snapshot.line_len(target_display_point.row()),
 8818        );
 8819
 8820        let mut element = self
 8821            .render_edit_prediction_line_popover(label, None, window, cx)?
 8822            .into_any();
 8823
 8824        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8825
 8826        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8827
 8828        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8829        let mut origin = start_point
 8830            + line_origin
 8831            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8832        origin.x = origin.x.max(content_origin.x);
 8833
 8834        let max_x = content_origin.x + editor_width - size.width;
 8835
 8836        if origin.x > max_x {
 8837            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8838
 8839            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8840                origin.y += offset;
 8841                IconName::ArrowUp
 8842            } else {
 8843                origin.y -= offset;
 8844                IconName::ArrowDown
 8845            };
 8846
 8847            element = self
 8848                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8849                .into_any();
 8850
 8851            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8852
 8853            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8854        }
 8855
 8856        element.prepaint_at(origin, window, cx);
 8857        Some((element, origin))
 8858    }
 8859
 8860    fn render_edit_prediction_diff_popover(
 8861        self: &Editor,
 8862        text_bounds: &Bounds<Pixels>,
 8863        content_origin: gpui::Point<Pixels>,
 8864        right_margin: Pixels,
 8865        editor_snapshot: &EditorSnapshot,
 8866        visible_row_range: Range<DisplayRow>,
 8867        line_layouts: &[LineWithInvisibles],
 8868        line_height: Pixels,
 8869        scroll_pixel_position: gpui::Point<Pixels>,
 8870        newest_selection_head: Option<DisplayPoint>,
 8871        editor_width: Pixels,
 8872        style: &EditorStyle,
 8873        edits: &Vec<(Range<Anchor>, String)>,
 8874        edit_preview: &Option<language::EditPreview>,
 8875        snapshot: &language::BufferSnapshot,
 8876        window: &mut Window,
 8877        cx: &mut App,
 8878    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8879        let edit_start = edits
 8880            .first()
 8881            .unwrap()
 8882            .0
 8883            .start
 8884            .to_display_point(editor_snapshot);
 8885        let edit_end = edits
 8886            .last()
 8887            .unwrap()
 8888            .0
 8889            .end
 8890            .to_display_point(editor_snapshot);
 8891
 8892        let is_visible = visible_row_range.contains(&edit_start.row())
 8893            || visible_row_range.contains(&edit_end.row());
 8894        if !is_visible {
 8895            return None;
 8896        }
 8897
 8898        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8899            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8900        } else {
 8901            // Fallback for providers without edit_preview
 8902            crate::edit_prediction_fallback_text(edits, cx)
 8903        };
 8904
 8905        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8906        let line_count = highlighted_edits.text.lines().count();
 8907
 8908        const BORDER_WIDTH: Pixels = px(1.);
 8909
 8910        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8911        let has_keybind = keybind.is_some();
 8912
 8913        let mut element = h_flex()
 8914            .items_start()
 8915            .child(
 8916                h_flex()
 8917                    .bg(cx.theme().colors().editor_background)
 8918                    .border(BORDER_WIDTH)
 8919                    .shadow_xs()
 8920                    .border_color(cx.theme().colors().border)
 8921                    .rounded_l_lg()
 8922                    .when(line_count > 1, |el| el.rounded_br_lg())
 8923                    .pr_1()
 8924                    .child(styled_text),
 8925            )
 8926            .child(
 8927                h_flex()
 8928                    .h(line_height + BORDER_WIDTH * 2.)
 8929                    .px_1p5()
 8930                    .gap_1()
 8931                    // Workaround: For some reason, there's a gap if we don't do this
 8932                    .ml(-BORDER_WIDTH)
 8933                    .shadow(vec![gpui::BoxShadow {
 8934                        color: gpui::black().opacity(0.05),
 8935                        offset: point(px(1.), px(1.)),
 8936                        blur_radius: px(2.),
 8937                        spread_radius: px(0.),
 8938                    }])
 8939                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8940                    .border(BORDER_WIDTH)
 8941                    .border_color(cx.theme().colors().border)
 8942                    .rounded_r_lg()
 8943                    .id("edit_prediction_diff_popover_keybind")
 8944                    .when(!has_keybind, |el| {
 8945                        let status_colors = cx.theme().status();
 8946
 8947                        el.bg(status_colors.error_background)
 8948                            .border_color(status_colors.error.opacity(0.6))
 8949                            .child(Icon::new(IconName::Info).color(Color::Error))
 8950                            .cursor_default()
 8951                            .hoverable_tooltip(move |_window, cx| {
 8952                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8953                            })
 8954                    })
 8955                    .children(keybind),
 8956            )
 8957            .into_any();
 8958
 8959        let longest_row =
 8960            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8961        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8962            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8963        } else {
 8964            layout_line(
 8965                longest_row,
 8966                editor_snapshot,
 8967                style,
 8968                editor_width,
 8969                |_| false,
 8970                window,
 8971                cx,
 8972            )
 8973            .width
 8974        };
 8975
 8976        let viewport_bounds =
 8977            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8978                right: -right_margin,
 8979                ..Default::default()
 8980            });
 8981
 8982        let x_after_longest =
 8983            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8984                - scroll_pixel_position.x;
 8985
 8986        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8987
 8988        // Fully visible if it can be displayed within the window (allow overlapping other
 8989        // panes). However, this is only allowed if the popover starts within text_bounds.
 8990        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8991            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8992
 8993        let mut origin = if can_position_to_the_right {
 8994            point(
 8995                x_after_longest,
 8996                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8997                    - scroll_pixel_position.y,
 8998            )
 8999        } else {
 9000            let cursor_row = newest_selection_head.map(|head| head.row());
 9001            let above_edit = edit_start
 9002                .row()
 9003                .0
 9004                .checked_sub(line_count as u32)
 9005                .map(DisplayRow);
 9006            let below_edit = Some(edit_end.row() + 1);
 9007            let above_cursor =
 9008                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9009            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9010
 9011            // Place the edit popover adjacent to the edit if there is a location
 9012            // available that is onscreen and does not obscure the cursor. Otherwise,
 9013            // place it adjacent to the cursor.
 9014            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9015                .into_iter()
 9016                .flatten()
 9017                .find(|&start_row| {
 9018                    let end_row = start_row + line_count as u32;
 9019                    visible_row_range.contains(&start_row)
 9020                        && visible_row_range.contains(&end_row)
 9021                        && cursor_row
 9022                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9023                })?;
 9024
 9025            content_origin
 9026                + point(
 9027                    -scroll_pixel_position.x,
 9028                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9029                )
 9030        };
 9031
 9032        origin.x -= BORDER_WIDTH;
 9033
 9034        window.defer_draw(element, origin, 1);
 9035
 9036        // Do not return an element, since it will already be drawn due to defer_draw.
 9037        None
 9038    }
 9039
 9040    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9041        px(30.)
 9042    }
 9043
 9044    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9045        if self.read_only(cx) {
 9046            cx.theme().players().read_only()
 9047        } else {
 9048            self.style.as_ref().unwrap().local_player
 9049        }
 9050    }
 9051
 9052    fn render_edit_prediction_accept_keybind(
 9053        &self,
 9054        window: &mut Window,
 9055        cx: &App,
 9056    ) -> Option<AnyElement> {
 9057        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9058        let accept_keystroke = accept_binding.keystroke()?;
 9059
 9060        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9061
 9062        let modifiers_color = if accept_keystroke.display_modifiers == window.modifiers() {
 9063            Color::Accent
 9064        } else {
 9065            Color::Muted
 9066        };
 9067
 9068        h_flex()
 9069            .px_0p5()
 9070            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9071            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9072            .text_size(TextSize::XSmall.rems(cx))
 9073            .child(h_flex().children(ui::render_modifiers(
 9074                &accept_keystroke.display_modifiers,
 9075                PlatformStyle::platform(),
 9076                Some(modifiers_color),
 9077                Some(IconSize::XSmall.rems().into()),
 9078                true,
 9079            )))
 9080            .when(is_platform_style_mac, |parent| {
 9081                parent.child(accept_keystroke.display_key.clone())
 9082            })
 9083            .when(!is_platform_style_mac, |parent| {
 9084                parent.child(
 9085                    Key::new(
 9086                        util::capitalize(&accept_keystroke.display_key),
 9087                        Some(Color::Default),
 9088                    )
 9089                    .size(Some(IconSize::XSmall.rems().into())),
 9090                )
 9091            })
 9092            .into_any()
 9093            .into()
 9094    }
 9095
 9096    fn render_edit_prediction_line_popover(
 9097        &self,
 9098        label: impl Into<SharedString>,
 9099        icon: Option<IconName>,
 9100        window: &mut Window,
 9101        cx: &App,
 9102    ) -> Option<Stateful<Div>> {
 9103        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9104
 9105        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9106        let has_keybind = keybind.is_some();
 9107
 9108        let result = h_flex()
 9109            .id("ep-line-popover")
 9110            .py_0p5()
 9111            .pl_1()
 9112            .pr(padding_right)
 9113            .gap_1()
 9114            .rounded_md()
 9115            .border_1()
 9116            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9117            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9118            .shadow_xs()
 9119            .when(!has_keybind, |el| {
 9120                let status_colors = cx.theme().status();
 9121
 9122                el.bg(status_colors.error_background)
 9123                    .border_color(status_colors.error.opacity(0.6))
 9124                    .pl_2()
 9125                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9126                    .cursor_default()
 9127                    .hoverable_tooltip(move |_window, cx| {
 9128                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9129                    })
 9130            })
 9131            .children(keybind)
 9132            .child(
 9133                Label::new(label)
 9134                    .size(LabelSize::Small)
 9135                    .when(!has_keybind, |el| {
 9136                        el.color(cx.theme().status().error.into()).strikethrough()
 9137                    }),
 9138            )
 9139            .when(!has_keybind, |el| {
 9140                el.child(
 9141                    h_flex().ml_1().child(
 9142                        Icon::new(IconName::Info)
 9143                            .size(IconSize::Small)
 9144                            .color(cx.theme().status().error.into()),
 9145                    ),
 9146                )
 9147            })
 9148            .when_some(icon, |element, icon| {
 9149                element.child(
 9150                    div()
 9151                        .mt(px(1.5))
 9152                        .child(Icon::new(icon).size(IconSize::Small)),
 9153                )
 9154            });
 9155
 9156        Some(result)
 9157    }
 9158
 9159    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9160        let accent_color = cx.theme().colors().text_accent;
 9161        let editor_bg_color = cx.theme().colors().editor_background;
 9162        editor_bg_color.blend(accent_color.opacity(0.1))
 9163    }
 9164
 9165    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9166        let accent_color = cx.theme().colors().text_accent;
 9167        let editor_bg_color = cx.theme().colors().editor_background;
 9168        editor_bg_color.blend(accent_color.opacity(0.6))
 9169    }
 9170    fn get_prediction_provider_icon_name(
 9171        provider: &Option<RegisteredEditPredictionProvider>,
 9172    ) -> IconName {
 9173        match provider {
 9174            Some(provider) => match provider.provider.name() {
 9175                "copilot" => IconName::Copilot,
 9176                "supermaven" => IconName::Supermaven,
 9177                _ => IconName::ZedPredict,
 9178            },
 9179            None => IconName::ZedPredict,
 9180        }
 9181    }
 9182
 9183    fn render_edit_prediction_cursor_popover(
 9184        &self,
 9185        min_width: Pixels,
 9186        max_width: Pixels,
 9187        cursor_point: Point,
 9188        style: &EditorStyle,
 9189        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9190        _window: &Window,
 9191        cx: &mut Context<Editor>,
 9192    ) -> Option<AnyElement> {
 9193        let provider = self.edit_prediction_provider.as_ref()?;
 9194        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9195
 9196        let is_refreshing = provider.provider.is_refreshing(cx);
 9197
 9198        fn pending_completion_container(icon: IconName) -> Div {
 9199            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9200        }
 9201
 9202        let completion = match &self.active_edit_prediction {
 9203            Some(prediction) => {
 9204                if !self.has_visible_completions_menu() {
 9205                    const RADIUS: Pixels = px(6.);
 9206                    const BORDER_WIDTH: Pixels = px(1.);
 9207
 9208                    return Some(
 9209                        h_flex()
 9210                            .elevation_2(cx)
 9211                            .border(BORDER_WIDTH)
 9212                            .border_color(cx.theme().colors().border)
 9213                            .when(accept_keystroke.is_none(), |el| {
 9214                                el.border_color(cx.theme().status().error)
 9215                            })
 9216                            .rounded(RADIUS)
 9217                            .rounded_tl(px(0.))
 9218                            .overflow_hidden()
 9219                            .child(div().px_1p5().child(match &prediction.completion {
 9220                                EditPrediction::Move { target, snapshot } => {
 9221                                    use text::ToPoint as _;
 9222                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9223                                    {
 9224                                        Icon::new(IconName::ZedPredictDown)
 9225                                    } else {
 9226                                        Icon::new(IconName::ZedPredictUp)
 9227                                    }
 9228                                }
 9229                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9230                            }))
 9231                            .child(
 9232                                h_flex()
 9233                                    .gap_1()
 9234                                    .py_1()
 9235                                    .px_2()
 9236                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9237                                    .border_l_1()
 9238                                    .border_color(cx.theme().colors().border)
 9239                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9240                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9241                                        el.child(
 9242                                            Label::new("Hold")
 9243                                                .size(LabelSize::Small)
 9244                                                .when(accept_keystroke.is_none(), |el| {
 9245                                                    el.strikethrough()
 9246                                                })
 9247                                                .line_height_style(LineHeightStyle::UiLabel),
 9248                                        )
 9249                                    })
 9250                                    .id("edit_prediction_cursor_popover_keybind")
 9251                                    .when(accept_keystroke.is_none(), |el| {
 9252                                        let status_colors = cx.theme().status();
 9253
 9254                                        el.bg(status_colors.error_background)
 9255                                            .border_color(status_colors.error.opacity(0.6))
 9256                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9257                                            .cursor_default()
 9258                                            .hoverable_tooltip(move |_window, cx| {
 9259                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9260                                                    .into()
 9261                                            })
 9262                                    })
 9263                                    .when_some(
 9264                                        accept_keystroke.as_ref(),
 9265                                        |el, accept_keystroke| {
 9266                                            el.child(h_flex().children(ui::render_modifiers(
 9267                                                &accept_keystroke.display_modifiers,
 9268                                                PlatformStyle::platform(),
 9269                                                Some(Color::Default),
 9270                                                Some(IconSize::XSmall.rems().into()),
 9271                                                false,
 9272                                            )))
 9273                                        },
 9274                                    ),
 9275                            )
 9276                            .into_any(),
 9277                    );
 9278                }
 9279
 9280                self.render_edit_prediction_cursor_popover_preview(
 9281                    prediction,
 9282                    cursor_point,
 9283                    style,
 9284                    cx,
 9285                )?
 9286            }
 9287
 9288            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9289                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9290                    stale_completion,
 9291                    cursor_point,
 9292                    style,
 9293                    cx,
 9294                )?,
 9295
 9296                None => pending_completion_container(provider_icon)
 9297                    .child(Label::new("...").size(LabelSize::Small)),
 9298            },
 9299
 9300            None => pending_completion_container(provider_icon)
 9301                .child(Label::new("...").size(LabelSize::Small)),
 9302        };
 9303
 9304        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9305            completion
 9306                .with_animation(
 9307                    "loading-completion",
 9308                    Animation::new(Duration::from_secs(2))
 9309                        .repeat()
 9310                        .with_easing(pulsating_between(0.4, 0.8)),
 9311                    |label, delta| label.opacity(delta),
 9312                )
 9313                .into_any_element()
 9314        } else {
 9315            completion.into_any_element()
 9316        };
 9317
 9318        let has_completion = self.active_edit_prediction.is_some();
 9319
 9320        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9321        Some(
 9322            h_flex()
 9323                .min_w(min_width)
 9324                .max_w(max_width)
 9325                .flex_1()
 9326                .elevation_2(cx)
 9327                .border_color(cx.theme().colors().border)
 9328                .child(
 9329                    div()
 9330                        .flex_1()
 9331                        .py_1()
 9332                        .px_2()
 9333                        .overflow_hidden()
 9334                        .child(completion),
 9335                )
 9336                .when_some(accept_keystroke, |el, accept_keystroke| {
 9337                    if !accept_keystroke.display_modifiers.modified() {
 9338                        return el;
 9339                    }
 9340
 9341                    el.child(
 9342                        h_flex()
 9343                            .h_full()
 9344                            .border_l_1()
 9345                            .rounded_r_lg()
 9346                            .border_color(cx.theme().colors().border)
 9347                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9348                            .gap_1()
 9349                            .py_1()
 9350                            .px_2()
 9351                            .child(
 9352                                h_flex()
 9353                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9354                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9355                                    .child(h_flex().children(ui::render_modifiers(
 9356                                        &accept_keystroke.display_modifiers,
 9357                                        PlatformStyle::platform(),
 9358                                        Some(if !has_completion {
 9359                                            Color::Muted
 9360                                        } else {
 9361                                            Color::Default
 9362                                        }),
 9363                                        None,
 9364                                        false,
 9365                                    ))),
 9366                            )
 9367                            .child(Label::new("Preview").into_any_element())
 9368                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9369                    )
 9370                })
 9371                .into_any(),
 9372        )
 9373    }
 9374
 9375    fn render_edit_prediction_cursor_popover_preview(
 9376        &self,
 9377        completion: &EditPredictionState,
 9378        cursor_point: Point,
 9379        style: &EditorStyle,
 9380        cx: &mut Context<Editor>,
 9381    ) -> Option<Div> {
 9382        use text::ToPoint as _;
 9383
 9384        fn render_relative_row_jump(
 9385            prefix: impl Into<String>,
 9386            current_row: u32,
 9387            target_row: u32,
 9388        ) -> Div {
 9389            let (row_diff, arrow) = if target_row < current_row {
 9390                (current_row - target_row, IconName::ArrowUp)
 9391            } else {
 9392                (target_row - current_row, IconName::ArrowDown)
 9393            };
 9394
 9395            h_flex()
 9396                .child(
 9397                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9398                        .color(Color::Muted)
 9399                        .size(LabelSize::Small),
 9400                )
 9401                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9402        }
 9403
 9404        let supports_jump = self
 9405            .edit_prediction_provider
 9406            .as_ref()
 9407            .map(|provider| provider.provider.supports_jump_to_edit())
 9408            .unwrap_or(true);
 9409
 9410        match &completion.completion {
 9411            EditPrediction::Move {
 9412                target, snapshot, ..
 9413            } => {
 9414                if !supports_jump {
 9415                    return None;
 9416                }
 9417
 9418                Some(
 9419                    h_flex()
 9420                        .px_2()
 9421                        .gap_2()
 9422                        .flex_1()
 9423                        .child(
 9424                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9425                                Icon::new(IconName::ZedPredictDown)
 9426                            } else {
 9427                                Icon::new(IconName::ZedPredictUp)
 9428                            },
 9429                        )
 9430                        .child(Label::new("Jump to Edit")),
 9431                )
 9432            }
 9433
 9434            EditPrediction::Edit {
 9435                edits,
 9436                edit_preview,
 9437                snapshot,
 9438                display_mode: _,
 9439            } => {
 9440                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9441
 9442                let (highlighted_edits, has_more_lines) =
 9443                    if let Some(edit_preview) = edit_preview.as_ref() {
 9444                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9445                            .first_line_preview()
 9446                    } else {
 9447                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9448                    };
 9449
 9450                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9451                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9452
 9453                let preview = h_flex()
 9454                    .gap_1()
 9455                    .min_w_16()
 9456                    .child(styled_text)
 9457                    .when(has_more_lines, |parent| parent.child(""));
 9458
 9459                let left = if supports_jump && first_edit_row != cursor_point.row {
 9460                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9461                        .into_any_element()
 9462                } else {
 9463                    let icon_name =
 9464                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9465                    Icon::new(icon_name).into_any_element()
 9466                };
 9467
 9468                Some(
 9469                    h_flex()
 9470                        .h_full()
 9471                        .flex_1()
 9472                        .gap_2()
 9473                        .pr_1()
 9474                        .overflow_x_hidden()
 9475                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9476                        .child(left)
 9477                        .child(preview),
 9478                )
 9479            }
 9480        }
 9481    }
 9482
 9483    pub fn render_context_menu(
 9484        &self,
 9485        style: &EditorStyle,
 9486        max_height_in_lines: u32,
 9487        window: &mut Window,
 9488        cx: &mut Context<Editor>,
 9489    ) -> Option<AnyElement> {
 9490        let menu = self.context_menu.borrow();
 9491        let menu = menu.as_ref()?;
 9492        if !menu.visible() {
 9493            return None;
 9494        };
 9495        Some(menu.render(style, max_height_in_lines, window, cx))
 9496    }
 9497
 9498    fn render_context_menu_aside(
 9499        &mut self,
 9500        max_size: Size<Pixels>,
 9501        window: &mut Window,
 9502        cx: &mut Context<Editor>,
 9503    ) -> Option<AnyElement> {
 9504        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9505            if menu.visible() {
 9506                menu.render_aside(max_size, window, cx)
 9507            } else {
 9508                None
 9509            }
 9510        })
 9511    }
 9512
 9513    fn hide_context_menu(
 9514        &mut self,
 9515        window: &mut Window,
 9516        cx: &mut Context<Self>,
 9517    ) -> Option<CodeContextMenu> {
 9518        cx.notify();
 9519        self.completion_tasks.clear();
 9520        let context_menu = self.context_menu.borrow_mut().take();
 9521        self.stale_edit_prediction_in_menu.take();
 9522        self.update_visible_edit_prediction(window, cx);
 9523        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9524            && let Some(completion_provider) = &self.completion_provider
 9525        {
 9526            completion_provider.selection_changed(None, window, cx);
 9527        }
 9528        context_menu
 9529    }
 9530
 9531    fn show_snippet_choices(
 9532        &mut self,
 9533        choices: &Vec<String>,
 9534        selection: Range<Anchor>,
 9535        cx: &mut Context<Self>,
 9536    ) {
 9537        let Some((_, buffer, _)) = self
 9538            .buffer()
 9539            .read(cx)
 9540            .excerpt_containing(selection.start, cx)
 9541        else {
 9542            return;
 9543        };
 9544        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9545        else {
 9546            return;
 9547        };
 9548        if buffer != end_buffer {
 9549            log::error!("expected anchor range to have matching buffer IDs");
 9550            return;
 9551        }
 9552
 9553        let id = post_inc(&mut self.next_completion_id);
 9554        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9555        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9556            CompletionsMenu::new_snippet_choices(
 9557                id,
 9558                true,
 9559                choices,
 9560                selection,
 9561                buffer,
 9562                snippet_sort_order,
 9563            ),
 9564        ));
 9565    }
 9566
 9567    pub fn insert_snippet(
 9568        &mut self,
 9569        insertion_ranges: &[Range<usize>],
 9570        snippet: Snippet,
 9571        window: &mut Window,
 9572        cx: &mut Context<Self>,
 9573    ) -> Result<()> {
 9574        struct Tabstop<T> {
 9575            is_end_tabstop: bool,
 9576            ranges: Vec<Range<T>>,
 9577            choices: Option<Vec<String>>,
 9578        }
 9579
 9580        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9581            let snippet_text: Arc<str> = snippet.text.clone().into();
 9582            let edits = insertion_ranges
 9583                .iter()
 9584                .cloned()
 9585                .map(|range| (range, snippet_text.clone()));
 9586            let autoindent_mode = AutoindentMode::Block {
 9587                original_indent_columns: Vec::new(),
 9588            };
 9589            buffer.edit(edits, Some(autoindent_mode), cx);
 9590
 9591            let snapshot = &*buffer.read(cx);
 9592            let snippet = &snippet;
 9593            snippet
 9594                .tabstops
 9595                .iter()
 9596                .map(|tabstop| {
 9597                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9598                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9599                    });
 9600                    let mut tabstop_ranges = tabstop
 9601                        .ranges
 9602                        .iter()
 9603                        .flat_map(|tabstop_range| {
 9604                            let mut delta = 0_isize;
 9605                            insertion_ranges.iter().map(move |insertion_range| {
 9606                                let insertion_start = insertion_range.start as isize + delta;
 9607                                delta +=
 9608                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9609
 9610                                let start = ((insertion_start + tabstop_range.start) as usize)
 9611                                    .min(snapshot.len());
 9612                                let end = ((insertion_start + tabstop_range.end) as usize)
 9613                                    .min(snapshot.len());
 9614                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9615                            })
 9616                        })
 9617                        .collect::<Vec<_>>();
 9618                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9619
 9620                    Tabstop {
 9621                        is_end_tabstop,
 9622                        ranges: tabstop_ranges,
 9623                        choices: tabstop.choices.clone(),
 9624                    }
 9625                })
 9626                .collect::<Vec<_>>()
 9627        });
 9628        if let Some(tabstop) = tabstops.first() {
 9629            self.change_selections(Default::default(), window, cx, |s| {
 9630                // Reverse order so that the first range is the newest created selection.
 9631                // Completions will use it and autoscroll will prioritize it.
 9632                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9633            });
 9634
 9635            if let Some(choices) = &tabstop.choices
 9636                && let Some(selection) = tabstop.ranges.first()
 9637            {
 9638                self.show_snippet_choices(choices, selection.clone(), cx)
 9639            }
 9640
 9641            // If we're already at the last tabstop and it's at the end of the snippet,
 9642            // we're done, we don't need to keep the state around.
 9643            if !tabstop.is_end_tabstop {
 9644                let choices = tabstops
 9645                    .iter()
 9646                    .map(|tabstop| tabstop.choices.clone())
 9647                    .collect();
 9648
 9649                let ranges = tabstops
 9650                    .into_iter()
 9651                    .map(|tabstop| tabstop.ranges)
 9652                    .collect::<Vec<_>>();
 9653
 9654                self.snippet_stack.push(SnippetState {
 9655                    active_index: 0,
 9656                    ranges,
 9657                    choices,
 9658                });
 9659            }
 9660
 9661            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9662            if self.autoclose_regions.is_empty() {
 9663                let snapshot = self.buffer.read(cx).snapshot(cx);
 9664                let mut all_selections = self.selections.all::<Point>(cx);
 9665                for selection in &mut all_selections {
 9666                    let selection_head = selection.head();
 9667                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9668                        continue;
 9669                    };
 9670
 9671                    let mut bracket_pair = None;
 9672                    let max_lookup_length = scope
 9673                        .brackets()
 9674                        .map(|(pair, _)| {
 9675                            pair.start
 9676                                .as_str()
 9677                                .chars()
 9678                                .count()
 9679                                .max(pair.end.as_str().chars().count())
 9680                        })
 9681                        .max();
 9682                    if let Some(max_lookup_length) = max_lookup_length {
 9683                        let next_text = snapshot
 9684                            .chars_at(selection_head)
 9685                            .take(max_lookup_length)
 9686                            .collect::<String>();
 9687                        let prev_text = snapshot
 9688                            .reversed_chars_at(selection_head)
 9689                            .take(max_lookup_length)
 9690                            .collect::<String>();
 9691
 9692                        for (pair, enabled) in scope.brackets() {
 9693                            if enabled
 9694                                && pair.close
 9695                                && prev_text.starts_with(pair.start.as_str())
 9696                                && next_text.starts_with(pair.end.as_str())
 9697                            {
 9698                                bracket_pair = Some(pair.clone());
 9699                                break;
 9700                            }
 9701                        }
 9702                    }
 9703
 9704                    if let Some(pair) = bracket_pair {
 9705                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9706                        let autoclose_enabled =
 9707                            self.use_autoclose && snapshot_settings.use_autoclose;
 9708                        if autoclose_enabled {
 9709                            let start = snapshot.anchor_after(selection_head);
 9710                            let end = snapshot.anchor_after(selection_head);
 9711                            self.autoclose_regions.push(AutocloseRegion {
 9712                                selection_id: selection.id,
 9713                                range: start..end,
 9714                                pair,
 9715                            });
 9716                        }
 9717                    }
 9718                }
 9719            }
 9720        }
 9721        Ok(())
 9722    }
 9723
 9724    pub fn move_to_next_snippet_tabstop(
 9725        &mut self,
 9726        window: &mut Window,
 9727        cx: &mut Context<Self>,
 9728    ) -> bool {
 9729        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9730    }
 9731
 9732    pub fn move_to_prev_snippet_tabstop(
 9733        &mut self,
 9734        window: &mut Window,
 9735        cx: &mut Context<Self>,
 9736    ) -> bool {
 9737        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9738    }
 9739
 9740    pub fn move_to_snippet_tabstop(
 9741        &mut self,
 9742        bias: Bias,
 9743        window: &mut Window,
 9744        cx: &mut Context<Self>,
 9745    ) -> bool {
 9746        if let Some(mut snippet) = self.snippet_stack.pop() {
 9747            match bias {
 9748                Bias::Left => {
 9749                    if snippet.active_index > 0 {
 9750                        snippet.active_index -= 1;
 9751                    } else {
 9752                        self.snippet_stack.push(snippet);
 9753                        return false;
 9754                    }
 9755                }
 9756                Bias::Right => {
 9757                    if snippet.active_index + 1 < snippet.ranges.len() {
 9758                        snippet.active_index += 1;
 9759                    } else {
 9760                        self.snippet_stack.push(snippet);
 9761                        return false;
 9762                    }
 9763                }
 9764            }
 9765            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9766                self.change_selections(Default::default(), window, cx, |s| {
 9767                    // Reverse order so that the first range is the newest created selection.
 9768                    // Completions will use it and autoscroll will prioritize it.
 9769                    s.select_ranges(current_ranges.iter().rev().cloned())
 9770                });
 9771
 9772                if let Some(choices) = &snippet.choices[snippet.active_index]
 9773                    && let Some(selection) = current_ranges.first()
 9774                {
 9775                    self.show_snippet_choices(choices, selection.clone(), cx);
 9776                }
 9777
 9778                // If snippet state is not at the last tabstop, push it back on the stack
 9779                if snippet.active_index + 1 < snippet.ranges.len() {
 9780                    self.snippet_stack.push(snippet);
 9781                }
 9782                return true;
 9783            }
 9784        }
 9785
 9786        false
 9787    }
 9788
 9789    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9790        self.transact(window, cx, |this, window, cx| {
 9791            this.select_all(&SelectAll, window, cx);
 9792            this.insert("", window, cx);
 9793        });
 9794    }
 9795
 9796    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9797        if self.read_only(cx) {
 9798            return;
 9799        }
 9800        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9801        self.transact(window, cx, |this, window, cx| {
 9802            this.select_autoclose_pair(window, cx);
 9803            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9804            if !this.linked_edit_ranges.is_empty() {
 9805                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9806                let snapshot = this.buffer.read(cx).snapshot(cx);
 9807
 9808                for selection in selections.iter() {
 9809                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9810                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9811                    if selection_start.buffer_id != selection_end.buffer_id {
 9812                        continue;
 9813                    }
 9814                    if let Some(ranges) =
 9815                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9816                    {
 9817                        for (buffer, entries) in ranges {
 9818                            linked_ranges.entry(buffer).or_default().extend(entries);
 9819                        }
 9820                    }
 9821                }
 9822            }
 9823
 9824            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9825            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9826            for selection in &mut selections {
 9827                if selection.is_empty() {
 9828                    let old_head = selection.head();
 9829                    let mut new_head =
 9830                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9831                            .to_point(&display_map);
 9832                    if let Some((buffer, line_buffer_range)) = display_map
 9833                        .buffer_snapshot
 9834                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9835                    {
 9836                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9837                        let indent_len = match indent_size.kind {
 9838                            IndentKind::Space => {
 9839                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9840                            }
 9841                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9842                        };
 9843                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9844                            let indent_len = indent_len.get();
 9845                            new_head = cmp::min(
 9846                                new_head,
 9847                                MultiBufferPoint::new(
 9848                                    old_head.row,
 9849                                    ((old_head.column - 1) / indent_len) * indent_len,
 9850                                ),
 9851                            );
 9852                        }
 9853                    }
 9854
 9855                    selection.set_head(new_head, SelectionGoal::None);
 9856                }
 9857            }
 9858
 9859            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9860            this.insert("", window, cx);
 9861            let empty_str: Arc<str> = Arc::from("");
 9862            for (buffer, edits) in linked_ranges {
 9863                let snapshot = buffer.read(cx).snapshot();
 9864                use text::ToPoint as TP;
 9865
 9866                let edits = edits
 9867                    .into_iter()
 9868                    .map(|range| {
 9869                        let end_point = TP::to_point(&range.end, &snapshot);
 9870                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9871
 9872                        if end_point == start_point {
 9873                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9874                                .saturating_sub(1);
 9875                            start_point =
 9876                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9877                        };
 9878
 9879                        (start_point..end_point, empty_str.clone())
 9880                    })
 9881                    .sorted_by_key(|(range, _)| range.start)
 9882                    .collect::<Vec<_>>();
 9883                buffer.update(cx, |this, cx| {
 9884                    this.edit(edits, None, cx);
 9885                })
 9886            }
 9887            this.refresh_edit_prediction(true, false, window, cx);
 9888            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9889        });
 9890    }
 9891
 9892    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9893        if self.read_only(cx) {
 9894            return;
 9895        }
 9896        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9897        self.transact(window, cx, |this, window, cx| {
 9898            this.change_selections(Default::default(), window, cx, |s| {
 9899                s.move_with(|map, selection| {
 9900                    if selection.is_empty() {
 9901                        let cursor = movement::right(map, selection.head());
 9902                        selection.end = cursor;
 9903                        selection.reversed = true;
 9904                        selection.goal = SelectionGoal::None;
 9905                    }
 9906                })
 9907            });
 9908            this.insert("", window, cx);
 9909            this.refresh_edit_prediction(true, false, window, cx);
 9910        });
 9911    }
 9912
 9913    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9914        if self.mode.is_single_line() {
 9915            cx.propagate();
 9916            return;
 9917        }
 9918
 9919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9920        if self.move_to_prev_snippet_tabstop(window, cx) {
 9921            return;
 9922        }
 9923        self.outdent(&Outdent, window, cx);
 9924    }
 9925
 9926    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9927        if self.mode.is_single_line() {
 9928            cx.propagate();
 9929            return;
 9930        }
 9931
 9932        if self.move_to_next_snippet_tabstop(window, cx) {
 9933            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9934            return;
 9935        }
 9936        if self.read_only(cx) {
 9937            return;
 9938        }
 9939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9940        let mut selections = self.selections.all_adjusted(cx);
 9941        let buffer = self.buffer.read(cx);
 9942        let snapshot = buffer.snapshot(cx);
 9943        let rows_iter = selections.iter().map(|s| s.head().row);
 9944        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9945
 9946        let has_some_cursor_in_whitespace = selections
 9947            .iter()
 9948            .filter(|selection| selection.is_empty())
 9949            .any(|selection| {
 9950                let cursor = selection.head();
 9951                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9952                cursor.column < current_indent.len
 9953            });
 9954
 9955        let mut edits = Vec::new();
 9956        let mut prev_edited_row = 0;
 9957        let mut row_delta = 0;
 9958        for selection in &mut selections {
 9959            if selection.start.row != prev_edited_row {
 9960                row_delta = 0;
 9961            }
 9962            prev_edited_row = selection.end.row;
 9963
 9964            // If the selection is non-empty, then increase the indentation of the selected lines.
 9965            if !selection.is_empty() {
 9966                row_delta =
 9967                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9968                continue;
 9969            }
 9970
 9971            let cursor = selection.head();
 9972            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9973            if let Some(suggested_indent) =
 9974                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9975            {
 9976                // Don't do anything if already at suggested indent
 9977                // and there is any other cursor which is not
 9978                if has_some_cursor_in_whitespace
 9979                    && cursor.column == current_indent.len
 9980                    && current_indent.len == suggested_indent.len
 9981                {
 9982                    continue;
 9983                }
 9984
 9985                // Adjust line and move cursor to suggested indent
 9986                // if cursor is not at suggested indent
 9987                if cursor.column < suggested_indent.len
 9988                    && cursor.column <= current_indent.len
 9989                    && current_indent.len <= suggested_indent.len
 9990                {
 9991                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9992                    selection.end = selection.start;
 9993                    if row_delta == 0 {
 9994                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9995                            cursor.row,
 9996                            current_indent,
 9997                            suggested_indent,
 9998                        ));
 9999                        row_delta = suggested_indent.len - current_indent.len;
10000                    }
10001                    continue;
10002                }
10003
10004                // If current indent is more than suggested indent
10005                // only move cursor to current indent and skip indent
10006                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10007                    selection.start = Point::new(cursor.row, current_indent.len);
10008                    selection.end = selection.start;
10009                    continue;
10010                }
10011            }
10012
10013            // Otherwise, insert a hard or soft tab.
10014            let settings = buffer.language_settings_at(cursor, cx);
10015            let tab_size = if settings.hard_tabs {
10016                IndentSize::tab()
10017            } else {
10018                let tab_size = settings.tab_size.get();
10019                let indent_remainder = snapshot
10020                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10021                    .flat_map(str::chars)
10022                    .fold(row_delta % tab_size, |counter: u32, c| {
10023                        if c == '\t' {
10024                            0
10025                        } else {
10026                            (counter + 1) % tab_size
10027                        }
10028                    });
10029
10030                let chars_to_next_tab_stop = tab_size - indent_remainder;
10031                IndentSize::spaces(chars_to_next_tab_stop)
10032            };
10033            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10034            selection.end = selection.start;
10035            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10036            row_delta += tab_size.len;
10037        }
10038
10039        self.transact(window, cx, |this, window, cx| {
10040            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10041            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10042            this.refresh_edit_prediction(true, false, window, cx);
10043        });
10044    }
10045
10046    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10047        if self.read_only(cx) {
10048            return;
10049        }
10050        if self.mode.is_single_line() {
10051            cx.propagate();
10052            return;
10053        }
10054
10055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10056        let mut selections = self.selections.all::<Point>(cx);
10057        let mut prev_edited_row = 0;
10058        let mut row_delta = 0;
10059        let mut edits = Vec::new();
10060        let buffer = self.buffer.read(cx);
10061        let snapshot = buffer.snapshot(cx);
10062        for selection in &mut selections {
10063            if selection.start.row != prev_edited_row {
10064                row_delta = 0;
10065            }
10066            prev_edited_row = selection.end.row;
10067
10068            row_delta =
10069                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10070        }
10071
10072        self.transact(window, cx, |this, window, cx| {
10073            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10074            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10075        });
10076    }
10077
10078    fn indent_selection(
10079        buffer: &MultiBuffer,
10080        snapshot: &MultiBufferSnapshot,
10081        selection: &mut Selection<Point>,
10082        edits: &mut Vec<(Range<Point>, String)>,
10083        delta_for_start_row: u32,
10084        cx: &App,
10085    ) -> u32 {
10086        let settings = buffer.language_settings_at(selection.start, cx);
10087        let tab_size = settings.tab_size.get();
10088        let indent_kind = if settings.hard_tabs {
10089            IndentKind::Tab
10090        } else {
10091            IndentKind::Space
10092        };
10093        let mut start_row = selection.start.row;
10094        let mut end_row = selection.end.row + 1;
10095
10096        // If a selection ends at the beginning of a line, don't indent
10097        // that last line.
10098        if selection.end.column == 0 && selection.end.row > selection.start.row {
10099            end_row -= 1;
10100        }
10101
10102        // Avoid re-indenting a row that has already been indented by a
10103        // previous selection, but still update this selection's column
10104        // to reflect that indentation.
10105        if delta_for_start_row > 0 {
10106            start_row += 1;
10107            selection.start.column += delta_for_start_row;
10108            if selection.end.row == selection.start.row {
10109                selection.end.column += delta_for_start_row;
10110            }
10111        }
10112
10113        let mut delta_for_end_row = 0;
10114        let has_multiple_rows = start_row + 1 != end_row;
10115        for row in start_row..end_row {
10116            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10117            let indent_delta = match (current_indent.kind, indent_kind) {
10118                (IndentKind::Space, IndentKind::Space) => {
10119                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10120                    IndentSize::spaces(columns_to_next_tab_stop)
10121                }
10122                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10123                (_, IndentKind::Tab) => IndentSize::tab(),
10124            };
10125
10126            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10127                0
10128            } else {
10129                selection.start.column
10130            };
10131            let row_start = Point::new(row, start);
10132            edits.push((
10133                row_start..row_start,
10134                indent_delta.chars().collect::<String>(),
10135            ));
10136
10137            // Update this selection's endpoints to reflect the indentation.
10138            if row == selection.start.row {
10139                selection.start.column += indent_delta.len;
10140            }
10141            if row == selection.end.row {
10142                selection.end.column += indent_delta.len;
10143                delta_for_end_row = indent_delta.len;
10144            }
10145        }
10146
10147        if selection.start.row == selection.end.row {
10148            delta_for_start_row + delta_for_end_row
10149        } else {
10150            delta_for_end_row
10151        }
10152    }
10153
10154    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10155        if self.read_only(cx) {
10156            return;
10157        }
10158        if self.mode.is_single_line() {
10159            cx.propagate();
10160            return;
10161        }
10162
10163        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10164        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10165        let selections = self.selections.all::<Point>(cx);
10166        let mut deletion_ranges = Vec::new();
10167        let mut last_outdent = None;
10168        {
10169            let buffer = self.buffer.read(cx);
10170            let snapshot = buffer.snapshot(cx);
10171            for selection in &selections {
10172                let settings = buffer.language_settings_at(selection.start, cx);
10173                let tab_size = settings.tab_size.get();
10174                let mut rows = selection.spanned_rows(false, &display_map);
10175
10176                // Avoid re-outdenting a row that has already been outdented by a
10177                // previous selection.
10178                if let Some(last_row) = last_outdent
10179                    && last_row == rows.start
10180                {
10181                    rows.start = rows.start.next_row();
10182                }
10183                let has_multiple_rows = rows.len() > 1;
10184                for row in rows.iter_rows() {
10185                    let indent_size = snapshot.indent_size_for_line(row);
10186                    if indent_size.len > 0 {
10187                        let deletion_len = match indent_size.kind {
10188                            IndentKind::Space => {
10189                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10190                                if columns_to_prev_tab_stop == 0 {
10191                                    tab_size
10192                                } else {
10193                                    columns_to_prev_tab_stop
10194                                }
10195                            }
10196                            IndentKind::Tab => 1,
10197                        };
10198                        let start = if has_multiple_rows
10199                            || deletion_len > selection.start.column
10200                            || indent_size.len < selection.start.column
10201                        {
10202                            0
10203                        } else {
10204                            selection.start.column - deletion_len
10205                        };
10206                        deletion_ranges.push(
10207                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10208                        );
10209                        last_outdent = Some(row);
10210                    }
10211                }
10212            }
10213        }
10214
10215        self.transact(window, cx, |this, window, cx| {
10216            this.buffer.update(cx, |buffer, cx| {
10217                let empty_str: Arc<str> = Arc::default();
10218                buffer.edit(
10219                    deletion_ranges
10220                        .into_iter()
10221                        .map(|range| (range, empty_str.clone())),
10222                    None,
10223                    cx,
10224                );
10225            });
10226            let selections = this.selections.all::<usize>(cx);
10227            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10228        });
10229    }
10230
10231    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10232        if self.read_only(cx) {
10233            return;
10234        }
10235        if self.mode.is_single_line() {
10236            cx.propagate();
10237            return;
10238        }
10239
10240        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10241        let selections = self
10242            .selections
10243            .all::<usize>(cx)
10244            .into_iter()
10245            .map(|s| s.range());
10246
10247        self.transact(window, cx, |this, window, cx| {
10248            this.buffer.update(cx, |buffer, cx| {
10249                buffer.autoindent_ranges(selections, cx);
10250            });
10251            let selections = this.selections.all::<usize>(cx);
10252            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10253        });
10254    }
10255
10256    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10257        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10258        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10259        let selections = self.selections.all::<Point>(cx);
10260
10261        let mut new_cursors = Vec::new();
10262        let mut edit_ranges = Vec::new();
10263        let mut selections = selections.iter().peekable();
10264        while let Some(selection) = selections.next() {
10265            let mut rows = selection.spanned_rows(false, &display_map);
10266            let goal_display_column = selection.head().to_display_point(&display_map).column();
10267
10268            // Accumulate contiguous regions of rows that we want to delete.
10269            while let Some(next_selection) = selections.peek() {
10270                let next_rows = next_selection.spanned_rows(false, &display_map);
10271                if next_rows.start <= rows.end {
10272                    rows.end = next_rows.end;
10273                    selections.next().unwrap();
10274                } else {
10275                    break;
10276                }
10277            }
10278
10279            let buffer = &display_map.buffer_snapshot;
10280            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10281            let edit_end;
10282            let cursor_buffer_row;
10283            if buffer.max_point().row >= rows.end.0 {
10284                // If there's a line after the range, delete the \n from the end of the row range
10285                // and position the cursor on the next line.
10286                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10287                cursor_buffer_row = rows.end;
10288            } else {
10289                // If there isn't a line after the range, delete the \n from the line before the
10290                // start of the row range and position the cursor there.
10291                edit_start = edit_start.saturating_sub(1);
10292                edit_end = buffer.len();
10293                cursor_buffer_row = rows.start.previous_row();
10294            }
10295
10296            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10297            *cursor.column_mut() =
10298                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10299
10300            new_cursors.push((
10301                selection.id,
10302                buffer.anchor_after(cursor.to_point(&display_map)),
10303            ));
10304            edit_ranges.push(edit_start..edit_end);
10305        }
10306
10307        self.transact(window, cx, |this, window, cx| {
10308            let buffer = this.buffer.update(cx, |buffer, cx| {
10309                let empty_str: Arc<str> = Arc::default();
10310                buffer.edit(
10311                    edit_ranges
10312                        .into_iter()
10313                        .map(|range| (range, empty_str.clone())),
10314                    None,
10315                    cx,
10316                );
10317                buffer.snapshot(cx)
10318            });
10319            let new_selections = new_cursors
10320                .into_iter()
10321                .map(|(id, cursor)| {
10322                    let cursor = cursor.to_point(&buffer);
10323                    Selection {
10324                        id,
10325                        start: cursor,
10326                        end: cursor,
10327                        reversed: false,
10328                        goal: SelectionGoal::None,
10329                    }
10330                })
10331                .collect();
10332
10333            this.change_selections(Default::default(), window, cx, |s| {
10334                s.select(new_selections);
10335            });
10336        });
10337    }
10338
10339    pub fn join_lines_impl(
10340        &mut self,
10341        insert_whitespace: bool,
10342        window: &mut Window,
10343        cx: &mut Context<Self>,
10344    ) {
10345        if self.read_only(cx) {
10346            return;
10347        }
10348        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10349        for selection in self.selections.all::<Point>(cx) {
10350            let start = MultiBufferRow(selection.start.row);
10351            // Treat single line selections as if they include the next line. Otherwise this action
10352            // would do nothing for single line selections individual cursors.
10353            let end = if selection.start.row == selection.end.row {
10354                MultiBufferRow(selection.start.row + 1)
10355            } else {
10356                MultiBufferRow(selection.end.row)
10357            };
10358
10359            if let Some(last_row_range) = row_ranges.last_mut()
10360                && start <= last_row_range.end
10361            {
10362                last_row_range.end = end;
10363                continue;
10364            }
10365            row_ranges.push(start..end);
10366        }
10367
10368        let snapshot = self.buffer.read(cx).snapshot(cx);
10369        let mut cursor_positions = Vec::new();
10370        for row_range in &row_ranges {
10371            let anchor = snapshot.anchor_before(Point::new(
10372                row_range.end.previous_row().0,
10373                snapshot.line_len(row_range.end.previous_row()),
10374            ));
10375            cursor_positions.push(anchor..anchor);
10376        }
10377
10378        self.transact(window, cx, |this, window, cx| {
10379            for row_range in row_ranges.into_iter().rev() {
10380                for row in row_range.iter_rows().rev() {
10381                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10382                    let next_line_row = row.next_row();
10383                    let indent = snapshot.indent_size_for_line(next_line_row);
10384                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10385
10386                    let replace =
10387                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10388                            " "
10389                        } else {
10390                            ""
10391                        };
10392
10393                    this.buffer.update(cx, |buffer, cx| {
10394                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10395                    });
10396                }
10397            }
10398
10399            this.change_selections(Default::default(), window, cx, |s| {
10400                s.select_anchor_ranges(cursor_positions)
10401            });
10402        });
10403    }
10404
10405    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10406        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10407        self.join_lines_impl(true, window, cx);
10408    }
10409
10410    pub fn sort_lines_case_sensitive(
10411        &mut self,
10412        _: &SortLinesCaseSensitive,
10413        window: &mut Window,
10414        cx: &mut Context<Self>,
10415    ) {
10416        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10417    }
10418
10419    pub fn sort_lines_by_length(
10420        &mut self,
10421        _: &SortLinesByLength,
10422        window: &mut Window,
10423        cx: &mut Context<Self>,
10424    ) {
10425        self.manipulate_immutable_lines(window, cx, |lines| {
10426            lines.sort_by_key(|&line| line.chars().count())
10427        })
10428    }
10429
10430    pub fn sort_lines_case_insensitive(
10431        &mut self,
10432        _: &SortLinesCaseInsensitive,
10433        window: &mut Window,
10434        cx: &mut Context<Self>,
10435    ) {
10436        self.manipulate_immutable_lines(window, cx, |lines| {
10437            lines.sort_by_key(|line| line.to_lowercase())
10438        })
10439    }
10440
10441    pub fn unique_lines_case_insensitive(
10442        &mut self,
10443        _: &UniqueLinesCaseInsensitive,
10444        window: &mut Window,
10445        cx: &mut Context<Self>,
10446    ) {
10447        self.manipulate_immutable_lines(window, cx, |lines| {
10448            let mut seen = HashSet::default();
10449            lines.retain(|line| seen.insert(line.to_lowercase()));
10450        })
10451    }
10452
10453    pub fn unique_lines_case_sensitive(
10454        &mut self,
10455        _: &UniqueLinesCaseSensitive,
10456        window: &mut Window,
10457        cx: &mut Context<Self>,
10458    ) {
10459        self.manipulate_immutable_lines(window, cx, |lines| {
10460            let mut seen = HashSet::default();
10461            lines.retain(|line| seen.insert(*line));
10462        })
10463    }
10464
10465    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10466        let Some(project) = self.project.clone() else {
10467            return;
10468        };
10469        self.reload(project, window, cx)
10470            .detach_and_notify_err(window, cx);
10471    }
10472
10473    pub fn restore_file(
10474        &mut self,
10475        _: &::git::RestoreFile,
10476        window: &mut Window,
10477        cx: &mut Context<Self>,
10478    ) {
10479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10480        let mut buffer_ids = HashSet::default();
10481        let snapshot = self.buffer().read(cx).snapshot(cx);
10482        for selection in self.selections.all::<usize>(cx) {
10483            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10484        }
10485
10486        let buffer = self.buffer().read(cx);
10487        let ranges = buffer_ids
10488            .into_iter()
10489            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10490            .collect::<Vec<_>>();
10491
10492        self.restore_hunks_in_ranges(ranges, window, cx);
10493    }
10494
10495    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10496        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10497        let selections = self
10498            .selections
10499            .all(cx)
10500            .into_iter()
10501            .map(|s| s.range())
10502            .collect();
10503        self.restore_hunks_in_ranges(selections, window, cx);
10504    }
10505
10506    pub fn restore_hunks_in_ranges(
10507        &mut self,
10508        ranges: Vec<Range<Point>>,
10509        window: &mut Window,
10510        cx: &mut Context<Editor>,
10511    ) {
10512        let mut revert_changes = HashMap::default();
10513        let chunk_by = self
10514            .snapshot(window, cx)
10515            .hunks_for_ranges(ranges)
10516            .into_iter()
10517            .chunk_by(|hunk| hunk.buffer_id);
10518        for (buffer_id, hunks) in &chunk_by {
10519            let hunks = hunks.collect::<Vec<_>>();
10520            for hunk in &hunks {
10521                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10522            }
10523            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10524        }
10525        drop(chunk_by);
10526        if !revert_changes.is_empty() {
10527            self.transact(window, cx, |editor, window, cx| {
10528                editor.restore(revert_changes, window, cx);
10529            });
10530        }
10531    }
10532
10533    pub fn open_active_item_in_terminal(
10534        &mut self,
10535        _: &OpenInTerminal,
10536        window: &mut Window,
10537        cx: &mut Context<Self>,
10538    ) {
10539        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10540            let project_path = buffer.read(cx).project_path(cx)?;
10541            let project = self.project()?.read(cx);
10542            let entry = project.entry_for_path(&project_path, cx)?;
10543            let parent = match &entry.canonical_path {
10544                Some(canonical_path) => canonical_path.to_path_buf(),
10545                None => project.absolute_path(&project_path, cx)?,
10546            }
10547            .parent()?
10548            .to_path_buf();
10549            Some(parent)
10550        }) {
10551            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10552        }
10553    }
10554
10555    fn set_breakpoint_context_menu(
10556        &mut self,
10557        display_row: DisplayRow,
10558        position: Option<Anchor>,
10559        clicked_point: gpui::Point<Pixels>,
10560        window: &mut Window,
10561        cx: &mut Context<Self>,
10562    ) {
10563        let source = self
10564            .buffer
10565            .read(cx)
10566            .snapshot(cx)
10567            .anchor_before(Point::new(display_row.0, 0u32));
10568
10569        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10570
10571        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10572            self,
10573            source,
10574            clicked_point,
10575            context_menu,
10576            window,
10577            cx,
10578        );
10579    }
10580
10581    fn add_edit_breakpoint_block(
10582        &mut self,
10583        anchor: Anchor,
10584        breakpoint: &Breakpoint,
10585        edit_action: BreakpointPromptEditAction,
10586        window: &mut Window,
10587        cx: &mut Context<Self>,
10588    ) {
10589        let weak_editor = cx.weak_entity();
10590        let bp_prompt = cx.new(|cx| {
10591            BreakpointPromptEditor::new(
10592                weak_editor,
10593                anchor,
10594                breakpoint.clone(),
10595                edit_action,
10596                window,
10597                cx,
10598            )
10599        });
10600
10601        let height = bp_prompt.update(cx, |this, cx| {
10602            this.prompt
10603                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10604        });
10605        let cloned_prompt = bp_prompt.clone();
10606        let blocks = vec![BlockProperties {
10607            style: BlockStyle::Sticky,
10608            placement: BlockPlacement::Above(anchor),
10609            height: Some(height),
10610            render: Arc::new(move |cx| {
10611                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10612                cloned_prompt.clone().into_any_element()
10613            }),
10614            priority: 0,
10615        }];
10616
10617        let focus_handle = bp_prompt.focus_handle(cx);
10618        window.focus(&focus_handle);
10619
10620        let block_ids = self.insert_blocks(blocks, None, cx);
10621        bp_prompt.update(cx, |prompt, _| {
10622            prompt.add_block_ids(block_ids);
10623        });
10624    }
10625
10626    pub(crate) fn breakpoint_at_row(
10627        &self,
10628        row: u32,
10629        window: &mut Window,
10630        cx: &mut Context<Self>,
10631    ) -> Option<(Anchor, Breakpoint)> {
10632        let snapshot = self.snapshot(window, cx);
10633        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10634
10635        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10636    }
10637
10638    pub(crate) fn breakpoint_at_anchor(
10639        &self,
10640        breakpoint_position: Anchor,
10641        snapshot: &EditorSnapshot,
10642        cx: &mut Context<Self>,
10643    ) -> Option<(Anchor, Breakpoint)> {
10644        let buffer = self
10645            .buffer
10646            .read(cx)
10647            .buffer_for_anchor(breakpoint_position, cx)?;
10648
10649        let enclosing_excerpt = breakpoint_position.excerpt_id;
10650        let buffer_snapshot = buffer.read(cx).snapshot();
10651
10652        let row = buffer_snapshot
10653            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10654            .row;
10655
10656        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10657        let anchor_end = snapshot
10658            .buffer_snapshot
10659            .anchor_after(Point::new(row, line_len));
10660
10661        self.breakpoint_store
10662            .as_ref()?
10663            .read_with(cx, |breakpoint_store, cx| {
10664                breakpoint_store
10665                    .breakpoints(
10666                        &buffer,
10667                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10668                        &buffer_snapshot,
10669                        cx,
10670                    )
10671                    .next()
10672                    .and_then(|(bp, _)| {
10673                        let breakpoint_row = buffer_snapshot
10674                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10675                            .row;
10676
10677                        if breakpoint_row == row {
10678                            snapshot
10679                                .buffer_snapshot
10680                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10681                                .map(|position| (position, bp.bp.clone()))
10682                        } else {
10683                            None
10684                        }
10685                    })
10686            })
10687    }
10688
10689    pub fn edit_log_breakpoint(
10690        &mut self,
10691        _: &EditLogBreakpoint,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10696            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10697                message: None,
10698                state: BreakpointState::Enabled,
10699                condition: None,
10700                hit_condition: None,
10701            });
10702
10703            self.add_edit_breakpoint_block(
10704                anchor,
10705                &breakpoint,
10706                BreakpointPromptEditAction::Log,
10707                window,
10708                cx,
10709            );
10710        }
10711    }
10712
10713    fn breakpoints_at_cursors(
10714        &self,
10715        window: &mut Window,
10716        cx: &mut Context<Self>,
10717    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10718        let snapshot = self.snapshot(window, cx);
10719        let cursors = self
10720            .selections
10721            .disjoint_anchors()
10722            .iter()
10723            .map(|selection| {
10724                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10725
10726                let breakpoint_position = self
10727                    .breakpoint_at_row(cursor_position.row, window, cx)
10728                    .map(|bp| bp.0)
10729                    .unwrap_or_else(|| {
10730                        snapshot
10731                            .display_snapshot
10732                            .buffer_snapshot
10733                            .anchor_after(Point::new(cursor_position.row, 0))
10734                    });
10735
10736                let breakpoint = self
10737                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10738                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10739
10740                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10741            })
10742            // 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.
10743            .collect::<HashMap<Anchor, _>>();
10744
10745        cursors.into_iter().collect()
10746    }
10747
10748    pub fn enable_breakpoint(
10749        &mut self,
10750        _: &crate::actions::EnableBreakpoint,
10751        window: &mut Window,
10752        cx: &mut Context<Self>,
10753    ) {
10754        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10755            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10756                continue;
10757            };
10758            self.edit_breakpoint_at_anchor(
10759                anchor,
10760                breakpoint,
10761                BreakpointEditAction::InvertState,
10762                cx,
10763            );
10764        }
10765    }
10766
10767    pub fn disable_breakpoint(
10768        &mut self,
10769        _: &crate::actions::DisableBreakpoint,
10770        window: &mut Window,
10771        cx: &mut Context<Self>,
10772    ) {
10773        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10774            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10775                continue;
10776            };
10777            self.edit_breakpoint_at_anchor(
10778                anchor,
10779                breakpoint,
10780                BreakpointEditAction::InvertState,
10781                cx,
10782            );
10783        }
10784    }
10785
10786    pub fn toggle_breakpoint(
10787        &mut self,
10788        _: &crate::actions::ToggleBreakpoint,
10789        window: &mut Window,
10790        cx: &mut Context<Self>,
10791    ) {
10792        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10793            if let Some(breakpoint) = breakpoint {
10794                self.edit_breakpoint_at_anchor(
10795                    anchor,
10796                    breakpoint,
10797                    BreakpointEditAction::Toggle,
10798                    cx,
10799                );
10800            } else {
10801                self.edit_breakpoint_at_anchor(
10802                    anchor,
10803                    Breakpoint::new_standard(),
10804                    BreakpointEditAction::Toggle,
10805                    cx,
10806                );
10807            }
10808        }
10809    }
10810
10811    pub fn edit_breakpoint_at_anchor(
10812        &mut self,
10813        breakpoint_position: Anchor,
10814        breakpoint: Breakpoint,
10815        edit_action: BreakpointEditAction,
10816        cx: &mut Context<Self>,
10817    ) {
10818        let Some(breakpoint_store) = &self.breakpoint_store else {
10819            return;
10820        };
10821
10822        let Some(buffer) = self
10823            .buffer
10824            .read(cx)
10825            .buffer_for_anchor(breakpoint_position, cx)
10826        else {
10827            return;
10828        };
10829
10830        breakpoint_store.update(cx, |breakpoint_store, cx| {
10831            breakpoint_store.toggle_breakpoint(
10832                buffer,
10833                BreakpointWithPosition {
10834                    position: breakpoint_position.text_anchor,
10835                    bp: breakpoint,
10836                },
10837                edit_action,
10838                cx,
10839            );
10840        });
10841
10842        cx.notify();
10843    }
10844
10845    #[cfg(any(test, feature = "test-support"))]
10846    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10847        self.breakpoint_store.clone()
10848    }
10849
10850    pub fn prepare_restore_change(
10851        &self,
10852        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10853        hunk: &MultiBufferDiffHunk,
10854        cx: &mut App,
10855    ) -> Option<()> {
10856        if hunk.is_created_file() {
10857            return None;
10858        }
10859        let buffer = self.buffer.read(cx);
10860        let diff = buffer.diff_for(hunk.buffer_id)?;
10861        let buffer = buffer.buffer(hunk.buffer_id)?;
10862        let buffer = buffer.read(cx);
10863        let original_text = diff
10864            .read(cx)
10865            .base_text()
10866            .as_rope()
10867            .slice(hunk.diff_base_byte_range.clone());
10868        let buffer_snapshot = buffer.snapshot();
10869        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10870        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10871            probe
10872                .0
10873                .start
10874                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10875                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10876        }) {
10877            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10878            Some(())
10879        } else {
10880            None
10881        }
10882    }
10883
10884    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10885        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10886    }
10887
10888    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10889        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10890    }
10891
10892    fn manipulate_lines<M>(
10893        &mut self,
10894        window: &mut Window,
10895        cx: &mut Context<Self>,
10896        mut manipulate: M,
10897    ) where
10898        M: FnMut(&str) -> LineManipulationResult,
10899    {
10900        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10901
10902        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10903        let buffer = self.buffer.read(cx).snapshot(cx);
10904
10905        let mut edits = Vec::new();
10906
10907        let selections = self.selections.all::<Point>(cx);
10908        let mut selections = selections.iter().peekable();
10909        let mut contiguous_row_selections = Vec::new();
10910        let mut new_selections = Vec::new();
10911        let mut added_lines = 0;
10912        let mut removed_lines = 0;
10913
10914        while let Some(selection) = selections.next() {
10915            let (start_row, end_row) = consume_contiguous_rows(
10916                &mut contiguous_row_selections,
10917                selection,
10918                &display_map,
10919                &mut selections,
10920            );
10921
10922            let start_point = Point::new(start_row.0, 0);
10923            let end_point = Point::new(
10924                end_row.previous_row().0,
10925                buffer.line_len(end_row.previous_row()),
10926            );
10927            let text = buffer
10928                .text_for_range(start_point..end_point)
10929                .collect::<String>();
10930
10931            let LineManipulationResult {
10932                new_text,
10933                line_count_before,
10934                line_count_after,
10935            } = manipulate(&text);
10936
10937            edits.push((start_point..end_point, new_text));
10938
10939            // Selections must change based on added and removed line count
10940            let start_row =
10941                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10942            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10943            new_selections.push(Selection {
10944                id: selection.id,
10945                start: start_row,
10946                end: end_row,
10947                goal: SelectionGoal::None,
10948                reversed: selection.reversed,
10949            });
10950
10951            if line_count_after > line_count_before {
10952                added_lines += line_count_after - line_count_before;
10953            } else if line_count_before > line_count_after {
10954                removed_lines += line_count_before - line_count_after;
10955            }
10956        }
10957
10958        self.transact(window, cx, |this, window, cx| {
10959            let buffer = this.buffer.update(cx, |buffer, cx| {
10960                buffer.edit(edits, None, cx);
10961                buffer.snapshot(cx)
10962            });
10963
10964            // Recalculate offsets on newly edited buffer
10965            let new_selections = new_selections
10966                .iter()
10967                .map(|s| {
10968                    let start_point = Point::new(s.start.0, 0);
10969                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10970                    Selection {
10971                        id: s.id,
10972                        start: buffer.point_to_offset(start_point),
10973                        end: buffer.point_to_offset(end_point),
10974                        goal: s.goal,
10975                        reversed: s.reversed,
10976                    }
10977                })
10978                .collect();
10979
10980            this.change_selections(Default::default(), window, cx, |s| {
10981                s.select(new_selections);
10982            });
10983
10984            this.request_autoscroll(Autoscroll::fit(), cx);
10985        });
10986    }
10987
10988    fn manipulate_immutable_lines<Fn>(
10989        &mut self,
10990        window: &mut Window,
10991        cx: &mut Context<Self>,
10992        mut callback: Fn,
10993    ) where
10994        Fn: FnMut(&mut Vec<&str>),
10995    {
10996        self.manipulate_lines(window, cx, |text| {
10997            let mut lines: Vec<&str> = text.split('\n').collect();
10998            let line_count_before = lines.len();
10999
11000            callback(&mut lines);
11001
11002            LineManipulationResult {
11003                new_text: lines.join("\n"),
11004                line_count_before,
11005                line_count_after: lines.len(),
11006            }
11007        });
11008    }
11009
11010    fn manipulate_mutable_lines<Fn>(
11011        &mut self,
11012        window: &mut Window,
11013        cx: &mut Context<Self>,
11014        mut callback: Fn,
11015    ) where
11016        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11017    {
11018        self.manipulate_lines(window, cx, |text| {
11019            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11020            let line_count_before = lines.len();
11021
11022            callback(&mut lines);
11023
11024            LineManipulationResult {
11025                new_text: lines.join("\n"),
11026                line_count_before,
11027                line_count_after: lines.len(),
11028            }
11029        });
11030    }
11031
11032    pub fn convert_indentation_to_spaces(
11033        &mut self,
11034        _: &ConvertIndentationToSpaces,
11035        window: &mut Window,
11036        cx: &mut Context<Self>,
11037    ) {
11038        let settings = self.buffer.read(cx).language_settings(cx);
11039        let tab_size = settings.tab_size.get() as usize;
11040
11041        self.manipulate_mutable_lines(window, cx, |lines| {
11042            // Allocates a reasonably sized scratch buffer once for the whole loop
11043            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11044            // Avoids recomputing spaces that could be inserted many times
11045            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11046                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11047                .collect();
11048
11049            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11050                let mut chars = line.as_ref().chars();
11051                let mut col = 0;
11052                let mut changed = false;
11053
11054                for ch in chars.by_ref() {
11055                    match ch {
11056                        ' ' => {
11057                            reindented_line.push(' ');
11058                            col += 1;
11059                        }
11060                        '\t' => {
11061                            // \t are converted to spaces depending on the current column
11062                            let spaces_len = tab_size - (col % tab_size);
11063                            reindented_line.extend(&space_cache[spaces_len - 1]);
11064                            col += spaces_len;
11065                            changed = true;
11066                        }
11067                        _ => {
11068                            // If we dont append before break, the character is consumed
11069                            reindented_line.push(ch);
11070                            break;
11071                        }
11072                    }
11073                }
11074
11075                if !changed {
11076                    reindented_line.clear();
11077                    continue;
11078                }
11079                // Append the rest of the line and replace old reference with new one
11080                reindented_line.extend(chars);
11081                *line = Cow::Owned(reindented_line.clone());
11082                reindented_line.clear();
11083            }
11084        });
11085    }
11086
11087    pub fn convert_indentation_to_tabs(
11088        &mut self,
11089        _: &ConvertIndentationToTabs,
11090        window: &mut Window,
11091        cx: &mut Context<Self>,
11092    ) {
11093        let settings = self.buffer.read(cx).language_settings(cx);
11094        let tab_size = settings.tab_size.get() as usize;
11095
11096        self.manipulate_mutable_lines(window, cx, |lines| {
11097            // Allocates a reasonably sized buffer once for the whole loop
11098            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11099            // Avoids recomputing spaces that could be inserted many times
11100            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11101                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11102                .collect();
11103
11104            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11105                let mut chars = line.chars();
11106                let mut spaces_count = 0;
11107                let mut first_non_indent_char = None;
11108                let mut changed = false;
11109
11110                for ch in chars.by_ref() {
11111                    match ch {
11112                        ' ' => {
11113                            // Keep track of spaces. Append \t when we reach tab_size
11114                            spaces_count += 1;
11115                            changed = true;
11116                            if spaces_count == tab_size {
11117                                reindented_line.push('\t');
11118                                spaces_count = 0;
11119                            }
11120                        }
11121                        '\t' => {
11122                            reindented_line.push('\t');
11123                            spaces_count = 0;
11124                        }
11125                        _ => {
11126                            // Dont append it yet, we might have remaining spaces
11127                            first_non_indent_char = Some(ch);
11128                            break;
11129                        }
11130                    }
11131                }
11132
11133                if !changed {
11134                    reindented_line.clear();
11135                    continue;
11136                }
11137                // Remaining spaces that didn't make a full tab stop
11138                if spaces_count > 0 {
11139                    reindented_line.extend(&space_cache[spaces_count - 1]);
11140                }
11141                // If we consume an extra character that was not indentation, add it back
11142                if let Some(extra_char) = first_non_indent_char {
11143                    reindented_line.push(extra_char);
11144                }
11145                // Append the rest of the line and replace old reference with new one
11146                reindented_line.extend(chars);
11147                *line = Cow::Owned(reindented_line.clone());
11148                reindented_line.clear();
11149            }
11150        });
11151    }
11152
11153    pub fn convert_to_upper_case(
11154        &mut self,
11155        _: &ConvertToUpperCase,
11156        window: &mut Window,
11157        cx: &mut Context<Self>,
11158    ) {
11159        self.manipulate_text(window, cx, |text| text.to_uppercase())
11160    }
11161
11162    pub fn convert_to_lower_case(
11163        &mut self,
11164        _: &ConvertToLowerCase,
11165        window: &mut Window,
11166        cx: &mut Context<Self>,
11167    ) {
11168        self.manipulate_text(window, cx, |text| text.to_lowercase())
11169    }
11170
11171    pub fn convert_to_title_case(
11172        &mut self,
11173        _: &ConvertToTitleCase,
11174        window: &mut Window,
11175        cx: &mut Context<Self>,
11176    ) {
11177        self.manipulate_text(window, cx, |text| {
11178            text.split('\n')
11179                .map(|line| line.to_case(Case::Title))
11180                .join("\n")
11181        })
11182    }
11183
11184    pub fn convert_to_snake_case(
11185        &mut self,
11186        _: &ConvertToSnakeCase,
11187        window: &mut Window,
11188        cx: &mut Context<Self>,
11189    ) {
11190        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11191    }
11192
11193    pub fn convert_to_kebab_case(
11194        &mut self,
11195        _: &ConvertToKebabCase,
11196        window: &mut Window,
11197        cx: &mut Context<Self>,
11198    ) {
11199        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11200    }
11201
11202    pub fn convert_to_upper_camel_case(
11203        &mut self,
11204        _: &ConvertToUpperCamelCase,
11205        window: &mut Window,
11206        cx: &mut Context<Self>,
11207    ) {
11208        self.manipulate_text(window, cx, |text| {
11209            text.split('\n')
11210                .map(|line| line.to_case(Case::UpperCamel))
11211                .join("\n")
11212        })
11213    }
11214
11215    pub fn convert_to_lower_camel_case(
11216        &mut self,
11217        _: &ConvertToLowerCamelCase,
11218        window: &mut Window,
11219        cx: &mut Context<Self>,
11220    ) {
11221        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11222    }
11223
11224    pub fn convert_to_opposite_case(
11225        &mut self,
11226        _: &ConvertToOppositeCase,
11227        window: &mut Window,
11228        cx: &mut Context<Self>,
11229    ) {
11230        self.manipulate_text(window, cx, |text| {
11231            text.chars()
11232                .fold(String::with_capacity(text.len()), |mut t, c| {
11233                    if c.is_uppercase() {
11234                        t.extend(c.to_lowercase());
11235                    } else {
11236                        t.extend(c.to_uppercase());
11237                    }
11238                    t
11239                })
11240        })
11241    }
11242
11243    pub fn convert_to_sentence_case(
11244        &mut self,
11245        _: &ConvertToSentenceCase,
11246        window: &mut Window,
11247        cx: &mut Context<Self>,
11248    ) {
11249        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11250    }
11251
11252    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11253        self.manipulate_text(window, cx, |text| {
11254            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11255            if has_upper_case_characters {
11256                text.to_lowercase()
11257            } else {
11258                text.to_uppercase()
11259            }
11260        })
11261    }
11262
11263    pub fn convert_to_rot13(
11264        &mut self,
11265        _: &ConvertToRot13,
11266        window: &mut Window,
11267        cx: &mut Context<Self>,
11268    ) {
11269        self.manipulate_text(window, cx, |text| {
11270            text.chars()
11271                .map(|c| match c {
11272                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11273                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11274                    _ => c,
11275                })
11276                .collect()
11277        })
11278    }
11279
11280    pub fn convert_to_rot47(
11281        &mut self,
11282        _: &ConvertToRot47,
11283        window: &mut Window,
11284        cx: &mut Context<Self>,
11285    ) {
11286        self.manipulate_text(window, cx, |text| {
11287            text.chars()
11288                .map(|c| {
11289                    let code_point = c as u32;
11290                    if code_point >= 33 && code_point <= 126 {
11291                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11292                    }
11293                    c
11294                })
11295                .collect()
11296        })
11297    }
11298
11299    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11300    where
11301        Fn: FnMut(&str) -> String,
11302    {
11303        let buffer = self.buffer.read(cx).snapshot(cx);
11304
11305        let mut new_selections = Vec::new();
11306        let mut edits = Vec::new();
11307        let mut selection_adjustment = 0i32;
11308
11309        for selection in self.selections.all::<usize>(cx) {
11310            let selection_is_empty = selection.is_empty();
11311
11312            let (start, end) = if selection_is_empty {
11313                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11314                (word_range.start, word_range.end)
11315            } else {
11316                (selection.start, selection.end)
11317            };
11318
11319            let text = buffer.text_for_range(start..end).collect::<String>();
11320            let old_length = text.len() as i32;
11321            let text = callback(&text);
11322
11323            new_selections.push(Selection {
11324                start: (start as i32 - selection_adjustment) as usize,
11325                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11326                goal: SelectionGoal::None,
11327                ..selection
11328            });
11329
11330            selection_adjustment += old_length - text.len() as i32;
11331
11332            edits.push((start..end, text));
11333        }
11334
11335        self.transact(window, cx, |this, window, cx| {
11336            this.buffer.update(cx, |buffer, cx| {
11337                buffer.edit(edits, None, cx);
11338            });
11339
11340            this.change_selections(Default::default(), window, cx, |s| {
11341                s.select(new_selections);
11342            });
11343
11344            this.request_autoscroll(Autoscroll::fit(), cx);
11345        });
11346    }
11347
11348    pub fn move_selection_on_drop(
11349        &mut self,
11350        selection: &Selection<Anchor>,
11351        target: DisplayPoint,
11352        is_cut: bool,
11353        window: &mut Window,
11354        cx: &mut Context<Self>,
11355    ) {
11356        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11357        let buffer = &display_map.buffer_snapshot;
11358        let mut edits = Vec::new();
11359        let insert_point = display_map
11360            .clip_point(target, Bias::Left)
11361            .to_point(&display_map);
11362        let text = buffer
11363            .text_for_range(selection.start..selection.end)
11364            .collect::<String>();
11365        if is_cut {
11366            edits.push(((selection.start..selection.end), String::new()));
11367        }
11368        let insert_anchor = buffer.anchor_before(insert_point);
11369        edits.push(((insert_anchor..insert_anchor), text));
11370        let last_edit_start = insert_anchor.bias_left(buffer);
11371        let last_edit_end = insert_anchor.bias_right(buffer);
11372        self.transact(window, cx, |this, window, cx| {
11373            this.buffer.update(cx, |buffer, cx| {
11374                buffer.edit(edits, None, cx);
11375            });
11376            this.change_selections(Default::default(), window, cx, |s| {
11377                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11378            });
11379        });
11380    }
11381
11382    pub fn clear_selection_drag_state(&mut self) {
11383        self.selection_drag_state = SelectionDragState::None;
11384    }
11385
11386    pub fn duplicate(
11387        &mut self,
11388        upwards: bool,
11389        whole_lines: bool,
11390        window: &mut Window,
11391        cx: &mut Context<Self>,
11392    ) {
11393        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11394
11395        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11396        let buffer = &display_map.buffer_snapshot;
11397        let selections = self.selections.all::<Point>(cx);
11398
11399        let mut edits = Vec::new();
11400        let mut selections_iter = selections.iter().peekable();
11401        while let Some(selection) = selections_iter.next() {
11402            let mut rows = selection.spanned_rows(false, &display_map);
11403            // duplicate line-wise
11404            if whole_lines || selection.start == selection.end {
11405                // Avoid duplicating the same lines twice.
11406                while let Some(next_selection) = selections_iter.peek() {
11407                    let next_rows = next_selection.spanned_rows(false, &display_map);
11408                    if next_rows.start < rows.end {
11409                        rows.end = next_rows.end;
11410                        selections_iter.next().unwrap();
11411                    } else {
11412                        break;
11413                    }
11414                }
11415
11416                // Copy the text from the selected row region and splice it either at the start
11417                // or end of the region.
11418                let start = Point::new(rows.start.0, 0);
11419                let end = Point::new(
11420                    rows.end.previous_row().0,
11421                    buffer.line_len(rows.end.previous_row()),
11422                );
11423                let text = buffer
11424                    .text_for_range(start..end)
11425                    .chain(Some("\n"))
11426                    .collect::<String>();
11427                let insert_location = if upwards {
11428                    Point::new(rows.end.0, 0)
11429                } else {
11430                    start
11431                };
11432                edits.push((insert_location..insert_location, text));
11433            } else {
11434                // duplicate character-wise
11435                let start = selection.start;
11436                let end = selection.end;
11437                let text = buffer.text_for_range(start..end).collect::<String>();
11438                edits.push((selection.end..selection.end, text));
11439            }
11440        }
11441
11442        self.transact(window, cx, |this, _, cx| {
11443            this.buffer.update(cx, |buffer, cx| {
11444                buffer.edit(edits, None, cx);
11445            });
11446
11447            this.request_autoscroll(Autoscroll::fit(), cx);
11448        });
11449    }
11450
11451    pub fn duplicate_line_up(
11452        &mut self,
11453        _: &DuplicateLineUp,
11454        window: &mut Window,
11455        cx: &mut Context<Self>,
11456    ) {
11457        self.duplicate(true, true, window, cx);
11458    }
11459
11460    pub fn duplicate_line_down(
11461        &mut self,
11462        _: &DuplicateLineDown,
11463        window: &mut Window,
11464        cx: &mut Context<Self>,
11465    ) {
11466        self.duplicate(false, true, window, cx);
11467    }
11468
11469    pub fn duplicate_selection(
11470        &mut self,
11471        _: &DuplicateSelection,
11472        window: &mut Window,
11473        cx: &mut Context<Self>,
11474    ) {
11475        self.duplicate(false, false, window, cx);
11476    }
11477
11478    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11479        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11480        if self.mode.is_single_line() {
11481            cx.propagate();
11482            return;
11483        }
11484
11485        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11486        let buffer = self.buffer.read(cx).snapshot(cx);
11487
11488        let mut edits = Vec::new();
11489        let mut unfold_ranges = Vec::new();
11490        let mut refold_creases = Vec::new();
11491
11492        let selections = self.selections.all::<Point>(cx);
11493        let mut selections = selections.iter().peekable();
11494        let mut contiguous_row_selections = Vec::new();
11495        let mut new_selections = Vec::new();
11496
11497        while let Some(selection) = selections.next() {
11498            // Find all the selections that span a contiguous row range
11499            let (start_row, end_row) = consume_contiguous_rows(
11500                &mut contiguous_row_selections,
11501                selection,
11502                &display_map,
11503                &mut selections,
11504            );
11505
11506            // Move the text spanned by the row range to be before the line preceding the row range
11507            if start_row.0 > 0 {
11508                let range_to_move = Point::new(
11509                    start_row.previous_row().0,
11510                    buffer.line_len(start_row.previous_row()),
11511                )
11512                    ..Point::new(
11513                        end_row.previous_row().0,
11514                        buffer.line_len(end_row.previous_row()),
11515                    );
11516                let insertion_point = display_map
11517                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11518                    .0;
11519
11520                // Don't move lines across excerpts
11521                if buffer
11522                    .excerpt_containing(insertion_point..range_to_move.end)
11523                    .is_some()
11524                {
11525                    let text = buffer
11526                        .text_for_range(range_to_move.clone())
11527                        .flat_map(|s| s.chars())
11528                        .skip(1)
11529                        .chain(['\n'])
11530                        .collect::<String>();
11531
11532                    edits.push((
11533                        buffer.anchor_after(range_to_move.start)
11534                            ..buffer.anchor_before(range_to_move.end),
11535                        String::new(),
11536                    ));
11537                    let insertion_anchor = buffer.anchor_after(insertion_point);
11538                    edits.push((insertion_anchor..insertion_anchor, text));
11539
11540                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11541
11542                    // Move selections up
11543                    new_selections.extend(contiguous_row_selections.drain(..).map(
11544                        |mut selection| {
11545                            selection.start.row -= row_delta;
11546                            selection.end.row -= row_delta;
11547                            selection
11548                        },
11549                    ));
11550
11551                    // Move folds up
11552                    unfold_ranges.push(range_to_move.clone());
11553                    for fold in display_map.folds_in_range(
11554                        buffer.anchor_before(range_to_move.start)
11555                            ..buffer.anchor_after(range_to_move.end),
11556                    ) {
11557                        let mut start = fold.range.start.to_point(&buffer);
11558                        let mut end = fold.range.end.to_point(&buffer);
11559                        start.row -= row_delta;
11560                        end.row -= row_delta;
11561                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11562                    }
11563                }
11564            }
11565
11566            // If we didn't move line(s), preserve the existing selections
11567            new_selections.append(&mut contiguous_row_selections);
11568        }
11569
11570        self.transact(window, cx, |this, window, cx| {
11571            this.unfold_ranges(&unfold_ranges, true, true, cx);
11572            this.buffer.update(cx, |buffer, cx| {
11573                for (range, text) in edits {
11574                    buffer.edit([(range, text)], None, cx);
11575                }
11576            });
11577            this.fold_creases(refold_creases, true, window, cx);
11578            this.change_selections(Default::default(), window, cx, |s| {
11579                s.select(new_selections);
11580            })
11581        });
11582    }
11583
11584    pub fn move_line_down(
11585        &mut self,
11586        _: &MoveLineDown,
11587        window: &mut Window,
11588        cx: &mut Context<Self>,
11589    ) {
11590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11591        if self.mode.is_single_line() {
11592            cx.propagate();
11593            return;
11594        }
11595
11596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11597        let buffer = self.buffer.read(cx).snapshot(cx);
11598
11599        let mut edits = Vec::new();
11600        let mut unfold_ranges = Vec::new();
11601        let mut refold_creases = Vec::new();
11602
11603        let selections = self.selections.all::<Point>(cx);
11604        let mut selections = selections.iter().peekable();
11605        let mut contiguous_row_selections = Vec::new();
11606        let mut new_selections = Vec::new();
11607
11608        while let Some(selection) = selections.next() {
11609            // Find all the selections that span a contiguous row range
11610            let (start_row, end_row) = consume_contiguous_rows(
11611                &mut contiguous_row_selections,
11612                selection,
11613                &display_map,
11614                &mut selections,
11615            );
11616
11617            // Move the text spanned by the row range to be after the last line of the row range
11618            if end_row.0 <= buffer.max_point().row {
11619                let range_to_move =
11620                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11621                let insertion_point = display_map
11622                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11623                    .0;
11624
11625                // Don't move lines across excerpt boundaries
11626                if buffer
11627                    .excerpt_containing(range_to_move.start..insertion_point)
11628                    .is_some()
11629                {
11630                    let mut text = String::from("\n");
11631                    text.extend(buffer.text_for_range(range_to_move.clone()));
11632                    text.pop(); // Drop trailing newline
11633                    edits.push((
11634                        buffer.anchor_after(range_to_move.start)
11635                            ..buffer.anchor_before(range_to_move.end),
11636                        String::new(),
11637                    ));
11638                    let insertion_anchor = buffer.anchor_after(insertion_point);
11639                    edits.push((insertion_anchor..insertion_anchor, text));
11640
11641                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11642
11643                    // Move selections down
11644                    new_selections.extend(contiguous_row_selections.drain(..).map(
11645                        |mut selection| {
11646                            selection.start.row += row_delta;
11647                            selection.end.row += row_delta;
11648                            selection
11649                        },
11650                    ));
11651
11652                    // Move folds down
11653                    unfold_ranges.push(range_to_move.clone());
11654                    for fold in display_map.folds_in_range(
11655                        buffer.anchor_before(range_to_move.start)
11656                            ..buffer.anchor_after(range_to_move.end),
11657                    ) {
11658                        let mut start = fold.range.start.to_point(&buffer);
11659                        let mut end = fold.range.end.to_point(&buffer);
11660                        start.row += row_delta;
11661                        end.row += row_delta;
11662                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11663                    }
11664                }
11665            }
11666
11667            // If we didn't move line(s), preserve the existing selections
11668            new_selections.append(&mut contiguous_row_selections);
11669        }
11670
11671        self.transact(window, cx, |this, window, cx| {
11672            this.unfold_ranges(&unfold_ranges, true, true, cx);
11673            this.buffer.update(cx, |buffer, cx| {
11674                for (range, text) in edits {
11675                    buffer.edit([(range, text)], None, cx);
11676                }
11677            });
11678            this.fold_creases(refold_creases, true, window, cx);
11679            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11680        });
11681    }
11682
11683    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11684        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11685        let text_layout_details = &self.text_layout_details(window);
11686        self.transact(window, cx, |this, window, cx| {
11687            let edits = this.change_selections(Default::default(), window, cx, |s| {
11688                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11689                s.move_with(|display_map, selection| {
11690                    if !selection.is_empty() {
11691                        return;
11692                    }
11693
11694                    let mut head = selection.head();
11695                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11696                    if head.column() == display_map.line_len(head.row()) {
11697                        transpose_offset = display_map
11698                            .buffer_snapshot
11699                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11700                    }
11701
11702                    if transpose_offset == 0 {
11703                        return;
11704                    }
11705
11706                    *head.column_mut() += 1;
11707                    head = display_map.clip_point(head, Bias::Right);
11708                    let goal = SelectionGoal::HorizontalPosition(
11709                        display_map
11710                            .x_for_display_point(head, text_layout_details)
11711                            .into(),
11712                    );
11713                    selection.collapse_to(head, goal);
11714
11715                    let transpose_start = display_map
11716                        .buffer_snapshot
11717                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11718                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11719                        let transpose_end = display_map
11720                            .buffer_snapshot
11721                            .clip_offset(transpose_offset + 1, Bias::Right);
11722                        if let Some(ch) =
11723                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11724                        {
11725                            edits.push((transpose_start..transpose_offset, String::new()));
11726                            edits.push((transpose_end..transpose_end, ch.to_string()));
11727                        }
11728                    }
11729                });
11730                edits
11731            });
11732            this.buffer
11733                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11734            let selections = this.selections.all::<usize>(cx);
11735            this.change_selections(Default::default(), window, cx, |s| {
11736                s.select(selections);
11737            });
11738        });
11739    }
11740
11741    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11743        if self.mode.is_single_line() {
11744            cx.propagate();
11745            return;
11746        }
11747
11748        self.rewrap_impl(RewrapOptions::default(), cx)
11749    }
11750
11751    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11752        let buffer = self.buffer.read(cx).snapshot(cx);
11753        let selections = self.selections.all::<Point>(cx);
11754
11755        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11756        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11757            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11758                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11759                .peekable();
11760
11761            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11762                row
11763            } else {
11764                return Vec::new();
11765            };
11766
11767            let language_settings = buffer.language_settings_at(selection.head(), cx);
11768            let language_scope = buffer.language_scope_at(selection.head());
11769
11770            let indent_and_prefix_for_row =
11771                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11772                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11773                    let (comment_prefix, rewrap_prefix) =
11774                        if let Some(language_scope) = &language_scope {
11775                            let indent_end = Point::new(row, indent.len);
11776                            let comment_prefix = language_scope
11777                                .line_comment_prefixes()
11778                                .iter()
11779                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11780                                .map(|prefix| prefix.to_string());
11781                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11782                            let line_text_after_indent = buffer
11783                                .text_for_range(indent_end..line_end)
11784                                .collect::<String>();
11785                            let rewrap_prefix = language_scope
11786                                .rewrap_prefixes()
11787                                .iter()
11788                                .find_map(|prefix_regex| {
11789                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11790                                        if mat.start() == 0 {
11791                                            Some(mat.as_str().to_string())
11792                                        } else {
11793                                            None
11794                                        }
11795                                    })
11796                                })
11797                                .flatten();
11798                            (comment_prefix, rewrap_prefix)
11799                        } else {
11800                            (None, None)
11801                        };
11802                    (indent, comment_prefix, rewrap_prefix)
11803                };
11804
11805            let mut ranges = Vec::new();
11806            let from_empty_selection = selection.is_empty();
11807
11808            let mut current_range_start = first_row;
11809            let mut prev_row = first_row;
11810            let (
11811                mut current_range_indent,
11812                mut current_range_comment_prefix,
11813                mut current_range_rewrap_prefix,
11814            ) = indent_and_prefix_for_row(first_row);
11815
11816            for row in non_blank_rows_iter.skip(1) {
11817                let has_paragraph_break = row > prev_row + 1;
11818
11819                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11820                    indent_and_prefix_for_row(row);
11821
11822                let has_indent_change = row_indent != current_range_indent;
11823                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11824
11825                let has_boundary_change = has_comment_change
11826                    || row_rewrap_prefix.is_some()
11827                    || (has_indent_change && current_range_comment_prefix.is_some());
11828
11829                if has_paragraph_break || has_boundary_change {
11830                    ranges.push((
11831                        language_settings.clone(),
11832                        Point::new(current_range_start, 0)
11833                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11834                        current_range_indent,
11835                        current_range_comment_prefix.clone(),
11836                        current_range_rewrap_prefix.clone(),
11837                        from_empty_selection,
11838                    ));
11839                    current_range_start = row;
11840                    current_range_indent = row_indent;
11841                    current_range_comment_prefix = row_comment_prefix;
11842                    current_range_rewrap_prefix = row_rewrap_prefix;
11843                }
11844                prev_row = row;
11845            }
11846
11847            ranges.push((
11848                language_settings.clone(),
11849                Point::new(current_range_start, 0)
11850                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11851                current_range_indent,
11852                current_range_comment_prefix,
11853                current_range_rewrap_prefix,
11854                from_empty_selection,
11855            ));
11856
11857            ranges
11858        });
11859
11860        let mut edits = Vec::new();
11861        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11862
11863        for (
11864            language_settings,
11865            wrap_range,
11866            indent_size,
11867            comment_prefix,
11868            rewrap_prefix,
11869            from_empty_selection,
11870        ) in wrap_ranges
11871        {
11872            let mut start_row = wrap_range.start.row;
11873            let mut end_row = wrap_range.end.row;
11874
11875            // Skip selections that overlap with a range that has already been rewrapped.
11876            let selection_range = start_row..end_row;
11877            if rewrapped_row_ranges
11878                .iter()
11879                .any(|range| range.overlaps(&selection_range))
11880            {
11881                continue;
11882            }
11883
11884            let tab_size = language_settings.tab_size;
11885
11886            let indent_prefix = indent_size.chars().collect::<String>();
11887            let mut line_prefix = indent_prefix.clone();
11888            let mut inside_comment = false;
11889            if let Some(prefix) = &comment_prefix {
11890                line_prefix.push_str(prefix);
11891                inside_comment = true;
11892            }
11893            if let Some(prefix) = &rewrap_prefix {
11894                line_prefix.push_str(prefix);
11895            }
11896
11897            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11898                RewrapBehavior::InComments => inside_comment,
11899                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11900                RewrapBehavior::Anywhere => true,
11901            };
11902
11903            let should_rewrap = options.override_language_settings
11904                || allow_rewrap_based_on_language
11905                || self.hard_wrap.is_some();
11906            if !should_rewrap {
11907                continue;
11908            }
11909
11910            if from_empty_selection {
11911                'expand_upwards: while start_row > 0 {
11912                    let prev_row = start_row - 1;
11913                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11914                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11915                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11916                    {
11917                        start_row = prev_row;
11918                    } else {
11919                        break 'expand_upwards;
11920                    }
11921                }
11922
11923                'expand_downwards: while end_row < buffer.max_point().row {
11924                    let next_row = end_row + 1;
11925                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11926                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11927                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11928                    {
11929                        end_row = next_row;
11930                    } else {
11931                        break 'expand_downwards;
11932                    }
11933                }
11934            }
11935
11936            let start = Point::new(start_row, 0);
11937            let start_offset = start.to_offset(&buffer);
11938            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11939            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11940            let Some(lines_without_prefixes) = selection_text
11941                .lines()
11942                .enumerate()
11943                .map(|(ix, line)| {
11944                    let line_trimmed = line.trim_start();
11945                    if rewrap_prefix.is_some() && ix > 0 {
11946                        Ok(line_trimmed)
11947                    } else {
11948                        line_trimmed
11949                            .strip_prefix(&line_prefix.trim_start())
11950                            .with_context(|| {
11951                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11952                            })
11953                    }
11954                })
11955                .collect::<Result<Vec<_>, _>>()
11956                .log_err()
11957            else {
11958                continue;
11959            };
11960
11961            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11962                buffer
11963                    .language_settings_at(Point::new(start_row, 0), cx)
11964                    .preferred_line_length as usize
11965            });
11966
11967            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11968                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11969            } else {
11970                line_prefix.clone()
11971            };
11972
11973            let wrapped_text = wrap_with_prefix(
11974                line_prefix,
11975                subsequent_lines_prefix,
11976                lines_without_prefixes.join("\n"),
11977                wrap_column,
11978                tab_size,
11979                options.preserve_existing_whitespace,
11980            );
11981
11982            // TODO: should always use char-based diff while still supporting cursor behavior that
11983            // matches vim.
11984            let mut diff_options = DiffOptions::default();
11985            if options.override_language_settings {
11986                diff_options.max_word_diff_len = 0;
11987                diff_options.max_word_diff_line_count = 0;
11988            } else {
11989                diff_options.max_word_diff_len = usize::MAX;
11990                diff_options.max_word_diff_line_count = usize::MAX;
11991            }
11992
11993            for (old_range, new_text) in
11994                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11995            {
11996                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11997                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11998                edits.push((edit_start..edit_end, new_text));
11999            }
12000
12001            rewrapped_row_ranges.push(start_row..=end_row);
12002        }
12003
12004        self.buffer
12005            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12006    }
12007
12008    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12009        let mut text = String::new();
12010        let buffer = self.buffer.read(cx).snapshot(cx);
12011        let mut selections = self.selections.all::<Point>(cx);
12012        let mut clipboard_selections = Vec::with_capacity(selections.len());
12013        {
12014            let max_point = buffer.max_point();
12015            let mut is_first = true;
12016            for selection in &mut selections {
12017                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12018                if is_entire_line {
12019                    selection.start = Point::new(selection.start.row, 0);
12020                    if !selection.is_empty() && selection.end.column == 0 {
12021                        selection.end = cmp::min(max_point, selection.end);
12022                    } else {
12023                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12024                    }
12025                    selection.goal = SelectionGoal::None;
12026                }
12027                if is_first {
12028                    is_first = false;
12029                } else {
12030                    text += "\n";
12031                }
12032                let mut len = 0;
12033                for chunk in buffer.text_for_range(selection.start..selection.end) {
12034                    text.push_str(chunk);
12035                    len += chunk.len();
12036                }
12037                clipboard_selections.push(ClipboardSelection {
12038                    len,
12039                    is_entire_line,
12040                    first_line_indent: buffer
12041                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12042                        .len,
12043                });
12044            }
12045        }
12046
12047        self.transact(window, cx, |this, window, cx| {
12048            this.change_selections(Default::default(), window, cx, |s| {
12049                s.select(selections);
12050            });
12051            this.insert("", window, cx);
12052        });
12053        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12054    }
12055
12056    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12057        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12058        let item = self.cut_common(window, cx);
12059        cx.write_to_clipboard(item);
12060    }
12061
12062    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12063        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12064        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12065            s.move_with(|snapshot, sel| {
12066                if sel.is_empty() {
12067                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12068                }
12069            });
12070        });
12071        let item = self.cut_common(window, cx);
12072        cx.set_global(KillRing(item))
12073    }
12074
12075    pub fn kill_ring_yank(
12076        &mut self,
12077        _: &KillRingYank,
12078        window: &mut Window,
12079        cx: &mut Context<Self>,
12080    ) {
12081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12082        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12083            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12084                (kill_ring.text().to_string(), kill_ring.metadata_json())
12085            } else {
12086                return;
12087            }
12088        } else {
12089            return;
12090        };
12091        self.do_paste(&text, metadata, false, window, cx);
12092    }
12093
12094    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12095        self.do_copy(true, cx);
12096    }
12097
12098    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12099        self.do_copy(false, cx);
12100    }
12101
12102    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12103        let selections = self.selections.all::<Point>(cx);
12104        let buffer = self.buffer.read(cx).read(cx);
12105        let mut text = String::new();
12106
12107        let mut clipboard_selections = Vec::with_capacity(selections.len());
12108        {
12109            let max_point = buffer.max_point();
12110            let mut is_first = true;
12111            for selection in &selections {
12112                let mut start = selection.start;
12113                let mut end = selection.end;
12114                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12115                if is_entire_line {
12116                    start = Point::new(start.row, 0);
12117                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12118                }
12119
12120                let mut trimmed_selections = Vec::new();
12121                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12122                    let row = MultiBufferRow(start.row);
12123                    let first_indent = buffer.indent_size_for_line(row);
12124                    if first_indent.len == 0 || start.column > first_indent.len {
12125                        trimmed_selections.push(start..end);
12126                    } else {
12127                        trimmed_selections.push(
12128                            Point::new(row.0, first_indent.len)
12129                                ..Point::new(row.0, buffer.line_len(row)),
12130                        );
12131                        for row in start.row + 1..=end.row {
12132                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12133                            if row == end.row {
12134                                line_len = end.column;
12135                            }
12136                            if line_len == 0 {
12137                                trimmed_selections
12138                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12139                                continue;
12140                            }
12141                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12142                            if row_indent_size.len >= first_indent.len {
12143                                trimmed_selections.push(
12144                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12145                                );
12146                            } else {
12147                                trimmed_selections.clear();
12148                                trimmed_selections.push(start..end);
12149                                break;
12150                            }
12151                        }
12152                    }
12153                } else {
12154                    trimmed_selections.push(start..end);
12155                }
12156
12157                for trimmed_range in trimmed_selections {
12158                    if is_first {
12159                        is_first = false;
12160                    } else {
12161                        text += "\n";
12162                    }
12163                    let mut len = 0;
12164                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12165                        text.push_str(chunk);
12166                        len += chunk.len();
12167                    }
12168                    clipboard_selections.push(ClipboardSelection {
12169                        len,
12170                        is_entire_line,
12171                        first_line_indent: buffer
12172                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12173                            .len,
12174                    });
12175                }
12176            }
12177        }
12178
12179        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12180            text,
12181            clipboard_selections,
12182        ));
12183    }
12184
12185    pub fn do_paste(
12186        &mut self,
12187        text: &String,
12188        clipboard_selections: Option<Vec<ClipboardSelection>>,
12189        handle_entire_lines: bool,
12190        window: &mut Window,
12191        cx: &mut Context<Self>,
12192    ) {
12193        if self.read_only(cx) {
12194            return;
12195        }
12196
12197        let clipboard_text = Cow::Borrowed(text);
12198
12199        self.transact(window, cx, |this, window, cx| {
12200            let had_active_edit_prediction = this.has_active_edit_prediction();
12201
12202            if let Some(mut clipboard_selections) = clipboard_selections {
12203                let old_selections = this.selections.all::<usize>(cx);
12204                let all_selections_were_entire_line =
12205                    clipboard_selections.iter().all(|s| s.is_entire_line);
12206                let first_selection_indent_column =
12207                    clipboard_selections.first().map(|s| s.first_line_indent);
12208                if clipboard_selections.len() != old_selections.len() {
12209                    clipboard_selections.drain(..);
12210                }
12211                let cursor_offset = this.selections.last::<usize>(cx).head();
12212                let mut auto_indent_on_paste = true;
12213
12214                this.buffer.update(cx, |buffer, cx| {
12215                    let snapshot = buffer.read(cx);
12216                    auto_indent_on_paste = snapshot
12217                        .language_settings_at(cursor_offset, cx)
12218                        .auto_indent_on_paste;
12219
12220                    let mut start_offset = 0;
12221                    let mut edits = Vec::new();
12222                    let mut original_indent_columns = Vec::new();
12223                    for (ix, selection) in old_selections.iter().enumerate() {
12224                        let to_insert;
12225                        let entire_line;
12226                        let original_indent_column;
12227                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12228                            let end_offset = start_offset + clipboard_selection.len;
12229                            to_insert = &clipboard_text[start_offset..end_offset];
12230                            entire_line = clipboard_selection.is_entire_line;
12231                            start_offset = end_offset + 1;
12232                            original_indent_column = Some(clipboard_selection.first_line_indent);
12233                        } else {
12234                            to_insert = clipboard_text.as_str();
12235                            entire_line = all_selections_were_entire_line;
12236                            original_indent_column = first_selection_indent_column
12237                        }
12238
12239                        // If the corresponding selection was empty when this slice of the
12240                        // clipboard text was written, then the entire line containing the
12241                        // selection was copied. If this selection is also currently empty,
12242                        // then paste the line before the current line of the buffer.
12243                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12244                            let column = selection.start.to_point(&snapshot).column as usize;
12245                            let line_start = selection.start - column;
12246                            line_start..line_start
12247                        } else {
12248                            selection.range()
12249                        };
12250
12251                        edits.push((range, to_insert));
12252                        original_indent_columns.push(original_indent_column);
12253                    }
12254                    drop(snapshot);
12255
12256                    buffer.edit(
12257                        edits,
12258                        if auto_indent_on_paste {
12259                            Some(AutoindentMode::Block {
12260                                original_indent_columns,
12261                            })
12262                        } else {
12263                            None
12264                        },
12265                        cx,
12266                    );
12267                });
12268
12269                let selections = this.selections.all::<usize>(cx);
12270                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12271            } else {
12272                this.insert(&clipboard_text, window, cx);
12273            }
12274
12275            let trigger_in_words =
12276                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12277
12278            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12279        });
12280    }
12281
12282    pub fn diff_clipboard_with_selection(
12283        &mut self,
12284        _: &DiffClipboardWithSelection,
12285        window: &mut Window,
12286        cx: &mut Context<Self>,
12287    ) {
12288        let selections = self.selections.all::<usize>(cx);
12289
12290        if selections.is_empty() {
12291            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12292            return;
12293        };
12294
12295        let clipboard_text = match cx.read_from_clipboard() {
12296            Some(item) => match item.entries().first() {
12297                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12298                _ => None,
12299            },
12300            None => None,
12301        };
12302
12303        let Some(clipboard_text) = clipboard_text else {
12304            log::warn!("Clipboard doesn't contain text.");
12305            return;
12306        };
12307
12308        window.dispatch_action(
12309            Box::new(DiffClipboardWithSelectionData {
12310                clipboard_text,
12311                editor: cx.entity(),
12312            }),
12313            cx,
12314        );
12315    }
12316
12317    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12318        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12319        if let Some(item) = cx.read_from_clipboard() {
12320            let entries = item.entries();
12321
12322            match entries.first() {
12323                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12324                // of all the pasted entries.
12325                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12326                    .do_paste(
12327                        clipboard_string.text(),
12328                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12329                        true,
12330                        window,
12331                        cx,
12332                    ),
12333                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12334            }
12335        }
12336    }
12337
12338    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12339        if self.read_only(cx) {
12340            return;
12341        }
12342
12343        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12344
12345        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12346            if let Some((selections, _)) =
12347                self.selection_history.transaction(transaction_id).cloned()
12348            {
12349                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12350                    s.select_anchors(selections.to_vec());
12351                });
12352            } else {
12353                log::error!(
12354                    "No entry in selection_history found for undo. \
12355                     This may correspond to a bug where undo does not update the selection. \
12356                     If this is occurring, please add details to \
12357                     https://github.com/zed-industries/zed/issues/22692"
12358                );
12359            }
12360            self.request_autoscroll(Autoscroll::fit(), cx);
12361            self.unmark_text(window, cx);
12362            self.refresh_edit_prediction(true, false, window, cx);
12363            cx.emit(EditorEvent::Edited { transaction_id });
12364            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12365        }
12366    }
12367
12368    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12369        if self.read_only(cx) {
12370            return;
12371        }
12372
12373        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12374
12375        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12376            if let Some((_, Some(selections))) =
12377                self.selection_history.transaction(transaction_id).cloned()
12378            {
12379                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12380                    s.select_anchors(selections.to_vec());
12381                });
12382            } else {
12383                log::error!(
12384                    "No entry in selection_history found for redo. \
12385                     This may correspond to a bug where undo does not update the selection. \
12386                     If this is occurring, please add details to \
12387                     https://github.com/zed-industries/zed/issues/22692"
12388                );
12389            }
12390            self.request_autoscroll(Autoscroll::fit(), cx);
12391            self.unmark_text(window, cx);
12392            self.refresh_edit_prediction(true, false, window, cx);
12393            cx.emit(EditorEvent::Edited { transaction_id });
12394        }
12395    }
12396
12397    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12398        self.buffer
12399            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12400    }
12401
12402    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12403        self.buffer
12404            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12405    }
12406
12407    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12409        self.change_selections(Default::default(), window, cx, |s| {
12410            s.move_with(|map, selection| {
12411                let cursor = if selection.is_empty() {
12412                    movement::left(map, selection.start)
12413                } else {
12414                    selection.start
12415                };
12416                selection.collapse_to(cursor, SelectionGoal::None);
12417            });
12418        })
12419    }
12420
12421    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12422        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12423        self.change_selections(Default::default(), window, cx, |s| {
12424            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12425        })
12426    }
12427
12428    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12429        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12430        self.change_selections(Default::default(), window, cx, |s| {
12431            s.move_with(|map, selection| {
12432                let cursor = if selection.is_empty() {
12433                    movement::right(map, selection.end)
12434                } else {
12435                    selection.end
12436                };
12437                selection.collapse_to(cursor, SelectionGoal::None)
12438            });
12439        })
12440    }
12441
12442    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12444        self.change_selections(Default::default(), window, cx, |s| {
12445            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12446        })
12447    }
12448
12449    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12450        if self.take_rename(true, window, cx).is_some() {
12451            return;
12452        }
12453
12454        if self.mode.is_single_line() {
12455            cx.propagate();
12456            return;
12457        }
12458
12459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12460
12461        let text_layout_details = &self.text_layout_details(window);
12462        let selection_count = self.selections.count();
12463        let first_selection = self.selections.first_anchor();
12464
12465        self.change_selections(Default::default(), window, cx, |s| {
12466            s.move_with(|map, selection| {
12467                if !selection.is_empty() {
12468                    selection.goal = SelectionGoal::None;
12469                }
12470                let (cursor, goal) = movement::up(
12471                    map,
12472                    selection.start,
12473                    selection.goal,
12474                    false,
12475                    text_layout_details,
12476                );
12477                selection.collapse_to(cursor, goal);
12478            });
12479        });
12480
12481        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12482        {
12483            cx.propagate();
12484        }
12485    }
12486
12487    pub fn move_up_by_lines(
12488        &mut self,
12489        action: &MoveUpByLines,
12490        window: &mut Window,
12491        cx: &mut Context<Self>,
12492    ) {
12493        if self.take_rename(true, window, cx).is_some() {
12494            return;
12495        }
12496
12497        if self.mode.is_single_line() {
12498            cx.propagate();
12499            return;
12500        }
12501
12502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12503
12504        let text_layout_details = &self.text_layout_details(window);
12505
12506        self.change_selections(Default::default(), window, cx, |s| {
12507            s.move_with(|map, selection| {
12508                if !selection.is_empty() {
12509                    selection.goal = SelectionGoal::None;
12510                }
12511                let (cursor, goal) = movement::up_by_rows(
12512                    map,
12513                    selection.start,
12514                    action.lines,
12515                    selection.goal,
12516                    false,
12517                    text_layout_details,
12518                );
12519                selection.collapse_to(cursor, goal);
12520            });
12521        })
12522    }
12523
12524    pub fn move_down_by_lines(
12525        &mut self,
12526        action: &MoveDownByLines,
12527        window: &mut Window,
12528        cx: &mut Context<Self>,
12529    ) {
12530        if self.take_rename(true, window, cx).is_some() {
12531            return;
12532        }
12533
12534        if self.mode.is_single_line() {
12535            cx.propagate();
12536            return;
12537        }
12538
12539        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12540
12541        let text_layout_details = &self.text_layout_details(window);
12542
12543        self.change_selections(Default::default(), window, cx, |s| {
12544            s.move_with(|map, selection| {
12545                if !selection.is_empty() {
12546                    selection.goal = SelectionGoal::None;
12547                }
12548                let (cursor, goal) = movement::down_by_rows(
12549                    map,
12550                    selection.start,
12551                    action.lines,
12552                    selection.goal,
12553                    false,
12554                    text_layout_details,
12555                );
12556                selection.collapse_to(cursor, goal);
12557            });
12558        })
12559    }
12560
12561    pub fn select_down_by_lines(
12562        &mut self,
12563        action: &SelectDownByLines,
12564        window: &mut Window,
12565        cx: &mut Context<Self>,
12566    ) {
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12568        let text_layout_details = &self.text_layout_details(window);
12569        self.change_selections(Default::default(), window, cx, |s| {
12570            s.move_heads_with(|map, head, goal| {
12571                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12572            })
12573        })
12574    }
12575
12576    pub fn select_up_by_lines(
12577        &mut self,
12578        action: &SelectUpByLines,
12579        window: &mut Window,
12580        cx: &mut Context<Self>,
12581    ) {
12582        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12583        let text_layout_details = &self.text_layout_details(window);
12584        self.change_selections(Default::default(), window, cx, |s| {
12585            s.move_heads_with(|map, head, goal| {
12586                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12587            })
12588        })
12589    }
12590
12591    pub fn select_page_up(
12592        &mut self,
12593        _: &SelectPageUp,
12594        window: &mut Window,
12595        cx: &mut Context<Self>,
12596    ) {
12597        let Some(row_count) = self.visible_row_count() else {
12598            return;
12599        };
12600
12601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12602
12603        let text_layout_details = &self.text_layout_details(window);
12604
12605        self.change_selections(Default::default(), window, cx, |s| {
12606            s.move_heads_with(|map, head, goal| {
12607                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12608            })
12609        })
12610    }
12611
12612    pub fn move_page_up(
12613        &mut self,
12614        action: &MovePageUp,
12615        window: &mut Window,
12616        cx: &mut Context<Self>,
12617    ) {
12618        if self.take_rename(true, window, cx).is_some() {
12619            return;
12620        }
12621
12622        if self
12623            .context_menu
12624            .borrow_mut()
12625            .as_mut()
12626            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12627            .unwrap_or(false)
12628        {
12629            return;
12630        }
12631
12632        if matches!(self.mode, EditorMode::SingleLine) {
12633            cx.propagate();
12634            return;
12635        }
12636
12637        let Some(row_count) = self.visible_row_count() else {
12638            return;
12639        };
12640
12641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12642
12643        let effects = if action.center_cursor {
12644            SelectionEffects::scroll(Autoscroll::center())
12645        } else {
12646            SelectionEffects::default()
12647        };
12648
12649        let text_layout_details = &self.text_layout_details(window);
12650
12651        self.change_selections(effects, window, cx, |s| {
12652            s.move_with(|map, selection| {
12653                if !selection.is_empty() {
12654                    selection.goal = SelectionGoal::None;
12655                }
12656                let (cursor, goal) = movement::up_by_rows(
12657                    map,
12658                    selection.end,
12659                    row_count,
12660                    selection.goal,
12661                    false,
12662                    text_layout_details,
12663                );
12664                selection.collapse_to(cursor, goal);
12665            });
12666        });
12667    }
12668
12669    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12670        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12671        let text_layout_details = &self.text_layout_details(window);
12672        self.change_selections(Default::default(), window, cx, |s| {
12673            s.move_heads_with(|map, head, goal| {
12674                movement::up(map, head, goal, false, text_layout_details)
12675            })
12676        })
12677    }
12678
12679    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12680        self.take_rename(true, window, cx);
12681
12682        if self.mode.is_single_line() {
12683            cx.propagate();
12684            return;
12685        }
12686
12687        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12688
12689        let text_layout_details = &self.text_layout_details(window);
12690        let selection_count = self.selections.count();
12691        let first_selection = self.selections.first_anchor();
12692
12693        self.change_selections(Default::default(), window, cx, |s| {
12694            s.move_with(|map, selection| {
12695                if !selection.is_empty() {
12696                    selection.goal = SelectionGoal::None;
12697                }
12698                let (cursor, goal) = movement::down(
12699                    map,
12700                    selection.end,
12701                    selection.goal,
12702                    false,
12703                    text_layout_details,
12704                );
12705                selection.collapse_to(cursor, goal);
12706            });
12707        });
12708
12709        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12710        {
12711            cx.propagate();
12712        }
12713    }
12714
12715    pub fn select_page_down(
12716        &mut self,
12717        _: &SelectPageDown,
12718        window: &mut Window,
12719        cx: &mut Context<Self>,
12720    ) {
12721        let Some(row_count) = self.visible_row_count() else {
12722            return;
12723        };
12724
12725        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12726
12727        let text_layout_details = &self.text_layout_details(window);
12728
12729        self.change_selections(Default::default(), window, cx, |s| {
12730            s.move_heads_with(|map, head, goal| {
12731                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12732            })
12733        })
12734    }
12735
12736    pub fn move_page_down(
12737        &mut self,
12738        action: &MovePageDown,
12739        window: &mut Window,
12740        cx: &mut Context<Self>,
12741    ) {
12742        if self.take_rename(true, window, cx).is_some() {
12743            return;
12744        }
12745
12746        if self
12747            .context_menu
12748            .borrow_mut()
12749            .as_mut()
12750            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12751            .unwrap_or(false)
12752        {
12753            return;
12754        }
12755
12756        if matches!(self.mode, EditorMode::SingleLine) {
12757            cx.propagate();
12758            return;
12759        }
12760
12761        let Some(row_count) = self.visible_row_count() else {
12762            return;
12763        };
12764
12765        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12766
12767        let effects = if action.center_cursor {
12768            SelectionEffects::scroll(Autoscroll::center())
12769        } else {
12770            SelectionEffects::default()
12771        };
12772
12773        let text_layout_details = &self.text_layout_details(window);
12774        self.change_selections(effects, window, cx, |s| {
12775            s.move_with(|map, selection| {
12776                if !selection.is_empty() {
12777                    selection.goal = SelectionGoal::None;
12778                }
12779                let (cursor, goal) = movement::down_by_rows(
12780                    map,
12781                    selection.end,
12782                    row_count,
12783                    selection.goal,
12784                    false,
12785                    text_layout_details,
12786                );
12787                selection.collapse_to(cursor, goal);
12788            });
12789        });
12790    }
12791
12792    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12794        let text_layout_details = &self.text_layout_details(window);
12795        self.change_selections(Default::default(), window, cx, |s| {
12796            s.move_heads_with(|map, head, goal| {
12797                movement::down(map, head, goal, false, text_layout_details)
12798            })
12799        });
12800    }
12801
12802    pub fn context_menu_first(
12803        &mut self,
12804        _: &ContextMenuFirst,
12805        window: &mut Window,
12806        cx: &mut Context<Self>,
12807    ) {
12808        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12809            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12810        }
12811    }
12812
12813    pub fn context_menu_prev(
12814        &mut self,
12815        _: &ContextMenuPrevious,
12816        window: &mut Window,
12817        cx: &mut Context<Self>,
12818    ) {
12819        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12820            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12821        }
12822    }
12823
12824    pub fn context_menu_next(
12825        &mut self,
12826        _: &ContextMenuNext,
12827        window: &mut Window,
12828        cx: &mut Context<Self>,
12829    ) {
12830        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12831            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12832        }
12833    }
12834
12835    pub fn context_menu_last(
12836        &mut self,
12837        _: &ContextMenuLast,
12838        window: &mut Window,
12839        cx: &mut Context<Self>,
12840    ) {
12841        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12842            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12843        }
12844    }
12845
12846    pub fn signature_help_prev(
12847        &mut self,
12848        _: &SignatureHelpPrevious,
12849        _: &mut Window,
12850        cx: &mut Context<Self>,
12851    ) {
12852        if let Some(popover) = self.signature_help_state.popover_mut() {
12853            if popover.current_signature == 0 {
12854                popover.current_signature = popover.signatures.len() - 1;
12855            } else {
12856                popover.current_signature -= 1;
12857            }
12858            cx.notify();
12859        }
12860    }
12861
12862    pub fn signature_help_next(
12863        &mut self,
12864        _: &SignatureHelpNext,
12865        _: &mut Window,
12866        cx: &mut Context<Self>,
12867    ) {
12868        if let Some(popover) = self.signature_help_state.popover_mut() {
12869            if popover.current_signature + 1 == popover.signatures.len() {
12870                popover.current_signature = 0;
12871            } else {
12872                popover.current_signature += 1;
12873            }
12874            cx.notify();
12875        }
12876    }
12877
12878    pub fn move_to_previous_word_start(
12879        &mut self,
12880        _: &MoveToPreviousWordStart,
12881        window: &mut Window,
12882        cx: &mut Context<Self>,
12883    ) {
12884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12885        self.change_selections(Default::default(), window, cx, |s| {
12886            s.move_cursors_with(|map, head, _| {
12887                (
12888                    movement::previous_word_start(map, head),
12889                    SelectionGoal::None,
12890                )
12891            });
12892        })
12893    }
12894
12895    pub fn move_to_previous_subword_start(
12896        &mut self,
12897        _: &MoveToPreviousSubwordStart,
12898        window: &mut Window,
12899        cx: &mut Context<Self>,
12900    ) {
12901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12902        self.change_selections(Default::default(), window, cx, |s| {
12903            s.move_cursors_with(|map, head, _| {
12904                (
12905                    movement::previous_subword_start(map, head),
12906                    SelectionGoal::None,
12907                )
12908            });
12909        })
12910    }
12911
12912    pub fn select_to_previous_word_start(
12913        &mut self,
12914        _: &SelectToPreviousWordStart,
12915        window: &mut Window,
12916        cx: &mut Context<Self>,
12917    ) {
12918        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12919        self.change_selections(Default::default(), window, cx, |s| {
12920            s.move_heads_with(|map, head, _| {
12921                (
12922                    movement::previous_word_start(map, head),
12923                    SelectionGoal::None,
12924                )
12925            });
12926        })
12927    }
12928
12929    pub fn select_to_previous_subword_start(
12930        &mut self,
12931        _: &SelectToPreviousSubwordStart,
12932        window: &mut Window,
12933        cx: &mut Context<Self>,
12934    ) {
12935        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12936        self.change_selections(Default::default(), window, cx, |s| {
12937            s.move_heads_with(|map, head, _| {
12938                (
12939                    movement::previous_subword_start(map, head),
12940                    SelectionGoal::None,
12941                )
12942            });
12943        })
12944    }
12945
12946    pub fn delete_to_previous_word_start(
12947        &mut self,
12948        action: &DeleteToPreviousWordStart,
12949        window: &mut Window,
12950        cx: &mut Context<Self>,
12951    ) {
12952        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12953        self.transact(window, cx, |this, window, cx| {
12954            this.select_autoclose_pair(window, cx);
12955            this.change_selections(Default::default(), window, cx, |s| {
12956                s.move_with(|map, selection| {
12957                    if selection.is_empty() {
12958                        let cursor = if action.ignore_newlines {
12959                            movement::previous_word_start(map, selection.head())
12960                        } else {
12961                            movement::previous_word_start_or_newline(map, selection.head())
12962                        };
12963                        selection.set_head(cursor, SelectionGoal::None);
12964                    }
12965                });
12966            });
12967            this.insert("", window, cx);
12968        });
12969    }
12970
12971    pub fn delete_to_previous_subword_start(
12972        &mut self,
12973        _: &DeleteToPreviousSubwordStart,
12974        window: &mut Window,
12975        cx: &mut Context<Self>,
12976    ) {
12977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12978        self.transact(window, cx, |this, window, cx| {
12979            this.select_autoclose_pair(window, cx);
12980            this.change_selections(Default::default(), window, cx, |s| {
12981                s.move_with(|map, selection| {
12982                    if selection.is_empty() {
12983                        let cursor = movement::previous_subword_start(map, selection.head());
12984                        selection.set_head(cursor, SelectionGoal::None);
12985                    }
12986                });
12987            });
12988            this.insert("", window, cx);
12989        });
12990    }
12991
12992    pub fn move_to_next_word_end(
12993        &mut self,
12994        _: &MoveToNextWordEnd,
12995        window: &mut Window,
12996        cx: &mut Context<Self>,
12997    ) {
12998        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12999        self.change_selections(Default::default(), window, cx, |s| {
13000            s.move_cursors_with(|map, head, _| {
13001                (movement::next_word_end(map, head), SelectionGoal::None)
13002            });
13003        })
13004    }
13005
13006    pub fn move_to_next_subword_end(
13007        &mut self,
13008        _: &MoveToNextSubwordEnd,
13009        window: &mut Window,
13010        cx: &mut Context<Self>,
13011    ) {
13012        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13013        self.change_selections(Default::default(), window, cx, |s| {
13014            s.move_cursors_with(|map, head, _| {
13015                (movement::next_subword_end(map, head), SelectionGoal::None)
13016            });
13017        })
13018    }
13019
13020    pub fn select_to_next_word_end(
13021        &mut self,
13022        _: &SelectToNextWordEnd,
13023        window: &mut Window,
13024        cx: &mut Context<Self>,
13025    ) {
13026        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13027        self.change_selections(Default::default(), window, cx, |s| {
13028            s.move_heads_with(|map, head, _| {
13029                (movement::next_word_end(map, head), SelectionGoal::None)
13030            });
13031        })
13032    }
13033
13034    pub fn select_to_next_subword_end(
13035        &mut self,
13036        _: &SelectToNextSubwordEnd,
13037        window: &mut Window,
13038        cx: &mut Context<Self>,
13039    ) {
13040        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13041        self.change_selections(Default::default(), window, cx, |s| {
13042            s.move_heads_with(|map, head, _| {
13043                (movement::next_subword_end(map, head), SelectionGoal::None)
13044            });
13045        })
13046    }
13047
13048    pub fn delete_to_next_word_end(
13049        &mut self,
13050        action: &DeleteToNextWordEnd,
13051        window: &mut Window,
13052        cx: &mut Context<Self>,
13053    ) {
13054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13055        self.transact(window, cx, |this, window, cx| {
13056            this.change_selections(Default::default(), window, cx, |s| {
13057                s.move_with(|map, selection| {
13058                    if selection.is_empty() {
13059                        let cursor = if action.ignore_newlines {
13060                            movement::next_word_end(map, selection.head())
13061                        } else {
13062                            movement::next_word_end_or_newline(map, selection.head())
13063                        };
13064                        selection.set_head(cursor, SelectionGoal::None);
13065                    }
13066                });
13067            });
13068            this.insert("", window, cx);
13069        });
13070    }
13071
13072    pub fn delete_to_next_subword_end(
13073        &mut self,
13074        _: &DeleteToNextSubwordEnd,
13075        window: &mut Window,
13076        cx: &mut Context<Self>,
13077    ) {
13078        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13079        self.transact(window, cx, |this, window, cx| {
13080            this.change_selections(Default::default(), window, cx, |s| {
13081                s.move_with(|map, selection| {
13082                    if selection.is_empty() {
13083                        let cursor = movement::next_subword_end(map, selection.head());
13084                        selection.set_head(cursor, SelectionGoal::None);
13085                    }
13086                });
13087            });
13088            this.insert("", window, cx);
13089        });
13090    }
13091
13092    pub fn move_to_beginning_of_line(
13093        &mut self,
13094        action: &MoveToBeginningOfLine,
13095        window: &mut Window,
13096        cx: &mut Context<Self>,
13097    ) {
13098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13099        self.change_selections(Default::default(), window, cx, |s| {
13100            s.move_cursors_with(|map, head, _| {
13101                (
13102                    movement::indented_line_beginning(
13103                        map,
13104                        head,
13105                        action.stop_at_soft_wraps,
13106                        action.stop_at_indent,
13107                    ),
13108                    SelectionGoal::None,
13109                )
13110            });
13111        })
13112    }
13113
13114    pub fn select_to_beginning_of_line(
13115        &mut self,
13116        action: &SelectToBeginningOfLine,
13117        window: &mut Window,
13118        cx: &mut Context<Self>,
13119    ) {
13120        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13121        self.change_selections(Default::default(), window, cx, |s| {
13122            s.move_heads_with(|map, head, _| {
13123                (
13124                    movement::indented_line_beginning(
13125                        map,
13126                        head,
13127                        action.stop_at_soft_wraps,
13128                        action.stop_at_indent,
13129                    ),
13130                    SelectionGoal::None,
13131                )
13132            });
13133        });
13134    }
13135
13136    pub fn delete_to_beginning_of_line(
13137        &mut self,
13138        action: &DeleteToBeginningOfLine,
13139        window: &mut Window,
13140        cx: &mut Context<Self>,
13141    ) {
13142        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13143        self.transact(window, cx, |this, window, cx| {
13144            this.change_selections(Default::default(), window, cx, |s| {
13145                s.move_with(|_, selection| {
13146                    selection.reversed = true;
13147                });
13148            });
13149
13150            this.select_to_beginning_of_line(
13151                &SelectToBeginningOfLine {
13152                    stop_at_soft_wraps: false,
13153                    stop_at_indent: action.stop_at_indent,
13154                },
13155                window,
13156                cx,
13157            );
13158            this.backspace(&Backspace, window, cx);
13159        });
13160    }
13161
13162    pub fn move_to_end_of_line(
13163        &mut self,
13164        action: &MoveToEndOfLine,
13165        window: &mut Window,
13166        cx: &mut Context<Self>,
13167    ) {
13168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13169        self.change_selections(Default::default(), window, cx, |s| {
13170            s.move_cursors_with(|map, head, _| {
13171                (
13172                    movement::line_end(map, head, action.stop_at_soft_wraps),
13173                    SelectionGoal::None,
13174                )
13175            });
13176        })
13177    }
13178
13179    pub fn select_to_end_of_line(
13180        &mut self,
13181        action: &SelectToEndOfLine,
13182        window: &mut Window,
13183        cx: &mut Context<Self>,
13184    ) {
13185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13186        self.change_selections(Default::default(), window, cx, |s| {
13187            s.move_heads_with(|map, head, _| {
13188                (
13189                    movement::line_end(map, head, action.stop_at_soft_wraps),
13190                    SelectionGoal::None,
13191                )
13192            });
13193        })
13194    }
13195
13196    pub fn delete_to_end_of_line(
13197        &mut self,
13198        _: &DeleteToEndOfLine,
13199        window: &mut Window,
13200        cx: &mut Context<Self>,
13201    ) {
13202        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13203        self.transact(window, cx, |this, window, cx| {
13204            this.select_to_end_of_line(
13205                &SelectToEndOfLine {
13206                    stop_at_soft_wraps: false,
13207                },
13208                window,
13209                cx,
13210            );
13211            this.delete(&Delete, window, cx);
13212        });
13213    }
13214
13215    pub fn cut_to_end_of_line(
13216        &mut self,
13217        _: &CutToEndOfLine,
13218        window: &mut Window,
13219        cx: &mut Context<Self>,
13220    ) {
13221        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13222        self.transact(window, cx, |this, window, cx| {
13223            this.select_to_end_of_line(
13224                &SelectToEndOfLine {
13225                    stop_at_soft_wraps: false,
13226                },
13227                window,
13228                cx,
13229            );
13230            this.cut(&Cut, window, cx);
13231        });
13232    }
13233
13234    pub fn move_to_start_of_paragraph(
13235        &mut self,
13236        _: &MoveToStartOfParagraph,
13237        window: &mut Window,
13238        cx: &mut Context<Self>,
13239    ) {
13240        if matches!(self.mode, EditorMode::SingleLine) {
13241            cx.propagate();
13242            return;
13243        }
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13245        self.change_selections(Default::default(), window, cx, |s| {
13246            s.move_with(|map, selection| {
13247                selection.collapse_to(
13248                    movement::start_of_paragraph(map, selection.head(), 1),
13249                    SelectionGoal::None,
13250                )
13251            });
13252        })
13253    }
13254
13255    pub fn move_to_end_of_paragraph(
13256        &mut self,
13257        _: &MoveToEndOfParagraph,
13258        window: &mut Window,
13259        cx: &mut Context<Self>,
13260    ) {
13261        if matches!(self.mode, EditorMode::SingleLine) {
13262            cx.propagate();
13263            return;
13264        }
13265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13266        self.change_selections(Default::default(), window, cx, |s| {
13267            s.move_with(|map, selection| {
13268                selection.collapse_to(
13269                    movement::end_of_paragraph(map, selection.head(), 1),
13270                    SelectionGoal::None,
13271                )
13272            });
13273        })
13274    }
13275
13276    pub fn select_to_start_of_paragraph(
13277        &mut self,
13278        _: &SelectToStartOfParagraph,
13279        window: &mut Window,
13280        cx: &mut Context<Self>,
13281    ) {
13282        if matches!(self.mode, EditorMode::SingleLine) {
13283            cx.propagate();
13284            return;
13285        }
13286        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13287        self.change_selections(Default::default(), window, cx, |s| {
13288            s.move_heads_with(|map, head, _| {
13289                (
13290                    movement::start_of_paragraph(map, head, 1),
13291                    SelectionGoal::None,
13292                )
13293            });
13294        })
13295    }
13296
13297    pub fn select_to_end_of_paragraph(
13298        &mut self,
13299        _: &SelectToEndOfParagraph,
13300        window: &mut Window,
13301        cx: &mut Context<Self>,
13302    ) {
13303        if matches!(self.mode, EditorMode::SingleLine) {
13304            cx.propagate();
13305            return;
13306        }
13307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13308        self.change_selections(Default::default(), window, cx, |s| {
13309            s.move_heads_with(|map, head, _| {
13310                (
13311                    movement::end_of_paragraph(map, head, 1),
13312                    SelectionGoal::None,
13313                )
13314            });
13315        })
13316    }
13317
13318    pub fn move_to_start_of_excerpt(
13319        &mut self,
13320        _: &MoveToStartOfExcerpt,
13321        window: &mut Window,
13322        cx: &mut Context<Self>,
13323    ) {
13324        if matches!(self.mode, EditorMode::SingleLine) {
13325            cx.propagate();
13326            return;
13327        }
13328        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13329        self.change_selections(Default::default(), window, cx, |s| {
13330            s.move_with(|map, selection| {
13331                selection.collapse_to(
13332                    movement::start_of_excerpt(
13333                        map,
13334                        selection.head(),
13335                        workspace::searchable::Direction::Prev,
13336                    ),
13337                    SelectionGoal::None,
13338                )
13339            });
13340        })
13341    }
13342
13343    pub fn move_to_start_of_next_excerpt(
13344        &mut self,
13345        _: &MoveToStartOfNextExcerpt,
13346        window: &mut Window,
13347        cx: &mut Context<Self>,
13348    ) {
13349        if matches!(self.mode, EditorMode::SingleLine) {
13350            cx.propagate();
13351            return;
13352        }
13353
13354        self.change_selections(Default::default(), window, cx, |s| {
13355            s.move_with(|map, selection| {
13356                selection.collapse_to(
13357                    movement::start_of_excerpt(
13358                        map,
13359                        selection.head(),
13360                        workspace::searchable::Direction::Next,
13361                    ),
13362                    SelectionGoal::None,
13363                )
13364            });
13365        })
13366    }
13367
13368    pub fn move_to_end_of_excerpt(
13369        &mut self,
13370        _: &MoveToEndOfExcerpt,
13371        window: &mut Window,
13372        cx: &mut Context<Self>,
13373    ) {
13374        if matches!(self.mode, EditorMode::SingleLine) {
13375            cx.propagate();
13376            return;
13377        }
13378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13379        self.change_selections(Default::default(), window, cx, |s| {
13380            s.move_with(|map, selection| {
13381                selection.collapse_to(
13382                    movement::end_of_excerpt(
13383                        map,
13384                        selection.head(),
13385                        workspace::searchable::Direction::Next,
13386                    ),
13387                    SelectionGoal::None,
13388                )
13389            });
13390        })
13391    }
13392
13393    pub fn move_to_end_of_previous_excerpt(
13394        &mut self,
13395        _: &MoveToEndOfPreviousExcerpt,
13396        window: &mut Window,
13397        cx: &mut Context<Self>,
13398    ) {
13399        if matches!(self.mode, EditorMode::SingleLine) {
13400            cx.propagate();
13401            return;
13402        }
13403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13404        self.change_selections(Default::default(), window, cx, |s| {
13405            s.move_with(|map, selection| {
13406                selection.collapse_to(
13407                    movement::end_of_excerpt(
13408                        map,
13409                        selection.head(),
13410                        workspace::searchable::Direction::Prev,
13411                    ),
13412                    SelectionGoal::None,
13413                )
13414            });
13415        })
13416    }
13417
13418    pub fn select_to_start_of_excerpt(
13419        &mut self,
13420        _: &SelectToStartOfExcerpt,
13421        window: &mut Window,
13422        cx: &mut Context<Self>,
13423    ) {
13424        if matches!(self.mode, EditorMode::SingleLine) {
13425            cx.propagate();
13426            return;
13427        }
13428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13429        self.change_selections(Default::default(), window, cx, |s| {
13430            s.move_heads_with(|map, head, _| {
13431                (
13432                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13433                    SelectionGoal::None,
13434                )
13435            });
13436        })
13437    }
13438
13439    pub fn select_to_start_of_next_excerpt(
13440        &mut self,
13441        _: &SelectToStartOfNextExcerpt,
13442        window: &mut Window,
13443        cx: &mut Context<Self>,
13444    ) {
13445        if matches!(self.mode, EditorMode::SingleLine) {
13446            cx.propagate();
13447            return;
13448        }
13449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13450        self.change_selections(Default::default(), window, cx, |s| {
13451            s.move_heads_with(|map, head, _| {
13452                (
13453                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13454                    SelectionGoal::None,
13455                )
13456            });
13457        })
13458    }
13459
13460    pub fn select_to_end_of_excerpt(
13461        &mut self,
13462        _: &SelectToEndOfExcerpt,
13463        window: &mut Window,
13464        cx: &mut Context<Self>,
13465    ) {
13466        if matches!(self.mode, EditorMode::SingleLine) {
13467            cx.propagate();
13468            return;
13469        }
13470        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13471        self.change_selections(Default::default(), window, cx, |s| {
13472            s.move_heads_with(|map, head, _| {
13473                (
13474                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13475                    SelectionGoal::None,
13476                )
13477            });
13478        })
13479    }
13480
13481    pub fn select_to_end_of_previous_excerpt(
13482        &mut self,
13483        _: &SelectToEndOfPreviousExcerpt,
13484        window: &mut Window,
13485        cx: &mut Context<Self>,
13486    ) {
13487        if matches!(self.mode, EditorMode::SingleLine) {
13488            cx.propagate();
13489            return;
13490        }
13491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13492        self.change_selections(Default::default(), window, cx, |s| {
13493            s.move_heads_with(|map, head, _| {
13494                (
13495                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13496                    SelectionGoal::None,
13497                )
13498            });
13499        })
13500    }
13501
13502    pub fn move_to_beginning(
13503        &mut self,
13504        _: &MoveToBeginning,
13505        window: &mut Window,
13506        cx: &mut Context<Self>,
13507    ) {
13508        if matches!(self.mode, EditorMode::SingleLine) {
13509            cx.propagate();
13510            return;
13511        }
13512        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13513        self.change_selections(Default::default(), window, cx, |s| {
13514            s.select_ranges(vec![0..0]);
13515        });
13516    }
13517
13518    pub fn select_to_beginning(
13519        &mut self,
13520        _: &SelectToBeginning,
13521        window: &mut Window,
13522        cx: &mut Context<Self>,
13523    ) {
13524        let mut selection = self.selections.last::<Point>(cx);
13525        selection.set_head(Point::zero(), SelectionGoal::None);
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.select(vec![selection]);
13529        });
13530    }
13531
13532    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13533        if matches!(self.mode, EditorMode::SingleLine) {
13534            cx.propagate();
13535            return;
13536        }
13537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13538        let cursor = self.buffer.read(cx).read(cx).len();
13539        self.change_selections(Default::default(), window, cx, |s| {
13540            s.select_ranges(vec![cursor..cursor])
13541        });
13542    }
13543
13544    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13545        self.nav_history = nav_history;
13546    }
13547
13548    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13549        self.nav_history.as_ref()
13550    }
13551
13552    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13553        self.push_to_nav_history(
13554            self.selections.newest_anchor().head(),
13555            None,
13556            false,
13557            true,
13558            cx,
13559        );
13560    }
13561
13562    fn push_to_nav_history(
13563        &mut self,
13564        cursor_anchor: Anchor,
13565        new_position: Option<Point>,
13566        is_deactivate: bool,
13567        always: bool,
13568        cx: &mut Context<Self>,
13569    ) {
13570        if let Some(nav_history) = self.nav_history.as_mut() {
13571            let buffer = self.buffer.read(cx).read(cx);
13572            let cursor_position = cursor_anchor.to_point(&buffer);
13573            let scroll_state = self.scroll_manager.anchor();
13574            let scroll_top_row = scroll_state.top_row(&buffer);
13575            drop(buffer);
13576
13577            if let Some(new_position) = new_position {
13578                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13579                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13580                    return;
13581                }
13582            }
13583
13584            nav_history.push(
13585                Some(NavigationData {
13586                    cursor_anchor,
13587                    cursor_position,
13588                    scroll_anchor: scroll_state,
13589                    scroll_top_row,
13590                }),
13591                cx,
13592            );
13593            cx.emit(EditorEvent::PushedToNavHistory {
13594                anchor: cursor_anchor,
13595                is_deactivate,
13596            })
13597        }
13598    }
13599
13600    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13602        let buffer = self.buffer.read(cx).snapshot(cx);
13603        let mut selection = self.selections.first::<usize>(cx);
13604        selection.set_head(buffer.len(), SelectionGoal::None);
13605        self.change_selections(Default::default(), window, cx, |s| {
13606            s.select(vec![selection]);
13607        });
13608    }
13609
13610    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13612        let end = self.buffer.read(cx).read(cx).len();
13613        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13614            s.select_ranges(vec![0..end]);
13615        });
13616    }
13617
13618    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13619        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13620        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13621        let mut selections = self.selections.all::<Point>(cx);
13622        let max_point = display_map.buffer_snapshot.max_point();
13623        for selection in &mut selections {
13624            let rows = selection.spanned_rows(true, &display_map);
13625            selection.start = Point::new(rows.start.0, 0);
13626            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13627            selection.reversed = false;
13628        }
13629        self.change_selections(Default::default(), window, cx, |s| {
13630            s.select(selections);
13631        });
13632    }
13633
13634    pub fn split_selection_into_lines(
13635        &mut self,
13636        action: &SplitSelectionIntoLines,
13637        window: &mut Window,
13638        cx: &mut Context<Self>,
13639    ) {
13640        let selections = self
13641            .selections
13642            .all::<Point>(cx)
13643            .into_iter()
13644            .map(|selection| selection.start..selection.end)
13645            .collect::<Vec<_>>();
13646        self.unfold_ranges(&selections, true, true, cx);
13647
13648        let mut new_selection_ranges = Vec::new();
13649        {
13650            let buffer = self.buffer.read(cx).read(cx);
13651            for selection in selections {
13652                for row in selection.start.row..selection.end.row {
13653                    let line_start = Point::new(row, 0);
13654                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13655
13656                    if action.keep_selections {
13657                        // Keep the selection range for each line
13658                        let selection_start = if row == selection.start.row {
13659                            selection.start
13660                        } else {
13661                            line_start
13662                        };
13663                        new_selection_ranges.push(selection_start..line_end);
13664                    } else {
13665                        // Collapse to cursor at end of line
13666                        new_selection_ranges.push(line_end..line_end);
13667                    }
13668                }
13669
13670                let is_multiline_selection = selection.start.row != selection.end.row;
13671                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13672                // so this action feels more ergonomic when paired with other selection operations
13673                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13674                if !should_skip_last {
13675                    if action.keep_selections {
13676                        if is_multiline_selection {
13677                            let line_start = Point::new(selection.end.row, 0);
13678                            new_selection_ranges.push(line_start..selection.end);
13679                        } else {
13680                            new_selection_ranges.push(selection.start..selection.end);
13681                        }
13682                    } else {
13683                        new_selection_ranges.push(selection.end..selection.end);
13684                    }
13685                }
13686            }
13687        }
13688        self.change_selections(Default::default(), window, cx, |s| {
13689            s.select_ranges(new_selection_ranges);
13690        });
13691    }
13692
13693    pub fn add_selection_above(
13694        &mut self,
13695        _: &AddSelectionAbove,
13696        window: &mut Window,
13697        cx: &mut Context<Self>,
13698    ) {
13699        self.add_selection(true, window, cx);
13700    }
13701
13702    pub fn add_selection_below(
13703        &mut self,
13704        _: &AddSelectionBelow,
13705        window: &mut Window,
13706        cx: &mut Context<Self>,
13707    ) {
13708        self.add_selection(false, window, cx);
13709    }
13710
13711    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13713
13714        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13715        let all_selections = self.selections.all::<Point>(cx);
13716        let text_layout_details = self.text_layout_details(window);
13717
13718        let (mut columnar_selections, new_selections_to_columnarize) = {
13719            if let Some(state) = self.add_selections_state.as_ref() {
13720                let columnar_selection_ids: HashSet<_> = state
13721                    .groups
13722                    .iter()
13723                    .flat_map(|group| group.stack.iter())
13724                    .copied()
13725                    .collect();
13726
13727                all_selections
13728                    .into_iter()
13729                    .partition(|s| columnar_selection_ids.contains(&s.id))
13730            } else {
13731                (Vec::new(), all_selections)
13732            }
13733        };
13734
13735        let mut state = self
13736            .add_selections_state
13737            .take()
13738            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13739
13740        for selection in new_selections_to_columnarize {
13741            let range = selection.display_range(&display_map).sorted();
13742            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13743            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13744            let positions = start_x.min(end_x)..start_x.max(end_x);
13745            let mut stack = Vec::new();
13746            for row in range.start.row().0..=range.end.row().0 {
13747                if let Some(selection) = self.selections.build_columnar_selection(
13748                    &display_map,
13749                    DisplayRow(row),
13750                    &positions,
13751                    selection.reversed,
13752                    &text_layout_details,
13753                ) {
13754                    stack.push(selection.id);
13755                    columnar_selections.push(selection);
13756                }
13757            }
13758            if !stack.is_empty() {
13759                if above {
13760                    stack.reverse();
13761                }
13762                state.groups.push(AddSelectionsGroup { above, stack });
13763            }
13764        }
13765
13766        let mut final_selections = Vec::new();
13767        let end_row = if above {
13768            DisplayRow(0)
13769        } else {
13770            display_map.max_point().row()
13771        };
13772
13773        let mut last_added_item_per_group = HashMap::default();
13774        for group in state.groups.iter_mut() {
13775            if let Some(last_id) = group.stack.last() {
13776                last_added_item_per_group.insert(*last_id, group);
13777            }
13778        }
13779
13780        for selection in columnar_selections {
13781            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13782                if above == group.above {
13783                    let range = selection.display_range(&display_map).sorted();
13784                    debug_assert_eq!(range.start.row(), range.end.row());
13785                    let mut row = range.start.row();
13786                    let positions =
13787                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13788                            px(start)..px(end)
13789                        } else {
13790                            let start_x =
13791                                display_map.x_for_display_point(range.start, &text_layout_details);
13792                            let end_x =
13793                                display_map.x_for_display_point(range.end, &text_layout_details);
13794                            start_x.min(end_x)..start_x.max(end_x)
13795                        };
13796
13797                    let mut maybe_new_selection = None;
13798                    while row != end_row {
13799                        if above {
13800                            row.0 -= 1;
13801                        } else {
13802                            row.0 += 1;
13803                        }
13804                        if let Some(new_selection) = self.selections.build_columnar_selection(
13805                            &display_map,
13806                            row,
13807                            &positions,
13808                            selection.reversed,
13809                            &text_layout_details,
13810                        ) {
13811                            maybe_new_selection = Some(new_selection);
13812                            break;
13813                        }
13814                    }
13815
13816                    if let Some(new_selection) = maybe_new_selection {
13817                        group.stack.push(new_selection.id);
13818                        if above {
13819                            final_selections.push(new_selection);
13820                            final_selections.push(selection);
13821                        } else {
13822                            final_selections.push(selection);
13823                            final_selections.push(new_selection);
13824                        }
13825                    } else {
13826                        final_selections.push(selection);
13827                    }
13828                } else {
13829                    group.stack.pop();
13830                }
13831            } else {
13832                final_selections.push(selection);
13833            }
13834        }
13835
13836        self.change_selections(Default::default(), window, cx, |s| {
13837            s.select(final_selections);
13838        });
13839
13840        let final_selection_ids: HashSet<_> = self
13841            .selections
13842            .all::<Point>(cx)
13843            .iter()
13844            .map(|s| s.id)
13845            .collect();
13846        state.groups.retain_mut(|group| {
13847            // selections might get merged above so we remove invalid items from stacks
13848            group.stack.retain(|id| final_selection_ids.contains(id));
13849
13850            // single selection in stack can be treated as initial state
13851            group.stack.len() > 1
13852        });
13853
13854        if !state.groups.is_empty() {
13855            self.add_selections_state = Some(state);
13856        }
13857    }
13858
13859    fn select_match_ranges(
13860        &mut self,
13861        range: Range<usize>,
13862        reversed: bool,
13863        replace_newest: bool,
13864        auto_scroll: Option<Autoscroll>,
13865        window: &mut Window,
13866        cx: &mut Context<Editor>,
13867    ) {
13868        self.unfold_ranges(
13869            std::slice::from_ref(&range),
13870            false,
13871            auto_scroll.is_some(),
13872            cx,
13873        );
13874        let effects = if let Some(scroll) = auto_scroll {
13875            SelectionEffects::scroll(scroll)
13876        } else {
13877            SelectionEffects::no_scroll()
13878        };
13879        self.change_selections(effects, window, cx, |s| {
13880            if replace_newest {
13881                s.delete(s.newest_anchor().id);
13882            }
13883            if reversed {
13884                s.insert_range(range.end..range.start);
13885            } else {
13886                s.insert_range(range);
13887            }
13888        });
13889    }
13890
13891    pub fn select_next_match_internal(
13892        &mut self,
13893        display_map: &DisplaySnapshot,
13894        replace_newest: bool,
13895        autoscroll: Option<Autoscroll>,
13896        window: &mut Window,
13897        cx: &mut Context<Self>,
13898    ) -> Result<()> {
13899        let buffer = &display_map.buffer_snapshot;
13900        let mut selections = self.selections.all::<usize>(cx);
13901        if let Some(mut select_next_state) = self.select_next_state.take() {
13902            let query = &select_next_state.query;
13903            if !select_next_state.done {
13904                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13905                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13906                let mut next_selected_range = None;
13907
13908                let bytes_after_last_selection =
13909                    buffer.bytes_in_range(last_selection.end..buffer.len());
13910                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13911                let query_matches = query
13912                    .stream_find_iter(bytes_after_last_selection)
13913                    .map(|result| (last_selection.end, result))
13914                    .chain(
13915                        query
13916                            .stream_find_iter(bytes_before_first_selection)
13917                            .map(|result| (0, result)),
13918                    );
13919
13920                for (start_offset, query_match) in query_matches {
13921                    let query_match = query_match.unwrap(); // can only fail due to I/O
13922                    let offset_range =
13923                        start_offset + query_match.start()..start_offset + query_match.end();
13924
13925                    if !select_next_state.wordwise
13926                        || (!buffer.is_inside_word(offset_range.start, false)
13927                            && !buffer.is_inside_word(offset_range.end, false))
13928                    {
13929                        // TODO: This is n^2, because we might check all the selections
13930                        if !selections
13931                            .iter()
13932                            .any(|selection| selection.range().overlaps(&offset_range))
13933                        {
13934                            next_selected_range = Some(offset_range);
13935                            break;
13936                        }
13937                    }
13938                }
13939
13940                if let Some(next_selected_range) = next_selected_range {
13941                    self.select_match_ranges(
13942                        next_selected_range,
13943                        last_selection.reversed,
13944                        replace_newest,
13945                        autoscroll,
13946                        window,
13947                        cx,
13948                    );
13949                } else {
13950                    select_next_state.done = true;
13951                }
13952            }
13953
13954            self.select_next_state = Some(select_next_state);
13955        } else {
13956            let mut only_carets = true;
13957            let mut same_text_selected = true;
13958            let mut selected_text = None;
13959
13960            let mut selections_iter = selections.iter().peekable();
13961            while let Some(selection) = selections_iter.next() {
13962                if selection.start != selection.end {
13963                    only_carets = false;
13964                }
13965
13966                if same_text_selected {
13967                    if selected_text.is_none() {
13968                        selected_text =
13969                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13970                    }
13971
13972                    if let Some(next_selection) = selections_iter.peek() {
13973                        if next_selection.range().len() == selection.range().len() {
13974                            let next_selected_text = buffer
13975                                .text_for_range(next_selection.range())
13976                                .collect::<String>();
13977                            if Some(next_selected_text) != selected_text {
13978                                same_text_selected = false;
13979                                selected_text = None;
13980                            }
13981                        } else {
13982                            same_text_selected = false;
13983                            selected_text = None;
13984                        }
13985                    }
13986                }
13987            }
13988
13989            if only_carets {
13990                for selection in &mut selections {
13991                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13992                    selection.start = word_range.start;
13993                    selection.end = word_range.end;
13994                    selection.goal = SelectionGoal::None;
13995                    selection.reversed = false;
13996                    self.select_match_ranges(
13997                        selection.start..selection.end,
13998                        selection.reversed,
13999                        replace_newest,
14000                        autoscroll,
14001                        window,
14002                        cx,
14003                    );
14004                }
14005
14006                if selections.len() == 1 {
14007                    let selection = selections
14008                        .last()
14009                        .expect("ensured that there's only one selection");
14010                    let query = buffer
14011                        .text_for_range(selection.start..selection.end)
14012                        .collect::<String>();
14013                    let is_empty = query.is_empty();
14014                    let select_state = SelectNextState {
14015                        query: AhoCorasick::new(&[query])?,
14016                        wordwise: true,
14017                        done: is_empty,
14018                    };
14019                    self.select_next_state = Some(select_state);
14020                } else {
14021                    self.select_next_state = None;
14022                }
14023            } else if let Some(selected_text) = selected_text {
14024                self.select_next_state = Some(SelectNextState {
14025                    query: AhoCorasick::new(&[selected_text])?,
14026                    wordwise: false,
14027                    done: false,
14028                });
14029                self.select_next_match_internal(
14030                    display_map,
14031                    replace_newest,
14032                    autoscroll,
14033                    window,
14034                    cx,
14035                )?;
14036            }
14037        }
14038        Ok(())
14039    }
14040
14041    pub fn select_all_matches(
14042        &mut self,
14043        _action: &SelectAllMatches,
14044        window: &mut Window,
14045        cx: &mut Context<Self>,
14046    ) -> Result<()> {
14047        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14048
14049        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14050
14051        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14052        let Some(select_next_state) = self.select_next_state.as_mut() else {
14053            return Ok(());
14054        };
14055        if select_next_state.done {
14056            return Ok(());
14057        }
14058
14059        let mut new_selections = Vec::new();
14060
14061        let reversed = self.selections.oldest::<usize>(cx).reversed;
14062        let buffer = &display_map.buffer_snapshot;
14063        let query_matches = select_next_state
14064            .query
14065            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14066
14067        for query_match in query_matches.into_iter() {
14068            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14069            let offset_range = if reversed {
14070                query_match.end()..query_match.start()
14071            } else {
14072                query_match.start()..query_match.end()
14073            };
14074
14075            if !select_next_state.wordwise
14076                || (!buffer.is_inside_word(offset_range.start, false)
14077                    && !buffer.is_inside_word(offset_range.end, false))
14078            {
14079                new_selections.push(offset_range.start..offset_range.end);
14080            }
14081        }
14082
14083        select_next_state.done = true;
14084
14085        if new_selections.is_empty() {
14086            log::error!("bug: new_selections is empty in select_all_matches");
14087            return Ok(());
14088        }
14089
14090        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14091        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14092            selections.select_ranges(new_selections)
14093        });
14094
14095        Ok(())
14096    }
14097
14098    pub fn select_next(
14099        &mut self,
14100        action: &SelectNext,
14101        window: &mut Window,
14102        cx: &mut Context<Self>,
14103    ) -> Result<()> {
14104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14105        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14106        self.select_next_match_internal(
14107            &display_map,
14108            action.replace_newest,
14109            Some(Autoscroll::newest()),
14110            window,
14111            cx,
14112        )?;
14113        Ok(())
14114    }
14115
14116    pub fn select_previous(
14117        &mut self,
14118        action: &SelectPrevious,
14119        window: &mut Window,
14120        cx: &mut Context<Self>,
14121    ) -> Result<()> {
14122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14123        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14124        let buffer = &display_map.buffer_snapshot;
14125        let mut selections = self.selections.all::<usize>(cx);
14126        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14127            let query = &select_prev_state.query;
14128            if !select_prev_state.done {
14129                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14130                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14131                let mut next_selected_range = None;
14132                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14133                let bytes_before_last_selection =
14134                    buffer.reversed_bytes_in_range(0..last_selection.start);
14135                let bytes_after_first_selection =
14136                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14137                let query_matches = query
14138                    .stream_find_iter(bytes_before_last_selection)
14139                    .map(|result| (last_selection.start, result))
14140                    .chain(
14141                        query
14142                            .stream_find_iter(bytes_after_first_selection)
14143                            .map(|result| (buffer.len(), result)),
14144                    );
14145                for (end_offset, query_match) in query_matches {
14146                    let query_match = query_match.unwrap(); // can only fail due to I/O
14147                    let offset_range =
14148                        end_offset - query_match.end()..end_offset - query_match.start();
14149
14150                    if !select_prev_state.wordwise
14151                        || (!buffer.is_inside_word(offset_range.start, false)
14152                            && !buffer.is_inside_word(offset_range.end, false))
14153                    {
14154                        next_selected_range = Some(offset_range);
14155                        break;
14156                    }
14157                }
14158
14159                if let Some(next_selected_range) = next_selected_range {
14160                    self.select_match_ranges(
14161                        next_selected_range,
14162                        last_selection.reversed,
14163                        action.replace_newest,
14164                        Some(Autoscroll::newest()),
14165                        window,
14166                        cx,
14167                    );
14168                } else {
14169                    select_prev_state.done = true;
14170                }
14171            }
14172
14173            self.select_prev_state = Some(select_prev_state);
14174        } else {
14175            let mut only_carets = true;
14176            let mut same_text_selected = true;
14177            let mut selected_text = None;
14178
14179            let mut selections_iter = selections.iter().peekable();
14180            while let Some(selection) = selections_iter.next() {
14181                if selection.start != selection.end {
14182                    only_carets = false;
14183                }
14184
14185                if same_text_selected {
14186                    if selected_text.is_none() {
14187                        selected_text =
14188                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14189                    }
14190
14191                    if let Some(next_selection) = selections_iter.peek() {
14192                        if next_selection.range().len() == selection.range().len() {
14193                            let next_selected_text = buffer
14194                                .text_for_range(next_selection.range())
14195                                .collect::<String>();
14196                            if Some(next_selected_text) != selected_text {
14197                                same_text_selected = false;
14198                                selected_text = None;
14199                            }
14200                        } else {
14201                            same_text_selected = false;
14202                            selected_text = None;
14203                        }
14204                    }
14205                }
14206            }
14207
14208            if only_carets {
14209                for selection in &mut selections {
14210                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14211                    selection.start = word_range.start;
14212                    selection.end = word_range.end;
14213                    selection.goal = SelectionGoal::None;
14214                    selection.reversed = false;
14215                    self.select_match_ranges(
14216                        selection.start..selection.end,
14217                        selection.reversed,
14218                        action.replace_newest,
14219                        Some(Autoscroll::newest()),
14220                        window,
14221                        cx,
14222                    );
14223                }
14224                if selections.len() == 1 {
14225                    let selection = selections
14226                        .last()
14227                        .expect("ensured that there's only one selection");
14228                    let query = buffer
14229                        .text_for_range(selection.start..selection.end)
14230                        .collect::<String>();
14231                    let is_empty = query.is_empty();
14232                    let select_state = SelectNextState {
14233                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14234                        wordwise: true,
14235                        done: is_empty,
14236                    };
14237                    self.select_prev_state = Some(select_state);
14238                } else {
14239                    self.select_prev_state = None;
14240                }
14241            } else if let Some(selected_text) = selected_text {
14242                self.select_prev_state = Some(SelectNextState {
14243                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14244                    wordwise: false,
14245                    done: false,
14246                });
14247                self.select_previous(action, window, cx)?;
14248            }
14249        }
14250        Ok(())
14251    }
14252
14253    pub fn find_next_match(
14254        &mut self,
14255        _: &FindNextMatch,
14256        window: &mut Window,
14257        cx: &mut Context<Self>,
14258    ) -> Result<()> {
14259        let selections = self.selections.disjoint_anchors();
14260        match selections.first() {
14261            Some(first) if selections.len() >= 2 => {
14262                self.change_selections(Default::default(), window, cx, |s| {
14263                    s.select_ranges([first.range()]);
14264                });
14265            }
14266            _ => self.select_next(
14267                &SelectNext {
14268                    replace_newest: true,
14269                },
14270                window,
14271                cx,
14272            )?,
14273        }
14274        Ok(())
14275    }
14276
14277    pub fn find_previous_match(
14278        &mut self,
14279        _: &FindPreviousMatch,
14280        window: &mut Window,
14281        cx: &mut Context<Self>,
14282    ) -> Result<()> {
14283        let selections = self.selections.disjoint_anchors();
14284        match selections.last() {
14285            Some(last) if selections.len() >= 2 => {
14286                self.change_selections(Default::default(), window, cx, |s| {
14287                    s.select_ranges([last.range()]);
14288                });
14289            }
14290            _ => self.select_previous(
14291                &SelectPrevious {
14292                    replace_newest: true,
14293                },
14294                window,
14295                cx,
14296            )?,
14297        }
14298        Ok(())
14299    }
14300
14301    pub fn toggle_comments(
14302        &mut self,
14303        action: &ToggleComments,
14304        window: &mut Window,
14305        cx: &mut Context<Self>,
14306    ) {
14307        if self.read_only(cx) {
14308            return;
14309        }
14310        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14311        let text_layout_details = &self.text_layout_details(window);
14312        self.transact(window, cx, |this, window, cx| {
14313            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14314            let mut edits = Vec::new();
14315            let mut selection_edit_ranges = Vec::new();
14316            let mut last_toggled_row = None;
14317            let snapshot = this.buffer.read(cx).read(cx);
14318            let empty_str: Arc<str> = Arc::default();
14319            let mut suffixes_inserted = Vec::new();
14320            let ignore_indent = action.ignore_indent;
14321
14322            fn comment_prefix_range(
14323                snapshot: &MultiBufferSnapshot,
14324                row: MultiBufferRow,
14325                comment_prefix: &str,
14326                comment_prefix_whitespace: &str,
14327                ignore_indent: bool,
14328            ) -> Range<Point> {
14329                let indent_size = if ignore_indent {
14330                    0
14331                } else {
14332                    snapshot.indent_size_for_line(row).len
14333                };
14334
14335                let start = Point::new(row.0, indent_size);
14336
14337                let mut line_bytes = snapshot
14338                    .bytes_in_range(start..snapshot.max_point())
14339                    .flatten()
14340                    .copied();
14341
14342                // If this line currently begins with the line comment prefix, then record
14343                // the range containing the prefix.
14344                if line_bytes
14345                    .by_ref()
14346                    .take(comment_prefix.len())
14347                    .eq(comment_prefix.bytes())
14348                {
14349                    // Include any whitespace that matches the comment prefix.
14350                    let matching_whitespace_len = line_bytes
14351                        .zip(comment_prefix_whitespace.bytes())
14352                        .take_while(|(a, b)| a == b)
14353                        .count() as u32;
14354                    let end = Point::new(
14355                        start.row,
14356                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14357                    );
14358                    start..end
14359                } else {
14360                    start..start
14361                }
14362            }
14363
14364            fn comment_suffix_range(
14365                snapshot: &MultiBufferSnapshot,
14366                row: MultiBufferRow,
14367                comment_suffix: &str,
14368                comment_suffix_has_leading_space: bool,
14369            ) -> Range<Point> {
14370                let end = Point::new(row.0, snapshot.line_len(row));
14371                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14372
14373                let mut line_end_bytes = snapshot
14374                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14375                    .flatten()
14376                    .copied();
14377
14378                let leading_space_len = if suffix_start_column > 0
14379                    && line_end_bytes.next() == Some(b' ')
14380                    && comment_suffix_has_leading_space
14381                {
14382                    1
14383                } else {
14384                    0
14385                };
14386
14387                // If this line currently begins with the line comment prefix, then record
14388                // the range containing the prefix.
14389                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14390                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14391                    start..end
14392                } else {
14393                    end..end
14394                }
14395            }
14396
14397            // TODO: Handle selections that cross excerpts
14398            for selection in &mut selections {
14399                let start_column = snapshot
14400                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14401                    .len;
14402                let language = if let Some(language) =
14403                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14404                {
14405                    language
14406                } else {
14407                    continue;
14408                };
14409
14410                selection_edit_ranges.clear();
14411
14412                // If multiple selections contain a given row, avoid processing that
14413                // row more than once.
14414                let mut start_row = MultiBufferRow(selection.start.row);
14415                if last_toggled_row == Some(start_row) {
14416                    start_row = start_row.next_row();
14417                }
14418                let end_row =
14419                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14420                        MultiBufferRow(selection.end.row - 1)
14421                    } else {
14422                        MultiBufferRow(selection.end.row)
14423                    };
14424                last_toggled_row = Some(end_row);
14425
14426                if start_row > end_row {
14427                    continue;
14428                }
14429
14430                // If the language has line comments, toggle those.
14431                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14432
14433                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14434                if ignore_indent {
14435                    full_comment_prefixes = full_comment_prefixes
14436                        .into_iter()
14437                        .map(|s| Arc::from(s.trim_end()))
14438                        .collect();
14439                }
14440
14441                if !full_comment_prefixes.is_empty() {
14442                    let first_prefix = full_comment_prefixes
14443                        .first()
14444                        .expect("prefixes is non-empty");
14445                    let prefix_trimmed_lengths = full_comment_prefixes
14446                        .iter()
14447                        .map(|p| p.trim_end_matches(' ').len())
14448                        .collect::<SmallVec<[usize; 4]>>();
14449
14450                    let mut all_selection_lines_are_comments = true;
14451
14452                    for row in start_row.0..=end_row.0 {
14453                        let row = MultiBufferRow(row);
14454                        if start_row < end_row && snapshot.is_line_blank(row) {
14455                            continue;
14456                        }
14457
14458                        let prefix_range = full_comment_prefixes
14459                            .iter()
14460                            .zip(prefix_trimmed_lengths.iter().copied())
14461                            .map(|(prefix, trimmed_prefix_len)| {
14462                                comment_prefix_range(
14463                                    snapshot.deref(),
14464                                    row,
14465                                    &prefix[..trimmed_prefix_len],
14466                                    &prefix[trimmed_prefix_len..],
14467                                    ignore_indent,
14468                                )
14469                            })
14470                            .max_by_key(|range| range.end.column - range.start.column)
14471                            .expect("prefixes is non-empty");
14472
14473                        if prefix_range.is_empty() {
14474                            all_selection_lines_are_comments = false;
14475                        }
14476
14477                        selection_edit_ranges.push(prefix_range);
14478                    }
14479
14480                    if all_selection_lines_are_comments {
14481                        edits.extend(
14482                            selection_edit_ranges
14483                                .iter()
14484                                .cloned()
14485                                .map(|range| (range, empty_str.clone())),
14486                        );
14487                    } else {
14488                        let min_column = selection_edit_ranges
14489                            .iter()
14490                            .map(|range| range.start.column)
14491                            .min()
14492                            .unwrap_or(0);
14493                        edits.extend(selection_edit_ranges.iter().map(|range| {
14494                            let position = Point::new(range.start.row, min_column);
14495                            (position..position, first_prefix.clone())
14496                        }));
14497                    }
14498                } else if let Some(BlockCommentConfig {
14499                    start: full_comment_prefix,
14500                    end: comment_suffix,
14501                    ..
14502                }) = language.block_comment()
14503                {
14504                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14505                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14506                    let prefix_range = comment_prefix_range(
14507                        snapshot.deref(),
14508                        start_row,
14509                        comment_prefix,
14510                        comment_prefix_whitespace,
14511                        ignore_indent,
14512                    );
14513                    let suffix_range = comment_suffix_range(
14514                        snapshot.deref(),
14515                        end_row,
14516                        comment_suffix.trim_start_matches(' '),
14517                        comment_suffix.starts_with(' '),
14518                    );
14519
14520                    if prefix_range.is_empty() || suffix_range.is_empty() {
14521                        edits.push((
14522                            prefix_range.start..prefix_range.start,
14523                            full_comment_prefix.clone(),
14524                        ));
14525                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14526                        suffixes_inserted.push((end_row, comment_suffix.len()));
14527                    } else {
14528                        edits.push((prefix_range, empty_str.clone()));
14529                        edits.push((suffix_range, empty_str.clone()));
14530                    }
14531                } else {
14532                    continue;
14533                }
14534            }
14535
14536            drop(snapshot);
14537            this.buffer.update(cx, |buffer, cx| {
14538                buffer.edit(edits, None, cx);
14539            });
14540
14541            // Adjust selections so that they end before any comment suffixes that
14542            // were inserted.
14543            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14544            let mut selections = this.selections.all::<Point>(cx);
14545            let snapshot = this.buffer.read(cx).read(cx);
14546            for selection in &mut selections {
14547                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14548                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14549                        Ordering::Less => {
14550                            suffixes_inserted.next();
14551                            continue;
14552                        }
14553                        Ordering::Greater => break,
14554                        Ordering::Equal => {
14555                            if selection.end.column == snapshot.line_len(row) {
14556                                if selection.is_empty() {
14557                                    selection.start.column -= suffix_len as u32;
14558                                }
14559                                selection.end.column -= suffix_len as u32;
14560                            }
14561                            break;
14562                        }
14563                    }
14564                }
14565            }
14566
14567            drop(snapshot);
14568            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14569
14570            let selections = this.selections.all::<Point>(cx);
14571            let selections_on_single_row = selections.windows(2).all(|selections| {
14572                selections[0].start.row == selections[1].start.row
14573                    && selections[0].end.row == selections[1].end.row
14574                    && selections[0].start.row == selections[0].end.row
14575            });
14576            let selections_selecting = selections
14577                .iter()
14578                .any(|selection| selection.start != selection.end);
14579            let advance_downwards = action.advance_downwards
14580                && selections_on_single_row
14581                && !selections_selecting
14582                && !matches!(this.mode, EditorMode::SingleLine);
14583
14584            if advance_downwards {
14585                let snapshot = this.buffer.read(cx).snapshot(cx);
14586
14587                this.change_selections(Default::default(), window, cx, |s| {
14588                    s.move_cursors_with(|display_snapshot, display_point, _| {
14589                        let mut point = display_point.to_point(display_snapshot);
14590                        point.row += 1;
14591                        point = snapshot.clip_point(point, Bias::Left);
14592                        let display_point = point.to_display_point(display_snapshot);
14593                        let goal = SelectionGoal::HorizontalPosition(
14594                            display_snapshot
14595                                .x_for_display_point(display_point, text_layout_details)
14596                                .into(),
14597                        );
14598                        (display_point, goal)
14599                    })
14600                });
14601            }
14602        });
14603    }
14604
14605    pub fn select_enclosing_symbol(
14606        &mut self,
14607        _: &SelectEnclosingSymbol,
14608        window: &mut Window,
14609        cx: &mut Context<Self>,
14610    ) {
14611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14612
14613        let buffer = self.buffer.read(cx).snapshot(cx);
14614        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14615
14616        fn update_selection(
14617            selection: &Selection<usize>,
14618            buffer_snap: &MultiBufferSnapshot,
14619        ) -> Option<Selection<usize>> {
14620            let cursor = selection.head();
14621            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14622            for symbol in symbols.iter().rev() {
14623                let start = symbol.range.start.to_offset(buffer_snap);
14624                let end = symbol.range.end.to_offset(buffer_snap);
14625                let new_range = start..end;
14626                if start < selection.start || end > selection.end {
14627                    return Some(Selection {
14628                        id: selection.id,
14629                        start: new_range.start,
14630                        end: new_range.end,
14631                        goal: SelectionGoal::None,
14632                        reversed: selection.reversed,
14633                    });
14634                }
14635            }
14636            None
14637        }
14638
14639        let mut selected_larger_symbol = false;
14640        let new_selections = old_selections
14641            .iter()
14642            .map(|selection| match update_selection(selection, &buffer) {
14643                Some(new_selection) => {
14644                    if new_selection.range() != selection.range() {
14645                        selected_larger_symbol = true;
14646                    }
14647                    new_selection
14648                }
14649                None => selection.clone(),
14650            })
14651            .collect::<Vec<_>>();
14652
14653        if selected_larger_symbol {
14654            self.change_selections(Default::default(), window, cx, |s| {
14655                s.select(new_selections);
14656            });
14657        }
14658    }
14659
14660    pub fn select_larger_syntax_node(
14661        &mut self,
14662        _: &SelectLargerSyntaxNode,
14663        window: &mut Window,
14664        cx: &mut Context<Self>,
14665    ) {
14666        let Some(visible_row_count) = self.visible_row_count() else {
14667            return;
14668        };
14669        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14670        if old_selections.is_empty() {
14671            return;
14672        }
14673
14674        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14675
14676        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14677        let buffer = self.buffer.read(cx).snapshot(cx);
14678
14679        let mut selected_larger_node = false;
14680        let mut new_selections = old_selections
14681            .iter()
14682            .map(|selection| {
14683                let old_range = selection.start..selection.end;
14684
14685                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14686                    // manually select word at selection
14687                    if ["string_content", "inline"].contains(&node.kind()) {
14688                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14689                        // ignore if word is already selected
14690                        if !word_range.is_empty() && old_range != word_range {
14691                            let (last_word_range, _) =
14692                                buffer.surrounding_word(old_range.end, false);
14693                            // only select word if start and end point belongs to same word
14694                            if word_range == last_word_range {
14695                                selected_larger_node = true;
14696                                return Selection {
14697                                    id: selection.id,
14698                                    start: word_range.start,
14699                                    end: word_range.end,
14700                                    goal: SelectionGoal::None,
14701                                    reversed: selection.reversed,
14702                                };
14703                            }
14704                        }
14705                    }
14706                }
14707
14708                let mut new_range = old_range.clone();
14709                while let Some((_node, containing_range)) =
14710                    buffer.syntax_ancestor(new_range.clone())
14711                {
14712                    new_range = match containing_range {
14713                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14714                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14715                    };
14716                    if !display_map.intersects_fold(new_range.start)
14717                        && !display_map.intersects_fold(new_range.end)
14718                    {
14719                        break;
14720                    }
14721                }
14722
14723                selected_larger_node |= new_range != old_range;
14724                Selection {
14725                    id: selection.id,
14726                    start: new_range.start,
14727                    end: new_range.end,
14728                    goal: SelectionGoal::None,
14729                    reversed: selection.reversed,
14730                }
14731            })
14732            .collect::<Vec<_>>();
14733
14734        if !selected_larger_node {
14735            return; // don't put this call in the history
14736        }
14737
14738        // scroll based on transformation done to the last selection created by the user
14739        let (last_old, last_new) = old_selections
14740            .last()
14741            .zip(new_selections.last().cloned())
14742            .expect("old_selections isn't empty");
14743
14744        // revert selection
14745        let is_selection_reversed = {
14746            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14747            new_selections.last_mut().expect("checked above").reversed =
14748                should_newest_selection_be_reversed;
14749            should_newest_selection_be_reversed
14750        };
14751
14752        if selected_larger_node {
14753            self.select_syntax_node_history.disable_clearing = true;
14754            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14755                s.select(new_selections.clone());
14756            });
14757            self.select_syntax_node_history.disable_clearing = false;
14758        }
14759
14760        let start_row = last_new.start.to_display_point(&display_map).row().0;
14761        let end_row = last_new.end.to_display_point(&display_map).row().0;
14762        let selection_height = end_row - start_row + 1;
14763        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14764
14765        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14766        let scroll_behavior = if fits_on_the_screen {
14767            self.request_autoscroll(Autoscroll::fit(), cx);
14768            SelectSyntaxNodeScrollBehavior::FitSelection
14769        } else if is_selection_reversed {
14770            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14771            SelectSyntaxNodeScrollBehavior::CursorTop
14772        } else {
14773            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14774            SelectSyntaxNodeScrollBehavior::CursorBottom
14775        };
14776
14777        self.select_syntax_node_history.push((
14778            old_selections,
14779            scroll_behavior,
14780            is_selection_reversed,
14781        ));
14782    }
14783
14784    pub fn select_smaller_syntax_node(
14785        &mut self,
14786        _: &SelectSmallerSyntaxNode,
14787        window: &mut Window,
14788        cx: &mut Context<Self>,
14789    ) {
14790        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14791
14792        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14793            self.select_syntax_node_history.pop()
14794        {
14795            if let Some(selection) = selections.last_mut() {
14796                selection.reversed = is_selection_reversed;
14797            }
14798
14799            self.select_syntax_node_history.disable_clearing = true;
14800            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14801                s.select(selections.to_vec());
14802            });
14803            self.select_syntax_node_history.disable_clearing = false;
14804
14805            match scroll_behavior {
14806                SelectSyntaxNodeScrollBehavior::CursorTop => {
14807                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14808                }
14809                SelectSyntaxNodeScrollBehavior::FitSelection => {
14810                    self.request_autoscroll(Autoscroll::fit(), cx);
14811                }
14812                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14813                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14814                }
14815            }
14816        }
14817    }
14818
14819    pub fn unwrap_syntax_node(
14820        &mut self,
14821        _: &UnwrapSyntaxNode,
14822        window: &mut Window,
14823        cx: &mut Context<Self>,
14824    ) {
14825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14826
14827        let buffer = self.buffer.read(cx).snapshot(cx);
14828        let selections = self
14829            .selections
14830            .all::<usize>(cx)
14831            .into_iter()
14832            // subtracting the offset requires sorting
14833            .sorted_by_key(|i| i.start);
14834
14835        let full_edits = selections
14836            .into_iter()
14837            .filter_map(|selection| {
14838                // Only requires two branches once if-let-chains stabilize (#53667)
14839                let child = if !selection.is_empty() {
14840                    selection.range()
14841                } else if let Some((_, ancestor_range)) =
14842                    buffer.syntax_ancestor(selection.start..selection.end)
14843                {
14844                    match ancestor_range {
14845                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14846                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14847                    }
14848                } else {
14849                    selection.range()
14850                };
14851
14852                let mut parent = child.clone();
14853                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14854                    parent = match ancestor_range {
14855                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14856                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14857                    };
14858                    if parent.start < child.start || parent.end > child.end {
14859                        break;
14860                    }
14861                }
14862
14863                if parent == child {
14864                    return None;
14865                }
14866                let text = buffer.text_for_range(child).collect::<String>();
14867                Some((selection.id, parent, text))
14868            })
14869            .collect::<Vec<_>>();
14870
14871        self.transact(window, cx, |this, window, cx| {
14872            this.buffer.update(cx, |buffer, cx| {
14873                buffer.edit(
14874                    full_edits
14875                        .iter()
14876                        .map(|(_, p, t)| (p.clone(), t.clone()))
14877                        .collect::<Vec<_>>(),
14878                    None,
14879                    cx,
14880                );
14881            });
14882            this.change_selections(Default::default(), window, cx, |s| {
14883                let mut offset = 0;
14884                let mut selections = vec![];
14885                for (id, parent, text) in full_edits {
14886                    let start = parent.start - offset;
14887                    offset += parent.len() - text.len();
14888                    selections.push(Selection {
14889                        id,
14890                        start,
14891                        end: start + text.len(),
14892                        reversed: false,
14893                        goal: Default::default(),
14894                    });
14895                }
14896                s.select(selections);
14897            });
14898        });
14899    }
14900
14901    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14902        if !EditorSettings::get_global(cx).gutter.runnables {
14903            self.clear_tasks();
14904            return Task::ready(());
14905        }
14906        let project = self.project().map(Entity::downgrade);
14907        let task_sources = self.lsp_task_sources(cx);
14908        let multi_buffer = self.buffer.downgrade();
14909        cx.spawn_in(window, async move |editor, cx| {
14910            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14911            let Some(project) = project.and_then(|p| p.upgrade()) else {
14912                return;
14913            };
14914            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14915                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14916            }) else {
14917                return;
14918            };
14919
14920            let hide_runnables = project
14921                .update(cx, |project, _| project.is_via_collab())
14922                .unwrap_or(true);
14923            if hide_runnables {
14924                return;
14925            }
14926            let new_rows =
14927                cx.background_spawn({
14928                    let snapshot = display_snapshot.clone();
14929                    async move {
14930                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14931                    }
14932                })
14933                    .await;
14934            let Ok(lsp_tasks) =
14935                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14936            else {
14937                return;
14938            };
14939            let lsp_tasks = lsp_tasks.await;
14940
14941            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14942                lsp_tasks
14943                    .into_iter()
14944                    .flat_map(|(kind, tasks)| {
14945                        tasks.into_iter().filter_map(move |(location, task)| {
14946                            Some((kind.clone(), location?, task))
14947                        })
14948                    })
14949                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14950                        let buffer = location.target.buffer;
14951                        let buffer_snapshot = buffer.read(cx).snapshot();
14952                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14953                            |(excerpt_id, snapshot, _)| {
14954                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14955                                    display_snapshot
14956                                        .buffer_snapshot
14957                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14958                                } else {
14959                                    None
14960                                }
14961                            },
14962                        );
14963                        if let Some(offset) = offset {
14964                            let task_buffer_range =
14965                                location.target.range.to_point(&buffer_snapshot);
14966                            let context_buffer_range =
14967                                task_buffer_range.to_offset(&buffer_snapshot);
14968                            let context_range = BufferOffset(context_buffer_range.start)
14969                                ..BufferOffset(context_buffer_range.end);
14970
14971                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14972                                .or_insert_with(|| RunnableTasks {
14973                                    templates: Vec::new(),
14974                                    offset,
14975                                    column: task_buffer_range.start.column,
14976                                    extra_variables: HashMap::default(),
14977                                    context_range,
14978                                })
14979                                .templates
14980                                .push((kind, task.original_task().clone()));
14981                        }
14982
14983                        acc
14984                    })
14985            }) else {
14986                return;
14987            };
14988
14989            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14990                buffer.language_settings(cx).tasks.prefer_lsp
14991            }) else {
14992                return;
14993            };
14994
14995            let rows = Self::runnable_rows(
14996                project,
14997                display_snapshot,
14998                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14999                new_rows,
15000                cx.clone(),
15001            )
15002            .await;
15003            editor
15004                .update(cx, |editor, _| {
15005                    editor.clear_tasks();
15006                    for (key, mut value) in rows {
15007                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15008                            value.templates.extend(lsp_tasks.templates);
15009                        }
15010
15011                        editor.insert_tasks(key, value);
15012                    }
15013                    for (key, value) in lsp_tasks_by_rows {
15014                        editor.insert_tasks(key, value);
15015                    }
15016                })
15017                .ok();
15018        })
15019    }
15020    fn fetch_runnable_ranges(
15021        snapshot: &DisplaySnapshot,
15022        range: Range<Anchor>,
15023    ) -> Vec<language::RunnableRange> {
15024        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15025    }
15026
15027    fn runnable_rows(
15028        project: Entity<Project>,
15029        snapshot: DisplaySnapshot,
15030        prefer_lsp: bool,
15031        runnable_ranges: Vec<RunnableRange>,
15032        cx: AsyncWindowContext,
15033    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15034        cx.spawn(async move |cx| {
15035            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15036            for mut runnable in runnable_ranges {
15037                let Some(tasks) = cx
15038                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15039                    .ok()
15040                else {
15041                    continue;
15042                };
15043                let mut tasks = tasks.await;
15044
15045                if prefer_lsp {
15046                    tasks.retain(|(task_kind, _)| {
15047                        !matches!(task_kind, TaskSourceKind::Language { .. })
15048                    });
15049                }
15050                if tasks.is_empty() {
15051                    continue;
15052                }
15053
15054                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15055                let Some(row) = snapshot
15056                    .buffer_snapshot
15057                    .buffer_line_for_row(MultiBufferRow(point.row))
15058                    .map(|(_, range)| range.start.row)
15059                else {
15060                    continue;
15061                };
15062
15063                let context_range =
15064                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15065                runnable_rows.push((
15066                    (runnable.buffer_id, row),
15067                    RunnableTasks {
15068                        templates: tasks,
15069                        offset: snapshot
15070                            .buffer_snapshot
15071                            .anchor_before(runnable.run_range.start),
15072                        context_range,
15073                        column: point.column,
15074                        extra_variables: runnable.extra_captures,
15075                    },
15076                ));
15077            }
15078            runnable_rows
15079        })
15080    }
15081
15082    fn templates_with_tags(
15083        project: &Entity<Project>,
15084        runnable: &mut Runnable,
15085        cx: &mut App,
15086    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15087        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15088            let (worktree_id, file) = project
15089                .buffer_for_id(runnable.buffer, cx)
15090                .and_then(|buffer| buffer.read(cx).file())
15091                .map(|file| (file.worktree_id(cx), file.clone()))
15092                .unzip();
15093
15094            (
15095                project.task_store().read(cx).task_inventory().cloned(),
15096                worktree_id,
15097                file,
15098            )
15099        });
15100
15101        let tags = mem::take(&mut runnable.tags);
15102        let language = runnable.language.clone();
15103        cx.spawn(async move |cx| {
15104            let mut templates_with_tags = Vec::new();
15105            if let Some(inventory) = inventory {
15106                for RunnableTag(tag) in tags {
15107                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15108                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15109                    }) else {
15110                        return templates_with_tags;
15111                    };
15112                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15113                        move |(_, template)| {
15114                            template.tags.iter().any(|source_tag| source_tag == &tag)
15115                        },
15116                    ));
15117                }
15118            }
15119            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15120
15121            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15122                // Strongest source wins; if we have worktree tag binding, prefer that to
15123                // global and language bindings;
15124                // if we have a global binding, prefer that to language binding.
15125                let first_mismatch = templates_with_tags
15126                    .iter()
15127                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15128                if let Some(index) = first_mismatch {
15129                    templates_with_tags.truncate(index);
15130                }
15131            }
15132
15133            templates_with_tags
15134        })
15135    }
15136
15137    pub fn move_to_enclosing_bracket(
15138        &mut self,
15139        _: &MoveToEnclosingBracket,
15140        window: &mut Window,
15141        cx: &mut Context<Self>,
15142    ) {
15143        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15144        self.change_selections(Default::default(), window, cx, |s| {
15145            s.move_offsets_with(|snapshot, selection| {
15146                let Some(enclosing_bracket_ranges) =
15147                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15148                else {
15149                    return;
15150                };
15151
15152                let mut best_length = usize::MAX;
15153                let mut best_inside = false;
15154                let mut best_in_bracket_range = false;
15155                let mut best_destination = None;
15156                for (open, close) in enclosing_bracket_ranges {
15157                    let close = close.to_inclusive();
15158                    let length = close.end() - open.start;
15159                    let inside = selection.start >= open.end && selection.end <= *close.start();
15160                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15161                        || close.contains(&selection.head());
15162
15163                    // If best is next to a bracket and current isn't, skip
15164                    if !in_bracket_range && best_in_bracket_range {
15165                        continue;
15166                    }
15167
15168                    // Prefer smaller lengths unless best is inside and current isn't
15169                    if length > best_length && (best_inside || !inside) {
15170                        continue;
15171                    }
15172
15173                    best_length = length;
15174                    best_inside = inside;
15175                    best_in_bracket_range = in_bracket_range;
15176                    best_destination = Some(
15177                        if close.contains(&selection.start) && close.contains(&selection.end) {
15178                            if inside { open.end } else { open.start }
15179                        } else if inside {
15180                            *close.start()
15181                        } else {
15182                            *close.end()
15183                        },
15184                    );
15185                }
15186
15187                if let Some(destination) = best_destination {
15188                    selection.collapse_to(destination, SelectionGoal::None);
15189                }
15190            })
15191        });
15192    }
15193
15194    pub fn undo_selection(
15195        &mut self,
15196        _: &UndoSelection,
15197        window: &mut Window,
15198        cx: &mut Context<Self>,
15199    ) {
15200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15201        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15202            self.selection_history.mode = SelectionHistoryMode::Undoing;
15203            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15204                this.end_selection(window, cx);
15205                this.change_selections(
15206                    SelectionEffects::scroll(Autoscroll::newest()),
15207                    window,
15208                    cx,
15209                    |s| s.select_anchors(entry.selections.to_vec()),
15210                );
15211            });
15212            self.selection_history.mode = SelectionHistoryMode::Normal;
15213
15214            self.select_next_state = entry.select_next_state;
15215            self.select_prev_state = entry.select_prev_state;
15216            self.add_selections_state = entry.add_selections_state;
15217        }
15218    }
15219
15220    pub fn redo_selection(
15221        &mut self,
15222        _: &RedoSelection,
15223        window: &mut Window,
15224        cx: &mut Context<Self>,
15225    ) {
15226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15227        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15228            self.selection_history.mode = SelectionHistoryMode::Redoing;
15229            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15230                this.end_selection(window, cx);
15231                this.change_selections(
15232                    SelectionEffects::scroll(Autoscroll::newest()),
15233                    window,
15234                    cx,
15235                    |s| s.select_anchors(entry.selections.to_vec()),
15236                );
15237            });
15238            self.selection_history.mode = SelectionHistoryMode::Normal;
15239
15240            self.select_next_state = entry.select_next_state;
15241            self.select_prev_state = entry.select_prev_state;
15242            self.add_selections_state = entry.add_selections_state;
15243        }
15244    }
15245
15246    pub fn expand_excerpts(
15247        &mut self,
15248        action: &ExpandExcerpts,
15249        _: &mut Window,
15250        cx: &mut Context<Self>,
15251    ) {
15252        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15253    }
15254
15255    pub fn expand_excerpts_down(
15256        &mut self,
15257        action: &ExpandExcerptsDown,
15258        _: &mut Window,
15259        cx: &mut Context<Self>,
15260    ) {
15261        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15262    }
15263
15264    pub fn expand_excerpts_up(
15265        &mut self,
15266        action: &ExpandExcerptsUp,
15267        _: &mut Window,
15268        cx: &mut Context<Self>,
15269    ) {
15270        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15271    }
15272
15273    pub fn expand_excerpts_for_direction(
15274        &mut self,
15275        lines: u32,
15276        direction: ExpandExcerptDirection,
15277
15278        cx: &mut Context<Self>,
15279    ) {
15280        let selections = self.selections.disjoint_anchors();
15281
15282        let lines = if lines == 0 {
15283            EditorSettings::get_global(cx).expand_excerpt_lines
15284        } else {
15285            lines
15286        };
15287
15288        self.buffer.update(cx, |buffer, cx| {
15289            let snapshot = buffer.snapshot(cx);
15290            let mut excerpt_ids = selections
15291                .iter()
15292                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15293                .collect::<Vec<_>>();
15294            excerpt_ids.sort();
15295            excerpt_ids.dedup();
15296            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15297        })
15298    }
15299
15300    pub fn expand_excerpt(
15301        &mut self,
15302        excerpt: ExcerptId,
15303        direction: ExpandExcerptDirection,
15304        window: &mut Window,
15305        cx: &mut Context<Self>,
15306    ) {
15307        let current_scroll_position = self.scroll_position(cx);
15308        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15309        let mut should_scroll_up = false;
15310
15311        if direction == ExpandExcerptDirection::Down {
15312            let multi_buffer = self.buffer.read(cx);
15313            let snapshot = multi_buffer.snapshot(cx);
15314            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15315                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15316                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15317            {
15318                let buffer_snapshot = buffer.read(cx).snapshot();
15319                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15320                let last_row = buffer_snapshot.max_point().row;
15321                let lines_below = last_row.saturating_sub(excerpt_end_row);
15322                should_scroll_up = lines_below >= lines_to_expand;
15323            }
15324        }
15325
15326        self.buffer.update(cx, |buffer, cx| {
15327            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15328        });
15329
15330        if should_scroll_up {
15331            let new_scroll_position =
15332                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15333            self.set_scroll_position(new_scroll_position, window, cx);
15334        }
15335    }
15336
15337    pub fn go_to_singleton_buffer_point(
15338        &mut self,
15339        point: Point,
15340        window: &mut Window,
15341        cx: &mut Context<Self>,
15342    ) {
15343        self.go_to_singleton_buffer_range(point..point, window, cx);
15344    }
15345
15346    pub fn go_to_singleton_buffer_range(
15347        &mut self,
15348        range: Range<Point>,
15349        window: &mut Window,
15350        cx: &mut Context<Self>,
15351    ) {
15352        let multibuffer = self.buffer().read(cx);
15353        let Some(buffer) = multibuffer.as_singleton() else {
15354            return;
15355        };
15356        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15357            return;
15358        };
15359        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15360            return;
15361        };
15362        self.change_selections(
15363            SelectionEffects::default().nav_history(true),
15364            window,
15365            cx,
15366            |s| s.select_anchor_ranges([start..end]),
15367        );
15368    }
15369
15370    pub fn go_to_diagnostic(
15371        &mut self,
15372        action: &GoToDiagnostic,
15373        window: &mut Window,
15374        cx: &mut Context<Self>,
15375    ) {
15376        if !self.diagnostics_enabled() {
15377            return;
15378        }
15379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15380        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15381    }
15382
15383    pub fn go_to_prev_diagnostic(
15384        &mut self,
15385        action: &GoToPreviousDiagnostic,
15386        window: &mut Window,
15387        cx: &mut Context<Self>,
15388    ) {
15389        if !self.diagnostics_enabled() {
15390            return;
15391        }
15392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15393        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15394    }
15395
15396    pub fn go_to_diagnostic_impl(
15397        &mut self,
15398        direction: Direction,
15399        severity: GoToDiagnosticSeverityFilter,
15400        window: &mut Window,
15401        cx: &mut Context<Self>,
15402    ) {
15403        let buffer = self.buffer.read(cx).snapshot(cx);
15404        let selection = self.selections.newest::<usize>(cx);
15405
15406        let mut active_group_id = None;
15407        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15408            && active_group.active_range.start.to_offset(&buffer) == selection.start
15409        {
15410            active_group_id = Some(active_group.group_id);
15411        }
15412
15413        fn filtered(
15414            snapshot: EditorSnapshot,
15415            severity: GoToDiagnosticSeverityFilter,
15416            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15417        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15418            diagnostics
15419                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15420                .filter(|entry| entry.range.start != entry.range.end)
15421                .filter(|entry| !entry.diagnostic.is_unnecessary)
15422                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15423        }
15424
15425        let snapshot = self.snapshot(window, cx);
15426        let before = filtered(
15427            snapshot.clone(),
15428            severity,
15429            buffer
15430                .diagnostics_in_range(0..selection.start)
15431                .filter(|entry| entry.range.start <= selection.start),
15432        );
15433        let after = filtered(
15434            snapshot,
15435            severity,
15436            buffer
15437                .diagnostics_in_range(selection.start..buffer.len())
15438                .filter(|entry| entry.range.start >= selection.start),
15439        );
15440
15441        let mut found: Option<DiagnosticEntry<usize>> = None;
15442        if direction == Direction::Prev {
15443            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15444            {
15445                for diagnostic in prev_diagnostics.into_iter().rev() {
15446                    if diagnostic.range.start != selection.start
15447                        || active_group_id
15448                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15449                    {
15450                        found = Some(diagnostic);
15451                        break 'outer;
15452                    }
15453                }
15454            }
15455        } else {
15456            for diagnostic in after.chain(before) {
15457                if diagnostic.range.start != selection.start
15458                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15459                {
15460                    found = Some(diagnostic);
15461                    break;
15462                }
15463            }
15464        }
15465        let Some(next_diagnostic) = found else {
15466            return;
15467        };
15468
15469        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15470        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15471            return;
15472        };
15473        self.change_selections(Default::default(), window, cx, |s| {
15474            s.select_ranges(vec![
15475                next_diagnostic.range.start..next_diagnostic.range.start,
15476            ])
15477        });
15478        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15479        self.refresh_edit_prediction(false, true, window, cx);
15480    }
15481
15482    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15483        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15484        let snapshot = self.snapshot(window, cx);
15485        let selection = self.selections.newest::<Point>(cx);
15486        self.go_to_hunk_before_or_after_position(
15487            &snapshot,
15488            selection.head(),
15489            Direction::Next,
15490            window,
15491            cx,
15492        );
15493    }
15494
15495    pub fn go_to_hunk_before_or_after_position(
15496        &mut self,
15497        snapshot: &EditorSnapshot,
15498        position: Point,
15499        direction: Direction,
15500        window: &mut Window,
15501        cx: &mut Context<Editor>,
15502    ) {
15503        let row = if direction == Direction::Next {
15504            self.hunk_after_position(snapshot, position)
15505                .map(|hunk| hunk.row_range.start)
15506        } else {
15507            self.hunk_before_position(snapshot, position)
15508        };
15509
15510        if let Some(row) = row {
15511            let destination = Point::new(row.0, 0);
15512            let autoscroll = Autoscroll::center();
15513
15514            self.unfold_ranges(&[destination..destination], false, false, cx);
15515            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15516                s.select_ranges([destination..destination]);
15517            });
15518        }
15519    }
15520
15521    fn hunk_after_position(
15522        &mut self,
15523        snapshot: &EditorSnapshot,
15524        position: Point,
15525    ) -> Option<MultiBufferDiffHunk> {
15526        snapshot
15527            .buffer_snapshot
15528            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15529            .find(|hunk| hunk.row_range.start.0 > position.row)
15530            .or_else(|| {
15531                snapshot
15532                    .buffer_snapshot
15533                    .diff_hunks_in_range(Point::zero()..position)
15534                    .find(|hunk| hunk.row_range.end.0 < position.row)
15535            })
15536    }
15537
15538    fn go_to_prev_hunk(
15539        &mut self,
15540        _: &GoToPreviousHunk,
15541        window: &mut Window,
15542        cx: &mut Context<Self>,
15543    ) {
15544        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15545        let snapshot = self.snapshot(window, cx);
15546        let selection = self.selections.newest::<Point>(cx);
15547        self.go_to_hunk_before_or_after_position(
15548            &snapshot,
15549            selection.head(),
15550            Direction::Prev,
15551            window,
15552            cx,
15553        );
15554    }
15555
15556    fn hunk_before_position(
15557        &mut self,
15558        snapshot: &EditorSnapshot,
15559        position: Point,
15560    ) -> Option<MultiBufferRow> {
15561        snapshot
15562            .buffer_snapshot
15563            .diff_hunk_before(position)
15564            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15565    }
15566
15567    fn go_to_next_change(
15568        &mut self,
15569        _: &GoToNextChange,
15570        window: &mut Window,
15571        cx: &mut Context<Self>,
15572    ) {
15573        if let Some(selections) = self
15574            .change_list
15575            .next_change(1, Direction::Next)
15576            .map(|s| s.to_vec())
15577        {
15578            self.change_selections(Default::default(), window, cx, |s| {
15579                let map = s.display_map();
15580                s.select_display_ranges(selections.iter().map(|a| {
15581                    let point = a.to_display_point(&map);
15582                    point..point
15583                }))
15584            })
15585        }
15586    }
15587
15588    fn go_to_previous_change(
15589        &mut self,
15590        _: &GoToPreviousChange,
15591        window: &mut Window,
15592        cx: &mut Context<Self>,
15593    ) {
15594        if let Some(selections) = self
15595            .change_list
15596            .next_change(1, Direction::Prev)
15597            .map(|s| s.to_vec())
15598        {
15599            self.change_selections(Default::default(), window, cx, |s| {
15600                let map = s.display_map();
15601                s.select_display_ranges(selections.iter().map(|a| {
15602                    let point = a.to_display_point(&map);
15603                    point..point
15604                }))
15605            })
15606        }
15607    }
15608
15609    fn go_to_line<T: 'static>(
15610        &mut self,
15611        position: Anchor,
15612        highlight_color: Option<Hsla>,
15613        window: &mut Window,
15614        cx: &mut Context<Self>,
15615    ) {
15616        let snapshot = self.snapshot(window, cx).display_snapshot;
15617        let position = position.to_point(&snapshot.buffer_snapshot);
15618        let start = snapshot
15619            .buffer_snapshot
15620            .clip_point(Point::new(position.row, 0), Bias::Left);
15621        let end = start + Point::new(1, 0);
15622        let start = snapshot.buffer_snapshot.anchor_before(start);
15623        let end = snapshot.buffer_snapshot.anchor_before(end);
15624
15625        self.highlight_rows::<T>(
15626            start..end,
15627            highlight_color
15628                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15629            Default::default(),
15630            cx,
15631        );
15632
15633        if self.buffer.read(cx).is_singleton() {
15634            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15635        }
15636    }
15637
15638    pub fn go_to_definition(
15639        &mut self,
15640        _: &GoToDefinition,
15641        window: &mut Window,
15642        cx: &mut Context<Self>,
15643    ) -> Task<Result<Navigated>> {
15644        let definition =
15645            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15646        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15647        cx.spawn_in(window, async move |editor, cx| {
15648            if definition.await? == Navigated::Yes {
15649                return Ok(Navigated::Yes);
15650            }
15651            match fallback_strategy {
15652                GoToDefinitionFallback::None => Ok(Navigated::No),
15653                GoToDefinitionFallback::FindAllReferences => {
15654                    match editor.update_in(cx, |editor, window, cx| {
15655                        editor.find_all_references(&FindAllReferences, window, cx)
15656                    })? {
15657                        Some(references) => references.await,
15658                        None => Ok(Navigated::No),
15659                    }
15660                }
15661            }
15662        })
15663    }
15664
15665    pub fn go_to_declaration(
15666        &mut self,
15667        _: &GoToDeclaration,
15668        window: &mut Window,
15669        cx: &mut Context<Self>,
15670    ) -> Task<Result<Navigated>> {
15671        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15672    }
15673
15674    pub fn go_to_declaration_split(
15675        &mut self,
15676        _: &GoToDeclaration,
15677        window: &mut Window,
15678        cx: &mut Context<Self>,
15679    ) -> Task<Result<Navigated>> {
15680        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15681    }
15682
15683    pub fn go_to_implementation(
15684        &mut self,
15685        _: &GoToImplementation,
15686        window: &mut Window,
15687        cx: &mut Context<Self>,
15688    ) -> Task<Result<Navigated>> {
15689        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15690    }
15691
15692    pub fn go_to_implementation_split(
15693        &mut self,
15694        _: &GoToImplementationSplit,
15695        window: &mut Window,
15696        cx: &mut Context<Self>,
15697    ) -> Task<Result<Navigated>> {
15698        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15699    }
15700
15701    pub fn go_to_type_definition(
15702        &mut self,
15703        _: &GoToTypeDefinition,
15704        window: &mut Window,
15705        cx: &mut Context<Self>,
15706    ) -> Task<Result<Navigated>> {
15707        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15708    }
15709
15710    pub fn go_to_definition_split(
15711        &mut self,
15712        _: &GoToDefinitionSplit,
15713        window: &mut Window,
15714        cx: &mut Context<Self>,
15715    ) -> Task<Result<Navigated>> {
15716        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15717    }
15718
15719    pub fn go_to_type_definition_split(
15720        &mut self,
15721        _: &GoToTypeDefinitionSplit,
15722        window: &mut Window,
15723        cx: &mut Context<Self>,
15724    ) -> Task<Result<Navigated>> {
15725        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15726    }
15727
15728    fn go_to_definition_of_kind(
15729        &mut self,
15730        kind: GotoDefinitionKind,
15731        split: bool,
15732        window: &mut Window,
15733        cx: &mut Context<Self>,
15734    ) -> Task<Result<Navigated>> {
15735        let Some(provider) = self.semantics_provider.clone() else {
15736            return Task::ready(Ok(Navigated::No));
15737        };
15738        let head = self.selections.newest::<usize>(cx).head();
15739        let buffer = self.buffer.read(cx);
15740        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15741            return Task::ready(Ok(Navigated::No));
15742        };
15743        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15744            return Task::ready(Ok(Navigated::No));
15745        };
15746
15747        cx.spawn_in(window, async move |editor, cx| {
15748            let Some(definitions) = definitions.await? else {
15749                return Ok(Navigated::No);
15750            };
15751            let navigated = editor
15752                .update_in(cx, |editor, window, cx| {
15753                    editor.navigate_to_hover_links(
15754                        Some(kind),
15755                        definitions
15756                            .into_iter()
15757                            .filter(|location| {
15758                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15759                            })
15760                            .map(HoverLink::Text)
15761                            .collect::<Vec<_>>(),
15762                        split,
15763                        window,
15764                        cx,
15765                    )
15766                })?
15767                .await?;
15768            anyhow::Ok(navigated)
15769        })
15770    }
15771
15772    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15773        let selection = self.selections.newest_anchor();
15774        let head = selection.head();
15775        let tail = selection.tail();
15776
15777        let Some((buffer, start_position)) =
15778            self.buffer.read(cx).text_anchor_for_position(head, cx)
15779        else {
15780            return;
15781        };
15782
15783        let end_position = if head != tail {
15784            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15785                return;
15786            };
15787            Some(pos)
15788        } else {
15789            None
15790        };
15791
15792        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15793            let url = if let Some(end_pos) = end_position {
15794                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15795            } else {
15796                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15797            };
15798
15799            if let Some(url) = url {
15800                editor.update(cx, |_, cx| {
15801                    cx.open_url(&url);
15802                })
15803            } else {
15804                Ok(())
15805            }
15806        });
15807
15808        url_finder.detach();
15809    }
15810
15811    pub fn open_selected_filename(
15812        &mut self,
15813        _: &OpenSelectedFilename,
15814        window: &mut Window,
15815        cx: &mut Context<Self>,
15816    ) {
15817        let Some(workspace) = self.workspace() else {
15818            return;
15819        };
15820
15821        let position = self.selections.newest_anchor().head();
15822
15823        let Some((buffer, buffer_position)) =
15824            self.buffer.read(cx).text_anchor_for_position(position, cx)
15825        else {
15826            return;
15827        };
15828
15829        let project = self.project.clone();
15830
15831        cx.spawn_in(window, async move |_, cx| {
15832            let result = find_file(&buffer, project, buffer_position, cx).await;
15833
15834            if let Some((_, path)) = result {
15835                workspace
15836                    .update_in(cx, |workspace, window, cx| {
15837                        workspace.open_resolved_path(path, window, cx)
15838                    })?
15839                    .await?;
15840            }
15841            anyhow::Ok(())
15842        })
15843        .detach();
15844    }
15845
15846    pub(crate) fn navigate_to_hover_links(
15847        &mut self,
15848        kind: Option<GotoDefinitionKind>,
15849        definitions: Vec<HoverLink>,
15850        split: bool,
15851        window: &mut Window,
15852        cx: &mut Context<Editor>,
15853    ) -> Task<Result<Navigated>> {
15854        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15855        let mut first_url_or_file = None;
15856        let definitions: Vec<_> = definitions
15857            .into_iter()
15858            .filter_map(|def| match def {
15859                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15860                HoverLink::InlayHint(lsp_location, server_id) => {
15861                    let computation =
15862                        self.compute_target_location(lsp_location, server_id, window, cx);
15863                    Some(cx.background_spawn(computation))
15864                }
15865                HoverLink::Url(url) => {
15866                    first_url_or_file = Some(Either::Left(url));
15867                    None
15868                }
15869                HoverLink::File(path) => {
15870                    first_url_or_file = Some(Either::Right(path));
15871                    None
15872                }
15873            })
15874            .collect();
15875
15876        let workspace = self.workspace();
15877
15878        cx.spawn_in(window, async move |editor, acx| {
15879            let mut locations: Vec<Location> = future::join_all(definitions)
15880                .await
15881                .into_iter()
15882                .filter_map(|location| location.transpose())
15883                .collect::<Result<_>>()
15884                .context("location tasks")?;
15885
15886            if locations.len() > 1 {
15887                let Some(workspace) = workspace else {
15888                    return Ok(Navigated::No);
15889                };
15890
15891                let tab_kind = match kind {
15892                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15893                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15894                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15895                    Some(GotoDefinitionKind::Type) => "Types",
15896                };
15897                let title = editor
15898                    .update_in(acx, |_, _, cx| {
15899                        let target = locations
15900                            .iter()
15901                            .map(|location| {
15902                                location
15903                                    .buffer
15904                                    .read(cx)
15905                                    .text_for_range(location.range.clone())
15906                                    .collect::<String>()
15907                            })
15908                            .filter(|text| !text.contains('\n'))
15909                            .unique()
15910                            .take(3)
15911                            .join(", ");
15912                        if target.is_empty() {
15913                            tab_kind.to_owned()
15914                        } else {
15915                            format!("{tab_kind} for {target}")
15916                        }
15917                    })
15918                    .context("buffer title")?;
15919
15920                let opened = workspace
15921                    .update_in(acx, |workspace, window, cx| {
15922                        Self::open_locations_in_multibuffer(
15923                            workspace,
15924                            locations,
15925                            title,
15926                            split,
15927                            MultibufferSelectionMode::First,
15928                            window,
15929                            cx,
15930                        )
15931                    })
15932                    .is_ok();
15933
15934                anyhow::Ok(Navigated::from_bool(opened))
15935            } else if locations.is_empty() {
15936                // If there is one definition, just open it directly
15937                match first_url_or_file {
15938                    Some(Either::Left(url)) => {
15939                        acx.update(|_, cx| cx.open_url(&url))?;
15940                        Ok(Navigated::Yes)
15941                    }
15942                    Some(Either::Right(path)) => {
15943                        let Some(workspace) = workspace else {
15944                            return Ok(Navigated::No);
15945                        };
15946
15947                        workspace
15948                            .update_in(acx, |workspace, window, cx| {
15949                                workspace.open_resolved_path(path, window, cx)
15950                            })?
15951                            .await?;
15952                        Ok(Navigated::Yes)
15953                    }
15954                    None => Ok(Navigated::No),
15955                }
15956            } else {
15957                let Some(workspace) = workspace else {
15958                    return Ok(Navigated::No);
15959                };
15960
15961                let target = locations.pop().unwrap();
15962                editor.update_in(acx, |editor, window, cx| {
15963                    let pane = workspace.read(cx).active_pane().clone();
15964
15965                    let range = target.range.to_point(target.buffer.read(cx));
15966                    let range = editor.range_for_match(&range);
15967                    let range = collapse_multiline_range(range);
15968
15969                    if !split
15970                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15971                    {
15972                        editor.go_to_singleton_buffer_range(range, window, cx);
15973                    } else {
15974                        window.defer(cx, move |window, cx| {
15975                            let target_editor: Entity<Self> =
15976                                workspace.update(cx, |workspace, cx| {
15977                                    let pane = if split {
15978                                        workspace.adjacent_pane(window, cx)
15979                                    } else {
15980                                        workspace.active_pane().clone()
15981                                    };
15982
15983                                    workspace.open_project_item(
15984                                        pane,
15985                                        target.buffer.clone(),
15986                                        true,
15987                                        true,
15988                                        window,
15989                                        cx,
15990                                    )
15991                                });
15992                            target_editor.update(cx, |target_editor, cx| {
15993                                // When selecting a definition in a different buffer, disable the nav history
15994                                // to avoid creating a history entry at the previous cursor location.
15995                                pane.update(cx, |pane, _| pane.disable_history());
15996                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15997                                pane.update(cx, |pane, _| pane.enable_history());
15998                            });
15999                        });
16000                    }
16001                    Navigated::Yes
16002                })
16003            }
16004        })
16005    }
16006
16007    fn compute_target_location(
16008        &self,
16009        lsp_location: lsp::Location,
16010        server_id: LanguageServerId,
16011        window: &mut Window,
16012        cx: &mut Context<Self>,
16013    ) -> Task<anyhow::Result<Option<Location>>> {
16014        let Some(project) = self.project.clone() else {
16015            return Task::ready(Ok(None));
16016        };
16017
16018        cx.spawn_in(window, async move |editor, cx| {
16019            let location_task = editor.update(cx, |_, cx| {
16020                project.update(cx, |project, cx| {
16021                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16022                })
16023            })?;
16024            let location = Some({
16025                let target_buffer_handle = location_task.await.context("open local buffer")?;
16026                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16027                    let target_start = target_buffer
16028                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16029                    let target_end = target_buffer
16030                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16031                    target_buffer.anchor_after(target_start)
16032                        ..target_buffer.anchor_before(target_end)
16033                })?;
16034                Location {
16035                    buffer: target_buffer_handle,
16036                    range,
16037                }
16038            });
16039            Ok(location)
16040        })
16041    }
16042
16043    pub fn find_all_references(
16044        &mut self,
16045        _: &FindAllReferences,
16046        window: &mut Window,
16047        cx: &mut Context<Self>,
16048    ) -> Option<Task<Result<Navigated>>> {
16049        let selection = self.selections.newest::<usize>(cx);
16050        let multi_buffer = self.buffer.read(cx);
16051        let head = selection.head();
16052
16053        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16054        let head_anchor = multi_buffer_snapshot.anchor_at(
16055            head,
16056            if head < selection.tail() {
16057                Bias::Right
16058            } else {
16059                Bias::Left
16060            },
16061        );
16062
16063        match self
16064            .find_all_references_task_sources
16065            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16066        {
16067            Ok(_) => {
16068                log::info!(
16069                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16070                );
16071                return None;
16072            }
16073            Err(i) => {
16074                self.find_all_references_task_sources.insert(i, head_anchor);
16075            }
16076        }
16077
16078        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16079        let workspace = self.workspace()?;
16080        let project = workspace.read(cx).project().clone();
16081        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16082        Some(cx.spawn_in(window, async move |editor, cx| {
16083            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16084                if let Ok(i) = editor
16085                    .find_all_references_task_sources
16086                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16087                {
16088                    editor.find_all_references_task_sources.remove(i);
16089                }
16090            });
16091
16092            let Some(locations) = references.await? else {
16093                return anyhow::Ok(Navigated::No);
16094            };
16095            if locations.is_empty() {
16096                return anyhow::Ok(Navigated::No);
16097            }
16098
16099            workspace.update_in(cx, |workspace, window, cx| {
16100                let target = locations
16101                    .iter()
16102                    .map(|location| {
16103                        location
16104                            .buffer
16105                            .read(cx)
16106                            .text_for_range(location.range.clone())
16107                            .collect::<String>()
16108                    })
16109                    .filter(|text| !text.contains('\n'))
16110                    .unique()
16111                    .take(3)
16112                    .join(", ");
16113                let title = if target.is_empty() {
16114                    "References".to_owned()
16115                } else {
16116                    format!("References to {target}")
16117                };
16118                Self::open_locations_in_multibuffer(
16119                    workspace,
16120                    locations,
16121                    title,
16122                    false,
16123                    MultibufferSelectionMode::First,
16124                    window,
16125                    cx,
16126                );
16127                Navigated::Yes
16128            })
16129        }))
16130    }
16131
16132    /// Opens a multibuffer with the given project locations in it
16133    pub fn open_locations_in_multibuffer(
16134        workspace: &mut Workspace,
16135        mut locations: Vec<Location>,
16136        title: String,
16137        split: bool,
16138        multibuffer_selection_mode: MultibufferSelectionMode,
16139        window: &mut Window,
16140        cx: &mut Context<Workspace>,
16141    ) {
16142        if locations.is_empty() {
16143            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16144            return;
16145        }
16146
16147        // If there are multiple definitions, open them in a multibuffer
16148        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16149        let mut locations = locations.into_iter().peekable();
16150        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16151        let capability = workspace.project().read(cx).capability();
16152
16153        let excerpt_buffer = cx.new(|cx| {
16154            let mut multibuffer = MultiBuffer::new(capability);
16155            while let Some(location) = locations.next() {
16156                let buffer = location.buffer.read(cx);
16157                let mut ranges_for_buffer = Vec::new();
16158                let range = location.range.to_point(buffer);
16159                ranges_for_buffer.push(range.clone());
16160
16161                while let Some(next_location) = locations.peek() {
16162                    if next_location.buffer == location.buffer {
16163                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16164                        locations.next();
16165                    } else {
16166                        break;
16167                    }
16168                }
16169
16170                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16171                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16172                    PathKey::for_buffer(&location.buffer, cx),
16173                    location.buffer.clone(),
16174                    ranges_for_buffer,
16175                    DEFAULT_MULTIBUFFER_CONTEXT,
16176                    cx,
16177                );
16178                ranges.extend(new_ranges)
16179            }
16180
16181            multibuffer.with_title(title)
16182        });
16183
16184        let editor = cx.new(|cx| {
16185            Editor::for_multibuffer(
16186                excerpt_buffer,
16187                Some(workspace.project().clone()),
16188                window,
16189                cx,
16190            )
16191        });
16192        editor.update(cx, |editor, cx| {
16193            match multibuffer_selection_mode {
16194                MultibufferSelectionMode::First => {
16195                    if let Some(first_range) = ranges.first() {
16196                        editor.change_selections(
16197                            SelectionEffects::no_scroll(),
16198                            window,
16199                            cx,
16200                            |selections| {
16201                                selections.clear_disjoint();
16202                                selections
16203                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16204                            },
16205                        );
16206                    }
16207                    editor.highlight_background::<Self>(
16208                        &ranges,
16209                        |theme| theme.colors().editor_highlighted_line_background,
16210                        cx,
16211                    );
16212                }
16213                MultibufferSelectionMode::All => {
16214                    editor.change_selections(
16215                        SelectionEffects::no_scroll(),
16216                        window,
16217                        cx,
16218                        |selections| {
16219                            selections.clear_disjoint();
16220                            selections.select_anchor_ranges(ranges);
16221                        },
16222                    );
16223                }
16224            }
16225            editor.register_buffers_with_language_servers(cx);
16226        });
16227
16228        let item = Box::new(editor);
16229        let item_id = item.item_id();
16230
16231        if split {
16232            workspace.split_item(SplitDirection::Right, item, window, cx);
16233        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16234            let (preview_item_id, preview_item_idx) =
16235                workspace.active_pane().read_with(cx, |pane, _| {
16236                    (pane.preview_item_id(), pane.preview_item_idx())
16237                });
16238
16239            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16240
16241            if let Some(preview_item_id) = preview_item_id {
16242                workspace.active_pane().update(cx, |pane, cx| {
16243                    pane.remove_item(preview_item_id, false, false, window, cx);
16244                });
16245            }
16246        } else {
16247            workspace.add_item_to_active_pane(item, None, true, window, cx);
16248        }
16249        workspace.active_pane().update(cx, |pane, cx| {
16250            pane.set_preview_item_id(Some(item_id), cx);
16251        });
16252    }
16253
16254    pub fn rename(
16255        &mut self,
16256        _: &Rename,
16257        window: &mut Window,
16258        cx: &mut Context<Self>,
16259    ) -> Option<Task<Result<()>>> {
16260        use language::ToOffset as _;
16261
16262        let provider = self.semantics_provider.clone()?;
16263        let selection = self.selections.newest_anchor().clone();
16264        let (cursor_buffer, cursor_buffer_position) = self
16265            .buffer
16266            .read(cx)
16267            .text_anchor_for_position(selection.head(), cx)?;
16268        let (tail_buffer, cursor_buffer_position_end) = self
16269            .buffer
16270            .read(cx)
16271            .text_anchor_for_position(selection.tail(), cx)?;
16272        if tail_buffer != cursor_buffer {
16273            return None;
16274        }
16275
16276        let snapshot = cursor_buffer.read(cx).snapshot();
16277        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16278        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16279        let prepare_rename = provider
16280            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16281            .unwrap_or_else(|| Task::ready(Ok(None)));
16282        drop(snapshot);
16283
16284        Some(cx.spawn_in(window, async move |this, cx| {
16285            let rename_range = if let Some(range) = prepare_rename.await? {
16286                Some(range)
16287            } else {
16288                this.update(cx, |this, cx| {
16289                    let buffer = this.buffer.read(cx).snapshot(cx);
16290                    let mut buffer_highlights = this
16291                        .document_highlights_for_position(selection.head(), &buffer)
16292                        .filter(|highlight| {
16293                            highlight.start.excerpt_id == selection.head().excerpt_id
16294                                && highlight.end.excerpt_id == selection.head().excerpt_id
16295                        });
16296                    buffer_highlights
16297                        .next()
16298                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16299                })?
16300            };
16301            if let Some(rename_range) = rename_range {
16302                this.update_in(cx, |this, window, cx| {
16303                    let snapshot = cursor_buffer.read(cx).snapshot();
16304                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16305                    let cursor_offset_in_rename_range =
16306                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16307                    let cursor_offset_in_rename_range_end =
16308                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16309
16310                    this.take_rename(false, window, cx);
16311                    let buffer = this.buffer.read(cx).read(cx);
16312                    let cursor_offset = selection.head().to_offset(&buffer);
16313                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16314                    let rename_end = rename_start + rename_buffer_range.len();
16315                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16316                    let mut old_highlight_id = None;
16317                    let old_name: Arc<str> = buffer
16318                        .chunks(rename_start..rename_end, true)
16319                        .map(|chunk| {
16320                            if old_highlight_id.is_none() {
16321                                old_highlight_id = chunk.syntax_highlight_id;
16322                            }
16323                            chunk.text
16324                        })
16325                        .collect::<String>()
16326                        .into();
16327
16328                    drop(buffer);
16329
16330                    // Position the selection in the rename editor so that it matches the current selection.
16331                    this.show_local_selections = false;
16332                    let rename_editor = cx.new(|cx| {
16333                        let mut editor = Editor::single_line(window, cx);
16334                        editor.buffer.update(cx, |buffer, cx| {
16335                            buffer.edit([(0..0, old_name.clone())], None, cx)
16336                        });
16337                        let rename_selection_range = match cursor_offset_in_rename_range
16338                            .cmp(&cursor_offset_in_rename_range_end)
16339                        {
16340                            Ordering::Equal => {
16341                                editor.select_all(&SelectAll, window, cx);
16342                                return editor;
16343                            }
16344                            Ordering::Less => {
16345                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16346                            }
16347                            Ordering::Greater => {
16348                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16349                            }
16350                        };
16351                        if rename_selection_range.end > old_name.len() {
16352                            editor.select_all(&SelectAll, window, cx);
16353                        } else {
16354                            editor.change_selections(Default::default(), window, cx, |s| {
16355                                s.select_ranges([rename_selection_range]);
16356                            });
16357                        }
16358                        editor
16359                    });
16360                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16361                        if e == &EditorEvent::Focused {
16362                            cx.emit(EditorEvent::FocusedIn)
16363                        }
16364                    })
16365                    .detach();
16366
16367                    let write_highlights =
16368                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16369                    let read_highlights =
16370                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16371                    let ranges = write_highlights
16372                        .iter()
16373                        .flat_map(|(_, ranges)| ranges.iter())
16374                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16375                        .cloned()
16376                        .collect();
16377
16378                    this.highlight_text::<Rename>(
16379                        ranges,
16380                        HighlightStyle {
16381                            fade_out: Some(0.6),
16382                            ..Default::default()
16383                        },
16384                        cx,
16385                    );
16386                    let rename_focus_handle = rename_editor.focus_handle(cx);
16387                    window.focus(&rename_focus_handle);
16388                    let block_id = this.insert_blocks(
16389                        [BlockProperties {
16390                            style: BlockStyle::Flex,
16391                            placement: BlockPlacement::Below(range.start),
16392                            height: Some(1),
16393                            render: Arc::new({
16394                                let rename_editor = rename_editor.clone();
16395                                move |cx: &mut BlockContext| {
16396                                    let mut text_style = cx.editor_style.text.clone();
16397                                    if let Some(highlight_style) = old_highlight_id
16398                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16399                                    {
16400                                        text_style = text_style.highlight(highlight_style);
16401                                    }
16402                                    div()
16403                                        .block_mouse_except_scroll()
16404                                        .pl(cx.anchor_x)
16405                                        .child(EditorElement::new(
16406                                            &rename_editor,
16407                                            EditorStyle {
16408                                                background: cx.theme().system().transparent,
16409                                                local_player: cx.editor_style.local_player,
16410                                                text: text_style,
16411                                                scrollbar_width: cx.editor_style.scrollbar_width,
16412                                                syntax: cx.editor_style.syntax.clone(),
16413                                                status: cx.editor_style.status.clone(),
16414                                                inlay_hints_style: HighlightStyle {
16415                                                    font_weight: Some(FontWeight::BOLD),
16416                                                    ..make_inlay_hints_style(cx.app)
16417                                                },
16418                                                edit_prediction_styles: make_suggestion_styles(
16419                                                    cx.app,
16420                                                ),
16421                                                ..EditorStyle::default()
16422                                            },
16423                                        ))
16424                                        .into_any_element()
16425                                }
16426                            }),
16427                            priority: 0,
16428                        }],
16429                        Some(Autoscroll::fit()),
16430                        cx,
16431                    )[0];
16432                    this.pending_rename = Some(RenameState {
16433                        range,
16434                        old_name,
16435                        editor: rename_editor,
16436                        block_id,
16437                    });
16438                })?;
16439            }
16440
16441            Ok(())
16442        }))
16443    }
16444
16445    pub fn confirm_rename(
16446        &mut self,
16447        _: &ConfirmRename,
16448        window: &mut Window,
16449        cx: &mut Context<Self>,
16450    ) -> Option<Task<Result<()>>> {
16451        let rename = self.take_rename(false, window, cx)?;
16452        let workspace = self.workspace()?.downgrade();
16453        let (buffer, start) = self
16454            .buffer
16455            .read(cx)
16456            .text_anchor_for_position(rename.range.start, cx)?;
16457        let (end_buffer, _) = self
16458            .buffer
16459            .read(cx)
16460            .text_anchor_for_position(rename.range.end, cx)?;
16461        if buffer != end_buffer {
16462            return None;
16463        }
16464
16465        let old_name = rename.old_name;
16466        let new_name = rename.editor.read(cx).text(cx);
16467
16468        let rename = self.semantics_provider.as_ref()?.perform_rename(
16469            &buffer,
16470            start,
16471            new_name.clone(),
16472            cx,
16473        )?;
16474
16475        Some(cx.spawn_in(window, async move |editor, cx| {
16476            let project_transaction = rename.await?;
16477            Self::open_project_transaction(
16478                &editor,
16479                workspace,
16480                project_transaction,
16481                format!("Rename: {}{}", old_name, new_name),
16482                cx,
16483            )
16484            .await?;
16485
16486            editor.update(cx, |editor, cx| {
16487                editor.refresh_document_highlights(cx);
16488            })?;
16489            Ok(())
16490        }))
16491    }
16492
16493    fn take_rename(
16494        &mut self,
16495        moving_cursor: bool,
16496        window: &mut Window,
16497        cx: &mut Context<Self>,
16498    ) -> Option<RenameState> {
16499        let rename = self.pending_rename.take()?;
16500        if rename.editor.focus_handle(cx).is_focused(window) {
16501            window.focus(&self.focus_handle);
16502        }
16503
16504        self.remove_blocks(
16505            [rename.block_id].into_iter().collect(),
16506            Some(Autoscroll::fit()),
16507            cx,
16508        );
16509        self.clear_highlights::<Rename>(cx);
16510        self.show_local_selections = true;
16511
16512        if moving_cursor {
16513            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16514                editor.selections.newest::<usize>(cx).head()
16515            });
16516
16517            // Update the selection to match the position of the selection inside
16518            // the rename editor.
16519            let snapshot = self.buffer.read(cx).read(cx);
16520            let rename_range = rename.range.to_offset(&snapshot);
16521            let cursor_in_editor = snapshot
16522                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16523                .min(rename_range.end);
16524            drop(snapshot);
16525
16526            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16527                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16528            });
16529        } else {
16530            self.refresh_document_highlights(cx);
16531        }
16532
16533        Some(rename)
16534    }
16535
16536    pub fn pending_rename(&self) -> Option<&RenameState> {
16537        self.pending_rename.as_ref()
16538    }
16539
16540    fn format(
16541        &mut self,
16542        _: &Format,
16543        window: &mut Window,
16544        cx: &mut Context<Self>,
16545    ) -> Option<Task<Result<()>>> {
16546        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16547
16548        let project = match &self.project {
16549            Some(project) => project.clone(),
16550            None => return None,
16551        };
16552
16553        Some(self.perform_format(
16554            project,
16555            FormatTrigger::Manual,
16556            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16557            window,
16558            cx,
16559        ))
16560    }
16561
16562    fn format_selections(
16563        &mut self,
16564        _: &FormatSelections,
16565        window: &mut Window,
16566        cx: &mut Context<Self>,
16567    ) -> Option<Task<Result<()>>> {
16568        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16569
16570        let project = match &self.project {
16571            Some(project) => project.clone(),
16572            None => return None,
16573        };
16574
16575        let ranges = self
16576            .selections
16577            .all_adjusted(cx)
16578            .into_iter()
16579            .map(|selection| selection.range())
16580            .collect_vec();
16581
16582        Some(self.perform_format(
16583            project,
16584            FormatTrigger::Manual,
16585            FormatTarget::Ranges(ranges),
16586            window,
16587            cx,
16588        ))
16589    }
16590
16591    fn perform_format(
16592        &mut self,
16593        project: Entity<Project>,
16594        trigger: FormatTrigger,
16595        target: FormatTarget,
16596        window: &mut Window,
16597        cx: &mut Context<Self>,
16598    ) -> Task<Result<()>> {
16599        let buffer = self.buffer.clone();
16600        let (buffers, target) = match target {
16601            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16602            FormatTarget::Ranges(selection_ranges) => {
16603                let multi_buffer = buffer.read(cx);
16604                let snapshot = multi_buffer.read(cx);
16605                let mut buffers = HashSet::default();
16606                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16607                    BTreeMap::new();
16608                for selection_range in selection_ranges {
16609                    for (buffer, buffer_range, _) in
16610                        snapshot.range_to_buffer_ranges(selection_range)
16611                    {
16612                        let buffer_id = buffer.remote_id();
16613                        let start = buffer.anchor_before(buffer_range.start);
16614                        let end = buffer.anchor_after(buffer_range.end);
16615                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16616                        buffer_id_to_ranges
16617                            .entry(buffer_id)
16618                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16619                            .or_insert_with(|| vec![start..end]);
16620                    }
16621                }
16622                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16623            }
16624        };
16625
16626        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16627        let selections_prev = transaction_id_prev
16628            .and_then(|transaction_id_prev| {
16629                // default to selections as they were after the last edit, if we have them,
16630                // instead of how they are now.
16631                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16632                // will take you back to where you made the last edit, instead of staying where you scrolled
16633                self.selection_history
16634                    .transaction(transaction_id_prev)
16635                    .map(|t| t.0.clone())
16636            })
16637            .unwrap_or_else(|| self.selections.disjoint_anchors());
16638
16639        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16640        let format = project.update(cx, |project, cx| {
16641            project.format(buffers, target, true, trigger, cx)
16642        });
16643
16644        cx.spawn_in(window, async move |editor, cx| {
16645            let transaction = futures::select_biased! {
16646                transaction = format.log_err().fuse() => transaction,
16647                () = timeout => {
16648                    log::warn!("timed out waiting for formatting");
16649                    None
16650                }
16651            };
16652
16653            buffer
16654                .update(cx, |buffer, cx| {
16655                    if let Some(transaction) = transaction
16656                        && !buffer.is_singleton()
16657                    {
16658                        buffer.push_transaction(&transaction.0, cx);
16659                    }
16660                    cx.notify();
16661                })
16662                .ok();
16663
16664            if let Some(transaction_id_now) =
16665                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16666            {
16667                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16668                if has_new_transaction {
16669                    _ = editor.update(cx, |editor, _| {
16670                        editor
16671                            .selection_history
16672                            .insert_transaction(transaction_id_now, selections_prev);
16673                    });
16674                }
16675            }
16676
16677            Ok(())
16678        })
16679    }
16680
16681    fn organize_imports(
16682        &mut self,
16683        _: &OrganizeImports,
16684        window: &mut Window,
16685        cx: &mut Context<Self>,
16686    ) -> Option<Task<Result<()>>> {
16687        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16688        let project = match &self.project {
16689            Some(project) => project.clone(),
16690            None => return None,
16691        };
16692        Some(self.perform_code_action_kind(
16693            project,
16694            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16695            window,
16696            cx,
16697        ))
16698    }
16699
16700    fn perform_code_action_kind(
16701        &mut self,
16702        project: Entity<Project>,
16703        kind: CodeActionKind,
16704        window: &mut Window,
16705        cx: &mut Context<Self>,
16706    ) -> Task<Result<()>> {
16707        let buffer = self.buffer.clone();
16708        let buffers = buffer.read(cx).all_buffers();
16709        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16710        let apply_action = project.update(cx, |project, cx| {
16711            project.apply_code_action_kind(buffers, kind, true, cx)
16712        });
16713        cx.spawn_in(window, async move |_, cx| {
16714            let transaction = futures::select_biased! {
16715                () = timeout => {
16716                    log::warn!("timed out waiting for executing code action");
16717                    None
16718                }
16719                transaction = apply_action.log_err().fuse() => transaction,
16720            };
16721            buffer
16722                .update(cx, |buffer, cx| {
16723                    // check if we need this
16724                    if let Some(transaction) = transaction
16725                        && !buffer.is_singleton()
16726                    {
16727                        buffer.push_transaction(&transaction.0, cx);
16728                    }
16729                    cx.notify();
16730                })
16731                .ok();
16732            Ok(())
16733        })
16734    }
16735
16736    pub fn restart_language_server(
16737        &mut self,
16738        _: &RestartLanguageServer,
16739        _: &mut Window,
16740        cx: &mut Context<Self>,
16741    ) {
16742        if let Some(project) = self.project.clone() {
16743            self.buffer.update(cx, |multi_buffer, cx| {
16744                project.update(cx, |project, cx| {
16745                    project.restart_language_servers_for_buffers(
16746                        multi_buffer.all_buffers().into_iter().collect(),
16747                        HashSet::default(),
16748                        cx,
16749                    );
16750                });
16751            })
16752        }
16753    }
16754
16755    pub fn stop_language_server(
16756        &mut self,
16757        _: &StopLanguageServer,
16758        _: &mut Window,
16759        cx: &mut Context<Self>,
16760    ) {
16761        if let Some(project) = self.project.clone() {
16762            self.buffer.update(cx, |multi_buffer, cx| {
16763                project.update(cx, |project, cx| {
16764                    project.stop_language_servers_for_buffers(
16765                        multi_buffer.all_buffers().into_iter().collect(),
16766                        HashSet::default(),
16767                        cx,
16768                    );
16769                    cx.emit(project::Event::RefreshInlayHints);
16770                });
16771            });
16772        }
16773    }
16774
16775    fn cancel_language_server_work(
16776        workspace: &mut Workspace,
16777        _: &actions::CancelLanguageServerWork,
16778        _: &mut Window,
16779        cx: &mut Context<Workspace>,
16780    ) {
16781        let project = workspace.project();
16782        let buffers = workspace
16783            .active_item(cx)
16784            .and_then(|item| item.act_as::<Editor>(cx))
16785            .map_or(HashSet::default(), |editor| {
16786                editor.read(cx).buffer.read(cx).all_buffers()
16787            });
16788        project.update(cx, |project, cx| {
16789            project.cancel_language_server_work_for_buffers(buffers, cx);
16790        });
16791    }
16792
16793    fn show_character_palette(
16794        &mut self,
16795        _: &ShowCharacterPalette,
16796        window: &mut Window,
16797        _: &mut Context<Self>,
16798    ) {
16799        window.show_character_palette();
16800    }
16801
16802    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16803        if !self.diagnostics_enabled() {
16804            return;
16805        }
16806
16807        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16808            let buffer = self.buffer.read(cx).snapshot(cx);
16809            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16810            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16811            let is_valid = buffer
16812                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16813                .any(|entry| {
16814                    entry.diagnostic.is_primary
16815                        && !entry.range.is_empty()
16816                        && entry.range.start == primary_range_start
16817                        && entry.diagnostic.message == active_diagnostics.active_message
16818                });
16819
16820            if !is_valid {
16821                self.dismiss_diagnostics(cx);
16822            }
16823        }
16824    }
16825
16826    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16827        match &self.active_diagnostics {
16828            ActiveDiagnostic::Group(group) => Some(group),
16829            _ => None,
16830        }
16831    }
16832
16833    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16834        if !self.diagnostics_enabled() {
16835            return;
16836        }
16837        self.dismiss_diagnostics(cx);
16838        self.active_diagnostics = ActiveDiagnostic::All;
16839    }
16840
16841    fn activate_diagnostics(
16842        &mut self,
16843        buffer_id: BufferId,
16844        diagnostic: DiagnosticEntry<usize>,
16845        window: &mut Window,
16846        cx: &mut Context<Self>,
16847    ) {
16848        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16849            return;
16850        }
16851        self.dismiss_diagnostics(cx);
16852        let snapshot = self.snapshot(window, cx);
16853        let buffer = self.buffer.read(cx).snapshot(cx);
16854        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16855            return;
16856        };
16857
16858        let diagnostic_group = buffer
16859            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16860            .collect::<Vec<_>>();
16861
16862        let blocks =
16863            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16864
16865        let blocks = self.display_map.update(cx, |display_map, cx| {
16866            display_map.insert_blocks(blocks, cx).into_iter().collect()
16867        });
16868        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16869            active_range: buffer.anchor_before(diagnostic.range.start)
16870                ..buffer.anchor_after(diagnostic.range.end),
16871            active_message: diagnostic.diagnostic.message.clone(),
16872            group_id: diagnostic.diagnostic.group_id,
16873            blocks,
16874        });
16875        cx.notify();
16876    }
16877
16878    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16879        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16880            return;
16881        };
16882
16883        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16884        if let ActiveDiagnostic::Group(group) = prev {
16885            self.display_map.update(cx, |display_map, cx| {
16886                display_map.remove_blocks(group.blocks, cx);
16887            });
16888            cx.notify();
16889        }
16890    }
16891
16892    /// Disable inline diagnostics rendering for this editor.
16893    pub fn disable_inline_diagnostics(&mut self) {
16894        self.inline_diagnostics_enabled = false;
16895        self.inline_diagnostics_update = Task::ready(());
16896        self.inline_diagnostics.clear();
16897    }
16898
16899    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16900        self.diagnostics_enabled = false;
16901        self.dismiss_diagnostics(cx);
16902        self.inline_diagnostics_update = Task::ready(());
16903        self.inline_diagnostics.clear();
16904    }
16905
16906    pub fn diagnostics_enabled(&self) -> bool {
16907        self.diagnostics_enabled && self.mode.is_full()
16908    }
16909
16910    pub fn inline_diagnostics_enabled(&self) -> bool {
16911        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16912    }
16913
16914    pub fn show_inline_diagnostics(&self) -> bool {
16915        self.show_inline_diagnostics
16916    }
16917
16918    pub fn toggle_inline_diagnostics(
16919        &mut self,
16920        _: &ToggleInlineDiagnostics,
16921        window: &mut Window,
16922        cx: &mut Context<Editor>,
16923    ) {
16924        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16925        self.refresh_inline_diagnostics(false, window, cx);
16926    }
16927
16928    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16929        self.diagnostics_max_severity = severity;
16930        self.display_map.update(cx, |display_map, _| {
16931            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16932        });
16933    }
16934
16935    pub fn toggle_diagnostics(
16936        &mut self,
16937        _: &ToggleDiagnostics,
16938        window: &mut Window,
16939        cx: &mut Context<Editor>,
16940    ) {
16941        if !self.diagnostics_enabled() {
16942            return;
16943        }
16944
16945        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16946            EditorSettings::get_global(cx)
16947                .diagnostics_max_severity
16948                .filter(|severity| severity != &DiagnosticSeverity::Off)
16949                .unwrap_or(DiagnosticSeverity::Hint)
16950        } else {
16951            DiagnosticSeverity::Off
16952        };
16953        self.set_max_diagnostics_severity(new_severity, cx);
16954        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16955            self.active_diagnostics = ActiveDiagnostic::None;
16956            self.inline_diagnostics_update = Task::ready(());
16957            self.inline_diagnostics.clear();
16958        } else {
16959            self.refresh_inline_diagnostics(false, window, cx);
16960        }
16961
16962        cx.notify();
16963    }
16964
16965    pub fn toggle_minimap(
16966        &mut self,
16967        _: &ToggleMinimap,
16968        window: &mut Window,
16969        cx: &mut Context<Editor>,
16970    ) {
16971        if self.supports_minimap(cx) {
16972            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16973        }
16974    }
16975
16976    fn refresh_inline_diagnostics(
16977        &mut self,
16978        debounce: bool,
16979        window: &mut Window,
16980        cx: &mut Context<Self>,
16981    ) {
16982        let max_severity = ProjectSettings::get_global(cx)
16983            .diagnostics
16984            .inline
16985            .max_severity
16986            .unwrap_or(self.diagnostics_max_severity);
16987
16988        if !self.inline_diagnostics_enabled()
16989            || !self.show_inline_diagnostics
16990            || max_severity == DiagnosticSeverity::Off
16991        {
16992            self.inline_diagnostics_update = Task::ready(());
16993            self.inline_diagnostics.clear();
16994            return;
16995        }
16996
16997        let debounce_ms = ProjectSettings::get_global(cx)
16998            .diagnostics
16999            .inline
17000            .update_debounce_ms;
17001        let debounce = if debounce && debounce_ms > 0 {
17002            Some(Duration::from_millis(debounce_ms))
17003        } else {
17004            None
17005        };
17006        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17007            if let Some(debounce) = debounce {
17008                cx.background_executor().timer(debounce).await;
17009            }
17010            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17011                editor
17012                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17013                    .ok()
17014            }) else {
17015                return;
17016            };
17017
17018            let new_inline_diagnostics = cx
17019                .background_spawn(async move {
17020                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17021                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17022                        let message = diagnostic_entry
17023                            .diagnostic
17024                            .message
17025                            .split_once('\n')
17026                            .map(|(line, _)| line)
17027                            .map(SharedString::new)
17028                            .unwrap_or_else(|| {
17029                                SharedString::from(diagnostic_entry.diagnostic.message)
17030                            });
17031                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17032                        let (Ok(i) | Err(i)) = inline_diagnostics
17033                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17034                        inline_diagnostics.insert(
17035                            i,
17036                            (
17037                                start_anchor,
17038                                InlineDiagnostic {
17039                                    message,
17040                                    group_id: diagnostic_entry.diagnostic.group_id,
17041                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17042                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17043                                    severity: diagnostic_entry.diagnostic.severity,
17044                                },
17045                            ),
17046                        );
17047                    }
17048                    inline_diagnostics
17049                })
17050                .await;
17051
17052            editor
17053                .update(cx, |editor, cx| {
17054                    editor.inline_diagnostics = new_inline_diagnostics;
17055                    cx.notify();
17056                })
17057                .ok();
17058        });
17059    }
17060
17061    fn pull_diagnostics(
17062        &mut self,
17063        buffer_id: Option<BufferId>,
17064        window: &Window,
17065        cx: &mut Context<Self>,
17066    ) -> Option<()> {
17067        if !self.mode().is_full() {
17068            return None;
17069        }
17070        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17071            .diagnostics
17072            .lsp_pull_diagnostics;
17073        if !pull_diagnostics_settings.enabled {
17074            return None;
17075        }
17076        let project = self.project()?.downgrade();
17077        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17078        let mut buffers = self.buffer.read(cx).all_buffers();
17079        if let Some(buffer_id) = buffer_id {
17080            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17081        }
17082
17083        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17084            cx.background_executor().timer(debounce).await;
17085
17086            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17087                buffers
17088                    .into_iter()
17089                    .filter_map(|buffer| {
17090                        project
17091                            .update(cx, |project, cx| {
17092                                project.lsp_store().update(cx, |lsp_store, cx| {
17093                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17094                                })
17095                            })
17096                            .ok()
17097                    })
17098                    .collect::<FuturesUnordered<_>>()
17099            }) else {
17100                return;
17101            };
17102
17103            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17104                match pull_task {
17105                    Ok(()) => {
17106                        if editor
17107                            .update_in(cx, |editor, window, cx| {
17108                                editor.update_diagnostics_state(window, cx);
17109                            })
17110                            .is_err()
17111                        {
17112                            return;
17113                        }
17114                    }
17115                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17116                }
17117            }
17118        });
17119
17120        Some(())
17121    }
17122
17123    pub fn set_selections_from_remote(
17124        &mut self,
17125        selections: Vec<Selection<Anchor>>,
17126        pending_selection: Option<Selection<Anchor>>,
17127        window: &mut Window,
17128        cx: &mut Context<Self>,
17129    ) {
17130        let old_cursor_position = self.selections.newest_anchor().head();
17131        self.selections.change_with(cx, |s| {
17132            s.select_anchors(selections);
17133            if let Some(pending_selection) = pending_selection {
17134                s.set_pending(pending_selection, SelectMode::Character);
17135            } else {
17136                s.clear_pending();
17137            }
17138        });
17139        self.selections_did_change(
17140            false,
17141            &old_cursor_position,
17142            SelectionEffects::default(),
17143            window,
17144            cx,
17145        );
17146    }
17147
17148    pub fn transact(
17149        &mut self,
17150        window: &mut Window,
17151        cx: &mut Context<Self>,
17152        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17153    ) -> Option<TransactionId> {
17154        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17155            this.start_transaction_at(Instant::now(), window, cx);
17156            update(this, window, cx);
17157            this.end_transaction_at(Instant::now(), cx)
17158        })
17159    }
17160
17161    pub fn start_transaction_at(
17162        &mut self,
17163        now: Instant,
17164        window: &mut Window,
17165        cx: &mut Context<Self>,
17166    ) -> Option<TransactionId> {
17167        self.end_selection(window, cx);
17168        if let Some(tx_id) = self
17169            .buffer
17170            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17171        {
17172            self.selection_history
17173                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17174            cx.emit(EditorEvent::TransactionBegun {
17175                transaction_id: tx_id,
17176            });
17177            Some(tx_id)
17178        } else {
17179            None
17180        }
17181    }
17182
17183    pub fn end_transaction_at(
17184        &mut self,
17185        now: Instant,
17186        cx: &mut Context<Self>,
17187    ) -> Option<TransactionId> {
17188        if let Some(transaction_id) = self
17189            .buffer
17190            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17191        {
17192            if let Some((_, end_selections)) =
17193                self.selection_history.transaction_mut(transaction_id)
17194            {
17195                *end_selections = Some(self.selections.disjoint_anchors());
17196            } else {
17197                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17198            }
17199
17200            cx.emit(EditorEvent::Edited { transaction_id });
17201            Some(transaction_id)
17202        } else {
17203            None
17204        }
17205    }
17206
17207    pub fn modify_transaction_selection_history(
17208        &mut self,
17209        transaction_id: TransactionId,
17210        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17211    ) -> bool {
17212        self.selection_history
17213            .transaction_mut(transaction_id)
17214            .map(modify)
17215            .is_some()
17216    }
17217
17218    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17219        if self.selection_mark_mode {
17220            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17221                s.move_with(|_, sel| {
17222                    sel.collapse_to(sel.head(), SelectionGoal::None);
17223                });
17224            })
17225        }
17226        self.selection_mark_mode = true;
17227        cx.notify();
17228    }
17229
17230    pub fn swap_selection_ends(
17231        &mut self,
17232        _: &actions::SwapSelectionEnds,
17233        window: &mut Window,
17234        cx: &mut Context<Self>,
17235    ) {
17236        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17237            s.move_with(|_, sel| {
17238                if sel.start != sel.end {
17239                    sel.reversed = !sel.reversed
17240                }
17241            });
17242        });
17243        self.request_autoscroll(Autoscroll::newest(), cx);
17244        cx.notify();
17245    }
17246
17247    pub fn toggle_focus(
17248        workspace: &mut Workspace,
17249        _: &actions::ToggleFocus,
17250        window: &mut Window,
17251        cx: &mut Context<Workspace>,
17252    ) {
17253        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17254            return;
17255        };
17256        workspace.activate_item(&item, true, true, window, cx);
17257    }
17258
17259    pub fn toggle_fold(
17260        &mut self,
17261        _: &actions::ToggleFold,
17262        window: &mut Window,
17263        cx: &mut Context<Self>,
17264    ) {
17265        if self.is_singleton(cx) {
17266            let selection = self.selections.newest::<Point>(cx);
17267
17268            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17269            let range = if selection.is_empty() {
17270                let point = selection.head().to_display_point(&display_map);
17271                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17272                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17273                    .to_point(&display_map);
17274                start..end
17275            } else {
17276                selection.range()
17277            };
17278            if display_map.folds_in_range(range).next().is_some() {
17279                self.unfold_lines(&Default::default(), window, cx)
17280            } else {
17281                self.fold(&Default::default(), window, cx)
17282            }
17283        } else {
17284            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17285            let buffer_ids: HashSet<_> = self
17286                .selections
17287                .disjoint_anchor_ranges()
17288                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17289                .collect();
17290
17291            let should_unfold = buffer_ids
17292                .iter()
17293                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17294
17295            for buffer_id in buffer_ids {
17296                if should_unfold {
17297                    self.unfold_buffer(buffer_id, cx);
17298                } else {
17299                    self.fold_buffer(buffer_id, cx);
17300                }
17301            }
17302        }
17303    }
17304
17305    pub fn toggle_fold_recursive(
17306        &mut self,
17307        _: &actions::ToggleFoldRecursive,
17308        window: &mut Window,
17309        cx: &mut Context<Self>,
17310    ) {
17311        let selection = self.selections.newest::<Point>(cx);
17312
17313        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17314        let range = if selection.is_empty() {
17315            let point = selection.head().to_display_point(&display_map);
17316            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17317            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17318                .to_point(&display_map);
17319            start..end
17320        } else {
17321            selection.range()
17322        };
17323        if display_map.folds_in_range(range).next().is_some() {
17324            self.unfold_recursive(&Default::default(), window, cx)
17325        } else {
17326            self.fold_recursive(&Default::default(), window, cx)
17327        }
17328    }
17329
17330    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17331        if self.is_singleton(cx) {
17332            let mut to_fold = Vec::new();
17333            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17334            let selections = self.selections.all_adjusted(cx);
17335
17336            for selection in selections {
17337                let range = selection.range().sorted();
17338                let buffer_start_row = range.start.row;
17339
17340                if range.start.row != range.end.row {
17341                    let mut found = false;
17342                    let mut row = range.start.row;
17343                    while row <= range.end.row {
17344                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17345                        {
17346                            found = true;
17347                            row = crease.range().end.row + 1;
17348                            to_fold.push(crease);
17349                        } else {
17350                            row += 1
17351                        }
17352                    }
17353                    if found {
17354                        continue;
17355                    }
17356                }
17357
17358                for row in (0..=range.start.row).rev() {
17359                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17360                        && crease.range().end.row >= buffer_start_row
17361                    {
17362                        to_fold.push(crease);
17363                        if row <= range.start.row {
17364                            break;
17365                        }
17366                    }
17367                }
17368            }
17369
17370            self.fold_creases(to_fold, true, window, cx);
17371        } else {
17372            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17373            let buffer_ids = self
17374                .selections
17375                .disjoint_anchor_ranges()
17376                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17377                .collect::<HashSet<_>>();
17378            for buffer_id in buffer_ids {
17379                self.fold_buffer(buffer_id, cx);
17380            }
17381        }
17382    }
17383
17384    pub fn toggle_fold_all(
17385        &mut self,
17386        _: &actions::ToggleFoldAll,
17387        window: &mut Window,
17388        cx: &mut Context<Self>,
17389    ) {
17390        if self.buffer.read(cx).is_singleton() {
17391            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17392            let has_folds = display_map
17393                .folds_in_range(0..display_map.buffer_snapshot.len())
17394                .next()
17395                .is_some();
17396
17397            if has_folds {
17398                self.unfold_all(&actions::UnfoldAll, window, cx);
17399            } else {
17400                self.fold_all(&actions::FoldAll, window, cx);
17401            }
17402        } else {
17403            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17404            let should_unfold = buffer_ids
17405                .iter()
17406                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17407
17408            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17409                editor
17410                    .update_in(cx, |editor, _, cx| {
17411                        for buffer_id in buffer_ids {
17412                            if should_unfold {
17413                                editor.unfold_buffer(buffer_id, cx);
17414                            } else {
17415                                editor.fold_buffer(buffer_id, cx);
17416                            }
17417                        }
17418                    })
17419                    .ok();
17420            });
17421        }
17422    }
17423
17424    fn fold_at_level(
17425        &mut self,
17426        fold_at: &FoldAtLevel,
17427        window: &mut Window,
17428        cx: &mut Context<Self>,
17429    ) {
17430        if !self.buffer.read(cx).is_singleton() {
17431            return;
17432        }
17433
17434        let fold_at_level = fold_at.0;
17435        let snapshot = self.buffer.read(cx).snapshot(cx);
17436        let mut to_fold = Vec::new();
17437        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17438
17439        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17440            while start_row < end_row {
17441                match self
17442                    .snapshot(window, cx)
17443                    .crease_for_buffer_row(MultiBufferRow(start_row))
17444                {
17445                    Some(crease) => {
17446                        let nested_start_row = crease.range().start.row + 1;
17447                        let nested_end_row = crease.range().end.row;
17448
17449                        if current_level < fold_at_level {
17450                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17451                        } else if current_level == fold_at_level {
17452                            to_fold.push(crease);
17453                        }
17454
17455                        start_row = nested_end_row + 1;
17456                    }
17457                    None => start_row += 1,
17458                }
17459            }
17460        }
17461
17462        self.fold_creases(to_fold, true, window, cx);
17463    }
17464
17465    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17466        if self.buffer.read(cx).is_singleton() {
17467            let mut fold_ranges = Vec::new();
17468            let snapshot = self.buffer.read(cx).snapshot(cx);
17469
17470            for row in 0..snapshot.max_row().0 {
17471                if let Some(foldable_range) = self
17472                    .snapshot(window, cx)
17473                    .crease_for_buffer_row(MultiBufferRow(row))
17474                {
17475                    fold_ranges.push(foldable_range);
17476                }
17477            }
17478
17479            self.fold_creases(fold_ranges, true, window, cx);
17480        } else {
17481            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17482                editor
17483                    .update_in(cx, |editor, _, cx| {
17484                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17485                            editor.fold_buffer(buffer_id, cx);
17486                        }
17487                    })
17488                    .ok();
17489            });
17490        }
17491    }
17492
17493    pub fn fold_function_bodies(
17494        &mut self,
17495        _: &actions::FoldFunctionBodies,
17496        window: &mut Window,
17497        cx: &mut Context<Self>,
17498    ) {
17499        let snapshot = self.buffer.read(cx).snapshot(cx);
17500
17501        let ranges = snapshot
17502            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17503            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17504            .collect::<Vec<_>>();
17505
17506        let creases = ranges
17507            .into_iter()
17508            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17509            .collect();
17510
17511        self.fold_creases(creases, true, window, cx);
17512    }
17513
17514    pub fn fold_recursive(
17515        &mut self,
17516        _: &actions::FoldRecursive,
17517        window: &mut Window,
17518        cx: &mut Context<Self>,
17519    ) {
17520        let mut to_fold = Vec::new();
17521        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17522        let selections = self.selections.all_adjusted(cx);
17523
17524        for selection in selections {
17525            let range = selection.range().sorted();
17526            let buffer_start_row = range.start.row;
17527
17528            if range.start.row != range.end.row {
17529                let mut found = false;
17530                for row in range.start.row..=range.end.row {
17531                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17532                        found = true;
17533                        to_fold.push(crease);
17534                    }
17535                }
17536                if found {
17537                    continue;
17538                }
17539            }
17540
17541            for row in (0..=range.start.row).rev() {
17542                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17543                    if crease.range().end.row >= buffer_start_row {
17544                        to_fold.push(crease);
17545                    } else {
17546                        break;
17547                    }
17548                }
17549            }
17550        }
17551
17552        self.fold_creases(to_fold, true, window, cx);
17553    }
17554
17555    pub fn fold_at(
17556        &mut self,
17557        buffer_row: MultiBufferRow,
17558        window: &mut Window,
17559        cx: &mut Context<Self>,
17560    ) {
17561        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17562
17563        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17564            let autoscroll = self
17565                .selections
17566                .all::<Point>(cx)
17567                .iter()
17568                .any(|selection| crease.range().overlaps(&selection.range()));
17569
17570            self.fold_creases(vec![crease], autoscroll, window, cx);
17571        }
17572    }
17573
17574    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17575        if self.is_singleton(cx) {
17576            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17577            let buffer = &display_map.buffer_snapshot;
17578            let selections = self.selections.all::<Point>(cx);
17579            let ranges = selections
17580                .iter()
17581                .map(|s| {
17582                    let range = s.display_range(&display_map).sorted();
17583                    let mut start = range.start.to_point(&display_map);
17584                    let mut end = range.end.to_point(&display_map);
17585                    start.column = 0;
17586                    end.column = buffer.line_len(MultiBufferRow(end.row));
17587                    start..end
17588                })
17589                .collect::<Vec<_>>();
17590
17591            self.unfold_ranges(&ranges, true, true, cx);
17592        } else {
17593            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17594            let buffer_ids = self
17595                .selections
17596                .disjoint_anchor_ranges()
17597                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17598                .collect::<HashSet<_>>();
17599            for buffer_id in buffer_ids {
17600                self.unfold_buffer(buffer_id, cx);
17601            }
17602        }
17603    }
17604
17605    pub fn unfold_recursive(
17606        &mut self,
17607        _: &UnfoldRecursive,
17608        _window: &mut Window,
17609        cx: &mut Context<Self>,
17610    ) {
17611        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17612        let selections = self.selections.all::<Point>(cx);
17613        let ranges = selections
17614            .iter()
17615            .map(|s| {
17616                let mut range = s.display_range(&display_map).sorted();
17617                *range.start.column_mut() = 0;
17618                *range.end.column_mut() = display_map.line_len(range.end.row());
17619                let start = range.start.to_point(&display_map);
17620                let end = range.end.to_point(&display_map);
17621                start..end
17622            })
17623            .collect::<Vec<_>>();
17624
17625        self.unfold_ranges(&ranges, true, true, cx);
17626    }
17627
17628    pub fn unfold_at(
17629        &mut self,
17630        buffer_row: MultiBufferRow,
17631        _window: &mut Window,
17632        cx: &mut Context<Self>,
17633    ) {
17634        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17635
17636        let intersection_range = Point::new(buffer_row.0, 0)
17637            ..Point::new(
17638                buffer_row.0,
17639                display_map.buffer_snapshot.line_len(buffer_row),
17640            );
17641
17642        let autoscroll = self
17643            .selections
17644            .all::<Point>(cx)
17645            .iter()
17646            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17647
17648        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17649    }
17650
17651    pub fn unfold_all(
17652        &mut self,
17653        _: &actions::UnfoldAll,
17654        _window: &mut Window,
17655        cx: &mut Context<Self>,
17656    ) {
17657        if self.buffer.read(cx).is_singleton() {
17658            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17659            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17660        } else {
17661            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17662                editor
17663                    .update(cx, |editor, cx| {
17664                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17665                            editor.unfold_buffer(buffer_id, cx);
17666                        }
17667                    })
17668                    .ok();
17669            });
17670        }
17671    }
17672
17673    pub fn fold_selected_ranges(
17674        &mut self,
17675        _: &FoldSelectedRanges,
17676        window: &mut Window,
17677        cx: &mut Context<Self>,
17678    ) {
17679        let selections = self.selections.all_adjusted(cx);
17680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17681        let ranges = selections
17682            .into_iter()
17683            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17684            .collect::<Vec<_>>();
17685        self.fold_creases(ranges, true, window, cx);
17686    }
17687
17688    pub fn fold_ranges<T: ToOffset + Clone>(
17689        &mut self,
17690        ranges: Vec<Range<T>>,
17691        auto_scroll: bool,
17692        window: &mut Window,
17693        cx: &mut Context<Self>,
17694    ) {
17695        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17696        let ranges = ranges
17697            .into_iter()
17698            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17699            .collect::<Vec<_>>();
17700        self.fold_creases(ranges, auto_scroll, window, cx);
17701    }
17702
17703    pub fn fold_creases<T: ToOffset + Clone>(
17704        &mut self,
17705        creases: Vec<Crease<T>>,
17706        auto_scroll: bool,
17707        _window: &mut Window,
17708        cx: &mut Context<Self>,
17709    ) {
17710        if creases.is_empty() {
17711            return;
17712        }
17713
17714        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17715
17716        if auto_scroll {
17717            self.request_autoscroll(Autoscroll::fit(), cx);
17718        }
17719
17720        cx.notify();
17721
17722        self.scrollbar_marker_state.dirty = true;
17723        self.folds_did_change(cx);
17724    }
17725
17726    /// Removes any folds whose ranges intersect any of the given ranges.
17727    pub fn unfold_ranges<T: ToOffset + Clone>(
17728        &mut self,
17729        ranges: &[Range<T>],
17730        inclusive: bool,
17731        auto_scroll: bool,
17732        cx: &mut Context<Self>,
17733    ) {
17734        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17735            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17736        });
17737        self.folds_did_change(cx);
17738    }
17739
17740    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17741        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17742            return;
17743        }
17744        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17745        self.display_map.update(cx, |display_map, cx| {
17746            display_map.fold_buffers([buffer_id], cx)
17747        });
17748        cx.emit(EditorEvent::BufferFoldToggled {
17749            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17750            folded: true,
17751        });
17752        cx.notify();
17753    }
17754
17755    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17756        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17757            return;
17758        }
17759        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17760        self.display_map.update(cx, |display_map, cx| {
17761            display_map.unfold_buffers([buffer_id], cx);
17762        });
17763        cx.emit(EditorEvent::BufferFoldToggled {
17764            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17765            folded: false,
17766        });
17767        cx.notify();
17768    }
17769
17770    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17771        self.display_map.read(cx).is_buffer_folded(buffer)
17772    }
17773
17774    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17775        self.display_map.read(cx).folded_buffers()
17776    }
17777
17778    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17779        self.display_map.update(cx, |display_map, cx| {
17780            display_map.disable_header_for_buffer(buffer_id, cx);
17781        });
17782        cx.notify();
17783    }
17784
17785    /// Removes any folds with the given ranges.
17786    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17787        &mut self,
17788        ranges: &[Range<T>],
17789        type_id: TypeId,
17790        auto_scroll: bool,
17791        cx: &mut Context<Self>,
17792    ) {
17793        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17794            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17795        });
17796        self.folds_did_change(cx);
17797    }
17798
17799    fn remove_folds_with<T: ToOffset + Clone>(
17800        &mut self,
17801        ranges: &[Range<T>],
17802        auto_scroll: bool,
17803        cx: &mut Context<Self>,
17804        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17805    ) {
17806        if ranges.is_empty() {
17807            return;
17808        }
17809
17810        let mut buffers_affected = HashSet::default();
17811        let multi_buffer = self.buffer().read(cx);
17812        for range in ranges {
17813            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17814                buffers_affected.insert(buffer.read(cx).remote_id());
17815            };
17816        }
17817
17818        self.display_map.update(cx, update);
17819
17820        if auto_scroll {
17821            self.request_autoscroll(Autoscroll::fit(), cx);
17822        }
17823
17824        cx.notify();
17825        self.scrollbar_marker_state.dirty = true;
17826        self.active_indent_guides_state.dirty = true;
17827    }
17828
17829    pub fn update_renderer_widths(
17830        &mut self,
17831        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17832        cx: &mut Context<Self>,
17833    ) -> bool {
17834        self.display_map
17835            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17836    }
17837
17838    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17839        self.display_map.read(cx).fold_placeholder.clone()
17840    }
17841
17842    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17843        self.buffer.update(cx, |buffer, cx| {
17844            buffer.set_all_diff_hunks_expanded(cx);
17845        });
17846    }
17847
17848    pub fn expand_all_diff_hunks(
17849        &mut self,
17850        _: &ExpandAllDiffHunks,
17851        _window: &mut Window,
17852        cx: &mut Context<Self>,
17853    ) {
17854        self.buffer.update(cx, |buffer, cx| {
17855            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17856        });
17857    }
17858
17859    pub fn toggle_selected_diff_hunks(
17860        &mut self,
17861        _: &ToggleSelectedDiffHunks,
17862        _window: &mut Window,
17863        cx: &mut Context<Self>,
17864    ) {
17865        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17866        self.toggle_diff_hunks_in_ranges(ranges, cx);
17867    }
17868
17869    pub fn diff_hunks_in_ranges<'a>(
17870        &'a self,
17871        ranges: &'a [Range<Anchor>],
17872        buffer: &'a MultiBufferSnapshot,
17873    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17874        ranges.iter().flat_map(move |range| {
17875            let end_excerpt_id = range.end.excerpt_id;
17876            let range = range.to_point(buffer);
17877            let mut peek_end = range.end;
17878            if range.end.row < buffer.max_row().0 {
17879                peek_end = Point::new(range.end.row + 1, 0);
17880            }
17881            buffer
17882                .diff_hunks_in_range(range.start..peek_end)
17883                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17884        })
17885    }
17886
17887    pub fn has_stageable_diff_hunks_in_ranges(
17888        &self,
17889        ranges: &[Range<Anchor>],
17890        snapshot: &MultiBufferSnapshot,
17891    ) -> bool {
17892        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17893        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17894    }
17895
17896    pub fn toggle_staged_selected_diff_hunks(
17897        &mut self,
17898        _: &::git::ToggleStaged,
17899        _: &mut Window,
17900        cx: &mut Context<Self>,
17901    ) {
17902        let snapshot = self.buffer.read(cx).snapshot(cx);
17903        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17904        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17905        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17906    }
17907
17908    pub fn set_render_diff_hunk_controls(
17909        &mut self,
17910        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17911        cx: &mut Context<Self>,
17912    ) {
17913        self.render_diff_hunk_controls = render_diff_hunk_controls;
17914        cx.notify();
17915    }
17916
17917    pub fn stage_and_next(
17918        &mut self,
17919        _: &::git::StageAndNext,
17920        window: &mut Window,
17921        cx: &mut Context<Self>,
17922    ) {
17923        self.do_stage_or_unstage_and_next(true, window, cx);
17924    }
17925
17926    pub fn unstage_and_next(
17927        &mut self,
17928        _: &::git::UnstageAndNext,
17929        window: &mut Window,
17930        cx: &mut Context<Self>,
17931    ) {
17932        self.do_stage_or_unstage_and_next(false, window, cx);
17933    }
17934
17935    pub fn stage_or_unstage_diff_hunks(
17936        &mut self,
17937        stage: bool,
17938        ranges: Vec<Range<Anchor>>,
17939        cx: &mut Context<Self>,
17940    ) {
17941        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17942        cx.spawn(async move |this, cx| {
17943            task.await?;
17944            this.update(cx, |this, cx| {
17945                let snapshot = this.buffer.read(cx).snapshot(cx);
17946                let chunk_by = this
17947                    .diff_hunks_in_ranges(&ranges, &snapshot)
17948                    .chunk_by(|hunk| hunk.buffer_id);
17949                for (buffer_id, hunks) in &chunk_by {
17950                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17951                }
17952            })
17953        })
17954        .detach_and_log_err(cx);
17955    }
17956
17957    fn save_buffers_for_ranges_if_needed(
17958        &mut self,
17959        ranges: &[Range<Anchor>],
17960        cx: &mut Context<Editor>,
17961    ) -> Task<Result<()>> {
17962        let multibuffer = self.buffer.read(cx);
17963        let snapshot = multibuffer.read(cx);
17964        let buffer_ids: HashSet<_> = ranges
17965            .iter()
17966            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17967            .collect();
17968        drop(snapshot);
17969
17970        let mut buffers = HashSet::default();
17971        for buffer_id in buffer_ids {
17972            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17973                let buffer = buffer_entity.read(cx);
17974                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17975                {
17976                    buffers.insert(buffer_entity);
17977                }
17978            }
17979        }
17980
17981        if let Some(project) = &self.project {
17982            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17983        } else {
17984            Task::ready(Ok(()))
17985        }
17986    }
17987
17988    fn do_stage_or_unstage_and_next(
17989        &mut self,
17990        stage: bool,
17991        window: &mut Window,
17992        cx: &mut Context<Self>,
17993    ) {
17994        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17995
17996        if ranges.iter().any(|range| range.start != range.end) {
17997            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17998            return;
17999        }
18000
18001        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18002        let snapshot = self.snapshot(window, cx);
18003        let position = self.selections.newest::<Point>(cx).head();
18004        let mut row = snapshot
18005            .buffer_snapshot
18006            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18007            .find(|hunk| hunk.row_range.start.0 > position.row)
18008            .map(|hunk| hunk.row_range.start);
18009
18010        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18011        // Outside of the project diff editor, wrap around to the beginning.
18012        if !all_diff_hunks_expanded {
18013            row = row.or_else(|| {
18014                snapshot
18015                    .buffer_snapshot
18016                    .diff_hunks_in_range(Point::zero()..position)
18017                    .find(|hunk| hunk.row_range.end.0 < position.row)
18018                    .map(|hunk| hunk.row_range.start)
18019            });
18020        }
18021
18022        if let Some(row) = row {
18023            let destination = Point::new(row.0, 0);
18024            let autoscroll = Autoscroll::center();
18025
18026            self.unfold_ranges(&[destination..destination], false, false, cx);
18027            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18028                s.select_ranges([destination..destination]);
18029            });
18030        }
18031    }
18032
18033    fn do_stage_or_unstage(
18034        &self,
18035        stage: bool,
18036        buffer_id: BufferId,
18037        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18038        cx: &mut App,
18039    ) -> Option<()> {
18040        let project = self.project()?;
18041        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18042        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18043        let buffer_snapshot = buffer.read(cx).snapshot();
18044        let file_exists = buffer_snapshot
18045            .file()
18046            .is_some_and(|file| file.disk_state().exists());
18047        diff.update(cx, |diff, cx| {
18048            diff.stage_or_unstage_hunks(
18049                stage,
18050                &hunks
18051                    .map(|hunk| buffer_diff::DiffHunk {
18052                        buffer_range: hunk.buffer_range,
18053                        diff_base_byte_range: hunk.diff_base_byte_range,
18054                        secondary_status: hunk.secondary_status,
18055                        range: Point::zero()..Point::zero(), // unused
18056                    })
18057                    .collect::<Vec<_>>(),
18058                &buffer_snapshot,
18059                file_exists,
18060                cx,
18061            )
18062        });
18063        None
18064    }
18065
18066    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18067        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18068        self.buffer
18069            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18070    }
18071
18072    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18073        self.buffer.update(cx, |buffer, cx| {
18074            let ranges = vec![Anchor::min()..Anchor::max()];
18075            if !buffer.all_diff_hunks_expanded()
18076                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18077            {
18078                buffer.collapse_diff_hunks(ranges, cx);
18079                true
18080            } else {
18081                false
18082            }
18083        })
18084    }
18085
18086    fn toggle_diff_hunks_in_ranges(
18087        &mut self,
18088        ranges: Vec<Range<Anchor>>,
18089        cx: &mut Context<Editor>,
18090    ) {
18091        self.buffer.update(cx, |buffer, cx| {
18092            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18093            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18094        })
18095    }
18096
18097    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18098        self.buffer.update(cx, |buffer, cx| {
18099            let snapshot = buffer.snapshot(cx);
18100            let excerpt_id = range.end.excerpt_id;
18101            let point_range = range.to_point(&snapshot);
18102            let expand = !buffer.single_hunk_is_expanded(range, cx);
18103            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18104        })
18105    }
18106
18107    pub(crate) fn apply_all_diff_hunks(
18108        &mut self,
18109        _: &ApplyAllDiffHunks,
18110        window: &mut Window,
18111        cx: &mut Context<Self>,
18112    ) {
18113        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18114
18115        let buffers = self.buffer.read(cx).all_buffers();
18116        for branch_buffer in buffers {
18117            branch_buffer.update(cx, |branch_buffer, cx| {
18118                branch_buffer.merge_into_base(Vec::new(), cx);
18119            });
18120        }
18121
18122        if let Some(project) = self.project.clone() {
18123            self.save(
18124                SaveOptions {
18125                    format: true,
18126                    autosave: false,
18127                },
18128                project,
18129                window,
18130                cx,
18131            )
18132            .detach_and_log_err(cx);
18133        }
18134    }
18135
18136    pub(crate) fn apply_selected_diff_hunks(
18137        &mut self,
18138        _: &ApplyDiffHunk,
18139        window: &mut Window,
18140        cx: &mut Context<Self>,
18141    ) {
18142        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18143        let snapshot = self.snapshot(window, cx);
18144        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18145        let mut ranges_by_buffer = HashMap::default();
18146        self.transact(window, cx, |editor, _window, cx| {
18147            for hunk in hunks {
18148                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18149                    ranges_by_buffer
18150                        .entry(buffer.clone())
18151                        .or_insert_with(Vec::new)
18152                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18153                }
18154            }
18155
18156            for (buffer, ranges) in ranges_by_buffer {
18157                buffer.update(cx, |buffer, cx| {
18158                    buffer.merge_into_base(ranges, cx);
18159                });
18160            }
18161        });
18162
18163        if let Some(project) = self.project.clone() {
18164            self.save(
18165                SaveOptions {
18166                    format: true,
18167                    autosave: false,
18168                },
18169                project,
18170                window,
18171                cx,
18172            )
18173            .detach_and_log_err(cx);
18174        }
18175    }
18176
18177    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18178        if hovered != self.gutter_hovered {
18179            self.gutter_hovered = hovered;
18180            cx.notify();
18181        }
18182    }
18183
18184    pub fn insert_blocks(
18185        &mut self,
18186        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18187        autoscroll: Option<Autoscroll>,
18188        cx: &mut Context<Self>,
18189    ) -> Vec<CustomBlockId> {
18190        let blocks = self
18191            .display_map
18192            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18193        if let Some(autoscroll) = autoscroll {
18194            self.request_autoscroll(autoscroll, cx);
18195        }
18196        cx.notify();
18197        blocks
18198    }
18199
18200    pub fn resize_blocks(
18201        &mut self,
18202        heights: HashMap<CustomBlockId, u32>,
18203        autoscroll: Option<Autoscroll>,
18204        cx: &mut Context<Self>,
18205    ) {
18206        self.display_map
18207            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18208        if let Some(autoscroll) = autoscroll {
18209            self.request_autoscroll(autoscroll, cx);
18210        }
18211        cx.notify();
18212    }
18213
18214    pub fn replace_blocks(
18215        &mut self,
18216        renderers: HashMap<CustomBlockId, RenderBlock>,
18217        autoscroll: Option<Autoscroll>,
18218        cx: &mut Context<Self>,
18219    ) {
18220        self.display_map
18221            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18222        if let Some(autoscroll) = autoscroll {
18223            self.request_autoscroll(autoscroll, cx);
18224        }
18225        cx.notify();
18226    }
18227
18228    pub fn remove_blocks(
18229        &mut self,
18230        block_ids: HashSet<CustomBlockId>,
18231        autoscroll: Option<Autoscroll>,
18232        cx: &mut Context<Self>,
18233    ) {
18234        self.display_map.update(cx, |display_map, cx| {
18235            display_map.remove_blocks(block_ids, cx)
18236        });
18237        if let Some(autoscroll) = autoscroll {
18238            self.request_autoscroll(autoscroll, cx);
18239        }
18240        cx.notify();
18241    }
18242
18243    pub fn row_for_block(
18244        &self,
18245        block_id: CustomBlockId,
18246        cx: &mut Context<Self>,
18247    ) -> Option<DisplayRow> {
18248        self.display_map
18249            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18250    }
18251
18252    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18253        self.focused_block = Some(focused_block);
18254    }
18255
18256    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18257        self.focused_block.take()
18258    }
18259
18260    pub fn insert_creases(
18261        &mut self,
18262        creases: impl IntoIterator<Item = Crease<Anchor>>,
18263        cx: &mut Context<Self>,
18264    ) -> Vec<CreaseId> {
18265        self.display_map
18266            .update(cx, |map, cx| map.insert_creases(creases, cx))
18267    }
18268
18269    pub fn remove_creases(
18270        &mut self,
18271        ids: impl IntoIterator<Item = CreaseId>,
18272        cx: &mut Context<Self>,
18273    ) -> Vec<(CreaseId, Range<Anchor>)> {
18274        self.display_map
18275            .update(cx, |map, cx| map.remove_creases(ids, cx))
18276    }
18277
18278    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18279        self.display_map
18280            .update(cx, |map, cx| map.snapshot(cx))
18281            .longest_row()
18282    }
18283
18284    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18285        self.display_map
18286            .update(cx, |map, cx| map.snapshot(cx))
18287            .max_point()
18288    }
18289
18290    pub fn text(&self, cx: &App) -> String {
18291        self.buffer.read(cx).read(cx).text()
18292    }
18293
18294    pub fn is_empty(&self, cx: &App) -> bool {
18295        self.buffer.read(cx).read(cx).is_empty()
18296    }
18297
18298    pub fn text_option(&self, cx: &App) -> Option<String> {
18299        let text = self.text(cx);
18300        let text = text.trim();
18301
18302        if text.is_empty() {
18303            return None;
18304        }
18305
18306        Some(text.to_string())
18307    }
18308
18309    pub fn set_text(
18310        &mut self,
18311        text: impl Into<Arc<str>>,
18312        window: &mut Window,
18313        cx: &mut Context<Self>,
18314    ) {
18315        self.transact(window, cx, |this, _, cx| {
18316            this.buffer
18317                .read(cx)
18318                .as_singleton()
18319                .expect("you can only call set_text on editors for singleton buffers")
18320                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18321        });
18322    }
18323
18324    pub fn display_text(&self, cx: &mut App) -> String {
18325        self.display_map
18326            .update(cx, |map, cx| map.snapshot(cx))
18327            .text()
18328    }
18329
18330    fn create_minimap(
18331        &self,
18332        minimap_settings: MinimapSettings,
18333        window: &mut Window,
18334        cx: &mut Context<Self>,
18335    ) -> Option<Entity<Self>> {
18336        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18337            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18338    }
18339
18340    fn initialize_new_minimap(
18341        &self,
18342        minimap_settings: MinimapSettings,
18343        window: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) -> Entity<Self> {
18346        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18347
18348        let mut minimap = Editor::new_internal(
18349            EditorMode::Minimap {
18350                parent: cx.weak_entity(),
18351            },
18352            self.buffer.clone(),
18353            None,
18354            Some(self.display_map.clone()),
18355            window,
18356            cx,
18357        );
18358        minimap.scroll_manager.clone_state(&self.scroll_manager);
18359        minimap.set_text_style_refinement(TextStyleRefinement {
18360            font_size: Some(MINIMAP_FONT_SIZE),
18361            font_weight: Some(MINIMAP_FONT_WEIGHT),
18362            ..Default::default()
18363        });
18364        minimap.update_minimap_configuration(minimap_settings, cx);
18365        cx.new(|_| minimap)
18366    }
18367
18368    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18369        let current_line_highlight = minimap_settings
18370            .current_line_highlight
18371            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18372        self.set_current_line_highlight(Some(current_line_highlight));
18373    }
18374
18375    pub fn minimap(&self) -> Option<&Entity<Self>> {
18376        self.minimap
18377            .as_ref()
18378            .filter(|_| self.minimap_visibility.visible())
18379    }
18380
18381    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18382        let mut wrap_guides = smallvec![];
18383
18384        if self.show_wrap_guides == Some(false) {
18385            return wrap_guides;
18386        }
18387
18388        let settings = self.buffer.read(cx).language_settings(cx);
18389        if settings.show_wrap_guides {
18390            match self.soft_wrap_mode(cx) {
18391                SoftWrap::Column(soft_wrap) => {
18392                    wrap_guides.push((soft_wrap as usize, true));
18393                }
18394                SoftWrap::Bounded(soft_wrap) => {
18395                    wrap_guides.push((soft_wrap as usize, true));
18396                }
18397                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18398            }
18399            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18400        }
18401
18402        wrap_guides
18403    }
18404
18405    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18406        let settings = self.buffer.read(cx).language_settings(cx);
18407        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18408        match mode {
18409            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18410                SoftWrap::None
18411            }
18412            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18413            language_settings::SoftWrap::PreferredLineLength => {
18414                SoftWrap::Column(settings.preferred_line_length)
18415            }
18416            language_settings::SoftWrap::Bounded => {
18417                SoftWrap::Bounded(settings.preferred_line_length)
18418            }
18419        }
18420    }
18421
18422    pub fn set_soft_wrap_mode(
18423        &mut self,
18424        mode: language_settings::SoftWrap,
18425
18426        cx: &mut Context<Self>,
18427    ) {
18428        self.soft_wrap_mode_override = Some(mode);
18429        cx.notify();
18430    }
18431
18432    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18433        self.hard_wrap = hard_wrap;
18434        cx.notify();
18435    }
18436
18437    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18438        self.text_style_refinement = Some(style);
18439    }
18440
18441    /// called by the Element so we know what style we were most recently rendered with.
18442    pub(crate) fn set_style(
18443        &mut self,
18444        style: EditorStyle,
18445        window: &mut Window,
18446        cx: &mut Context<Self>,
18447    ) {
18448        // We intentionally do not inform the display map about the minimap style
18449        // so that wrapping is not recalculated and stays consistent for the editor
18450        // and its linked minimap.
18451        if !self.mode.is_minimap() {
18452            let rem_size = window.rem_size();
18453            self.display_map.update(cx, |map, cx| {
18454                map.set_font(
18455                    style.text.font(),
18456                    style.text.font_size.to_pixels(rem_size),
18457                    cx,
18458                )
18459            });
18460        }
18461        self.style = Some(style);
18462    }
18463
18464    pub fn style(&self) -> Option<&EditorStyle> {
18465        self.style.as_ref()
18466    }
18467
18468    // Called by the element. This method is not designed to be called outside of the editor
18469    // element's layout code because it does not notify when rewrapping is computed synchronously.
18470    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18471        self.display_map
18472            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18473    }
18474
18475    pub fn set_soft_wrap(&mut self) {
18476        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18477    }
18478
18479    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18480        if self.soft_wrap_mode_override.is_some() {
18481            self.soft_wrap_mode_override.take();
18482        } else {
18483            let soft_wrap = match self.soft_wrap_mode(cx) {
18484                SoftWrap::GitDiff => return,
18485                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18486                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18487                    language_settings::SoftWrap::None
18488                }
18489            };
18490            self.soft_wrap_mode_override = Some(soft_wrap);
18491        }
18492        cx.notify();
18493    }
18494
18495    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18496        let Some(workspace) = self.workspace() else {
18497            return;
18498        };
18499        let fs = workspace.read(cx).app_state().fs.clone();
18500        let current_show = TabBarSettings::get_global(cx).show;
18501        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18502            setting.show = Some(!current_show);
18503        });
18504    }
18505
18506    pub fn toggle_indent_guides(
18507        &mut self,
18508        _: &ToggleIndentGuides,
18509        _: &mut Window,
18510        cx: &mut Context<Self>,
18511    ) {
18512        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18513            self.buffer
18514                .read(cx)
18515                .language_settings(cx)
18516                .indent_guides
18517                .enabled
18518        });
18519        self.show_indent_guides = Some(!currently_enabled);
18520        cx.notify();
18521    }
18522
18523    fn should_show_indent_guides(&self) -> Option<bool> {
18524        self.show_indent_guides
18525    }
18526
18527    pub fn toggle_line_numbers(
18528        &mut self,
18529        _: &ToggleLineNumbers,
18530        _: &mut Window,
18531        cx: &mut Context<Self>,
18532    ) {
18533        let mut editor_settings = EditorSettings::get_global(cx).clone();
18534        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18535        EditorSettings::override_global(editor_settings, cx);
18536    }
18537
18538    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18539        if let Some(show_line_numbers) = self.show_line_numbers {
18540            return show_line_numbers;
18541        }
18542        EditorSettings::get_global(cx).gutter.line_numbers
18543    }
18544
18545    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18546        self.use_relative_line_numbers
18547            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18548    }
18549
18550    pub fn toggle_relative_line_numbers(
18551        &mut self,
18552        _: &ToggleRelativeLineNumbers,
18553        _: &mut Window,
18554        cx: &mut Context<Self>,
18555    ) {
18556        let is_relative = self.should_use_relative_line_numbers(cx);
18557        self.set_relative_line_number(Some(!is_relative), cx)
18558    }
18559
18560    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18561        self.use_relative_line_numbers = is_relative;
18562        cx.notify();
18563    }
18564
18565    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18566        self.show_gutter = show_gutter;
18567        cx.notify();
18568    }
18569
18570    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18571        self.show_scrollbars = ScrollbarAxes {
18572            horizontal: show,
18573            vertical: show,
18574        };
18575        cx.notify();
18576    }
18577
18578    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18579        self.show_scrollbars.vertical = show;
18580        cx.notify();
18581    }
18582
18583    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18584        self.show_scrollbars.horizontal = show;
18585        cx.notify();
18586    }
18587
18588    pub fn set_minimap_visibility(
18589        &mut self,
18590        minimap_visibility: MinimapVisibility,
18591        window: &mut Window,
18592        cx: &mut Context<Self>,
18593    ) {
18594        if self.minimap_visibility != minimap_visibility {
18595            if minimap_visibility.visible() && self.minimap.is_none() {
18596                let minimap_settings = EditorSettings::get_global(cx).minimap;
18597                self.minimap =
18598                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18599            }
18600            self.minimap_visibility = minimap_visibility;
18601            cx.notify();
18602        }
18603    }
18604
18605    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18606        self.set_show_scrollbars(false, cx);
18607        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18608    }
18609
18610    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18611        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18612    }
18613
18614    /// Normally the text in full mode and auto height editors is padded on the
18615    /// left side by roughly half a character width for improved hit testing.
18616    ///
18617    /// Use this method to disable this for cases where this is not wanted (e.g.
18618    /// if you want to align the editor text with some other text above or below)
18619    /// or if you want to add this padding to single-line editors.
18620    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18621        self.offset_content = offset_content;
18622        cx.notify();
18623    }
18624
18625    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18626        self.show_line_numbers = Some(show_line_numbers);
18627        cx.notify();
18628    }
18629
18630    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18631        self.disable_expand_excerpt_buttons = true;
18632        cx.notify();
18633    }
18634
18635    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18636        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18637        cx.notify();
18638    }
18639
18640    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18641        self.show_code_actions = Some(show_code_actions);
18642        cx.notify();
18643    }
18644
18645    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18646        self.show_runnables = Some(show_runnables);
18647        cx.notify();
18648    }
18649
18650    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18651        self.show_breakpoints = Some(show_breakpoints);
18652        cx.notify();
18653    }
18654
18655    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18656        if self.display_map.read(cx).masked != masked {
18657            self.display_map.update(cx, |map, _| map.masked = masked);
18658        }
18659        cx.notify()
18660    }
18661
18662    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18663        self.show_wrap_guides = Some(show_wrap_guides);
18664        cx.notify();
18665    }
18666
18667    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18668        self.show_indent_guides = Some(show_indent_guides);
18669        cx.notify();
18670    }
18671
18672    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18673        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18674            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18675                && let Some(dir) = file.abs_path(cx).parent()
18676            {
18677                return Some(dir.to_owned());
18678            }
18679
18680            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18681                return Some(project_path.path.to_path_buf());
18682            }
18683        }
18684
18685        None
18686    }
18687
18688    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18689        self.active_excerpt(cx)?
18690            .1
18691            .read(cx)
18692            .file()
18693            .and_then(|f| f.as_local())
18694    }
18695
18696    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18697        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18698            let buffer = buffer.read(cx);
18699            if let Some(project_path) = buffer.project_path(cx) {
18700                let project = self.project()?.read(cx);
18701                project.absolute_path(&project_path, cx)
18702            } else {
18703                buffer
18704                    .file()
18705                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18706            }
18707        })
18708    }
18709
18710    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18711        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18712            let project_path = buffer.read(cx).project_path(cx)?;
18713            let project = self.project()?.read(cx);
18714            let entry = project.entry_for_path(&project_path, cx)?;
18715            let path = entry.path.to_path_buf();
18716            Some(path)
18717        })
18718    }
18719
18720    pub fn reveal_in_finder(
18721        &mut self,
18722        _: &RevealInFileManager,
18723        _window: &mut Window,
18724        cx: &mut Context<Self>,
18725    ) {
18726        if let Some(target) = self.target_file(cx) {
18727            cx.reveal_path(&target.abs_path(cx));
18728        }
18729    }
18730
18731    pub fn copy_path(
18732        &mut self,
18733        _: &zed_actions::workspace::CopyPath,
18734        _window: &mut Window,
18735        cx: &mut Context<Self>,
18736    ) {
18737        if let Some(path) = self.target_file_abs_path(cx)
18738            && let Some(path) = path.to_str()
18739        {
18740            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18741        }
18742    }
18743
18744    pub fn copy_relative_path(
18745        &mut self,
18746        _: &zed_actions::workspace::CopyRelativePath,
18747        _window: &mut Window,
18748        cx: &mut Context<Self>,
18749    ) {
18750        if let Some(path) = self.target_file_path(cx)
18751            && let Some(path) = path.to_str()
18752        {
18753            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18754        }
18755    }
18756
18757    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18758        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18759            buffer.read(cx).project_path(cx)
18760        } else {
18761            None
18762        }
18763    }
18764
18765    // Returns true if the editor handled a go-to-line request
18766    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18767        maybe!({
18768            let breakpoint_store = self.breakpoint_store.as_ref()?;
18769
18770            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18771            else {
18772                self.clear_row_highlights::<ActiveDebugLine>();
18773                return None;
18774            };
18775
18776            let position = active_stack_frame.position;
18777            let buffer_id = position.buffer_id?;
18778            let snapshot = self
18779                .project
18780                .as_ref()?
18781                .read(cx)
18782                .buffer_for_id(buffer_id, cx)?
18783                .read(cx)
18784                .snapshot();
18785
18786            let mut handled = false;
18787            for (id, ExcerptRange { context, .. }) in
18788                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18789            {
18790                if context.start.cmp(&position, &snapshot).is_ge()
18791                    || context.end.cmp(&position, &snapshot).is_lt()
18792                {
18793                    continue;
18794                }
18795                let snapshot = self.buffer.read(cx).snapshot(cx);
18796                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18797
18798                handled = true;
18799                self.clear_row_highlights::<ActiveDebugLine>();
18800
18801                self.go_to_line::<ActiveDebugLine>(
18802                    multibuffer_anchor,
18803                    Some(cx.theme().colors().editor_debugger_active_line_background),
18804                    window,
18805                    cx,
18806                );
18807
18808                cx.notify();
18809            }
18810
18811            handled.then_some(())
18812        })
18813        .is_some()
18814    }
18815
18816    pub fn copy_file_name_without_extension(
18817        &mut self,
18818        _: &CopyFileNameWithoutExtension,
18819        _: &mut Window,
18820        cx: &mut Context<Self>,
18821    ) {
18822        if let Some(file) = self.target_file(cx)
18823            && let Some(file_stem) = file.path().file_stem()
18824            && let Some(name) = file_stem.to_str()
18825        {
18826            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18827        }
18828    }
18829
18830    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18831        if let Some(file) = self.target_file(cx)
18832            && let Some(file_name) = file.path().file_name()
18833            && let Some(name) = file_name.to_str()
18834        {
18835            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18836        }
18837    }
18838
18839    pub fn toggle_git_blame(
18840        &mut self,
18841        _: &::git::Blame,
18842        window: &mut Window,
18843        cx: &mut Context<Self>,
18844    ) {
18845        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18846
18847        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18848            self.start_git_blame(true, window, cx);
18849        }
18850
18851        cx.notify();
18852    }
18853
18854    pub fn toggle_git_blame_inline(
18855        &mut self,
18856        _: &ToggleGitBlameInline,
18857        window: &mut Window,
18858        cx: &mut Context<Self>,
18859    ) {
18860        self.toggle_git_blame_inline_internal(true, window, cx);
18861        cx.notify();
18862    }
18863
18864    pub fn open_git_blame_commit(
18865        &mut self,
18866        _: &OpenGitBlameCommit,
18867        window: &mut Window,
18868        cx: &mut Context<Self>,
18869    ) {
18870        self.open_git_blame_commit_internal(window, cx);
18871    }
18872
18873    fn open_git_blame_commit_internal(
18874        &mut self,
18875        window: &mut Window,
18876        cx: &mut Context<Self>,
18877    ) -> Option<()> {
18878        let blame = self.blame.as_ref()?;
18879        let snapshot = self.snapshot(window, cx);
18880        let cursor = self.selections.newest::<Point>(cx).head();
18881        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18882        let blame_entry = blame
18883            .update(cx, |blame, cx| {
18884                blame
18885                    .blame_for_rows(
18886                        &[RowInfo {
18887                            buffer_id: Some(buffer.remote_id()),
18888                            buffer_row: Some(point.row),
18889                            ..Default::default()
18890                        }],
18891                        cx,
18892                    )
18893                    .next()
18894            })
18895            .flatten()?;
18896        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18897        let repo = blame.read(cx).repository(cx)?;
18898        let workspace = self.workspace()?.downgrade();
18899        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18900        None
18901    }
18902
18903    pub fn git_blame_inline_enabled(&self) -> bool {
18904        self.git_blame_inline_enabled
18905    }
18906
18907    pub fn toggle_selection_menu(
18908        &mut self,
18909        _: &ToggleSelectionMenu,
18910        _: &mut Window,
18911        cx: &mut Context<Self>,
18912    ) {
18913        self.show_selection_menu = self
18914            .show_selection_menu
18915            .map(|show_selections_menu| !show_selections_menu)
18916            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18917
18918        cx.notify();
18919    }
18920
18921    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18922        self.show_selection_menu
18923            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18924    }
18925
18926    fn start_git_blame(
18927        &mut self,
18928        user_triggered: bool,
18929        window: &mut Window,
18930        cx: &mut Context<Self>,
18931    ) {
18932        if let Some(project) = self.project() {
18933            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18934                return;
18935            };
18936
18937            if buffer.read(cx).file().is_none() {
18938                return;
18939            }
18940
18941            let focused = self.focus_handle(cx).contains_focused(window, cx);
18942
18943            let project = project.clone();
18944            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18945            self.blame_subscription =
18946                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18947            self.blame = Some(blame);
18948        }
18949    }
18950
18951    fn toggle_git_blame_inline_internal(
18952        &mut self,
18953        user_triggered: bool,
18954        window: &mut Window,
18955        cx: &mut Context<Self>,
18956    ) {
18957        if self.git_blame_inline_enabled {
18958            self.git_blame_inline_enabled = false;
18959            self.show_git_blame_inline = false;
18960            self.show_git_blame_inline_delay_task.take();
18961        } else {
18962            self.git_blame_inline_enabled = true;
18963            self.start_git_blame_inline(user_triggered, window, cx);
18964        }
18965
18966        cx.notify();
18967    }
18968
18969    fn start_git_blame_inline(
18970        &mut self,
18971        user_triggered: bool,
18972        window: &mut Window,
18973        cx: &mut Context<Self>,
18974    ) {
18975        self.start_git_blame(user_triggered, window, cx);
18976
18977        if ProjectSettings::get_global(cx)
18978            .git
18979            .inline_blame_delay()
18980            .is_some()
18981        {
18982            self.start_inline_blame_timer(window, cx);
18983        } else {
18984            self.show_git_blame_inline = true
18985        }
18986    }
18987
18988    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18989        self.blame.as_ref()
18990    }
18991
18992    pub fn show_git_blame_gutter(&self) -> bool {
18993        self.show_git_blame_gutter
18994    }
18995
18996    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18997        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18998    }
18999
19000    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19001        self.show_git_blame_inline
19002            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19003            && !self.newest_selection_head_on_empty_line(cx)
19004            && self.has_blame_entries(cx)
19005    }
19006
19007    fn has_blame_entries(&self, cx: &App) -> bool {
19008        self.blame()
19009            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19010    }
19011
19012    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19013        let cursor_anchor = self.selections.newest_anchor().head();
19014
19015        let snapshot = self.buffer.read(cx).snapshot(cx);
19016        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19017
19018        snapshot.line_len(buffer_row) == 0
19019    }
19020
19021    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19022        let buffer_and_selection = maybe!({
19023            let selection = self.selections.newest::<Point>(cx);
19024            let selection_range = selection.range();
19025
19026            let multi_buffer = self.buffer().read(cx);
19027            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19028            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19029
19030            let (buffer, range, _) = if selection.reversed {
19031                buffer_ranges.first()
19032            } else {
19033                buffer_ranges.last()
19034            }?;
19035
19036            let selection = text::ToPoint::to_point(&range.start, buffer).row
19037                ..text::ToPoint::to_point(&range.end, buffer).row;
19038            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19039        });
19040
19041        let Some((buffer, selection)) = buffer_and_selection else {
19042            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19043        };
19044
19045        let Some(project) = self.project() else {
19046            return Task::ready(Err(anyhow!("editor does not have project")));
19047        };
19048
19049        project.update(cx, |project, cx| {
19050            project.get_permalink_to_line(&buffer, selection, cx)
19051        })
19052    }
19053
19054    pub fn copy_permalink_to_line(
19055        &mut self,
19056        _: &CopyPermalinkToLine,
19057        window: &mut Window,
19058        cx: &mut Context<Self>,
19059    ) {
19060        let permalink_task = self.get_permalink_to_line(cx);
19061        let workspace = self.workspace();
19062
19063        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19064            Ok(permalink) => {
19065                cx.update(|_, cx| {
19066                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19067                })
19068                .ok();
19069            }
19070            Err(err) => {
19071                let message = format!("Failed to copy permalink: {err}");
19072
19073                anyhow::Result::<()>::Err(err).log_err();
19074
19075                if let Some(workspace) = workspace {
19076                    workspace
19077                        .update_in(cx, |workspace, _, cx| {
19078                            struct CopyPermalinkToLine;
19079
19080                            workspace.show_toast(
19081                                Toast::new(
19082                                    NotificationId::unique::<CopyPermalinkToLine>(),
19083                                    message,
19084                                ),
19085                                cx,
19086                            )
19087                        })
19088                        .ok();
19089                }
19090            }
19091        })
19092        .detach();
19093    }
19094
19095    pub fn copy_file_location(
19096        &mut self,
19097        _: &CopyFileLocation,
19098        _: &mut Window,
19099        cx: &mut Context<Self>,
19100    ) {
19101        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19102        if let Some(file) = self.target_file(cx)
19103            && let Some(path) = file.path().to_str()
19104        {
19105            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19106        }
19107    }
19108
19109    pub fn open_permalink_to_line(
19110        &mut self,
19111        _: &OpenPermalinkToLine,
19112        window: &mut Window,
19113        cx: &mut Context<Self>,
19114    ) {
19115        let permalink_task = self.get_permalink_to_line(cx);
19116        let workspace = self.workspace();
19117
19118        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19119            Ok(permalink) => {
19120                cx.update(|_, cx| {
19121                    cx.open_url(permalink.as_ref());
19122                })
19123                .ok();
19124            }
19125            Err(err) => {
19126                let message = format!("Failed to open permalink: {err}");
19127
19128                anyhow::Result::<()>::Err(err).log_err();
19129
19130                if let Some(workspace) = workspace {
19131                    workspace
19132                        .update(cx, |workspace, cx| {
19133                            struct OpenPermalinkToLine;
19134
19135                            workspace.show_toast(
19136                                Toast::new(
19137                                    NotificationId::unique::<OpenPermalinkToLine>(),
19138                                    message,
19139                                ),
19140                                cx,
19141                            )
19142                        })
19143                        .ok();
19144                }
19145            }
19146        })
19147        .detach();
19148    }
19149
19150    pub fn insert_uuid_v4(
19151        &mut self,
19152        _: &InsertUuidV4,
19153        window: &mut Window,
19154        cx: &mut Context<Self>,
19155    ) {
19156        self.insert_uuid(UuidVersion::V4, window, cx);
19157    }
19158
19159    pub fn insert_uuid_v7(
19160        &mut self,
19161        _: &InsertUuidV7,
19162        window: &mut Window,
19163        cx: &mut Context<Self>,
19164    ) {
19165        self.insert_uuid(UuidVersion::V7, window, cx);
19166    }
19167
19168    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19169        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19170        self.transact(window, cx, |this, window, cx| {
19171            let edits = this
19172                .selections
19173                .all::<Point>(cx)
19174                .into_iter()
19175                .map(|selection| {
19176                    let uuid = match version {
19177                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19178                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19179                    };
19180
19181                    (selection.range(), uuid.to_string())
19182                });
19183            this.edit(edits, cx);
19184            this.refresh_edit_prediction(true, false, window, cx);
19185        });
19186    }
19187
19188    pub fn open_selections_in_multibuffer(
19189        &mut self,
19190        _: &OpenSelectionsInMultibuffer,
19191        window: &mut Window,
19192        cx: &mut Context<Self>,
19193    ) {
19194        let multibuffer = self.buffer.read(cx);
19195
19196        let Some(buffer) = multibuffer.as_singleton() else {
19197            return;
19198        };
19199
19200        let Some(workspace) = self.workspace() else {
19201            return;
19202        };
19203
19204        let title = multibuffer.title(cx).to_string();
19205
19206        let locations = self
19207            .selections
19208            .all_anchors(cx)
19209            .iter()
19210            .map(|selection| Location {
19211                buffer: buffer.clone(),
19212                range: selection.start.text_anchor..selection.end.text_anchor,
19213            })
19214            .collect::<Vec<_>>();
19215
19216        cx.spawn_in(window, async move |_, cx| {
19217            workspace.update_in(cx, |workspace, window, cx| {
19218                Self::open_locations_in_multibuffer(
19219                    workspace,
19220                    locations,
19221                    format!("Selections for '{title}'"),
19222                    false,
19223                    MultibufferSelectionMode::All,
19224                    window,
19225                    cx,
19226                );
19227            })
19228        })
19229        .detach();
19230    }
19231
19232    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19233    /// last highlight added will be used.
19234    ///
19235    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19236    pub fn highlight_rows<T: 'static>(
19237        &mut self,
19238        range: Range<Anchor>,
19239        color: Hsla,
19240        options: RowHighlightOptions,
19241        cx: &mut Context<Self>,
19242    ) {
19243        let snapshot = self.buffer().read(cx).snapshot(cx);
19244        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19245        let ix = row_highlights.binary_search_by(|highlight| {
19246            Ordering::Equal
19247                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19248                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19249        });
19250
19251        if let Err(mut ix) = ix {
19252            let index = post_inc(&mut self.highlight_order);
19253
19254            // If this range intersects with the preceding highlight, then merge it with
19255            // the preceding highlight. Otherwise insert a new highlight.
19256            let mut merged = false;
19257            if ix > 0 {
19258                let prev_highlight = &mut row_highlights[ix - 1];
19259                if prev_highlight
19260                    .range
19261                    .end
19262                    .cmp(&range.start, &snapshot)
19263                    .is_ge()
19264                {
19265                    ix -= 1;
19266                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19267                        prev_highlight.range.end = range.end;
19268                    }
19269                    merged = true;
19270                    prev_highlight.index = index;
19271                    prev_highlight.color = color;
19272                    prev_highlight.options = options;
19273                }
19274            }
19275
19276            if !merged {
19277                row_highlights.insert(
19278                    ix,
19279                    RowHighlight {
19280                        range,
19281                        index,
19282                        color,
19283                        options,
19284                        type_id: TypeId::of::<T>(),
19285                    },
19286                );
19287            }
19288
19289            // If any of the following highlights intersect with this one, merge them.
19290            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19291                let highlight = &row_highlights[ix];
19292                if next_highlight
19293                    .range
19294                    .start
19295                    .cmp(&highlight.range.end, &snapshot)
19296                    .is_le()
19297                {
19298                    if next_highlight
19299                        .range
19300                        .end
19301                        .cmp(&highlight.range.end, &snapshot)
19302                        .is_gt()
19303                    {
19304                        row_highlights[ix].range.end = next_highlight.range.end;
19305                    }
19306                    row_highlights.remove(ix + 1);
19307                } else {
19308                    break;
19309                }
19310            }
19311        }
19312    }
19313
19314    /// Remove any highlighted row ranges of the given type that intersect the
19315    /// given ranges.
19316    pub fn remove_highlighted_rows<T: 'static>(
19317        &mut self,
19318        ranges_to_remove: Vec<Range<Anchor>>,
19319        cx: &mut Context<Self>,
19320    ) {
19321        let snapshot = self.buffer().read(cx).snapshot(cx);
19322        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19323        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19324        row_highlights.retain(|highlight| {
19325            while let Some(range_to_remove) = ranges_to_remove.peek() {
19326                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19327                    Ordering::Less | Ordering::Equal => {
19328                        ranges_to_remove.next();
19329                    }
19330                    Ordering::Greater => {
19331                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19332                            Ordering::Less | Ordering::Equal => {
19333                                return false;
19334                            }
19335                            Ordering::Greater => break,
19336                        }
19337                    }
19338                }
19339            }
19340
19341            true
19342        })
19343    }
19344
19345    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19346    pub fn clear_row_highlights<T: 'static>(&mut self) {
19347        self.highlighted_rows.remove(&TypeId::of::<T>());
19348    }
19349
19350    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19351    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19352        self.highlighted_rows
19353            .get(&TypeId::of::<T>())
19354            .map_or(&[] as &[_], |vec| vec.as_slice())
19355            .iter()
19356            .map(|highlight| (highlight.range.clone(), highlight.color))
19357    }
19358
19359    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19360    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19361    /// Allows to ignore certain kinds of highlights.
19362    pub fn highlighted_display_rows(
19363        &self,
19364        window: &mut Window,
19365        cx: &mut App,
19366    ) -> BTreeMap<DisplayRow, LineHighlight> {
19367        let snapshot = self.snapshot(window, cx);
19368        let mut used_highlight_orders = HashMap::default();
19369        self.highlighted_rows
19370            .iter()
19371            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19372            .fold(
19373                BTreeMap::<DisplayRow, LineHighlight>::new(),
19374                |mut unique_rows, highlight| {
19375                    let start = highlight.range.start.to_display_point(&snapshot);
19376                    let end = highlight.range.end.to_display_point(&snapshot);
19377                    let start_row = start.row().0;
19378                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19379                        && end.column() == 0
19380                    {
19381                        end.row().0.saturating_sub(1)
19382                    } else {
19383                        end.row().0
19384                    };
19385                    for row in start_row..=end_row {
19386                        let used_index =
19387                            used_highlight_orders.entry(row).or_insert(highlight.index);
19388                        if highlight.index >= *used_index {
19389                            *used_index = highlight.index;
19390                            unique_rows.insert(
19391                                DisplayRow(row),
19392                                LineHighlight {
19393                                    include_gutter: highlight.options.include_gutter,
19394                                    border: None,
19395                                    background: highlight.color.into(),
19396                                    type_id: Some(highlight.type_id),
19397                                },
19398                            );
19399                        }
19400                    }
19401                    unique_rows
19402                },
19403            )
19404    }
19405
19406    pub fn highlighted_display_row_for_autoscroll(
19407        &self,
19408        snapshot: &DisplaySnapshot,
19409    ) -> Option<DisplayRow> {
19410        self.highlighted_rows
19411            .values()
19412            .flat_map(|highlighted_rows| highlighted_rows.iter())
19413            .filter_map(|highlight| {
19414                if highlight.options.autoscroll {
19415                    Some(highlight.range.start.to_display_point(snapshot).row())
19416                } else {
19417                    None
19418                }
19419            })
19420            .min()
19421    }
19422
19423    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19424        self.highlight_background::<SearchWithinRange>(
19425            ranges,
19426            |colors| colors.colors().editor_document_highlight_read_background,
19427            cx,
19428        )
19429    }
19430
19431    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19432        self.breadcrumb_header = Some(new_header);
19433    }
19434
19435    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19436        self.clear_background_highlights::<SearchWithinRange>(cx);
19437    }
19438
19439    pub fn highlight_background<T: 'static>(
19440        &mut self,
19441        ranges: &[Range<Anchor>],
19442        color_fetcher: fn(&Theme) -> Hsla,
19443        cx: &mut Context<Self>,
19444    ) {
19445        self.background_highlights.insert(
19446            HighlightKey::Type(TypeId::of::<T>()),
19447            (color_fetcher, Arc::from(ranges)),
19448        );
19449        self.scrollbar_marker_state.dirty = true;
19450        cx.notify();
19451    }
19452
19453    pub fn highlight_background_key<T: 'static>(
19454        &mut self,
19455        key: usize,
19456        ranges: &[Range<Anchor>],
19457        color_fetcher: fn(&Theme) -> Hsla,
19458        cx: &mut Context<Self>,
19459    ) {
19460        self.background_highlights.insert(
19461            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19462            (color_fetcher, Arc::from(ranges)),
19463        );
19464        self.scrollbar_marker_state.dirty = true;
19465        cx.notify();
19466    }
19467
19468    pub fn clear_background_highlights<T: 'static>(
19469        &mut self,
19470        cx: &mut Context<Self>,
19471    ) -> Option<BackgroundHighlight> {
19472        let text_highlights = self
19473            .background_highlights
19474            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19475        if !text_highlights.1.is_empty() {
19476            self.scrollbar_marker_state.dirty = true;
19477            cx.notify();
19478        }
19479        Some(text_highlights)
19480    }
19481
19482    pub fn highlight_gutter<T: 'static>(
19483        &mut self,
19484        ranges: impl Into<Vec<Range<Anchor>>>,
19485        color_fetcher: fn(&App) -> Hsla,
19486        cx: &mut Context<Self>,
19487    ) {
19488        self.gutter_highlights
19489            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19490        cx.notify();
19491    }
19492
19493    pub fn clear_gutter_highlights<T: 'static>(
19494        &mut self,
19495        cx: &mut Context<Self>,
19496    ) -> Option<GutterHighlight> {
19497        cx.notify();
19498        self.gutter_highlights.remove(&TypeId::of::<T>())
19499    }
19500
19501    pub fn insert_gutter_highlight<T: 'static>(
19502        &mut self,
19503        range: Range<Anchor>,
19504        color_fetcher: fn(&App) -> Hsla,
19505        cx: &mut Context<Self>,
19506    ) {
19507        let snapshot = self.buffer().read(cx).snapshot(cx);
19508        let mut highlights = self
19509            .gutter_highlights
19510            .remove(&TypeId::of::<T>())
19511            .map(|(_, highlights)| highlights)
19512            .unwrap_or_default();
19513        let ix = highlights.binary_search_by(|highlight| {
19514            Ordering::Equal
19515                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19516                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19517        });
19518        if let Err(ix) = ix {
19519            highlights.insert(ix, range);
19520        }
19521        self.gutter_highlights
19522            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19523    }
19524
19525    pub fn remove_gutter_highlights<T: 'static>(
19526        &mut self,
19527        ranges_to_remove: Vec<Range<Anchor>>,
19528        cx: &mut Context<Self>,
19529    ) {
19530        let snapshot = self.buffer().read(cx).snapshot(cx);
19531        let Some((color_fetcher, mut gutter_highlights)) =
19532            self.gutter_highlights.remove(&TypeId::of::<T>())
19533        else {
19534            return;
19535        };
19536        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19537        gutter_highlights.retain(|highlight| {
19538            while let Some(range_to_remove) = ranges_to_remove.peek() {
19539                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19540                    Ordering::Less | Ordering::Equal => {
19541                        ranges_to_remove.next();
19542                    }
19543                    Ordering::Greater => {
19544                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19545                            Ordering::Less | Ordering::Equal => {
19546                                return false;
19547                            }
19548                            Ordering::Greater => break,
19549                        }
19550                    }
19551                }
19552            }
19553
19554            true
19555        });
19556        self.gutter_highlights
19557            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19558    }
19559
19560    #[cfg(feature = "test-support")]
19561    pub fn all_text_highlights(
19562        &self,
19563        window: &mut Window,
19564        cx: &mut Context<Self>,
19565    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19566        let snapshot = self.snapshot(window, cx);
19567        self.display_map.update(cx, |display_map, _| {
19568            display_map
19569                .all_text_highlights()
19570                .map(|highlight| {
19571                    let (style, ranges) = highlight.as_ref();
19572                    (
19573                        *style,
19574                        ranges
19575                            .iter()
19576                            .map(|range| range.clone().to_display_points(&snapshot))
19577                            .collect(),
19578                    )
19579                })
19580                .collect()
19581        })
19582    }
19583
19584    #[cfg(feature = "test-support")]
19585    pub fn all_text_background_highlights(
19586        &self,
19587        window: &mut Window,
19588        cx: &mut Context<Self>,
19589    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19590        let snapshot = self.snapshot(window, cx);
19591        let buffer = &snapshot.buffer_snapshot;
19592        let start = buffer.anchor_before(0);
19593        let end = buffer.anchor_after(buffer.len());
19594        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19595    }
19596
19597    #[cfg(feature = "test-support")]
19598    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19599        let snapshot = self.buffer().read(cx).snapshot(cx);
19600
19601        let highlights = self
19602            .background_highlights
19603            .get(&HighlightKey::Type(TypeId::of::<
19604                items::BufferSearchHighlights,
19605            >()));
19606
19607        if let Some((_color, ranges)) = highlights {
19608            ranges
19609                .iter()
19610                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19611                .collect_vec()
19612        } else {
19613            vec![]
19614        }
19615    }
19616
19617    fn document_highlights_for_position<'a>(
19618        &'a self,
19619        position: Anchor,
19620        buffer: &'a MultiBufferSnapshot,
19621    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19622        let read_highlights = self
19623            .background_highlights
19624            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19625            .map(|h| &h.1);
19626        let write_highlights = self
19627            .background_highlights
19628            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19629            .map(|h| &h.1);
19630        let left_position = position.bias_left(buffer);
19631        let right_position = position.bias_right(buffer);
19632        read_highlights
19633            .into_iter()
19634            .chain(write_highlights)
19635            .flat_map(move |ranges| {
19636                let start_ix = match ranges.binary_search_by(|probe| {
19637                    let cmp = probe.end.cmp(&left_position, buffer);
19638                    if cmp.is_ge() {
19639                        Ordering::Greater
19640                    } else {
19641                        Ordering::Less
19642                    }
19643                }) {
19644                    Ok(i) | Err(i) => i,
19645                };
19646
19647                ranges[start_ix..]
19648                    .iter()
19649                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19650            })
19651    }
19652
19653    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19654        self.background_highlights
19655            .get(&HighlightKey::Type(TypeId::of::<T>()))
19656            .is_some_and(|(_, highlights)| !highlights.is_empty())
19657    }
19658
19659    pub fn background_highlights_in_range(
19660        &self,
19661        search_range: Range<Anchor>,
19662        display_snapshot: &DisplaySnapshot,
19663        theme: &Theme,
19664    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19665        let mut results = Vec::new();
19666        for (color_fetcher, ranges) in self.background_highlights.values() {
19667            let color = color_fetcher(theme);
19668            let start_ix = match ranges.binary_search_by(|probe| {
19669                let cmp = probe
19670                    .end
19671                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19672                if cmp.is_gt() {
19673                    Ordering::Greater
19674                } else {
19675                    Ordering::Less
19676                }
19677            }) {
19678                Ok(i) | Err(i) => i,
19679            };
19680            for range in &ranges[start_ix..] {
19681                if range
19682                    .start
19683                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19684                    .is_ge()
19685                {
19686                    break;
19687                }
19688
19689                let start = range.start.to_display_point(display_snapshot);
19690                let end = range.end.to_display_point(display_snapshot);
19691                results.push((start..end, color))
19692            }
19693        }
19694        results
19695    }
19696
19697    pub fn background_highlight_row_ranges<T: 'static>(
19698        &self,
19699        search_range: Range<Anchor>,
19700        display_snapshot: &DisplaySnapshot,
19701        count: usize,
19702    ) -> Vec<RangeInclusive<DisplayPoint>> {
19703        let mut results = Vec::new();
19704        let Some((_, ranges)) = self
19705            .background_highlights
19706            .get(&HighlightKey::Type(TypeId::of::<T>()))
19707        else {
19708            return vec![];
19709        };
19710
19711        let start_ix = match ranges.binary_search_by(|probe| {
19712            let cmp = probe
19713                .end
19714                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19715            if cmp.is_gt() {
19716                Ordering::Greater
19717            } else {
19718                Ordering::Less
19719            }
19720        }) {
19721            Ok(i) | Err(i) => i,
19722        };
19723        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19724            if let (Some(start_display), Some(end_display)) = (start, end) {
19725                results.push(
19726                    start_display.to_display_point(display_snapshot)
19727                        ..=end_display.to_display_point(display_snapshot),
19728                );
19729            }
19730        };
19731        let mut start_row: Option<Point> = None;
19732        let mut end_row: Option<Point> = None;
19733        if ranges.len() > count {
19734            return Vec::new();
19735        }
19736        for range in &ranges[start_ix..] {
19737            if range
19738                .start
19739                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19740                .is_ge()
19741            {
19742                break;
19743            }
19744            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19745            if let Some(current_row) = &end_row
19746                && end.row == current_row.row
19747            {
19748                continue;
19749            }
19750            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19751            if start_row.is_none() {
19752                assert_eq!(end_row, None);
19753                start_row = Some(start);
19754                end_row = Some(end);
19755                continue;
19756            }
19757            if let Some(current_end) = end_row.as_mut() {
19758                if start.row > current_end.row + 1 {
19759                    push_region(start_row, end_row);
19760                    start_row = Some(start);
19761                    end_row = Some(end);
19762                } else {
19763                    // Merge two hunks.
19764                    *current_end = end;
19765                }
19766            } else {
19767                unreachable!();
19768            }
19769        }
19770        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19771        push_region(start_row, end_row);
19772        results
19773    }
19774
19775    pub fn gutter_highlights_in_range(
19776        &self,
19777        search_range: Range<Anchor>,
19778        display_snapshot: &DisplaySnapshot,
19779        cx: &App,
19780    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19781        let mut results = Vec::new();
19782        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19783            let color = color_fetcher(cx);
19784            let start_ix = match ranges.binary_search_by(|probe| {
19785                let cmp = probe
19786                    .end
19787                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19788                if cmp.is_gt() {
19789                    Ordering::Greater
19790                } else {
19791                    Ordering::Less
19792                }
19793            }) {
19794                Ok(i) | Err(i) => i,
19795            };
19796            for range in &ranges[start_ix..] {
19797                if range
19798                    .start
19799                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19800                    .is_ge()
19801                {
19802                    break;
19803                }
19804
19805                let start = range.start.to_display_point(display_snapshot);
19806                let end = range.end.to_display_point(display_snapshot);
19807                results.push((start..end, color))
19808            }
19809        }
19810        results
19811    }
19812
19813    /// Get the text ranges corresponding to the redaction query
19814    pub fn redacted_ranges(
19815        &self,
19816        search_range: Range<Anchor>,
19817        display_snapshot: &DisplaySnapshot,
19818        cx: &App,
19819    ) -> Vec<Range<DisplayPoint>> {
19820        display_snapshot
19821            .buffer_snapshot
19822            .redacted_ranges(search_range, |file| {
19823                if let Some(file) = file {
19824                    file.is_private()
19825                        && EditorSettings::get(
19826                            Some(SettingsLocation {
19827                                worktree_id: file.worktree_id(cx),
19828                                path: file.path().as_ref(),
19829                            }),
19830                            cx,
19831                        )
19832                        .redact_private_values
19833                } else {
19834                    false
19835                }
19836            })
19837            .map(|range| {
19838                range.start.to_display_point(display_snapshot)
19839                    ..range.end.to_display_point(display_snapshot)
19840            })
19841            .collect()
19842    }
19843
19844    pub fn highlight_text_key<T: 'static>(
19845        &mut self,
19846        key: usize,
19847        ranges: Vec<Range<Anchor>>,
19848        style: HighlightStyle,
19849        cx: &mut Context<Self>,
19850    ) {
19851        self.display_map.update(cx, |map, _| {
19852            map.highlight_text(
19853                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19854                ranges,
19855                style,
19856            );
19857        });
19858        cx.notify();
19859    }
19860
19861    pub fn highlight_text<T: 'static>(
19862        &mut self,
19863        ranges: Vec<Range<Anchor>>,
19864        style: HighlightStyle,
19865        cx: &mut Context<Self>,
19866    ) {
19867        self.display_map.update(cx, |map, _| {
19868            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19869        });
19870        cx.notify();
19871    }
19872
19873    pub(crate) fn highlight_inlays<T: 'static>(
19874        &mut self,
19875        highlights: Vec<InlayHighlight>,
19876        style: HighlightStyle,
19877        cx: &mut Context<Self>,
19878    ) {
19879        self.display_map.update(cx, |map, _| {
19880            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19881        });
19882        cx.notify();
19883    }
19884
19885    pub fn text_highlights<'a, T: 'static>(
19886        &'a self,
19887        cx: &'a App,
19888    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19889        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19890    }
19891
19892    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19893        let cleared = self
19894            .display_map
19895            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19896        if cleared {
19897            cx.notify();
19898        }
19899    }
19900
19901    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19902        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19903            && self.focus_handle.is_focused(window)
19904    }
19905
19906    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19907        self.show_cursor_when_unfocused = is_enabled;
19908        cx.notify();
19909    }
19910
19911    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19912        cx.notify();
19913    }
19914
19915    fn on_debug_session_event(
19916        &mut self,
19917        _session: Entity<Session>,
19918        event: &SessionEvent,
19919        cx: &mut Context<Self>,
19920    ) {
19921        if let SessionEvent::InvalidateInlineValue = event {
19922            self.refresh_inline_values(cx);
19923        }
19924    }
19925
19926    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19927        let Some(project) = self.project.clone() else {
19928            return;
19929        };
19930
19931        if !self.inline_value_cache.enabled {
19932            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19933            self.splice_inlays(&inlays, Vec::new(), cx);
19934            return;
19935        }
19936
19937        let current_execution_position = self
19938            .highlighted_rows
19939            .get(&TypeId::of::<ActiveDebugLine>())
19940            .and_then(|lines| lines.last().map(|line| line.range.end));
19941
19942        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19943            let inline_values = editor
19944                .update(cx, |editor, cx| {
19945                    let Some(current_execution_position) = current_execution_position else {
19946                        return Some(Task::ready(Ok(Vec::new())));
19947                    };
19948
19949                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19950                        let snapshot = buffer.snapshot(cx);
19951
19952                        let excerpt = snapshot.excerpt_containing(
19953                            current_execution_position..current_execution_position,
19954                        )?;
19955
19956                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19957                    })?;
19958
19959                    let range =
19960                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19961
19962                    project.inline_values(buffer, range, cx)
19963                })
19964                .ok()
19965                .flatten()?
19966                .await
19967                .context("refreshing debugger inlays")
19968                .log_err()?;
19969
19970            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19971
19972            for (buffer_id, inline_value) in inline_values
19973                .into_iter()
19974                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19975            {
19976                buffer_inline_values
19977                    .entry(buffer_id)
19978                    .or_default()
19979                    .push(inline_value);
19980            }
19981
19982            editor
19983                .update(cx, |editor, cx| {
19984                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19985                    let mut new_inlays = Vec::default();
19986
19987                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19988                        let buffer_id = buffer_snapshot.remote_id();
19989                        buffer_inline_values
19990                            .get(&buffer_id)
19991                            .into_iter()
19992                            .flatten()
19993                            .for_each(|hint| {
19994                                let inlay = Inlay::debugger(
19995                                    post_inc(&mut editor.next_inlay_id),
19996                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19997                                    hint.text(),
19998                                );
19999                                if !inlay.text.chars().contains(&'\n') {
20000                                    new_inlays.push(inlay);
20001                                }
20002                            });
20003                    }
20004
20005                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20006                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20007
20008                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20009                })
20010                .ok()?;
20011            Some(())
20012        });
20013    }
20014
20015    fn on_buffer_event(
20016        &mut self,
20017        multibuffer: &Entity<MultiBuffer>,
20018        event: &multi_buffer::Event,
20019        window: &mut Window,
20020        cx: &mut Context<Self>,
20021    ) {
20022        match event {
20023            multi_buffer::Event::Edited {
20024                singleton_buffer_edited,
20025                edited_buffer,
20026            } => {
20027                self.scrollbar_marker_state.dirty = true;
20028                self.active_indent_guides_state.dirty = true;
20029                self.refresh_active_diagnostics(cx);
20030                self.refresh_code_actions(window, cx);
20031                self.refresh_selected_text_highlights(true, window, cx);
20032                self.refresh_single_line_folds(window, cx);
20033                refresh_matching_bracket_highlights(self, window, cx);
20034                if self.has_active_edit_prediction() {
20035                    self.update_visible_edit_prediction(window, cx);
20036                }
20037                if let Some(project) = self.project.as_ref()
20038                    && let Some(edited_buffer) = edited_buffer
20039                {
20040                    project.update(cx, |project, cx| {
20041                        self.registered_buffers
20042                            .entry(edited_buffer.read(cx).remote_id())
20043                            .or_insert_with(|| {
20044                                project.register_buffer_with_language_servers(edited_buffer, cx)
20045                            });
20046                    });
20047                }
20048                cx.emit(EditorEvent::BufferEdited);
20049                cx.emit(SearchEvent::MatchesInvalidated);
20050
20051                if let Some(buffer) = edited_buffer {
20052                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20053                }
20054
20055                if *singleton_buffer_edited {
20056                    if let Some(buffer) = edited_buffer
20057                        && buffer.read(cx).file().is_none()
20058                    {
20059                        cx.emit(EditorEvent::TitleChanged);
20060                    }
20061                    if let Some(project) = &self.project {
20062                        #[allow(clippy::mutable_key_type)]
20063                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20064                            multibuffer
20065                                .all_buffers()
20066                                .into_iter()
20067                                .filter_map(|buffer| {
20068                                    buffer.update(cx, |buffer, cx| {
20069                                        let language = buffer.language()?;
20070                                        let should_discard = project.update(cx, |project, cx| {
20071                                            project.is_local()
20072                                                && !project.has_language_servers_for(buffer, cx)
20073                                        });
20074                                        should_discard.not().then_some(language.clone())
20075                                    })
20076                                })
20077                                .collect::<HashSet<_>>()
20078                        });
20079                        if !languages_affected.is_empty() {
20080                            self.refresh_inlay_hints(
20081                                InlayHintRefreshReason::BufferEdited(languages_affected),
20082                                cx,
20083                            );
20084                        }
20085                    }
20086                }
20087
20088                let Some(project) = &self.project else { return };
20089                let (telemetry, is_via_ssh) = {
20090                    let project = project.read(cx);
20091                    let telemetry = project.client().telemetry().clone();
20092                    let is_via_ssh = project.is_via_remote_server();
20093                    (telemetry, is_via_ssh)
20094                };
20095                refresh_linked_ranges(self, window, cx);
20096                telemetry.log_edit_event("editor", is_via_ssh);
20097            }
20098            multi_buffer::Event::ExcerptsAdded {
20099                buffer,
20100                predecessor,
20101                excerpts,
20102            } => {
20103                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20104                let buffer_id = buffer.read(cx).remote_id();
20105                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20106                    && let Some(project) = &self.project
20107                {
20108                    update_uncommitted_diff_for_buffer(
20109                        cx.entity(),
20110                        project,
20111                        [buffer.clone()],
20112                        self.buffer.clone(),
20113                        cx,
20114                    )
20115                    .detach();
20116                }
20117                self.update_lsp_data(false, Some(buffer_id), window, cx);
20118                cx.emit(EditorEvent::ExcerptsAdded {
20119                    buffer: buffer.clone(),
20120                    predecessor: *predecessor,
20121                    excerpts: excerpts.clone(),
20122                });
20123                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20124            }
20125            multi_buffer::Event::ExcerptsRemoved {
20126                ids,
20127                removed_buffer_ids,
20128            } => {
20129                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20130                let buffer = self.buffer.read(cx);
20131                self.registered_buffers
20132                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20133                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20134                cx.emit(EditorEvent::ExcerptsRemoved {
20135                    ids: ids.clone(),
20136                    removed_buffer_ids: removed_buffer_ids.clone(),
20137                });
20138            }
20139            multi_buffer::Event::ExcerptsEdited {
20140                excerpt_ids,
20141                buffer_ids,
20142            } => {
20143                self.display_map.update(cx, |map, cx| {
20144                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20145                });
20146                cx.emit(EditorEvent::ExcerptsEdited {
20147                    ids: excerpt_ids.clone(),
20148                });
20149            }
20150            multi_buffer::Event::ExcerptsExpanded { ids } => {
20151                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20152                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20153            }
20154            multi_buffer::Event::Reparsed(buffer_id) => {
20155                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20156                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20157
20158                cx.emit(EditorEvent::Reparsed(*buffer_id));
20159            }
20160            multi_buffer::Event::DiffHunksToggled => {
20161                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20162            }
20163            multi_buffer::Event::LanguageChanged(buffer_id) => {
20164                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20165                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20166                cx.emit(EditorEvent::Reparsed(*buffer_id));
20167                cx.notify();
20168            }
20169            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20170            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20171            multi_buffer::Event::FileHandleChanged
20172            | multi_buffer::Event::Reloaded
20173            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20174            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20175            multi_buffer::Event::DiagnosticsUpdated => {
20176                self.update_diagnostics_state(window, cx);
20177            }
20178            _ => {}
20179        };
20180    }
20181
20182    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20183        if !self.diagnostics_enabled() {
20184            return;
20185        }
20186        self.refresh_active_diagnostics(cx);
20187        self.refresh_inline_diagnostics(true, window, cx);
20188        self.scrollbar_marker_state.dirty = true;
20189        cx.notify();
20190    }
20191
20192    pub fn start_temporary_diff_override(&mut self) {
20193        self.load_diff_task.take();
20194        self.temporary_diff_override = true;
20195    }
20196
20197    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20198        self.temporary_diff_override = false;
20199        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20200        self.buffer.update(cx, |buffer, cx| {
20201            buffer.set_all_diff_hunks_collapsed(cx);
20202        });
20203
20204        if let Some(project) = self.project.clone() {
20205            self.load_diff_task = Some(
20206                update_uncommitted_diff_for_buffer(
20207                    cx.entity(),
20208                    &project,
20209                    self.buffer.read(cx).all_buffers(),
20210                    self.buffer.clone(),
20211                    cx,
20212                )
20213                .shared(),
20214            );
20215        }
20216    }
20217
20218    fn on_display_map_changed(
20219        &mut self,
20220        _: Entity<DisplayMap>,
20221        _: &mut Window,
20222        cx: &mut Context<Self>,
20223    ) {
20224        cx.notify();
20225    }
20226
20227    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20228        if self.diagnostics_enabled() {
20229            let new_severity = EditorSettings::get_global(cx)
20230                .diagnostics_max_severity
20231                .unwrap_or(DiagnosticSeverity::Hint);
20232            self.set_max_diagnostics_severity(new_severity, cx);
20233        }
20234        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20235        self.update_edit_prediction_settings(cx);
20236        self.refresh_edit_prediction(true, false, window, cx);
20237        self.refresh_inline_values(cx);
20238        self.refresh_inlay_hints(
20239            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20240                self.selections.newest_anchor().head(),
20241                &self.buffer.read(cx).snapshot(cx),
20242                cx,
20243            )),
20244            cx,
20245        );
20246
20247        let old_cursor_shape = self.cursor_shape;
20248        let old_show_breadcrumbs = self.show_breadcrumbs;
20249
20250        {
20251            let editor_settings = EditorSettings::get_global(cx);
20252            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20253            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20254            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20255            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20256        }
20257
20258        if old_cursor_shape != self.cursor_shape {
20259            cx.emit(EditorEvent::CursorShapeChanged);
20260        }
20261
20262        if old_show_breadcrumbs != self.show_breadcrumbs {
20263            cx.emit(EditorEvent::BreadcrumbsChanged);
20264        }
20265
20266        let project_settings = ProjectSettings::get_global(cx);
20267        self.serialize_dirty_buffers =
20268            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20269
20270        if self.mode.is_full() {
20271            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20272            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20273            if self.show_inline_diagnostics != show_inline_diagnostics {
20274                self.show_inline_diagnostics = show_inline_diagnostics;
20275                self.refresh_inline_diagnostics(false, window, cx);
20276            }
20277
20278            if self.git_blame_inline_enabled != inline_blame_enabled {
20279                self.toggle_git_blame_inline_internal(false, window, cx);
20280            }
20281
20282            let minimap_settings = EditorSettings::get_global(cx).minimap;
20283            if self.minimap_visibility != MinimapVisibility::Disabled {
20284                if self.minimap_visibility.settings_visibility()
20285                    != minimap_settings.minimap_enabled()
20286                {
20287                    self.set_minimap_visibility(
20288                        MinimapVisibility::for_mode(self.mode(), cx),
20289                        window,
20290                        cx,
20291                    );
20292                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20293                    minimap_entity.update(cx, |minimap_editor, cx| {
20294                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20295                    })
20296                }
20297            }
20298        }
20299
20300        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20301            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20302        }) {
20303            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20304                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20305            }
20306            self.refresh_colors(false, None, window, cx);
20307        }
20308
20309        cx.notify();
20310    }
20311
20312    pub fn set_searchable(&mut self, searchable: bool) {
20313        self.searchable = searchable;
20314    }
20315
20316    pub fn searchable(&self) -> bool {
20317        self.searchable
20318    }
20319
20320    fn open_proposed_changes_editor(
20321        &mut self,
20322        _: &OpenProposedChangesEditor,
20323        window: &mut Window,
20324        cx: &mut Context<Self>,
20325    ) {
20326        let Some(workspace) = self.workspace() else {
20327            cx.propagate();
20328            return;
20329        };
20330
20331        let selections = self.selections.all::<usize>(cx);
20332        let multi_buffer = self.buffer.read(cx);
20333        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20334        let mut new_selections_by_buffer = HashMap::default();
20335        for selection in selections {
20336            for (buffer, range, _) in
20337                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20338            {
20339                let mut range = range.to_point(buffer);
20340                range.start.column = 0;
20341                range.end.column = buffer.line_len(range.end.row);
20342                new_selections_by_buffer
20343                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20344                    .or_insert(Vec::new())
20345                    .push(range)
20346            }
20347        }
20348
20349        let proposed_changes_buffers = new_selections_by_buffer
20350            .into_iter()
20351            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20352            .collect::<Vec<_>>();
20353        let proposed_changes_editor = cx.new(|cx| {
20354            ProposedChangesEditor::new(
20355                "Proposed changes",
20356                proposed_changes_buffers,
20357                self.project.clone(),
20358                window,
20359                cx,
20360            )
20361        });
20362
20363        window.defer(cx, move |window, cx| {
20364            workspace.update(cx, |workspace, cx| {
20365                workspace.active_pane().update(cx, |pane, cx| {
20366                    pane.add_item(
20367                        Box::new(proposed_changes_editor),
20368                        true,
20369                        true,
20370                        None,
20371                        window,
20372                        cx,
20373                    );
20374                });
20375            });
20376        });
20377    }
20378
20379    pub fn open_excerpts_in_split(
20380        &mut self,
20381        _: &OpenExcerptsSplit,
20382        window: &mut Window,
20383        cx: &mut Context<Self>,
20384    ) {
20385        self.open_excerpts_common(None, true, window, cx)
20386    }
20387
20388    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20389        self.open_excerpts_common(None, false, window, cx)
20390    }
20391
20392    fn open_excerpts_common(
20393        &mut self,
20394        jump_data: Option<JumpData>,
20395        split: bool,
20396        window: &mut Window,
20397        cx: &mut Context<Self>,
20398    ) {
20399        let Some(workspace) = self.workspace() else {
20400            cx.propagate();
20401            return;
20402        };
20403
20404        if self.buffer.read(cx).is_singleton() {
20405            cx.propagate();
20406            return;
20407        }
20408
20409        let mut new_selections_by_buffer = HashMap::default();
20410        match &jump_data {
20411            Some(JumpData::MultiBufferPoint {
20412                excerpt_id,
20413                position,
20414                anchor,
20415                line_offset_from_top,
20416            }) => {
20417                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20418                if let Some(buffer) = multi_buffer_snapshot
20419                    .buffer_id_for_excerpt(*excerpt_id)
20420                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20421                {
20422                    let buffer_snapshot = buffer.read(cx).snapshot();
20423                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20424                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20425                    } else {
20426                        buffer_snapshot.clip_point(*position, Bias::Left)
20427                    };
20428                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20429                    new_selections_by_buffer.insert(
20430                        buffer,
20431                        (
20432                            vec![jump_to_offset..jump_to_offset],
20433                            Some(*line_offset_from_top),
20434                        ),
20435                    );
20436                }
20437            }
20438            Some(JumpData::MultiBufferRow {
20439                row,
20440                line_offset_from_top,
20441            }) => {
20442                let point = MultiBufferPoint::new(row.0, 0);
20443                if let Some((buffer, buffer_point, _)) =
20444                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20445                {
20446                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20447                    new_selections_by_buffer
20448                        .entry(buffer)
20449                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20450                        .0
20451                        .push(buffer_offset..buffer_offset)
20452                }
20453            }
20454            None => {
20455                let selections = self.selections.all::<usize>(cx);
20456                let multi_buffer = self.buffer.read(cx);
20457                for selection in selections {
20458                    for (snapshot, range, _, anchor) in multi_buffer
20459                        .snapshot(cx)
20460                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20461                    {
20462                        if let Some(anchor) = anchor {
20463                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20464                            else {
20465                                continue;
20466                            };
20467                            let offset = text::ToOffset::to_offset(
20468                                &anchor.text_anchor,
20469                                &buffer_handle.read(cx).snapshot(),
20470                            );
20471                            let range = offset..offset;
20472                            new_selections_by_buffer
20473                                .entry(buffer_handle)
20474                                .or_insert((Vec::new(), None))
20475                                .0
20476                                .push(range)
20477                        } else {
20478                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20479                            else {
20480                                continue;
20481                            };
20482                            new_selections_by_buffer
20483                                .entry(buffer_handle)
20484                                .or_insert((Vec::new(), None))
20485                                .0
20486                                .push(range)
20487                        }
20488                    }
20489                }
20490            }
20491        }
20492
20493        new_selections_by_buffer
20494            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20495
20496        if new_selections_by_buffer.is_empty() {
20497            return;
20498        }
20499
20500        // We defer the pane interaction because we ourselves are a workspace item
20501        // and activating a new item causes the pane to call a method on us reentrantly,
20502        // which panics if we're on the stack.
20503        window.defer(cx, move |window, cx| {
20504            workspace.update(cx, |workspace, cx| {
20505                let pane = if split {
20506                    workspace.adjacent_pane(window, cx)
20507                } else {
20508                    workspace.active_pane().clone()
20509                };
20510
20511                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20512                    let editor = buffer
20513                        .read(cx)
20514                        .file()
20515                        .is_none()
20516                        .then(|| {
20517                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20518                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20519                            // Instead, we try to activate the existing editor in the pane first.
20520                            let (editor, pane_item_index) =
20521                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20522                                    let editor = item.downcast::<Editor>()?;
20523                                    let singleton_buffer =
20524                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20525                                    if singleton_buffer == buffer {
20526                                        Some((editor, i))
20527                                    } else {
20528                                        None
20529                                    }
20530                                })?;
20531                            pane.update(cx, |pane, cx| {
20532                                pane.activate_item(pane_item_index, true, true, window, cx)
20533                            });
20534                            Some(editor)
20535                        })
20536                        .flatten()
20537                        .unwrap_or_else(|| {
20538                            workspace.open_project_item::<Self>(
20539                                pane.clone(),
20540                                buffer,
20541                                true,
20542                                true,
20543                                window,
20544                                cx,
20545                            )
20546                        });
20547
20548                    editor.update(cx, |editor, cx| {
20549                        let autoscroll = match scroll_offset {
20550                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20551                            None => Autoscroll::newest(),
20552                        };
20553                        let nav_history = editor.nav_history.take();
20554                        editor.change_selections(
20555                            SelectionEffects::scroll(autoscroll),
20556                            window,
20557                            cx,
20558                            |s| {
20559                                s.select_ranges(ranges);
20560                            },
20561                        );
20562                        editor.nav_history = nav_history;
20563                    });
20564                }
20565            })
20566        });
20567    }
20568
20569    // For now, don't allow opening excerpts in buffers that aren't backed by
20570    // regular project files.
20571    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20572        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20573    }
20574
20575    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20576        let snapshot = self.buffer.read(cx).read(cx);
20577        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20578        Some(
20579            ranges
20580                .iter()
20581                .map(move |range| {
20582                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20583                })
20584                .collect(),
20585        )
20586    }
20587
20588    fn selection_replacement_ranges(
20589        &self,
20590        range: Range<OffsetUtf16>,
20591        cx: &mut App,
20592    ) -> Vec<Range<OffsetUtf16>> {
20593        let selections = self.selections.all::<OffsetUtf16>(cx);
20594        let newest_selection = selections
20595            .iter()
20596            .max_by_key(|selection| selection.id)
20597            .unwrap();
20598        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20599        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20600        let snapshot = self.buffer.read(cx).read(cx);
20601        selections
20602            .into_iter()
20603            .map(|mut selection| {
20604                selection.start.0 =
20605                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20606                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20607                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20608                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20609            })
20610            .collect()
20611    }
20612
20613    fn report_editor_event(
20614        &self,
20615        reported_event: ReportEditorEvent,
20616        file_extension: Option<String>,
20617        cx: &App,
20618    ) {
20619        if cfg!(any(test, feature = "test-support")) {
20620            return;
20621        }
20622
20623        let Some(project) = &self.project else { return };
20624
20625        // If None, we are in a file without an extension
20626        let file = self
20627            .buffer
20628            .read(cx)
20629            .as_singleton()
20630            .and_then(|b| b.read(cx).file());
20631        let file_extension = file_extension.or(file
20632            .as_ref()
20633            .and_then(|file| Path::new(file.file_name(cx)).extension())
20634            .and_then(|e| e.to_str())
20635            .map(|a| a.to_string()));
20636
20637        let vim_mode = vim_enabled(cx);
20638
20639        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20640        let copilot_enabled = edit_predictions_provider
20641            == language::language_settings::EditPredictionProvider::Copilot;
20642        let copilot_enabled_for_language = self
20643            .buffer
20644            .read(cx)
20645            .language_settings(cx)
20646            .show_edit_predictions;
20647
20648        let project = project.read(cx);
20649        let event_type = reported_event.event_type();
20650
20651        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20652            telemetry::event!(
20653                event_type,
20654                type = if auto_saved {"autosave"} else {"manual"},
20655                file_extension,
20656                vim_mode,
20657                copilot_enabled,
20658                copilot_enabled_for_language,
20659                edit_predictions_provider,
20660                is_via_ssh = project.is_via_remote_server(),
20661            );
20662        } else {
20663            telemetry::event!(
20664                event_type,
20665                file_extension,
20666                vim_mode,
20667                copilot_enabled,
20668                copilot_enabled_for_language,
20669                edit_predictions_provider,
20670                is_via_ssh = project.is_via_remote_server(),
20671            );
20672        };
20673    }
20674
20675    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20676    /// with each line being an array of {text, highlight} objects.
20677    fn copy_highlight_json(
20678        &mut self,
20679        _: &CopyHighlightJson,
20680        window: &mut Window,
20681        cx: &mut Context<Self>,
20682    ) {
20683        #[derive(Serialize)]
20684        struct Chunk<'a> {
20685            text: String,
20686            highlight: Option<&'a str>,
20687        }
20688
20689        let snapshot = self.buffer.read(cx).snapshot(cx);
20690        let range = self
20691            .selected_text_range(false, window, cx)
20692            .and_then(|selection| {
20693                if selection.range.is_empty() {
20694                    None
20695                } else {
20696                    Some(selection.range)
20697                }
20698            })
20699            .unwrap_or_else(|| 0..snapshot.len());
20700
20701        let chunks = snapshot.chunks(range, true);
20702        let mut lines = Vec::new();
20703        let mut line: VecDeque<Chunk> = VecDeque::new();
20704
20705        let Some(style) = self.style.as_ref() else {
20706            return;
20707        };
20708
20709        for chunk in chunks {
20710            let highlight = chunk
20711                .syntax_highlight_id
20712                .and_then(|id| id.name(&style.syntax));
20713            let mut chunk_lines = chunk.text.split('\n').peekable();
20714            while let Some(text) = chunk_lines.next() {
20715                let mut merged_with_last_token = false;
20716                if let Some(last_token) = line.back_mut()
20717                    && last_token.highlight == highlight
20718                {
20719                    last_token.text.push_str(text);
20720                    merged_with_last_token = true;
20721                }
20722
20723                if !merged_with_last_token {
20724                    line.push_back(Chunk {
20725                        text: text.into(),
20726                        highlight,
20727                    });
20728                }
20729
20730                if chunk_lines.peek().is_some() {
20731                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20732                        line.pop_front();
20733                    }
20734                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20735                        line.pop_back();
20736                    }
20737
20738                    lines.push(mem::take(&mut line));
20739                }
20740            }
20741        }
20742
20743        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20744            return;
20745        };
20746        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20747    }
20748
20749    pub fn open_context_menu(
20750        &mut self,
20751        _: &OpenContextMenu,
20752        window: &mut Window,
20753        cx: &mut Context<Self>,
20754    ) {
20755        self.request_autoscroll(Autoscroll::newest(), cx);
20756        let position = self.selections.newest_display(cx).start;
20757        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20758    }
20759
20760    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20761        &self.inlay_hint_cache
20762    }
20763
20764    pub fn replay_insert_event(
20765        &mut self,
20766        text: &str,
20767        relative_utf16_range: Option<Range<isize>>,
20768        window: &mut Window,
20769        cx: &mut Context<Self>,
20770    ) {
20771        if !self.input_enabled {
20772            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20773            return;
20774        }
20775        if let Some(relative_utf16_range) = relative_utf16_range {
20776            let selections = self.selections.all::<OffsetUtf16>(cx);
20777            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20778                let new_ranges = selections.into_iter().map(|range| {
20779                    let start = OffsetUtf16(
20780                        range
20781                            .head()
20782                            .0
20783                            .saturating_add_signed(relative_utf16_range.start),
20784                    );
20785                    let end = OffsetUtf16(
20786                        range
20787                            .head()
20788                            .0
20789                            .saturating_add_signed(relative_utf16_range.end),
20790                    );
20791                    start..end
20792                });
20793                s.select_ranges(new_ranges);
20794            });
20795        }
20796
20797        self.handle_input(text, window, cx);
20798    }
20799
20800    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20801        let Some(provider) = self.semantics_provider.as_ref() else {
20802            return false;
20803        };
20804
20805        let mut supports = false;
20806        self.buffer().update(cx, |this, cx| {
20807            this.for_each_buffer(|buffer| {
20808                supports |= provider.supports_inlay_hints(buffer, cx);
20809            });
20810        });
20811
20812        supports
20813    }
20814
20815    pub fn is_focused(&self, window: &Window) -> bool {
20816        self.focus_handle.is_focused(window)
20817    }
20818
20819    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20820        cx.emit(EditorEvent::Focused);
20821
20822        if let Some(descendant) = self
20823            .last_focused_descendant
20824            .take()
20825            .and_then(|descendant| descendant.upgrade())
20826        {
20827            window.focus(&descendant);
20828        } else {
20829            if let Some(blame) = self.blame.as_ref() {
20830                blame.update(cx, GitBlame::focus)
20831            }
20832
20833            self.blink_manager.update(cx, BlinkManager::enable);
20834            self.show_cursor_names(window, cx);
20835            self.buffer.update(cx, |buffer, cx| {
20836                buffer.finalize_last_transaction(cx);
20837                if self.leader_id.is_none() {
20838                    buffer.set_active_selections(
20839                        &self.selections.disjoint_anchors(),
20840                        self.selections.line_mode,
20841                        self.cursor_shape,
20842                        cx,
20843                    );
20844                }
20845            });
20846        }
20847    }
20848
20849    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20850        cx.emit(EditorEvent::FocusedIn)
20851    }
20852
20853    fn handle_focus_out(
20854        &mut self,
20855        event: FocusOutEvent,
20856        _window: &mut Window,
20857        cx: &mut Context<Self>,
20858    ) {
20859        if event.blurred != self.focus_handle {
20860            self.last_focused_descendant = Some(event.blurred);
20861        }
20862        self.selection_drag_state = SelectionDragState::None;
20863        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20864    }
20865
20866    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20867        self.blink_manager.update(cx, BlinkManager::disable);
20868        self.buffer
20869            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20870
20871        if let Some(blame) = self.blame.as_ref() {
20872            blame.update(cx, GitBlame::blur)
20873        }
20874        if !self.hover_state.focused(window, cx) {
20875            hide_hover(self, cx);
20876        }
20877        if !self
20878            .context_menu
20879            .borrow()
20880            .as_ref()
20881            .is_some_and(|context_menu| context_menu.focused(window, cx))
20882        {
20883            self.hide_context_menu(window, cx);
20884        }
20885        self.discard_edit_prediction(false, cx);
20886        cx.emit(EditorEvent::Blurred);
20887        cx.notify();
20888    }
20889
20890    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20891        let mut pending: String = window
20892            .pending_input_keystrokes()
20893            .into_iter()
20894            .flatten()
20895            .filter_map(|keystroke| {
20896                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20897                    keystroke.key_char.clone()
20898                } else {
20899                    None
20900                }
20901            })
20902            .collect();
20903
20904        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20905            pending = "".to_string();
20906        }
20907
20908        let existing_pending = self
20909            .text_highlights::<PendingInput>(cx)
20910            .map(|(_, ranges)| ranges.to_vec());
20911        if existing_pending.is_none() && pending.is_empty() {
20912            return;
20913        }
20914        let transaction =
20915            self.transact(window, cx, |this, window, cx| {
20916                let selections = this.selections.all::<usize>(cx);
20917                let edits = selections
20918                    .iter()
20919                    .map(|selection| (selection.end..selection.end, pending.clone()));
20920                this.edit(edits, cx);
20921                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20922                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20923                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20924                    }));
20925                });
20926                if let Some(existing_ranges) = existing_pending {
20927                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20928                    this.edit(edits, cx);
20929                }
20930            });
20931
20932        let snapshot = self.snapshot(window, cx);
20933        let ranges = self
20934            .selections
20935            .all::<usize>(cx)
20936            .into_iter()
20937            .map(|selection| {
20938                snapshot.buffer_snapshot.anchor_after(selection.end)
20939                    ..snapshot
20940                        .buffer_snapshot
20941                        .anchor_before(selection.end + pending.len())
20942            })
20943            .collect();
20944
20945        if pending.is_empty() {
20946            self.clear_highlights::<PendingInput>(cx);
20947        } else {
20948            self.highlight_text::<PendingInput>(
20949                ranges,
20950                HighlightStyle {
20951                    underline: Some(UnderlineStyle {
20952                        thickness: px(1.),
20953                        color: None,
20954                        wavy: false,
20955                    }),
20956                    ..Default::default()
20957                },
20958                cx,
20959            );
20960        }
20961
20962        self.ime_transaction = self.ime_transaction.or(transaction);
20963        if let Some(transaction) = self.ime_transaction {
20964            self.buffer.update(cx, |buffer, cx| {
20965                buffer.group_until_transaction(transaction, cx);
20966            });
20967        }
20968
20969        if self.text_highlights::<PendingInput>(cx).is_none() {
20970            self.ime_transaction.take();
20971        }
20972    }
20973
20974    pub fn register_action_renderer(
20975        &mut self,
20976        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20977    ) -> Subscription {
20978        let id = self.next_editor_action_id.post_inc();
20979        self.editor_actions
20980            .borrow_mut()
20981            .insert(id, Box::new(listener));
20982
20983        let editor_actions = self.editor_actions.clone();
20984        Subscription::new(move || {
20985            editor_actions.borrow_mut().remove(&id);
20986        })
20987    }
20988
20989    pub fn register_action<A: Action>(
20990        &mut self,
20991        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20992    ) -> Subscription {
20993        let id = self.next_editor_action_id.post_inc();
20994        let listener = Arc::new(listener);
20995        self.editor_actions.borrow_mut().insert(
20996            id,
20997            Box::new(move |_, window, _| {
20998                let listener = listener.clone();
20999                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21000                    let action = action.downcast_ref().unwrap();
21001                    if phase == DispatchPhase::Bubble {
21002                        listener(action, window, cx)
21003                    }
21004                })
21005            }),
21006        );
21007
21008        let editor_actions = self.editor_actions.clone();
21009        Subscription::new(move || {
21010            editor_actions.borrow_mut().remove(&id);
21011        })
21012    }
21013
21014    pub fn file_header_size(&self) -> u32 {
21015        FILE_HEADER_HEIGHT
21016    }
21017
21018    pub fn restore(
21019        &mut self,
21020        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21021        window: &mut Window,
21022        cx: &mut Context<Self>,
21023    ) {
21024        let workspace = self.workspace();
21025        let project = self.project();
21026        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21027            let mut tasks = Vec::new();
21028            for (buffer_id, changes) in revert_changes {
21029                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21030                    buffer.update(cx, |buffer, cx| {
21031                        buffer.edit(
21032                            changes
21033                                .into_iter()
21034                                .map(|(range, text)| (range, text.to_string())),
21035                            None,
21036                            cx,
21037                        );
21038                    });
21039
21040                    if let Some(project) =
21041                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21042                    {
21043                        project.update(cx, |project, cx| {
21044                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21045                        })
21046                    }
21047                }
21048            }
21049            tasks
21050        });
21051        cx.spawn_in(window, async move |_, cx| {
21052            for (buffer, task) in save_tasks {
21053                let result = task.await;
21054                if result.is_err() {
21055                    let Some(path) = buffer
21056                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21057                        .ok()
21058                    else {
21059                        continue;
21060                    };
21061                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21062                        let Some(task) = cx
21063                            .update_window_entity(workspace, |workspace, window, cx| {
21064                                workspace
21065                                    .open_path_preview(path, None, false, false, false, window, cx)
21066                            })
21067                            .ok()
21068                        else {
21069                            continue;
21070                        };
21071                        task.await.log_err();
21072                    }
21073                }
21074            }
21075        })
21076        .detach();
21077        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21078            selections.refresh()
21079        });
21080    }
21081
21082    pub fn to_pixel_point(
21083        &self,
21084        source: multi_buffer::Anchor,
21085        editor_snapshot: &EditorSnapshot,
21086        window: &mut Window,
21087    ) -> Option<gpui::Point<Pixels>> {
21088        let source_point = source.to_display_point(editor_snapshot);
21089        self.display_to_pixel_point(source_point, editor_snapshot, window)
21090    }
21091
21092    pub fn display_to_pixel_point(
21093        &self,
21094        source: DisplayPoint,
21095        editor_snapshot: &EditorSnapshot,
21096        window: &mut Window,
21097    ) -> Option<gpui::Point<Pixels>> {
21098        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21099        let text_layout_details = self.text_layout_details(window);
21100        let scroll_top = text_layout_details
21101            .scroll_anchor
21102            .scroll_position(editor_snapshot)
21103            .y;
21104
21105        if source.row().as_f32() < scroll_top.floor() {
21106            return None;
21107        }
21108        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21109        let source_y = line_height * (source.row().as_f32() - scroll_top);
21110        Some(gpui::Point::new(source_x, source_y))
21111    }
21112
21113    pub fn has_visible_completions_menu(&self) -> bool {
21114        !self.edit_prediction_preview_is_active()
21115            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21116                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21117            })
21118    }
21119
21120    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21121        if self.mode.is_minimap() {
21122            return;
21123        }
21124        self.addons
21125            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21126    }
21127
21128    pub fn unregister_addon<T: Addon>(&mut self) {
21129        self.addons.remove(&std::any::TypeId::of::<T>());
21130    }
21131
21132    pub fn addon<T: Addon>(&self) -> Option<&T> {
21133        let type_id = std::any::TypeId::of::<T>();
21134        self.addons
21135            .get(&type_id)
21136            .and_then(|item| item.to_any().downcast_ref::<T>())
21137    }
21138
21139    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21140        let type_id = std::any::TypeId::of::<T>();
21141        self.addons
21142            .get_mut(&type_id)
21143            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21144    }
21145
21146    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21147        let text_layout_details = self.text_layout_details(window);
21148        let style = &text_layout_details.editor_style;
21149        let font_id = window.text_system().resolve_font(&style.text.font());
21150        let font_size = style.text.font_size.to_pixels(window.rem_size());
21151        let line_height = style.text.line_height_in_pixels(window.rem_size());
21152        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21153        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21154
21155        CharacterDimensions {
21156            em_width,
21157            em_advance,
21158            line_height,
21159        }
21160    }
21161
21162    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21163        self.load_diff_task.clone()
21164    }
21165
21166    fn read_metadata_from_db(
21167        &mut self,
21168        item_id: u64,
21169        workspace_id: WorkspaceId,
21170        window: &mut Window,
21171        cx: &mut Context<Editor>,
21172    ) {
21173        if self.is_singleton(cx)
21174            && !self.mode.is_minimap()
21175            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21176        {
21177            let buffer_snapshot = OnceCell::new();
21178
21179            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21180                && !folds.is_empty()
21181            {
21182                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21183                self.fold_ranges(
21184                    folds
21185                        .into_iter()
21186                        .map(|(start, end)| {
21187                            snapshot.clip_offset(start, Bias::Left)
21188                                ..snapshot.clip_offset(end, Bias::Right)
21189                        })
21190                        .collect(),
21191                    false,
21192                    window,
21193                    cx,
21194                );
21195            }
21196
21197            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21198                && !selections.is_empty()
21199            {
21200                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21201                // skip adding the initial selection to selection history
21202                self.selection_history.mode = SelectionHistoryMode::Skipping;
21203                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21204                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21205                        snapshot.clip_offset(start, Bias::Left)
21206                            ..snapshot.clip_offset(end, Bias::Right)
21207                    }));
21208                });
21209                self.selection_history.mode = SelectionHistoryMode::Normal;
21210            };
21211        }
21212
21213        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21214    }
21215
21216    fn update_lsp_data(
21217        &mut self,
21218        ignore_cache: bool,
21219        for_buffer: Option<BufferId>,
21220        window: &mut Window,
21221        cx: &mut Context<'_, Self>,
21222    ) {
21223        self.pull_diagnostics(for_buffer, window, cx);
21224        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21225    }
21226}
21227
21228fn vim_enabled(cx: &App) -> bool {
21229    cx.global::<SettingsStore>()
21230        .raw_user_settings()
21231        .get("vim_mode")
21232        == Some(&serde_json::Value::Bool(true))
21233}
21234
21235fn process_completion_for_edit(
21236    completion: &Completion,
21237    intent: CompletionIntent,
21238    buffer: &Entity<Buffer>,
21239    cursor_position: &text::Anchor,
21240    cx: &mut Context<Editor>,
21241) -> CompletionEdit {
21242    let buffer = buffer.read(cx);
21243    let buffer_snapshot = buffer.snapshot();
21244    let (snippet, new_text) = if completion.is_snippet() {
21245        // Workaround for typescript language server issues so that methods don't expand within
21246        // strings and functions with type expressions. The previous point is used because the query
21247        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21248        let mut snippet_source = completion.new_text.clone();
21249        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21250        previous_point.column = previous_point.column.saturating_sub(1);
21251        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21252            && scope.prefers_label_for_snippet_in_completion()
21253            && let Some(label) = completion.label()
21254            && matches!(
21255                completion.kind(),
21256                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21257            )
21258        {
21259            snippet_source = label;
21260        }
21261        match Snippet::parse(&snippet_source).log_err() {
21262            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21263            None => (None, completion.new_text.clone()),
21264        }
21265    } else {
21266        (None, completion.new_text.clone())
21267    };
21268
21269    let mut range_to_replace = {
21270        let replace_range = &completion.replace_range;
21271        if let CompletionSource::Lsp {
21272            insert_range: Some(insert_range),
21273            ..
21274        } = &completion.source
21275        {
21276            debug_assert_eq!(
21277                insert_range.start, replace_range.start,
21278                "insert_range and replace_range should start at the same position"
21279            );
21280            debug_assert!(
21281                insert_range
21282                    .start
21283                    .cmp(cursor_position, &buffer_snapshot)
21284                    .is_le(),
21285                "insert_range should start before or at cursor position"
21286            );
21287            debug_assert!(
21288                replace_range
21289                    .start
21290                    .cmp(cursor_position, &buffer_snapshot)
21291                    .is_le(),
21292                "replace_range should start before or at cursor position"
21293            );
21294
21295            let should_replace = match intent {
21296                CompletionIntent::CompleteWithInsert => false,
21297                CompletionIntent::CompleteWithReplace => true,
21298                CompletionIntent::Complete | CompletionIntent::Compose => {
21299                    let insert_mode =
21300                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21301                            .completions
21302                            .lsp_insert_mode;
21303                    match insert_mode {
21304                        LspInsertMode::Insert => false,
21305                        LspInsertMode::Replace => true,
21306                        LspInsertMode::ReplaceSubsequence => {
21307                            let mut text_to_replace = buffer.chars_for_range(
21308                                buffer.anchor_before(replace_range.start)
21309                                    ..buffer.anchor_after(replace_range.end),
21310                            );
21311                            let mut current_needle = text_to_replace.next();
21312                            for haystack_ch in completion.label.text.chars() {
21313                                if let Some(needle_ch) = current_needle
21314                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21315                                {
21316                                    current_needle = text_to_replace.next();
21317                                }
21318                            }
21319                            current_needle.is_none()
21320                        }
21321                        LspInsertMode::ReplaceSuffix => {
21322                            if replace_range
21323                                .end
21324                                .cmp(cursor_position, &buffer_snapshot)
21325                                .is_gt()
21326                            {
21327                                let range_after_cursor = *cursor_position..replace_range.end;
21328                                let text_after_cursor = buffer
21329                                    .text_for_range(
21330                                        buffer.anchor_before(range_after_cursor.start)
21331                                            ..buffer.anchor_after(range_after_cursor.end),
21332                                    )
21333                                    .collect::<String>()
21334                                    .to_ascii_lowercase();
21335                                completion
21336                                    .label
21337                                    .text
21338                                    .to_ascii_lowercase()
21339                                    .ends_with(&text_after_cursor)
21340                            } else {
21341                                true
21342                            }
21343                        }
21344                    }
21345                }
21346            };
21347
21348            if should_replace {
21349                replace_range.clone()
21350            } else {
21351                insert_range.clone()
21352            }
21353        } else {
21354            replace_range.clone()
21355        }
21356    };
21357
21358    if range_to_replace
21359        .end
21360        .cmp(cursor_position, &buffer_snapshot)
21361        .is_lt()
21362    {
21363        range_to_replace.end = *cursor_position;
21364    }
21365
21366    CompletionEdit {
21367        new_text,
21368        replace_range: range_to_replace.to_offset(buffer),
21369        snippet,
21370    }
21371}
21372
21373struct CompletionEdit {
21374    new_text: String,
21375    replace_range: Range<usize>,
21376    snippet: Option<Snippet>,
21377}
21378
21379fn insert_extra_newline_brackets(
21380    buffer: &MultiBufferSnapshot,
21381    range: Range<usize>,
21382    language: &language::LanguageScope,
21383) -> bool {
21384    let leading_whitespace_len = buffer
21385        .reversed_chars_at(range.start)
21386        .take_while(|c| c.is_whitespace() && *c != '\n')
21387        .map(|c| c.len_utf8())
21388        .sum::<usize>();
21389    let trailing_whitespace_len = buffer
21390        .chars_at(range.end)
21391        .take_while(|c| c.is_whitespace() && *c != '\n')
21392        .map(|c| c.len_utf8())
21393        .sum::<usize>();
21394    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21395
21396    language.brackets().any(|(pair, enabled)| {
21397        let pair_start = pair.start.trim_end();
21398        let pair_end = pair.end.trim_start();
21399
21400        enabled
21401            && pair.newline
21402            && buffer.contains_str_at(range.end, pair_end)
21403            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21404    })
21405}
21406
21407fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21408    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21409        [(buffer, range, _)] => (*buffer, range.clone()),
21410        _ => return false,
21411    };
21412    let pair = {
21413        let mut result: Option<BracketMatch> = None;
21414
21415        for pair in buffer
21416            .all_bracket_ranges(range.clone())
21417            .filter(move |pair| {
21418                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21419            })
21420        {
21421            let len = pair.close_range.end - pair.open_range.start;
21422
21423            if let Some(existing) = &result {
21424                let existing_len = existing.close_range.end - existing.open_range.start;
21425                if len > existing_len {
21426                    continue;
21427                }
21428            }
21429
21430            result = Some(pair);
21431        }
21432
21433        result
21434    };
21435    let Some(pair) = pair else {
21436        return false;
21437    };
21438    pair.newline_only
21439        && buffer
21440            .chars_for_range(pair.open_range.end..range.start)
21441            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21442            .all(|c| c.is_whitespace() && c != '\n')
21443}
21444
21445fn update_uncommitted_diff_for_buffer(
21446    editor: Entity<Editor>,
21447    project: &Entity<Project>,
21448    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21449    buffer: Entity<MultiBuffer>,
21450    cx: &mut App,
21451) -> Task<()> {
21452    let mut tasks = Vec::new();
21453    project.update(cx, |project, cx| {
21454        for buffer in buffers {
21455            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21456                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21457            }
21458        }
21459    });
21460    cx.spawn(async move |cx| {
21461        let diffs = future::join_all(tasks).await;
21462        if editor
21463            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21464            .unwrap_or(false)
21465        {
21466            return;
21467        }
21468
21469        buffer
21470            .update(cx, |buffer, cx| {
21471                for diff in diffs.into_iter().flatten() {
21472                    buffer.add_diff(diff, cx);
21473                }
21474            })
21475            .ok();
21476    })
21477}
21478
21479fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21480    let tab_size = tab_size.get() as usize;
21481    let mut width = offset;
21482
21483    for ch in text.chars() {
21484        width += if ch == '\t' {
21485            tab_size - (width % tab_size)
21486        } else {
21487            1
21488        };
21489    }
21490
21491    width - offset
21492}
21493
21494#[cfg(test)]
21495mod tests {
21496    use super::*;
21497
21498    #[test]
21499    fn test_string_size_with_expanded_tabs() {
21500        let nz = |val| NonZeroU32::new(val).unwrap();
21501        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21502        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21503        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21504        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21505        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21506        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21507        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21508        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21509    }
21510}
21511
21512/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21513struct WordBreakingTokenizer<'a> {
21514    input: &'a str,
21515}
21516
21517impl<'a> WordBreakingTokenizer<'a> {
21518    fn new(input: &'a str) -> Self {
21519        Self { input }
21520    }
21521}
21522
21523fn is_char_ideographic(ch: char) -> bool {
21524    use unicode_script::Script::*;
21525    use unicode_script::UnicodeScript;
21526    matches!(ch.script(), Han | Tangut | Yi)
21527}
21528
21529fn is_grapheme_ideographic(text: &str) -> bool {
21530    text.chars().any(is_char_ideographic)
21531}
21532
21533fn is_grapheme_whitespace(text: &str) -> bool {
21534    text.chars().any(|x| x.is_whitespace())
21535}
21536
21537fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21538    text.chars()
21539        .next()
21540        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21541}
21542
21543#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21544enum WordBreakToken<'a> {
21545    Word { token: &'a str, grapheme_len: usize },
21546    InlineWhitespace { token: &'a str, grapheme_len: usize },
21547    Newline,
21548}
21549
21550impl<'a> Iterator for WordBreakingTokenizer<'a> {
21551    /// Yields a span, the count of graphemes in the token, and whether it was
21552    /// whitespace. Note that it also breaks at word boundaries.
21553    type Item = WordBreakToken<'a>;
21554
21555    fn next(&mut self) -> Option<Self::Item> {
21556        use unicode_segmentation::UnicodeSegmentation;
21557        if self.input.is_empty() {
21558            return None;
21559        }
21560
21561        let mut iter = self.input.graphemes(true).peekable();
21562        let mut offset = 0;
21563        let mut grapheme_len = 0;
21564        if let Some(first_grapheme) = iter.next() {
21565            let is_newline = first_grapheme == "\n";
21566            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21567            offset += first_grapheme.len();
21568            grapheme_len += 1;
21569            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21570                if let Some(grapheme) = iter.peek().copied()
21571                    && should_stay_with_preceding_ideograph(grapheme)
21572                {
21573                    offset += grapheme.len();
21574                    grapheme_len += 1;
21575                }
21576            } else {
21577                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21578                let mut next_word_bound = words.peek().copied();
21579                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21580                    next_word_bound = words.next();
21581                }
21582                while let Some(grapheme) = iter.peek().copied() {
21583                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21584                        break;
21585                    };
21586                    if is_grapheme_whitespace(grapheme) != is_whitespace
21587                        || (grapheme == "\n") != is_newline
21588                    {
21589                        break;
21590                    };
21591                    offset += grapheme.len();
21592                    grapheme_len += 1;
21593                    iter.next();
21594                }
21595            }
21596            let token = &self.input[..offset];
21597            self.input = &self.input[offset..];
21598            if token == "\n" {
21599                Some(WordBreakToken::Newline)
21600            } else if is_whitespace {
21601                Some(WordBreakToken::InlineWhitespace {
21602                    token,
21603                    grapheme_len,
21604                })
21605            } else {
21606                Some(WordBreakToken::Word {
21607                    token,
21608                    grapheme_len,
21609                })
21610            }
21611        } else {
21612            None
21613        }
21614    }
21615}
21616
21617#[test]
21618fn test_word_breaking_tokenizer() {
21619    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21620        ("", &[]),
21621        ("  ", &[whitespace("  ", 2)]),
21622        ("Ʒ", &[word("Ʒ", 1)]),
21623        ("Ǽ", &[word("Ǽ", 1)]),
21624        ("", &[word("", 1)]),
21625        ("⋑⋑", &[word("⋑⋑", 2)]),
21626        (
21627            "原理,进而",
21628            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21629        ),
21630        (
21631            "hello world",
21632            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21633        ),
21634        (
21635            "hello, world",
21636            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21637        ),
21638        (
21639            "  hello world",
21640            &[
21641                whitespace("  ", 2),
21642                word("hello", 5),
21643                whitespace(" ", 1),
21644                word("world", 5),
21645            ],
21646        ),
21647        (
21648            "这是什么 \n 钢笔",
21649            &[
21650                word("", 1),
21651                word("", 1),
21652                word("", 1),
21653                word("", 1),
21654                whitespace(" ", 1),
21655                newline(),
21656                whitespace(" ", 1),
21657                word("", 1),
21658                word("", 1),
21659            ],
21660        ),
21661        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21662    ];
21663
21664    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21665        WordBreakToken::Word {
21666            token,
21667            grapheme_len,
21668        }
21669    }
21670
21671    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21672        WordBreakToken::InlineWhitespace {
21673            token,
21674            grapheme_len,
21675        }
21676    }
21677
21678    fn newline() -> WordBreakToken<'static> {
21679        WordBreakToken::Newline
21680    }
21681
21682    for (input, result) in tests {
21683        assert_eq!(
21684            WordBreakingTokenizer::new(input)
21685                .collect::<Vec<_>>()
21686                .as_slice(),
21687            *result,
21688        );
21689    }
21690}
21691
21692fn wrap_with_prefix(
21693    first_line_prefix: String,
21694    subsequent_lines_prefix: String,
21695    unwrapped_text: String,
21696    wrap_column: usize,
21697    tab_size: NonZeroU32,
21698    preserve_existing_whitespace: bool,
21699) -> String {
21700    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21701    let subsequent_lines_prefix_len =
21702        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21703    let mut wrapped_text = String::new();
21704    let mut current_line = first_line_prefix;
21705    let mut is_first_line = true;
21706
21707    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21708    let mut current_line_len = first_line_prefix_len;
21709    let mut in_whitespace = false;
21710    for token in tokenizer {
21711        let have_preceding_whitespace = in_whitespace;
21712        match token {
21713            WordBreakToken::Word {
21714                token,
21715                grapheme_len,
21716            } => {
21717                in_whitespace = false;
21718                let current_prefix_len = if is_first_line {
21719                    first_line_prefix_len
21720                } else {
21721                    subsequent_lines_prefix_len
21722                };
21723                if current_line_len + grapheme_len > wrap_column
21724                    && current_line_len != current_prefix_len
21725                {
21726                    wrapped_text.push_str(current_line.trim_end());
21727                    wrapped_text.push('\n');
21728                    is_first_line = false;
21729                    current_line = subsequent_lines_prefix.clone();
21730                    current_line_len = subsequent_lines_prefix_len;
21731                }
21732                current_line.push_str(token);
21733                current_line_len += grapheme_len;
21734            }
21735            WordBreakToken::InlineWhitespace {
21736                mut token,
21737                mut grapheme_len,
21738            } => {
21739                in_whitespace = true;
21740                if have_preceding_whitespace && !preserve_existing_whitespace {
21741                    continue;
21742                }
21743                if !preserve_existing_whitespace {
21744                    token = " ";
21745                    grapheme_len = 1;
21746                }
21747                let current_prefix_len = if is_first_line {
21748                    first_line_prefix_len
21749                } else {
21750                    subsequent_lines_prefix_len
21751                };
21752                if current_line_len + grapheme_len > wrap_column {
21753                    wrapped_text.push_str(current_line.trim_end());
21754                    wrapped_text.push('\n');
21755                    is_first_line = false;
21756                    current_line = subsequent_lines_prefix.clone();
21757                    current_line_len = subsequent_lines_prefix_len;
21758                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21759                    current_line.push_str(token);
21760                    current_line_len += grapheme_len;
21761                }
21762            }
21763            WordBreakToken::Newline => {
21764                in_whitespace = true;
21765                let current_prefix_len = if is_first_line {
21766                    first_line_prefix_len
21767                } else {
21768                    subsequent_lines_prefix_len
21769                };
21770                if preserve_existing_whitespace {
21771                    wrapped_text.push_str(current_line.trim_end());
21772                    wrapped_text.push('\n');
21773                    is_first_line = false;
21774                    current_line = subsequent_lines_prefix.clone();
21775                    current_line_len = subsequent_lines_prefix_len;
21776                } else if have_preceding_whitespace {
21777                    continue;
21778                } else if current_line_len + 1 > wrap_column
21779                    && current_line_len != current_prefix_len
21780                {
21781                    wrapped_text.push_str(current_line.trim_end());
21782                    wrapped_text.push('\n');
21783                    is_first_line = false;
21784                    current_line = subsequent_lines_prefix.clone();
21785                    current_line_len = subsequent_lines_prefix_len;
21786                } else if current_line_len != current_prefix_len {
21787                    current_line.push(' ');
21788                    current_line_len += 1;
21789                }
21790            }
21791        }
21792    }
21793
21794    if !current_line.is_empty() {
21795        wrapped_text.push_str(&current_line);
21796    }
21797    wrapped_text
21798}
21799
21800#[test]
21801fn test_wrap_with_prefix() {
21802    assert_eq!(
21803        wrap_with_prefix(
21804            "# ".to_string(),
21805            "# ".to_string(),
21806            "abcdefg".to_string(),
21807            4,
21808            NonZeroU32::new(4).unwrap(),
21809            false,
21810        ),
21811        "# abcdefg"
21812    );
21813    assert_eq!(
21814        wrap_with_prefix(
21815            "".to_string(),
21816            "".to_string(),
21817            "\thello world".to_string(),
21818            8,
21819            NonZeroU32::new(4).unwrap(),
21820            false,
21821        ),
21822        "hello\nworld"
21823    );
21824    assert_eq!(
21825        wrap_with_prefix(
21826            "// ".to_string(),
21827            "// ".to_string(),
21828            "xx \nyy zz aa bb cc".to_string(),
21829            12,
21830            NonZeroU32::new(4).unwrap(),
21831            false,
21832        ),
21833        "// xx yy zz\n// aa bb cc"
21834    );
21835    assert_eq!(
21836        wrap_with_prefix(
21837            String::new(),
21838            String::new(),
21839            "这是什么 \n 钢笔".to_string(),
21840            3,
21841            NonZeroU32::new(4).unwrap(),
21842            false,
21843        ),
21844        "这是什\n么 钢\n"
21845    );
21846}
21847
21848pub trait CollaborationHub {
21849    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21850    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21851    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21852}
21853
21854impl CollaborationHub for Entity<Project> {
21855    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21856        self.read(cx).collaborators()
21857    }
21858
21859    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21860        self.read(cx).user_store().read(cx).participant_indices()
21861    }
21862
21863    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21864        let this = self.read(cx);
21865        let user_ids = this.collaborators().values().map(|c| c.user_id);
21866        this.user_store().read(cx).participant_names(user_ids, cx)
21867    }
21868}
21869
21870pub trait SemanticsProvider {
21871    fn hover(
21872        &self,
21873        buffer: &Entity<Buffer>,
21874        position: text::Anchor,
21875        cx: &mut App,
21876    ) -> Option<Task<Option<Vec<project::Hover>>>>;
21877
21878    fn inline_values(
21879        &self,
21880        buffer_handle: Entity<Buffer>,
21881        range: Range<text::Anchor>,
21882        cx: &mut App,
21883    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21884
21885    fn inlay_hints(
21886        &self,
21887        buffer_handle: Entity<Buffer>,
21888        range: Range<text::Anchor>,
21889        cx: &mut App,
21890    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21891
21892    fn resolve_inlay_hint(
21893        &self,
21894        hint: InlayHint,
21895        buffer_handle: Entity<Buffer>,
21896        server_id: LanguageServerId,
21897        cx: &mut App,
21898    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21899
21900    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21901
21902    fn document_highlights(
21903        &self,
21904        buffer: &Entity<Buffer>,
21905        position: text::Anchor,
21906        cx: &mut App,
21907    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21908
21909    fn definitions(
21910        &self,
21911        buffer: &Entity<Buffer>,
21912        position: text::Anchor,
21913        kind: GotoDefinitionKind,
21914        cx: &mut App,
21915    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
21916
21917    fn range_for_rename(
21918        &self,
21919        buffer: &Entity<Buffer>,
21920        position: text::Anchor,
21921        cx: &mut App,
21922    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21923
21924    fn perform_rename(
21925        &self,
21926        buffer: &Entity<Buffer>,
21927        position: text::Anchor,
21928        new_name: String,
21929        cx: &mut App,
21930    ) -> Option<Task<Result<ProjectTransaction>>>;
21931}
21932
21933pub trait CompletionProvider {
21934    fn completions(
21935        &self,
21936        excerpt_id: ExcerptId,
21937        buffer: &Entity<Buffer>,
21938        buffer_position: text::Anchor,
21939        trigger: CompletionContext,
21940        window: &mut Window,
21941        cx: &mut Context<Editor>,
21942    ) -> Task<Result<Vec<CompletionResponse>>>;
21943
21944    fn resolve_completions(
21945        &self,
21946        _buffer: Entity<Buffer>,
21947        _completion_indices: Vec<usize>,
21948        _completions: Rc<RefCell<Box<[Completion]>>>,
21949        _cx: &mut Context<Editor>,
21950    ) -> Task<Result<bool>> {
21951        Task::ready(Ok(false))
21952    }
21953
21954    fn apply_additional_edits_for_completion(
21955        &self,
21956        _buffer: Entity<Buffer>,
21957        _completions: Rc<RefCell<Box<[Completion]>>>,
21958        _completion_index: usize,
21959        _push_to_history: bool,
21960        _cx: &mut Context<Editor>,
21961    ) -> Task<Result<Option<language::Transaction>>> {
21962        Task::ready(Ok(None))
21963    }
21964
21965    fn is_completion_trigger(
21966        &self,
21967        buffer: &Entity<Buffer>,
21968        position: language::Anchor,
21969        text: &str,
21970        trigger_in_words: bool,
21971        menu_is_open: bool,
21972        cx: &mut Context<Editor>,
21973    ) -> bool;
21974
21975    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21976
21977    fn sort_completions(&self) -> bool {
21978        true
21979    }
21980
21981    fn filter_completions(&self) -> bool {
21982        true
21983    }
21984}
21985
21986pub trait CodeActionProvider {
21987    fn id(&self) -> Arc<str>;
21988
21989    fn code_actions(
21990        &self,
21991        buffer: &Entity<Buffer>,
21992        range: Range<text::Anchor>,
21993        window: &mut Window,
21994        cx: &mut App,
21995    ) -> Task<Result<Vec<CodeAction>>>;
21996
21997    fn apply_code_action(
21998        &self,
21999        buffer_handle: Entity<Buffer>,
22000        action: CodeAction,
22001        excerpt_id: ExcerptId,
22002        push_to_history: bool,
22003        window: &mut Window,
22004        cx: &mut App,
22005    ) -> Task<Result<ProjectTransaction>>;
22006}
22007
22008impl CodeActionProvider for Entity<Project> {
22009    fn id(&self) -> Arc<str> {
22010        "project".into()
22011    }
22012
22013    fn code_actions(
22014        &self,
22015        buffer: &Entity<Buffer>,
22016        range: Range<text::Anchor>,
22017        _window: &mut Window,
22018        cx: &mut App,
22019    ) -> Task<Result<Vec<CodeAction>>> {
22020        self.update(cx, |project, cx| {
22021            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22022            let code_actions = project.code_actions(buffer, range, None, cx);
22023            cx.background_spawn(async move {
22024                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22025                Ok(code_lens_actions
22026                    .context("code lens fetch")?
22027                    .into_iter()
22028                    .flatten()
22029                    .chain(
22030                        code_actions
22031                            .context("code action fetch")?
22032                            .into_iter()
22033                            .flatten(),
22034                    )
22035                    .collect())
22036            })
22037        })
22038    }
22039
22040    fn apply_code_action(
22041        &self,
22042        buffer_handle: Entity<Buffer>,
22043        action: CodeAction,
22044        _excerpt_id: ExcerptId,
22045        push_to_history: bool,
22046        _window: &mut Window,
22047        cx: &mut App,
22048    ) -> Task<Result<ProjectTransaction>> {
22049        self.update(cx, |project, cx| {
22050            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22051        })
22052    }
22053}
22054
22055fn snippet_completions(
22056    project: &Project,
22057    buffer: &Entity<Buffer>,
22058    buffer_position: text::Anchor,
22059    cx: &mut App,
22060) -> Task<Result<CompletionResponse>> {
22061    let languages = buffer.read(cx).languages_at(buffer_position);
22062    let snippet_store = project.snippets().read(cx);
22063
22064    let scopes: Vec<_> = languages
22065        .iter()
22066        .filter_map(|language| {
22067            let language_name = language.lsp_id();
22068            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22069
22070            if snippets.is_empty() {
22071                None
22072            } else {
22073                Some((language.default_scope(), snippets))
22074            }
22075        })
22076        .collect();
22077
22078    if scopes.is_empty() {
22079        return Task::ready(Ok(CompletionResponse {
22080            completions: vec![],
22081            display_options: CompletionDisplayOptions::default(),
22082            is_incomplete: false,
22083        }));
22084    }
22085
22086    let snapshot = buffer.read(cx).text_snapshot();
22087    let chars: String = snapshot
22088        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22089        .collect();
22090    let executor = cx.background_executor().clone();
22091
22092    cx.background_spawn(async move {
22093        let mut is_incomplete = false;
22094        let mut completions: Vec<Completion> = Vec::new();
22095        for (scope, snippets) in scopes.into_iter() {
22096            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22097            let mut last_word = chars
22098                .chars()
22099                .take_while(|c| classifier.is_word(*c))
22100                .collect::<String>();
22101            last_word = last_word.chars().rev().collect();
22102
22103            if last_word.is_empty() {
22104                return Ok(CompletionResponse {
22105                    completions: vec![],
22106                    display_options: CompletionDisplayOptions::default(),
22107                    is_incomplete: true,
22108                });
22109            }
22110
22111            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22112            let to_lsp = |point: &text::Anchor| {
22113                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22114                point_to_lsp(end)
22115            };
22116            let lsp_end = to_lsp(&buffer_position);
22117
22118            let candidates = snippets
22119                .iter()
22120                .enumerate()
22121                .flat_map(|(ix, snippet)| {
22122                    snippet
22123                        .prefix
22124                        .iter()
22125                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22126                })
22127                .collect::<Vec<StringMatchCandidate>>();
22128
22129            const MAX_RESULTS: usize = 100;
22130            let mut matches = fuzzy::match_strings(
22131                &candidates,
22132                &last_word,
22133                last_word.chars().any(|c| c.is_uppercase()),
22134                true,
22135                MAX_RESULTS,
22136                &Default::default(),
22137                executor.clone(),
22138            )
22139            .await;
22140
22141            if matches.len() >= MAX_RESULTS {
22142                is_incomplete = true;
22143            }
22144
22145            // Remove all candidates where the query's start does not match the start of any word in the candidate
22146            if let Some(query_start) = last_word.chars().next() {
22147                matches.retain(|string_match| {
22148                    split_words(&string_match.string).any(|word| {
22149                        // Check that the first codepoint of the word as lowercase matches the first
22150                        // codepoint of the query as lowercase
22151                        word.chars()
22152                            .flat_map(|codepoint| codepoint.to_lowercase())
22153                            .zip(query_start.to_lowercase())
22154                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22155                    })
22156                });
22157            }
22158
22159            let matched_strings = matches
22160                .into_iter()
22161                .map(|m| m.string)
22162                .collect::<HashSet<_>>();
22163
22164            completions.extend(snippets.iter().filter_map(|snippet| {
22165                let matching_prefix = snippet
22166                    .prefix
22167                    .iter()
22168                    .find(|prefix| matched_strings.contains(*prefix))?;
22169                let start = as_offset - last_word.len();
22170                let start = snapshot.anchor_before(start);
22171                let range = start..buffer_position;
22172                let lsp_start = to_lsp(&start);
22173                let lsp_range = lsp::Range {
22174                    start: lsp_start,
22175                    end: lsp_end,
22176                };
22177                Some(Completion {
22178                    replace_range: range,
22179                    new_text: snippet.body.clone(),
22180                    source: CompletionSource::Lsp {
22181                        insert_range: None,
22182                        server_id: LanguageServerId(usize::MAX),
22183                        resolved: true,
22184                        lsp_completion: Box::new(lsp::CompletionItem {
22185                            label: snippet.prefix.first().unwrap().clone(),
22186                            kind: Some(CompletionItemKind::SNIPPET),
22187                            label_details: snippet.description.as_ref().map(|description| {
22188                                lsp::CompletionItemLabelDetails {
22189                                    detail: Some(description.clone()),
22190                                    description: None,
22191                                }
22192                            }),
22193                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22194                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22195                                lsp::InsertReplaceEdit {
22196                                    new_text: snippet.body.clone(),
22197                                    insert: lsp_range,
22198                                    replace: lsp_range,
22199                                },
22200                            )),
22201                            filter_text: Some(snippet.body.clone()),
22202                            sort_text: Some(char::MAX.to_string()),
22203                            ..lsp::CompletionItem::default()
22204                        }),
22205                        lsp_defaults: None,
22206                    },
22207                    label: CodeLabel {
22208                        text: matching_prefix.clone(),
22209                        runs: Vec::new(),
22210                        filter_range: 0..matching_prefix.len(),
22211                    },
22212                    icon_path: None,
22213                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22214                        single_line: snippet.name.clone().into(),
22215                        plain_text: snippet
22216                            .description
22217                            .clone()
22218                            .map(|description| description.into()),
22219                    }),
22220                    insert_text_mode: None,
22221                    confirm: None,
22222                })
22223            }))
22224        }
22225
22226        Ok(CompletionResponse {
22227            completions,
22228            display_options: CompletionDisplayOptions::default(),
22229            is_incomplete,
22230        })
22231    })
22232}
22233
22234impl CompletionProvider for Entity<Project> {
22235    fn completions(
22236        &self,
22237        _excerpt_id: ExcerptId,
22238        buffer: &Entity<Buffer>,
22239        buffer_position: text::Anchor,
22240        options: CompletionContext,
22241        _window: &mut Window,
22242        cx: &mut Context<Editor>,
22243    ) -> Task<Result<Vec<CompletionResponse>>> {
22244        self.update(cx, |project, cx| {
22245            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22246            let project_completions = project.completions(buffer, buffer_position, options, cx);
22247            cx.background_spawn(async move {
22248                let mut responses = project_completions.await?;
22249                let snippets = snippets.await?;
22250                if !snippets.completions.is_empty() {
22251                    responses.push(snippets);
22252                }
22253                Ok(responses)
22254            })
22255        })
22256    }
22257
22258    fn resolve_completions(
22259        &self,
22260        buffer: Entity<Buffer>,
22261        completion_indices: Vec<usize>,
22262        completions: Rc<RefCell<Box<[Completion]>>>,
22263        cx: &mut Context<Editor>,
22264    ) -> Task<Result<bool>> {
22265        self.update(cx, |project, cx| {
22266            project.lsp_store().update(cx, |lsp_store, cx| {
22267                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22268            })
22269        })
22270    }
22271
22272    fn apply_additional_edits_for_completion(
22273        &self,
22274        buffer: Entity<Buffer>,
22275        completions: Rc<RefCell<Box<[Completion]>>>,
22276        completion_index: usize,
22277        push_to_history: bool,
22278        cx: &mut Context<Editor>,
22279    ) -> Task<Result<Option<language::Transaction>>> {
22280        self.update(cx, |project, cx| {
22281            project.lsp_store().update(cx, |lsp_store, cx| {
22282                lsp_store.apply_additional_edits_for_completion(
22283                    buffer,
22284                    completions,
22285                    completion_index,
22286                    push_to_history,
22287                    cx,
22288                )
22289            })
22290        })
22291    }
22292
22293    fn is_completion_trigger(
22294        &self,
22295        buffer: &Entity<Buffer>,
22296        position: language::Anchor,
22297        text: &str,
22298        trigger_in_words: bool,
22299        menu_is_open: bool,
22300        cx: &mut Context<Editor>,
22301    ) -> bool {
22302        let mut chars = text.chars();
22303        let char = if let Some(char) = chars.next() {
22304            char
22305        } else {
22306            return false;
22307        };
22308        if chars.next().is_some() {
22309            return false;
22310        }
22311
22312        let buffer = buffer.read(cx);
22313        let snapshot = buffer.snapshot();
22314        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22315            return false;
22316        }
22317        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22318        if trigger_in_words && classifier.is_word(char) {
22319            return true;
22320        }
22321
22322        buffer.completion_triggers().contains(text)
22323    }
22324}
22325
22326impl SemanticsProvider for Entity<Project> {
22327    fn hover(
22328        &self,
22329        buffer: &Entity<Buffer>,
22330        position: text::Anchor,
22331        cx: &mut App,
22332    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22333        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22334    }
22335
22336    fn document_highlights(
22337        &self,
22338        buffer: &Entity<Buffer>,
22339        position: text::Anchor,
22340        cx: &mut App,
22341    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22342        Some(self.update(cx, |project, cx| {
22343            project.document_highlights(buffer, position, cx)
22344        }))
22345    }
22346
22347    fn definitions(
22348        &self,
22349        buffer: &Entity<Buffer>,
22350        position: text::Anchor,
22351        kind: GotoDefinitionKind,
22352        cx: &mut App,
22353    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22354        Some(self.update(cx, |project, cx| match kind {
22355            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22356            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22357            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22358            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22359        }))
22360    }
22361
22362    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22363        self.update(cx, |project, cx| {
22364            if project
22365                .active_debug_session(cx)
22366                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22367            {
22368                return true;
22369            }
22370
22371            buffer.update(cx, |buffer, cx| {
22372                project.any_language_server_supports_inlay_hints(buffer, cx)
22373            })
22374        })
22375    }
22376
22377    fn inline_values(
22378        &self,
22379        buffer_handle: Entity<Buffer>,
22380        range: Range<text::Anchor>,
22381        cx: &mut App,
22382    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22383        self.update(cx, |project, cx| {
22384            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22385
22386            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22387        })
22388    }
22389
22390    fn inlay_hints(
22391        &self,
22392        buffer_handle: Entity<Buffer>,
22393        range: Range<text::Anchor>,
22394        cx: &mut App,
22395    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22396        Some(self.update(cx, |project, cx| {
22397            project.inlay_hints(buffer_handle, range, cx)
22398        }))
22399    }
22400
22401    fn resolve_inlay_hint(
22402        &self,
22403        hint: InlayHint,
22404        buffer_handle: Entity<Buffer>,
22405        server_id: LanguageServerId,
22406        cx: &mut App,
22407    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22408        Some(self.update(cx, |project, cx| {
22409            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22410        }))
22411    }
22412
22413    fn range_for_rename(
22414        &self,
22415        buffer: &Entity<Buffer>,
22416        position: text::Anchor,
22417        cx: &mut App,
22418    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22419        Some(self.update(cx, |project, cx| {
22420            let buffer = buffer.clone();
22421            let task = project.prepare_rename(buffer.clone(), position, cx);
22422            cx.spawn(async move |_, cx| {
22423                Ok(match task.await? {
22424                    PrepareRenameResponse::Success(range) => Some(range),
22425                    PrepareRenameResponse::InvalidPosition => None,
22426                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22427                        // Fallback on using TreeSitter info to determine identifier range
22428                        buffer.read_with(cx, |buffer, _| {
22429                            let snapshot = buffer.snapshot();
22430                            let (range, kind) = snapshot.surrounding_word(position, false);
22431                            if kind != Some(CharKind::Word) {
22432                                return None;
22433                            }
22434                            Some(
22435                                snapshot.anchor_before(range.start)
22436                                    ..snapshot.anchor_after(range.end),
22437                            )
22438                        })?
22439                    }
22440                })
22441            })
22442        }))
22443    }
22444
22445    fn perform_rename(
22446        &self,
22447        buffer: &Entity<Buffer>,
22448        position: text::Anchor,
22449        new_name: String,
22450        cx: &mut App,
22451    ) -> Option<Task<Result<ProjectTransaction>>> {
22452        Some(self.update(cx, |project, cx| {
22453            project.perform_rename(buffer.clone(), position, new_name, cx)
22454        }))
22455    }
22456}
22457
22458fn inlay_hint_settings(
22459    location: Anchor,
22460    snapshot: &MultiBufferSnapshot,
22461    cx: &mut Context<Editor>,
22462) -> InlayHintSettings {
22463    let file = snapshot.file_at(location);
22464    let language = snapshot.language_at(location).map(|l| l.name());
22465    language_settings(language, file, cx).inlay_hints
22466}
22467
22468fn consume_contiguous_rows(
22469    contiguous_row_selections: &mut Vec<Selection<Point>>,
22470    selection: &Selection<Point>,
22471    display_map: &DisplaySnapshot,
22472    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22473) -> (MultiBufferRow, MultiBufferRow) {
22474    contiguous_row_selections.push(selection.clone());
22475    let start_row = starting_row(selection, display_map);
22476    let mut end_row = ending_row(selection, display_map);
22477
22478    while let Some(next_selection) = selections.peek() {
22479        if next_selection.start.row <= end_row.0 {
22480            end_row = ending_row(next_selection, display_map);
22481            contiguous_row_selections.push(selections.next().unwrap().clone());
22482        } else {
22483            break;
22484        }
22485    }
22486    (start_row, end_row)
22487}
22488
22489fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22490    if selection.start.column > 0 {
22491        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22492    } else {
22493        MultiBufferRow(selection.start.row)
22494    }
22495}
22496
22497fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22498    if next_selection.end.column > 0 || next_selection.is_empty() {
22499        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22500    } else {
22501        MultiBufferRow(next_selection.end.row)
22502    }
22503}
22504
22505impl EditorSnapshot {
22506    pub fn remote_selections_in_range<'a>(
22507        &'a self,
22508        range: &'a Range<Anchor>,
22509        collaboration_hub: &dyn CollaborationHub,
22510        cx: &'a App,
22511    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22512        let participant_names = collaboration_hub.user_names(cx);
22513        let participant_indices = collaboration_hub.user_participant_indices(cx);
22514        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22515        let collaborators_by_replica_id = collaborators_by_peer_id
22516            .values()
22517            .map(|collaborator| (collaborator.replica_id, collaborator))
22518            .collect::<HashMap<_, _>>();
22519        self.buffer_snapshot
22520            .selections_in_range(range, false)
22521            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22522                if replica_id == AGENT_REPLICA_ID {
22523                    Some(RemoteSelection {
22524                        replica_id,
22525                        selection,
22526                        cursor_shape,
22527                        line_mode,
22528                        collaborator_id: CollaboratorId::Agent,
22529                        user_name: Some("Agent".into()),
22530                        color: cx.theme().players().agent(),
22531                    })
22532                } else {
22533                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22534                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22535                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22536                    Some(RemoteSelection {
22537                        replica_id,
22538                        selection,
22539                        cursor_shape,
22540                        line_mode,
22541                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22542                        user_name,
22543                        color: if let Some(index) = participant_index {
22544                            cx.theme().players().color_for_participant(index.0)
22545                        } else {
22546                            cx.theme().players().absent()
22547                        },
22548                    })
22549                }
22550            })
22551    }
22552
22553    pub fn hunks_for_ranges(
22554        &self,
22555        ranges: impl IntoIterator<Item = Range<Point>>,
22556    ) -> Vec<MultiBufferDiffHunk> {
22557        let mut hunks = Vec::new();
22558        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22559            HashMap::default();
22560        for query_range in ranges {
22561            let query_rows =
22562                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22563            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22564                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22565            ) {
22566                // Include deleted hunks that are adjacent to the query range, because
22567                // otherwise they would be missed.
22568                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22569                if hunk.status().is_deleted() {
22570                    intersects_range |= hunk.row_range.start == query_rows.end;
22571                    intersects_range |= hunk.row_range.end == query_rows.start;
22572                }
22573                if intersects_range {
22574                    if !processed_buffer_rows
22575                        .entry(hunk.buffer_id)
22576                        .or_default()
22577                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22578                    {
22579                        continue;
22580                    }
22581                    hunks.push(hunk);
22582                }
22583            }
22584        }
22585
22586        hunks
22587    }
22588
22589    fn display_diff_hunks_for_rows<'a>(
22590        &'a self,
22591        display_rows: Range<DisplayRow>,
22592        folded_buffers: &'a HashSet<BufferId>,
22593    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22594        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22595        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22596
22597        self.buffer_snapshot
22598            .diff_hunks_in_range(buffer_start..buffer_end)
22599            .filter_map(|hunk| {
22600                if folded_buffers.contains(&hunk.buffer_id) {
22601                    return None;
22602                }
22603
22604                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22605                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22606
22607                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22608                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22609
22610                let display_hunk = if hunk_display_start.column() != 0 {
22611                    DisplayDiffHunk::Folded {
22612                        display_row: hunk_display_start.row(),
22613                    }
22614                } else {
22615                    let mut end_row = hunk_display_end.row();
22616                    if hunk_display_end.column() > 0 {
22617                        end_row.0 += 1;
22618                    }
22619                    let is_created_file = hunk.is_created_file();
22620                    DisplayDiffHunk::Unfolded {
22621                        status: hunk.status(),
22622                        diff_base_byte_range: hunk.diff_base_byte_range,
22623                        display_row_range: hunk_display_start.row()..end_row,
22624                        multi_buffer_range: Anchor::range_in_buffer(
22625                            hunk.excerpt_id,
22626                            hunk.buffer_id,
22627                            hunk.buffer_range,
22628                        ),
22629                        is_created_file,
22630                    }
22631                };
22632
22633                Some(display_hunk)
22634            })
22635    }
22636
22637    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22638        self.display_snapshot.buffer_snapshot.language_at(position)
22639    }
22640
22641    pub fn is_focused(&self) -> bool {
22642        self.is_focused
22643    }
22644
22645    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22646        self.placeholder_text.as_ref()
22647    }
22648
22649    pub fn scroll_position(&self) -> gpui::Point<f32> {
22650        self.scroll_anchor.scroll_position(&self.display_snapshot)
22651    }
22652
22653    fn gutter_dimensions(
22654        &self,
22655        font_id: FontId,
22656        font_size: Pixels,
22657        max_line_number_width: Pixels,
22658        cx: &App,
22659    ) -> Option<GutterDimensions> {
22660        if !self.show_gutter {
22661            return None;
22662        }
22663
22664        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22665        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22666
22667        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22668            matches!(
22669                ProjectSettings::get_global(cx).git.git_gutter,
22670                Some(GitGutterSetting::TrackedFiles)
22671            )
22672        });
22673        let gutter_settings = EditorSettings::get_global(cx).gutter;
22674        let show_line_numbers = self
22675            .show_line_numbers
22676            .unwrap_or(gutter_settings.line_numbers);
22677        let line_gutter_width = if show_line_numbers {
22678            // Avoid flicker-like gutter resizes when the line number gains another digit by
22679            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22680            let min_width_for_number_on_gutter =
22681                ch_advance * gutter_settings.min_line_number_digits as f32;
22682            max_line_number_width.max(min_width_for_number_on_gutter)
22683        } else {
22684            0.0.into()
22685        };
22686
22687        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22688        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22689
22690        let git_blame_entries_width =
22691            self.git_blame_gutter_max_author_length
22692                .map(|max_author_length| {
22693                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22694                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22695
22696                    /// The number of characters to dedicate to gaps and margins.
22697                    const SPACING_WIDTH: usize = 4;
22698
22699                    let max_char_count = max_author_length.min(renderer.max_author_length())
22700                        + ::git::SHORT_SHA_LENGTH
22701                        + MAX_RELATIVE_TIMESTAMP.len()
22702                        + SPACING_WIDTH;
22703
22704                    ch_advance * max_char_count
22705                });
22706
22707        let is_singleton = self.buffer_snapshot.is_singleton();
22708
22709        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22710        left_padding += if !is_singleton {
22711            ch_width * 4.0
22712        } else if show_runnables || show_breakpoints {
22713            ch_width * 3.0
22714        } else if show_git_gutter && show_line_numbers {
22715            ch_width * 2.0
22716        } else if show_git_gutter || show_line_numbers {
22717            ch_width
22718        } else {
22719            px(0.)
22720        };
22721
22722        let shows_folds = is_singleton && gutter_settings.folds;
22723
22724        let right_padding = if shows_folds && show_line_numbers {
22725            ch_width * 4.0
22726        } else if shows_folds || (!is_singleton && show_line_numbers) {
22727            ch_width * 3.0
22728        } else if show_line_numbers {
22729            ch_width
22730        } else {
22731            px(0.)
22732        };
22733
22734        Some(GutterDimensions {
22735            left_padding,
22736            right_padding,
22737            width: line_gutter_width + left_padding + right_padding,
22738            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22739            git_blame_entries_width,
22740        })
22741    }
22742
22743    pub fn render_crease_toggle(
22744        &self,
22745        buffer_row: MultiBufferRow,
22746        row_contains_cursor: bool,
22747        editor: Entity<Editor>,
22748        window: &mut Window,
22749        cx: &mut App,
22750    ) -> Option<AnyElement> {
22751        let folded = self.is_line_folded(buffer_row);
22752        let mut is_foldable = false;
22753
22754        if let Some(crease) = self
22755            .crease_snapshot
22756            .query_row(buffer_row, &self.buffer_snapshot)
22757        {
22758            is_foldable = true;
22759            match crease {
22760                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22761                    if let Some(render_toggle) = render_toggle {
22762                        let toggle_callback =
22763                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22764                                if folded {
22765                                    editor.update(cx, |editor, cx| {
22766                                        editor.fold_at(buffer_row, window, cx)
22767                                    });
22768                                } else {
22769                                    editor.update(cx, |editor, cx| {
22770                                        editor.unfold_at(buffer_row, window, cx)
22771                                    });
22772                                }
22773                            });
22774                        return Some((render_toggle)(
22775                            buffer_row,
22776                            folded,
22777                            toggle_callback,
22778                            window,
22779                            cx,
22780                        ));
22781                    }
22782                }
22783            }
22784        }
22785
22786        is_foldable |= self.starts_indent(buffer_row);
22787
22788        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22789            Some(
22790                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22791                    .toggle_state(folded)
22792                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22793                        if folded {
22794                            this.unfold_at(buffer_row, window, cx);
22795                        } else {
22796                            this.fold_at(buffer_row, window, cx);
22797                        }
22798                    }))
22799                    .into_any_element(),
22800            )
22801        } else {
22802            None
22803        }
22804    }
22805
22806    pub fn render_crease_trailer(
22807        &self,
22808        buffer_row: MultiBufferRow,
22809        window: &mut Window,
22810        cx: &mut App,
22811    ) -> Option<AnyElement> {
22812        let folded = self.is_line_folded(buffer_row);
22813        if let Crease::Inline { render_trailer, .. } = self
22814            .crease_snapshot
22815            .query_row(buffer_row, &self.buffer_snapshot)?
22816        {
22817            let render_trailer = render_trailer.as_ref()?;
22818            Some(render_trailer(buffer_row, folded, window, cx))
22819        } else {
22820            None
22821        }
22822    }
22823}
22824
22825impl Deref for EditorSnapshot {
22826    type Target = DisplaySnapshot;
22827
22828    fn deref(&self) -> &Self::Target {
22829        &self.display_snapshot
22830    }
22831}
22832
22833#[derive(Clone, Debug, PartialEq, Eq)]
22834pub enum EditorEvent {
22835    InputIgnored {
22836        text: Arc<str>,
22837    },
22838    InputHandled {
22839        utf16_range_to_replace: Option<Range<isize>>,
22840        text: Arc<str>,
22841    },
22842    ExcerptsAdded {
22843        buffer: Entity<Buffer>,
22844        predecessor: ExcerptId,
22845        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22846    },
22847    ExcerptsRemoved {
22848        ids: Vec<ExcerptId>,
22849        removed_buffer_ids: Vec<BufferId>,
22850    },
22851    BufferFoldToggled {
22852        ids: Vec<ExcerptId>,
22853        folded: bool,
22854    },
22855    ExcerptsEdited {
22856        ids: Vec<ExcerptId>,
22857    },
22858    ExcerptsExpanded {
22859        ids: Vec<ExcerptId>,
22860    },
22861    BufferEdited,
22862    Edited {
22863        transaction_id: clock::Lamport,
22864    },
22865    Reparsed(BufferId),
22866    Focused,
22867    FocusedIn,
22868    Blurred,
22869    DirtyChanged,
22870    Saved,
22871    TitleChanged,
22872    DiffBaseChanged,
22873    SelectionsChanged {
22874        local: bool,
22875    },
22876    ScrollPositionChanged {
22877        local: bool,
22878        autoscroll: bool,
22879    },
22880    Closed,
22881    TransactionUndone {
22882        transaction_id: clock::Lamport,
22883    },
22884    TransactionBegun {
22885        transaction_id: clock::Lamport,
22886    },
22887    Reloaded,
22888    CursorShapeChanged,
22889    BreadcrumbsChanged,
22890    PushedToNavHistory {
22891        anchor: Anchor,
22892        is_deactivate: bool,
22893    },
22894}
22895
22896impl EventEmitter<EditorEvent> for Editor {}
22897
22898impl Focusable for Editor {
22899    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22900        self.focus_handle.clone()
22901    }
22902}
22903
22904impl Render for Editor {
22905    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22906        let settings = ThemeSettings::get_global(cx);
22907
22908        let mut text_style = match self.mode {
22909            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
22910                color: cx.theme().colors().editor_foreground,
22911                font_family: settings.ui_font.family.clone(),
22912                font_features: settings.ui_font.features.clone(),
22913                font_fallbacks: settings.ui_font.fallbacks.clone(),
22914                font_size: rems(0.875).into(),
22915                font_weight: settings.ui_font.weight,
22916                line_height: relative(settings.buffer_line_height.value()),
22917                ..Default::default()
22918            },
22919            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22920                color: cx.theme().colors().editor_foreground,
22921                font_family: settings.buffer_font.family.clone(),
22922                font_features: settings.buffer_font.features.clone(),
22923                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22924                font_size: settings.buffer_font_size(cx).into(),
22925                font_weight: settings.buffer_font.weight,
22926                line_height: relative(settings.buffer_line_height.value()),
22927                ..Default::default()
22928            },
22929        };
22930        if let Some(text_style_refinement) = &self.text_style_refinement {
22931            text_style.refine(text_style_refinement)
22932        }
22933
22934        let background = match self.mode {
22935            EditorMode::SingleLine => cx.theme().system().transparent,
22936            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22937            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22938            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22939        };
22940
22941        EditorElement::new(
22942            &cx.entity(),
22943            EditorStyle {
22944                background,
22945                border: cx.theme().colors().border,
22946                local_player: cx.theme().players().local(),
22947                text: text_style,
22948                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22949                syntax: cx.theme().syntax().clone(),
22950                status: cx.theme().status().clone(),
22951                inlay_hints_style: make_inlay_hints_style(cx),
22952                edit_prediction_styles: make_suggestion_styles(cx),
22953                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22954                show_underlines: self.diagnostics_enabled(),
22955            },
22956        )
22957    }
22958}
22959
22960impl EntityInputHandler for Editor {
22961    fn text_for_range(
22962        &mut self,
22963        range_utf16: Range<usize>,
22964        adjusted_range: &mut Option<Range<usize>>,
22965        _: &mut Window,
22966        cx: &mut Context<Self>,
22967    ) -> Option<String> {
22968        let snapshot = self.buffer.read(cx).read(cx);
22969        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22970        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22971        if (start.0..end.0) != range_utf16 {
22972            adjusted_range.replace(start.0..end.0);
22973        }
22974        Some(snapshot.text_for_range(start..end).collect())
22975    }
22976
22977    fn selected_text_range(
22978        &mut self,
22979        ignore_disabled_input: bool,
22980        _: &mut Window,
22981        cx: &mut Context<Self>,
22982    ) -> Option<UTF16Selection> {
22983        // Prevent the IME menu from appearing when holding down an alphabetic key
22984        // while input is disabled.
22985        if !ignore_disabled_input && !self.input_enabled {
22986            return None;
22987        }
22988
22989        let selection = self.selections.newest::<OffsetUtf16>(cx);
22990        let range = selection.range();
22991
22992        Some(UTF16Selection {
22993            range: range.start.0..range.end.0,
22994            reversed: selection.reversed,
22995        })
22996    }
22997
22998    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22999        let snapshot = self.buffer.read(cx).read(cx);
23000        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23001        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23002    }
23003
23004    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23005        self.clear_highlights::<InputComposition>(cx);
23006        self.ime_transaction.take();
23007    }
23008
23009    fn replace_text_in_range(
23010        &mut self,
23011        range_utf16: Option<Range<usize>>,
23012        text: &str,
23013        window: &mut Window,
23014        cx: &mut Context<Self>,
23015    ) {
23016        if !self.input_enabled {
23017            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23018            return;
23019        }
23020
23021        self.transact(window, cx, |this, window, cx| {
23022            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23023                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23024                Some(this.selection_replacement_ranges(range_utf16, cx))
23025            } else {
23026                this.marked_text_ranges(cx)
23027            };
23028
23029            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23030                let newest_selection_id = this.selections.newest_anchor().id;
23031                this.selections
23032                    .all::<OffsetUtf16>(cx)
23033                    .iter()
23034                    .zip(ranges_to_replace.iter())
23035                    .find_map(|(selection, range)| {
23036                        if selection.id == newest_selection_id {
23037                            Some(
23038                                (range.start.0 as isize - selection.head().0 as isize)
23039                                    ..(range.end.0 as isize - selection.head().0 as isize),
23040                            )
23041                        } else {
23042                            None
23043                        }
23044                    })
23045            });
23046
23047            cx.emit(EditorEvent::InputHandled {
23048                utf16_range_to_replace: range_to_replace,
23049                text: text.into(),
23050            });
23051
23052            if let Some(new_selected_ranges) = new_selected_ranges {
23053                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23054                    selections.select_ranges(new_selected_ranges)
23055                });
23056                this.backspace(&Default::default(), window, cx);
23057            }
23058
23059            this.handle_input(text, window, cx);
23060        });
23061
23062        if let Some(transaction) = self.ime_transaction {
23063            self.buffer.update(cx, |buffer, cx| {
23064                buffer.group_until_transaction(transaction, cx);
23065            });
23066        }
23067
23068        self.unmark_text(window, cx);
23069    }
23070
23071    fn replace_and_mark_text_in_range(
23072        &mut self,
23073        range_utf16: Option<Range<usize>>,
23074        text: &str,
23075        new_selected_range_utf16: Option<Range<usize>>,
23076        window: &mut Window,
23077        cx: &mut Context<Self>,
23078    ) {
23079        if !self.input_enabled {
23080            return;
23081        }
23082
23083        let transaction = self.transact(window, cx, |this, window, cx| {
23084            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23085                let snapshot = this.buffer.read(cx).read(cx);
23086                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23087                    for marked_range in &mut marked_ranges {
23088                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23089                        marked_range.start.0 += relative_range_utf16.start;
23090                        marked_range.start =
23091                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23092                        marked_range.end =
23093                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23094                    }
23095                }
23096                Some(marked_ranges)
23097            } else if let Some(range_utf16) = range_utf16 {
23098                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23099                Some(this.selection_replacement_ranges(range_utf16, cx))
23100            } else {
23101                None
23102            };
23103
23104            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23105                let newest_selection_id = this.selections.newest_anchor().id;
23106                this.selections
23107                    .all::<OffsetUtf16>(cx)
23108                    .iter()
23109                    .zip(ranges_to_replace.iter())
23110                    .find_map(|(selection, range)| {
23111                        if selection.id == newest_selection_id {
23112                            Some(
23113                                (range.start.0 as isize - selection.head().0 as isize)
23114                                    ..(range.end.0 as isize - selection.head().0 as isize),
23115                            )
23116                        } else {
23117                            None
23118                        }
23119                    })
23120            });
23121
23122            cx.emit(EditorEvent::InputHandled {
23123                utf16_range_to_replace: range_to_replace,
23124                text: text.into(),
23125            });
23126
23127            if let Some(ranges) = ranges_to_replace {
23128                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23129                    s.select_ranges(ranges)
23130                });
23131            }
23132
23133            let marked_ranges = {
23134                let snapshot = this.buffer.read(cx).read(cx);
23135                this.selections
23136                    .disjoint_anchors()
23137                    .iter()
23138                    .map(|selection| {
23139                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23140                    })
23141                    .collect::<Vec<_>>()
23142            };
23143
23144            if text.is_empty() {
23145                this.unmark_text(window, cx);
23146            } else {
23147                this.highlight_text::<InputComposition>(
23148                    marked_ranges.clone(),
23149                    HighlightStyle {
23150                        underline: Some(UnderlineStyle {
23151                            thickness: px(1.),
23152                            color: None,
23153                            wavy: false,
23154                        }),
23155                        ..Default::default()
23156                    },
23157                    cx,
23158                );
23159            }
23160
23161            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23162            let use_autoclose = this.use_autoclose;
23163            let use_auto_surround = this.use_auto_surround;
23164            this.set_use_autoclose(false);
23165            this.set_use_auto_surround(false);
23166            this.handle_input(text, window, cx);
23167            this.set_use_autoclose(use_autoclose);
23168            this.set_use_auto_surround(use_auto_surround);
23169
23170            if let Some(new_selected_range) = new_selected_range_utf16 {
23171                let snapshot = this.buffer.read(cx).read(cx);
23172                let new_selected_ranges = marked_ranges
23173                    .into_iter()
23174                    .map(|marked_range| {
23175                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23176                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23177                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23178                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23179                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23180                    })
23181                    .collect::<Vec<_>>();
23182
23183                drop(snapshot);
23184                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23185                    selections.select_ranges(new_selected_ranges)
23186                });
23187            }
23188        });
23189
23190        self.ime_transaction = self.ime_transaction.or(transaction);
23191        if let Some(transaction) = self.ime_transaction {
23192            self.buffer.update(cx, |buffer, cx| {
23193                buffer.group_until_transaction(transaction, cx);
23194            });
23195        }
23196
23197        if self.text_highlights::<InputComposition>(cx).is_none() {
23198            self.ime_transaction.take();
23199        }
23200    }
23201
23202    fn bounds_for_range(
23203        &mut self,
23204        range_utf16: Range<usize>,
23205        element_bounds: gpui::Bounds<Pixels>,
23206        window: &mut Window,
23207        cx: &mut Context<Self>,
23208    ) -> Option<gpui::Bounds<Pixels>> {
23209        let text_layout_details = self.text_layout_details(window);
23210        let CharacterDimensions {
23211            em_width,
23212            em_advance,
23213            line_height,
23214        } = self.character_dimensions(window);
23215
23216        let snapshot = self.snapshot(window, cx);
23217        let scroll_position = snapshot.scroll_position();
23218        let scroll_left = scroll_position.x * em_advance;
23219
23220        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23221        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23222            + self.gutter_dimensions.full_width();
23223        let y = line_height * (start.row().as_f32() - scroll_position.y);
23224
23225        Some(Bounds {
23226            origin: element_bounds.origin + point(x, y),
23227            size: size(em_width, line_height),
23228        })
23229    }
23230
23231    fn character_index_for_point(
23232        &mut self,
23233        point: gpui::Point<Pixels>,
23234        _window: &mut Window,
23235        _cx: &mut Context<Self>,
23236    ) -> Option<usize> {
23237        let position_map = self.last_position_map.as_ref()?;
23238        if !position_map.text_hitbox.contains(&point) {
23239            return None;
23240        }
23241        let display_point = position_map.point_for_position(point).previous_valid;
23242        let anchor = position_map
23243            .snapshot
23244            .display_point_to_anchor(display_point, Bias::Left);
23245        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23246        Some(utf16_offset.0)
23247    }
23248}
23249
23250trait SelectionExt {
23251    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23252    fn spanned_rows(
23253        &self,
23254        include_end_if_at_line_start: bool,
23255        map: &DisplaySnapshot,
23256    ) -> Range<MultiBufferRow>;
23257}
23258
23259impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23260    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23261        let start = self
23262            .start
23263            .to_point(&map.buffer_snapshot)
23264            .to_display_point(map);
23265        let end = self
23266            .end
23267            .to_point(&map.buffer_snapshot)
23268            .to_display_point(map);
23269        if self.reversed {
23270            end..start
23271        } else {
23272            start..end
23273        }
23274    }
23275
23276    fn spanned_rows(
23277        &self,
23278        include_end_if_at_line_start: bool,
23279        map: &DisplaySnapshot,
23280    ) -> Range<MultiBufferRow> {
23281        let start = self.start.to_point(&map.buffer_snapshot);
23282        let mut end = self.end.to_point(&map.buffer_snapshot);
23283        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23284            end.row -= 1;
23285        }
23286
23287        let buffer_start = map.prev_line_boundary(start).0;
23288        let buffer_end = map.next_line_boundary(end).0;
23289        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23290    }
23291}
23292
23293impl<T: InvalidationRegion> InvalidationStack<T> {
23294    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23295    where
23296        S: Clone + ToOffset,
23297    {
23298        while let Some(region) = self.last() {
23299            let all_selections_inside_invalidation_ranges =
23300                if selections.len() == region.ranges().len() {
23301                    selections
23302                        .iter()
23303                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23304                        .all(|(selection, invalidation_range)| {
23305                            let head = selection.head().to_offset(buffer);
23306                            invalidation_range.start <= head && invalidation_range.end >= head
23307                        })
23308                } else {
23309                    false
23310                };
23311
23312            if all_selections_inside_invalidation_ranges {
23313                break;
23314            } else {
23315                self.pop();
23316            }
23317        }
23318    }
23319}
23320
23321impl<T> Default for InvalidationStack<T> {
23322    fn default() -> Self {
23323        Self(Default::default())
23324    }
23325}
23326
23327impl<T> Deref for InvalidationStack<T> {
23328    type Target = Vec<T>;
23329
23330    fn deref(&self) -> &Self::Target {
23331        &self.0
23332    }
23333}
23334
23335impl<T> DerefMut for InvalidationStack<T> {
23336    fn deref_mut(&mut self) -> &mut Self::Target {
23337        &mut self.0
23338    }
23339}
23340
23341impl InvalidationRegion for SnippetState {
23342    fn ranges(&self) -> &[Range<Anchor>] {
23343        &self.ranges[self.active_index]
23344    }
23345}
23346
23347fn edit_prediction_edit_text(
23348    current_snapshot: &BufferSnapshot,
23349    edits: &[(Range<Anchor>, String)],
23350    edit_preview: &EditPreview,
23351    include_deletions: bool,
23352    cx: &App,
23353) -> HighlightedText {
23354    let edits = edits
23355        .iter()
23356        .map(|(anchor, text)| {
23357            (
23358                anchor.start.text_anchor..anchor.end.text_anchor,
23359                text.clone(),
23360            )
23361        })
23362        .collect::<Vec<_>>();
23363
23364    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23365}
23366
23367fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23368    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23369    // Just show the raw edit text with basic styling
23370    let mut text = String::new();
23371    let mut highlights = Vec::new();
23372
23373    let insertion_highlight_style = HighlightStyle {
23374        color: Some(cx.theme().colors().text),
23375        ..Default::default()
23376    };
23377
23378    for (_, edit_text) in edits {
23379        let start_offset = text.len();
23380        text.push_str(edit_text);
23381        let end_offset = text.len();
23382
23383        if start_offset < end_offset {
23384            highlights.push((start_offset..end_offset, insertion_highlight_style));
23385        }
23386    }
23387
23388    HighlightedText {
23389        text: text.into(),
23390        highlights,
23391    }
23392}
23393
23394pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23395    match severity {
23396        lsp::DiagnosticSeverity::ERROR => colors.error,
23397        lsp::DiagnosticSeverity::WARNING => colors.warning,
23398        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23399        lsp::DiagnosticSeverity::HINT => colors.info,
23400        _ => colors.ignored,
23401    }
23402}
23403
23404pub fn styled_runs_for_code_label<'a>(
23405    label: &'a CodeLabel,
23406    syntax_theme: &'a theme::SyntaxTheme,
23407) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23408    let fade_out = HighlightStyle {
23409        fade_out: Some(0.35),
23410        ..Default::default()
23411    };
23412
23413    let mut prev_end = label.filter_range.end;
23414    label
23415        .runs
23416        .iter()
23417        .enumerate()
23418        .flat_map(move |(ix, (range, highlight_id))| {
23419            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23420                style
23421            } else {
23422                return Default::default();
23423            };
23424            let mut muted_style = style;
23425            muted_style.highlight(fade_out);
23426
23427            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23428            if range.start >= label.filter_range.end {
23429                if range.start > prev_end {
23430                    runs.push((prev_end..range.start, fade_out));
23431                }
23432                runs.push((range.clone(), muted_style));
23433            } else if range.end <= label.filter_range.end {
23434                runs.push((range.clone(), style));
23435            } else {
23436                runs.push((range.start..label.filter_range.end, style));
23437                runs.push((label.filter_range.end..range.end, muted_style));
23438            }
23439            prev_end = cmp::max(prev_end, range.end);
23440
23441            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23442                runs.push((prev_end..label.text.len(), fade_out));
23443            }
23444
23445            runs
23446        })
23447}
23448
23449pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23450    let mut prev_index = 0;
23451    let mut prev_codepoint: Option<char> = None;
23452    text.char_indices()
23453        .chain([(text.len(), '\0')])
23454        .filter_map(move |(index, codepoint)| {
23455            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23456            let is_boundary = index == text.len()
23457                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23458                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23459            if is_boundary {
23460                let chunk = &text[prev_index..index];
23461                prev_index = index;
23462                Some(chunk)
23463            } else {
23464                None
23465            }
23466        })
23467}
23468
23469pub trait RangeToAnchorExt: Sized {
23470    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23471
23472    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23473        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23474        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23475    }
23476}
23477
23478impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23479    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23480        let start_offset = self.start.to_offset(snapshot);
23481        let end_offset = self.end.to_offset(snapshot);
23482        if start_offset == end_offset {
23483            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23484        } else {
23485            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23486        }
23487    }
23488}
23489
23490pub trait RowExt {
23491    fn as_f32(&self) -> f32;
23492
23493    fn next_row(&self) -> Self;
23494
23495    fn previous_row(&self) -> Self;
23496
23497    fn minus(&self, other: Self) -> u32;
23498}
23499
23500impl RowExt for DisplayRow {
23501    fn as_f32(&self) -> f32 {
23502        self.0 as f32
23503    }
23504
23505    fn next_row(&self) -> Self {
23506        Self(self.0 + 1)
23507    }
23508
23509    fn previous_row(&self) -> Self {
23510        Self(self.0.saturating_sub(1))
23511    }
23512
23513    fn minus(&self, other: Self) -> u32 {
23514        self.0 - other.0
23515    }
23516}
23517
23518impl RowExt for MultiBufferRow {
23519    fn as_f32(&self) -> f32 {
23520        self.0 as f32
23521    }
23522
23523    fn next_row(&self) -> Self {
23524        Self(self.0 + 1)
23525    }
23526
23527    fn previous_row(&self) -> Self {
23528        Self(self.0.saturating_sub(1))
23529    }
23530
23531    fn minus(&self, other: Self) -> u32 {
23532        self.0 - other.0
23533    }
23534}
23535
23536trait RowRangeExt {
23537    type Row;
23538
23539    fn len(&self) -> usize;
23540
23541    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23542}
23543
23544impl RowRangeExt for Range<MultiBufferRow> {
23545    type Row = MultiBufferRow;
23546
23547    fn len(&self) -> usize {
23548        (self.end.0 - self.start.0) as usize
23549    }
23550
23551    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23552        (self.start.0..self.end.0).map(MultiBufferRow)
23553    }
23554}
23555
23556impl RowRangeExt for Range<DisplayRow> {
23557    type Row = DisplayRow;
23558
23559    fn len(&self) -> usize {
23560        (self.end.0 - self.start.0) as usize
23561    }
23562
23563    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23564        (self.start.0..self.end.0).map(DisplayRow)
23565    }
23566}
23567
23568/// If select range has more than one line, we
23569/// just point the cursor to range.start.
23570fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23571    if range.start.row == range.end.row {
23572        range
23573    } else {
23574        range.start..range.start
23575    }
23576}
23577pub struct KillRing(ClipboardItem);
23578impl Global for KillRing {}
23579
23580const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23581
23582enum BreakpointPromptEditAction {
23583    Log,
23584    Condition,
23585    HitCondition,
23586}
23587
23588struct BreakpointPromptEditor {
23589    pub(crate) prompt: Entity<Editor>,
23590    editor: WeakEntity<Editor>,
23591    breakpoint_anchor: Anchor,
23592    breakpoint: Breakpoint,
23593    edit_action: BreakpointPromptEditAction,
23594    block_ids: HashSet<CustomBlockId>,
23595    editor_margins: Arc<Mutex<EditorMargins>>,
23596    _subscriptions: Vec<Subscription>,
23597}
23598
23599impl BreakpointPromptEditor {
23600    const MAX_LINES: u8 = 4;
23601
23602    fn new(
23603        editor: WeakEntity<Editor>,
23604        breakpoint_anchor: Anchor,
23605        breakpoint: Breakpoint,
23606        edit_action: BreakpointPromptEditAction,
23607        window: &mut Window,
23608        cx: &mut Context<Self>,
23609    ) -> Self {
23610        let base_text = match edit_action {
23611            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23612            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23613            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23614        }
23615        .map(|msg| msg.to_string())
23616        .unwrap_or_default();
23617
23618        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23619        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23620
23621        let prompt = cx.new(|cx| {
23622            let mut prompt = Editor::new(
23623                EditorMode::AutoHeight {
23624                    min_lines: 1,
23625                    max_lines: Some(Self::MAX_LINES as usize),
23626                },
23627                buffer,
23628                None,
23629                window,
23630                cx,
23631            );
23632            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23633            prompt.set_show_cursor_when_unfocused(false, cx);
23634            prompt.set_placeholder_text(
23635                match edit_action {
23636                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23637                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23638                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23639                },
23640                cx,
23641            );
23642
23643            prompt
23644        });
23645
23646        Self {
23647            prompt,
23648            editor,
23649            breakpoint_anchor,
23650            breakpoint,
23651            edit_action,
23652            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23653            block_ids: Default::default(),
23654            _subscriptions: vec![],
23655        }
23656    }
23657
23658    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23659        self.block_ids.extend(block_ids)
23660    }
23661
23662    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23663        if let Some(editor) = self.editor.upgrade() {
23664            let message = self
23665                .prompt
23666                .read(cx)
23667                .buffer
23668                .read(cx)
23669                .as_singleton()
23670                .expect("A multi buffer in breakpoint prompt isn't possible")
23671                .read(cx)
23672                .as_rope()
23673                .to_string();
23674
23675            editor.update(cx, |editor, cx| {
23676                editor.edit_breakpoint_at_anchor(
23677                    self.breakpoint_anchor,
23678                    self.breakpoint.clone(),
23679                    match self.edit_action {
23680                        BreakpointPromptEditAction::Log => {
23681                            BreakpointEditAction::EditLogMessage(message.into())
23682                        }
23683                        BreakpointPromptEditAction::Condition => {
23684                            BreakpointEditAction::EditCondition(message.into())
23685                        }
23686                        BreakpointPromptEditAction::HitCondition => {
23687                            BreakpointEditAction::EditHitCondition(message.into())
23688                        }
23689                    },
23690                    cx,
23691                );
23692
23693                editor.remove_blocks(self.block_ids.clone(), None, cx);
23694                cx.focus_self(window);
23695            });
23696        }
23697    }
23698
23699    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23700        self.editor
23701            .update(cx, |editor, cx| {
23702                editor.remove_blocks(self.block_ids.clone(), None, cx);
23703                window.focus(&editor.focus_handle);
23704            })
23705            .log_err();
23706    }
23707
23708    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23709        let settings = ThemeSettings::get_global(cx);
23710        let text_style = TextStyle {
23711            color: if self.prompt.read(cx).read_only(cx) {
23712                cx.theme().colors().text_disabled
23713            } else {
23714                cx.theme().colors().text
23715            },
23716            font_family: settings.buffer_font.family.clone(),
23717            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23718            font_size: settings.buffer_font_size(cx).into(),
23719            font_weight: settings.buffer_font.weight,
23720            line_height: relative(settings.buffer_line_height.value()),
23721            ..Default::default()
23722        };
23723        EditorElement::new(
23724            &self.prompt,
23725            EditorStyle {
23726                background: cx.theme().colors().editor_background,
23727                local_player: cx.theme().players().local(),
23728                text: text_style,
23729                ..Default::default()
23730            },
23731        )
23732    }
23733}
23734
23735impl Render for BreakpointPromptEditor {
23736    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23737        let editor_margins = *self.editor_margins.lock();
23738        let gutter_dimensions = editor_margins.gutter;
23739        h_flex()
23740            .key_context("Editor")
23741            .bg(cx.theme().colors().editor_background)
23742            .border_y_1()
23743            .border_color(cx.theme().status().info_border)
23744            .size_full()
23745            .py(window.line_height() / 2.5)
23746            .on_action(cx.listener(Self::confirm))
23747            .on_action(cx.listener(Self::cancel))
23748            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23749            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23750    }
23751}
23752
23753impl Focusable for BreakpointPromptEditor {
23754    fn focus_handle(&self, cx: &App) -> FocusHandle {
23755        self.prompt.focus_handle(cx)
23756    }
23757}
23758
23759fn all_edits_insertions_or_deletions(
23760    edits: &Vec<(Range<Anchor>, String)>,
23761    snapshot: &MultiBufferSnapshot,
23762) -> bool {
23763    let mut all_insertions = true;
23764    let mut all_deletions = true;
23765
23766    for (range, new_text) in edits.iter() {
23767        let range_is_empty = range.to_offset(snapshot).is_empty();
23768        let text_is_empty = new_text.is_empty();
23769
23770        if range_is_empty != text_is_empty {
23771            if range_is_empty {
23772                all_deletions = false;
23773            } else {
23774                all_insertions = false;
23775            }
23776        } else {
23777            return false;
23778        }
23779
23780        if !all_insertions && !all_deletions {
23781            return false;
23782        }
23783    }
23784    all_insertions || all_deletions
23785}
23786
23787struct MissingEditPredictionKeybindingTooltip;
23788
23789impl Render for MissingEditPredictionKeybindingTooltip {
23790    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23791        ui::tooltip_container(window, cx, |container, _, cx| {
23792            container
23793                .flex_shrink_0()
23794                .max_w_80()
23795                .min_h(rems_from_px(124.))
23796                .justify_between()
23797                .child(
23798                    v_flex()
23799                        .flex_1()
23800                        .text_ui_sm(cx)
23801                        .child(Label::new("Conflict with Accept Keybinding"))
23802                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23803                )
23804                .child(
23805                    h_flex()
23806                        .pb_1()
23807                        .gap_1()
23808                        .items_end()
23809                        .w_full()
23810                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23811                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23812                        }))
23813                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23814                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23815                        })),
23816                )
23817        })
23818    }
23819}
23820
23821#[derive(Debug, Clone, Copy, PartialEq)]
23822pub struct LineHighlight {
23823    pub background: Background,
23824    pub border: Option<gpui::Hsla>,
23825    pub include_gutter: bool,
23826    pub type_id: Option<TypeId>,
23827}
23828
23829struct LineManipulationResult {
23830    pub new_text: String,
23831    pub line_count_before: usize,
23832    pub line_count_after: usize,
23833}
23834
23835fn render_diff_hunk_controls(
23836    row: u32,
23837    status: &DiffHunkStatus,
23838    hunk_range: Range<Anchor>,
23839    is_created_file: bool,
23840    line_height: Pixels,
23841    editor: &Entity<Editor>,
23842    _window: &mut Window,
23843    cx: &mut App,
23844) -> AnyElement {
23845    h_flex()
23846        .h(line_height)
23847        .mr_1()
23848        .gap_1()
23849        .px_0p5()
23850        .pb_1()
23851        .border_x_1()
23852        .border_b_1()
23853        .border_color(cx.theme().colors().border_variant)
23854        .rounded_b_lg()
23855        .bg(cx.theme().colors().editor_background)
23856        .gap_1()
23857        .block_mouse_except_scroll()
23858        .shadow_md()
23859        .child(if status.has_secondary_hunk() {
23860            Button::new(("stage", row as u64), "Stage")
23861                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23862                .tooltip({
23863                    let focus_handle = editor.focus_handle(cx);
23864                    move |window, cx| {
23865                        Tooltip::for_action_in(
23866                            "Stage Hunk",
23867                            &::git::ToggleStaged,
23868                            &focus_handle,
23869                            window,
23870                            cx,
23871                        )
23872                    }
23873                })
23874                .on_click({
23875                    let editor = editor.clone();
23876                    move |_event, _window, cx| {
23877                        editor.update(cx, |editor, cx| {
23878                            editor.stage_or_unstage_diff_hunks(
23879                                true,
23880                                vec![hunk_range.start..hunk_range.start],
23881                                cx,
23882                            );
23883                        });
23884                    }
23885                })
23886        } else {
23887            Button::new(("unstage", row as u64), "Unstage")
23888                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23889                .tooltip({
23890                    let focus_handle = editor.focus_handle(cx);
23891                    move |window, cx| {
23892                        Tooltip::for_action_in(
23893                            "Unstage Hunk",
23894                            &::git::ToggleStaged,
23895                            &focus_handle,
23896                            window,
23897                            cx,
23898                        )
23899                    }
23900                })
23901                .on_click({
23902                    let editor = editor.clone();
23903                    move |_event, _window, cx| {
23904                        editor.update(cx, |editor, cx| {
23905                            editor.stage_or_unstage_diff_hunks(
23906                                false,
23907                                vec![hunk_range.start..hunk_range.start],
23908                                cx,
23909                            );
23910                        });
23911                    }
23912                })
23913        })
23914        .child(
23915            Button::new(("restore", row as u64), "Restore")
23916                .tooltip({
23917                    let focus_handle = editor.focus_handle(cx);
23918                    move |window, cx| {
23919                        Tooltip::for_action_in(
23920                            "Restore Hunk",
23921                            &::git::Restore,
23922                            &focus_handle,
23923                            window,
23924                            cx,
23925                        )
23926                    }
23927                })
23928                .on_click({
23929                    let editor = editor.clone();
23930                    move |_event, window, cx| {
23931                        editor.update(cx, |editor, cx| {
23932                            let snapshot = editor.snapshot(window, cx);
23933                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23934                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23935                        });
23936                    }
23937                })
23938                .disabled(is_created_file),
23939        )
23940        .when(
23941            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23942            |el| {
23943                el.child(
23944                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23945                        .shape(IconButtonShape::Square)
23946                        .icon_size(IconSize::Small)
23947                        // .disabled(!has_multiple_hunks)
23948                        .tooltip({
23949                            let focus_handle = editor.focus_handle(cx);
23950                            move |window, cx| {
23951                                Tooltip::for_action_in(
23952                                    "Next Hunk",
23953                                    &GoToHunk,
23954                                    &focus_handle,
23955                                    window,
23956                                    cx,
23957                                )
23958                            }
23959                        })
23960                        .on_click({
23961                            let editor = editor.clone();
23962                            move |_event, window, cx| {
23963                                editor.update(cx, |editor, cx| {
23964                                    let snapshot = editor.snapshot(window, cx);
23965                                    let position =
23966                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23967                                    editor.go_to_hunk_before_or_after_position(
23968                                        &snapshot,
23969                                        position,
23970                                        Direction::Next,
23971                                        window,
23972                                        cx,
23973                                    );
23974                                    editor.expand_selected_diff_hunks(cx);
23975                                });
23976                            }
23977                        }),
23978                )
23979                .child(
23980                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23981                        .shape(IconButtonShape::Square)
23982                        .icon_size(IconSize::Small)
23983                        // .disabled(!has_multiple_hunks)
23984                        .tooltip({
23985                            let focus_handle = editor.focus_handle(cx);
23986                            move |window, cx| {
23987                                Tooltip::for_action_in(
23988                                    "Previous Hunk",
23989                                    &GoToPreviousHunk,
23990                                    &focus_handle,
23991                                    window,
23992                                    cx,
23993                                )
23994                            }
23995                        })
23996                        .on_click({
23997                            let editor = editor.clone();
23998                            move |_event, window, cx| {
23999                                editor.update(cx, |editor, cx| {
24000                                    let snapshot = editor.snapshot(window, cx);
24001                                    let point =
24002                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24003                                    editor.go_to_hunk_before_or_after_position(
24004                                        &snapshot,
24005                                        point,
24006                                        Direction::Prev,
24007                                        window,
24008                                        cx,
24009                                    );
24010                                    editor.expand_selected_diff_hunks(cx);
24011                                });
24012                            }
24013                        }),
24014                )
24015            },
24016        )
24017        .into_any_element()
24018}