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, CompletionIntent, CompletionResponse,
  151    CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
  152    PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::OnceCell,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::Not,
  186    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use sum_tree::TreeMap;
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  223const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  224const MAX_LINE_LEN: usize = 1024;
  225const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  226const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  227pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  228#[doc(hidden)]
  229pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  230const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  231
  232pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253enum ReportEditorEvent {
  254    Saved { auto_saved: bool },
  255    EditorOpened,
  256    ZetaTosClicked,
  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::ZetaTosClicked => "Edit Prediction Provider ToS Clicked",
  266            Self::Closed => "Editor Closed",
  267        }
  268    }
  269}
  270
  271struct InlineValueCache {
  272    enabled: bool,
  273    inlays: Vec<InlayId>,
  274    refresh_task: Task<Option<()>>,
  275}
  276
  277impl InlineValueCache {
  278    fn new(enabled: bool) -> Self {
  279        Self {
  280            enabled,
  281            inlays: Vec::new(),
  282            refresh_task: Task::ready(None),
  283        }
  284    }
  285}
  286
  287#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  288pub enum InlayId {
  289    EditPrediction(usize),
  290    DebuggerValue(usize),
  291    // LSP
  292    Hint(usize),
  293    Color(usize),
  294}
  295
  296impl InlayId {
  297    fn id(&self) -> usize {
  298        match self {
  299            Self::EditPrediction(id) => *id,
  300            Self::DebuggerValue(id) => *id,
  301            Self::Hint(id) => *id,
  302            Self::Color(id) => *id,
  303        }
  304    }
  305}
  306
  307pub enum ActiveDebugLine {}
  308pub enum DebugStackFrameLine {}
  309enum DocumentHighlightRead {}
  310enum DocumentHighlightWrite {}
  311enum InputComposition {}
  312pub enum PendingInput {}
  313enum SelectedTextHighlight {}
  314
  315pub enum ConflictsOuter {}
  316pub enum ConflictsOurs {}
  317pub enum ConflictsTheirs {}
  318pub enum ConflictsOursMarker {}
  319pub enum ConflictsTheirsMarker {}
  320
  321#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  322pub enum Navigated {
  323    Yes,
  324    No,
  325}
  326
  327impl Navigated {
  328    pub fn from_bool(yes: bool) -> Navigated {
  329        if yes { Navigated::Yes } else { Navigated::No }
  330    }
  331}
  332
  333#[derive(Debug, Clone, PartialEq, Eq)]
  334enum DisplayDiffHunk {
  335    Folded {
  336        display_row: DisplayRow,
  337    },
  338    Unfolded {
  339        is_created_file: bool,
  340        diff_base_byte_range: Range<usize>,
  341        display_row_range: Range<DisplayRow>,
  342        multi_buffer_range: Range<Anchor>,
  343        status: DiffHunkStatus,
  344    },
  345}
  346
  347pub enum HideMouseCursorOrigin {
  348    TypingAction,
  349    MovementAction,
  350}
  351
  352pub fn init_settings(cx: &mut App) {
  353    EditorSettings::register(cx);
  354}
  355
  356pub fn init(cx: &mut App) {
  357    init_settings(cx);
  358
  359    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  360
  361    workspace::register_project_item::<Editor>(cx);
  362    workspace::FollowableViewRegistry::register::<Editor>(cx);
  363    workspace::register_serializable_item::<Editor>(cx);
  364
  365    cx.observe_new(
  366        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  367            workspace.register_action(Editor::new_file);
  368            workspace.register_action(Editor::new_file_vertical);
  369            workspace.register_action(Editor::new_file_horizontal);
  370            workspace.register_action(Editor::cancel_language_server_work);
  371            workspace.register_action(Editor::toggle_focus);
  372        },
  373    )
  374    .detach();
  375
  376    cx.on_action(move |_: &workspace::NewFile, cx| {
  377        let app_state = workspace::AppState::global(cx);
  378        if let Some(app_state) = app_state.upgrade() {
  379            workspace::open_new(
  380                Default::default(),
  381                app_state,
  382                cx,
  383                |workspace, window, cx| {
  384                    Editor::new_file(workspace, &Default::default(), window, cx)
  385                },
  386            )
  387            .detach();
  388        }
  389    });
  390    cx.on_action(move |_: &workspace::NewWindow, cx| {
  391        let app_state = workspace::AppState::global(cx);
  392        if let Some(app_state) = app_state.upgrade() {
  393            workspace::open_new(
  394                Default::default(),
  395                app_state,
  396                cx,
  397                |workspace, window, cx| {
  398                    cx.activate(true);
  399                    Editor::new_file(workspace, &Default::default(), window, cx)
  400                },
  401            )
  402            .detach();
  403        }
  404    });
  405}
  406
  407pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  408    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  409}
  410
  411pub trait DiagnosticRenderer {
  412    fn render_group(
  413        &self,
  414        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  415        buffer_id: BufferId,
  416        snapshot: EditorSnapshot,
  417        editor: WeakEntity<Editor>,
  418        cx: &mut App,
  419    ) -> Vec<BlockProperties<Anchor>>;
  420
  421    fn render_hover(
  422        &self,
  423        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  424        range: Range<Point>,
  425        buffer_id: BufferId,
  426        cx: &mut App,
  427    ) -> Option<Entity<markdown::Markdown>>;
  428
  429    fn open_link(
  430        &self,
  431        editor: &mut Editor,
  432        link: SharedString,
  433        window: &mut Window,
  434        cx: &mut Context<Editor>,
  435    );
  436}
  437
  438pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  439
  440impl GlobalDiagnosticRenderer {
  441    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  442        cx.try_global::<Self>().map(|g| g.0.clone())
  443    }
  444}
  445
  446impl gpui::Global for GlobalDiagnosticRenderer {}
  447pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  448    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  449}
  450
  451pub struct SearchWithinRange;
  452
  453trait InvalidationRegion {
  454    fn ranges(&self) -> &[Range<Anchor>];
  455}
  456
  457#[derive(Clone, Debug, PartialEq)]
  458pub enum SelectPhase {
  459    Begin {
  460        position: DisplayPoint,
  461        add: bool,
  462        click_count: usize,
  463    },
  464    BeginColumnar {
  465        position: DisplayPoint,
  466        reset: bool,
  467        mode: ColumnarMode,
  468        goal_column: u32,
  469    },
  470    Extend {
  471        position: DisplayPoint,
  472        click_count: usize,
  473    },
  474    Update {
  475        position: DisplayPoint,
  476        goal_column: u32,
  477        scroll_delta: gpui::Point<f32>,
  478    },
  479    End,
  480}
  481
  482#[derive(Clone, Debug, PartialEq)]
  483pub enum ColumnarMode {
  484    FromMouse,
  485    FromSelection,
  486}
  487
  488#[derive(Clone, Debug)]
  489pub enum SelectMode {
  490    Character,
  491    Word(Range<Anchor>),
  492    Line(Range<Anchor>),
  493    All,
  494}
  495
  496#[derive(Clone, PartialEq, Eq, Debug)]
  497pub enum EditorMode {
  498    SingleLine,
  499    AutoHeight {
  500        min_lines: usize,
  501        max_lines: Option<usize>,
  502    },
  503    Full {
  504        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  505        scale_ui_elements_with_buffer_font_size: bool,
  506        /// When set to `true`, the editor will render a background for the active line.
  507        show_active_line_background: bool,
  508        /// When set to `true`, the editor's height will be determined by its content.
  509        sized_by_content: bool,
  510    },
  511    Minimap {
  512        parent: WeakEntity<Editor>,
  513    },
  514}
  515
  516impl EditorMode {
  517    pub fn full() -> Self {
  518        Self::Full {
  519            scale_ui_elements_with_buffer_font_size: true,
  520            show_active_line_background: true,
  521            sized_by_content: false,
  522        }
  523    }
  524
  525    #[inline]
  526    pub fn is_full(&self) -> bool {
  527        matches!(self, Self::Full { .. })
  528    }
  529
  530    #[inline]
  531    pub fn is_single_line(&self) -> bool {
  532        matches!(self, Self::SingleLine { .. })
  533    }
  534
  535    #[inline]
  536    fn is_minimap(&self) -> bool {
  537        matches!(self, Self::Minimap { .. })
  538    }
  539}
  540
  541#[derive(Copy, Clone, Debug)]
  542pub enum SoftWrap {
  543    /// Prefer not to wrap at all.
  544    ///
  545    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  546    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  547    GitDiff,
  548    /// Prefer a single line generally, unless an overly long line is encountered.
  549    None,
  550    /// Soft wrap lines that exceed the editor width.
  551    EditorWidth,
  552    /// Soft wrap lines at the preferred line length.
  553    Column(u32),
  554    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  555    Bounded(u32),
  556}
  557
  558#[derive(Clone)]
  559pub struct EditorStyle {
  560    pub background: Hsla,
  561    pub border: Hsla,
  562    pub local_player: PlayerColor,
  563    pub text: TextStyle,
  564    pub scrollbar_width: Pixels,
  565    pub syntax: Arc<SyntaxTheme>,
  566    pub status: StatusColors,
  567    pub inlay_hints_style: HighlightStyle,
  568    pub edit_prediction_styles: EditPredictionStyles,
  569    pub unnecessary_code_fade: f32,
  570    pub show_underlines: bool,
  571}
  572
  573impl Default for EditorStyle {
  574    fn default() -> Self {
  575        Self {
  576            background: Hsla::default(),
  577            border: Hsla::default(),
  578            local_player: PlayerColor::default(),
  579            text: TextStyle::default(),
  580            scrollbar_width: Pixels::default(),
  581            syntax: Default::default(),
  582            // HACK: Status colors don't have a real default.
  583            // We should look into removing the status colors from the editor
  584            // style and retrieve them directly from the theme.
  585            status: StatusColors::dark(),
  586            inlay_hints_style: HighlightStyle::default(),
  587            edit_prediction_styles: EditPredictionStyles {
  588                insertion: HighlightStyle::default(),
  589                whitespace: HighlightStyle::default(),
  590            },
  591            unnecessary_code_fade: Default::default(),
  592            show_underlines: true,
  593        }
  594    }
  595}
  596
  597pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  598    let show_background = language_settings::language_settings(None, None, cx)
  599        .inlay_hints
  600        .show_background;
  601
  602    HighlightStyle {
  603        color: Some(cx.theme().status().hint),
  604        background_color: show_background.then(|| cx.theme().status().hint_background),
  605        ..HighlightStyle::default()
  606    }
  607}
  608
  609pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  610    EditPredictionStyles {
  611        insertion: HighlightStyle {
  612            color: Some(cx.theme().status().predictive),
  613            ..HighlightStyle::default()
  614        },
  615        whitespace: HighlightStyle {
  616            background_color: Some(cx.theme().status().created_background),
  617            ..HighlightStyle::default()
  618        },
  619    }
  620}
  621
  622type CompletionId = usize;
  623
  624pub(crate) enum EditDisplayMode {
  625    TabAccept,
  626    DiffPopover,
  627    Inline,
  628}
  629
  630enum EditPrediction {
  631    Edit {
  632        edits: Vec<(Range<Anchor>, String)>,
  633        edit_preview: Option<EditPreview>,
  634        display_mode: EditDisplayMode,
  635        snapshot: BufferSnapshot,
  636    },
  637    Move {
  638        target: Anchor,
  639        snapshot: BufferSnapshot,
  640    },
  641}
  642
  643struct EditPredictionState {
  644    inlay_ids: Vec<InlayId>,
  645    completion: EditPrediction,
  646    completion_id: Option<SharedString>,
  647    invalidation_range: Range<Anchor>,
  648}
  649
  650enum EditPredictionSettings {
  651    Disabled,
  652    Enabled {
  653        show_in_menu: bool,
  654        preview_requires_modifier: bool,
  655    },
  656}
  657
  658enum EditPredictionHighlight {}
  659
  660#[derive(Debug, Clone)]
  661struct InlineDiagnostic {
  662    message: SharedString,
  663    group_id: usize,
  664    is_primary: bool,
  665    start: Point,
  666    severity: lsp::DiagnosticSeverity,
  667}
  668
  669pub enum MenuEditPredictionsPolicy {
  670    Never,
  671    ByProvider,
  672}
  673
  674pub enum EditPredictionPreview {
  675    /// Modifier is not pressed
  676    Inactive { released_too_fast: bool },
  677    /// Modifier pressed
  678    Active {
  679        since: Instant,
  680        previous_scroll_position: Option<ScrollAnchor>,
  681    },
  682}
  683
  684impl EditPredictionPreview {
  685    pub fn released_too_fast(&self) -> bool {
  686        match self {
  687            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  688            EditPredictionPreview::Active { .. } => false,
  689        }
  690    }
  691
  692    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  693        if let EditPredictionPreview::Active {
  694            previous_scroll_position,
  695            ..
  696        } = self
  697        {
  698            *previous_scroll_position = scroll_position;
  699        }
  700    }
  701}
  702
  703pub struct ContextMenuOptions {
  704    pub min_entries_visible: usize,
  705    pub max_entries_visible: usize,
  706    pub placement: Option<ContextMenuPlacement>,
  707}
  708
  709#[derive(Debug, Clone, PartialEq, Eq)]
  710pub enum ContextMenuPlacement {
  711    Above,
  712    Below,
  713}
  714
  715#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  716struct EditorActionId(usize);
  717
  718impl EditorActionId {
  719    pub fn post_inc(&mut self) -> Self {
  720        let answer = self.0;
  721
  722        *self = Self(answer + 1);
  723
  724        Self(answer)
  725    }
  726}
  727
  728// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  729// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  730
  731type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  732type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  733
  734#[derive(Default)]
  735struct ScrollbarMarkerState {
  736    scrollbar_size: Size<Pixels>,
  737    dirty: bool,
  738    markers: Arc<[PaintQuad]>,
  739    pending_refresh: Option<Task<Result<()>>>,
  740}
  741
  742impl ScrollbarMarkerState {
  743    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  744        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  745    }
  746}
  747
  748#[derive(Clone, Copy, PartialEq, Eq)]
  749pub enum MinimapVisibility {
  750    Disabled,
  751    Enabled {
  752        /// The configuration currently present in the users settings.
  753        setting_configuration: bool,
  754        /// Whether to override the currently set visibility from the users setting.
  755        toggle_override: bool,
  756    },
  757}
  758
  759impl MinimapVisibility {
  760    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  761        if mode.is_full() {
  762            Self::Enabled {
  763                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  764                toggle_override: false,
  765            }
  766        } else {
  767            Self::Disabled
  768        }
  769    }
  770
  771    fn hidden(&self) -> Self {
  772        match *self {
  773            Self::Enabled {
  774                setting_configuration,
  775                ..
  776            } => Self::Enabled {
  777                setting_configuration,
  778                toggle_override: setting_configuration,
  779            },
  780            Self::Disabled => Self::Disabled,
  781        }
  782    }
  783
  784    fn disabled(&self) -> bool {
  785        match *self {
  786            Self::Disabled => true,
  787            _ => false,
  788        }
  789    }
  790
  791    fn settings_visibility(&self) -> bool {
  792        match *self {
  793            Self::Enabled {
  794                setting_configuration,
  795                ..
  796            } => setting_configuration,
  797            _ => false,
  798        }
  799    }
  800
  801    fn visible(&self) -> bool {
  802        match *self {
  803            Self::Enabled {
  804                setting_configuration,
  805                toggle_override,
  806            } => setting_configuration ^ toggle_override,
  807            _ => false,
  808        }
  809    }
  810
  811    fn toggle_visibility(&self) -> Self {
  812        match *self {
  813            Self::Enabled {
  814                toggle_override,
  815                setting_configuration,
  816            } => Self::Enabled {
  817                setting_configuration,
  818                toggle_override: !toggle_override,
  819            },
  820            Self::Disabled => Self::Disabled,
  821        }
  822    }
  823}
  824
  825#[derive(Clone, Debug)]
  826struct RunnableTasks {
  827    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  828    offset: multi_buffer::Anchor,
  829    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  830    column: u32,
  831    // Values of all named captures, including those starting with '_'
  832    extra_variables: HashMap<String, String>,
  833    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  834    context_range: Range<BufferOffset>,
  835}
  836
  837impl RunnableTasks {
  838    fn resolve<'a>(
  839        &'a self,
  840        cx: &'a task::TaskContext,
  841    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  842        self.templates.iter().filter_map(|(kind, template)| {
  843            template
  844                .resolve_task(&kind.to_id_base(), cx)
  845                .map(|task| (kind.clone(), task))
  846        })
  847    }
  848}
  849
  850#[derive(Clone)]
  851pub struct ResolvedTasks {
  852    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  853    position: Anchor,
  854}
  855
  856#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  857struct BufferOffset(usize);
  858
  859// Addons allow storing per-editor state in other crates (e.g. Vim)
  860pub trait Addon: 'static {
  861    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  862
  863    fn render_buffer_header_controls(
  864        &self,
  865        _: &ExcerptInfo,
  866        _: &Window,
  867        _: &App,
  868    ) -> Option<AnyElement> {
  869        None
  870    }
  871
  872    fn to_any(&self) -> &dyn std::any::Any;
  873
  874    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  875        None
  876    }
  877}
  878
  879struct ChangeLocation {
  880    current: Option<Vec<Anchor>>,
  881    original: Vec<Anchor>,
  882}
  883impl ChangeLocation {
  884    fn locations(&self) -> &[Anchor] {
  885        self.current.as_ref().unwrap_or(&self.original)
  886    }
  887}
  888
  889/// A set of caret positions, registered when the editor was edited.
  890pub struct ChangeList {
  891    changes: Vec<ChangeLocation>,
  892    /// Currently "selected" change.
  893    position: Option<usize>,
  894}
  895
  896impl ChangeList {
  897    pub fn new() -> Self {
  898        Self {
  899            changes: Vec::new(),
  900            position: None,
  901        }
  902    }
  903
  904    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  905    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  906    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  907        if self.changes.is_empty() {
  908            return None;
  909        }
  910
  911        let prev = self.position.unwrap_or(self.changes.len());
  912        let next = if direction == Direction::Prev {
  913            prev.saturating_sub(count)
  914        } else {
  915            (prev + count).min(self.changes.len() - 1)
  916        };
  917        self.position = Some(next);
  918        self.changes.get(next).map(|change| change.locations())
  919    }
  920
  921    /// Adds a new change to the list, resetting the change list position.
  922    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  923        self.position.take();
  924        if let Some(last) = self.changes.last_mut()
  925            && group
  926        {
  927            last.current = Some(new_positions)
  928        } else {
  929            self.changes.push(ChangeLocation {
  930                original: new_positions,
  931                current: None,
  932            });
  933        }
  934    }
  935
  936    pub fn last(&self) -> Option<&[Anchor]> {
  937        self.changes.last().map(|change| change.locations())
  938    }
  939
  940    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  941        self.changes.last().map(|change| change.original.as_slice())
  942    }
  943
  944    pub fn invert_last_group(&mut self) {
  945        if let Some(last) = self.changes.last_mut()
  946            && let Some(current) = last.current.as_mut()
  947        {
  948            mem::swap(&mut last.original, current);
  949        }
  950    }
  951}
  952
  953#[derive(Clone)]
  954struct InlineBlamePopoverState {
  955    scroll_handle: ScrollHandle,
  956    commit_message: Option<ParsedCommitMessage>,
  957    markdown: Entity<Markdown>,
  958}
  959
  960struct InlineBlamePopover {
  961    position: gpui::Point<Pixels>,
  962    hide_task: Option<Task<()>>,
  963    popover_bounds: Option<Bounds<Pixels>>,
  964    popover_state: InlineBlamePopoverState,
  965    keyboard_grace: bool,
  966}
  967
  968enum SelectionDragState {
  969    /// State when no drag related activity is detected.
  970    None,
  971    /// State when the mouse is down on a selection that is about to be dragged.
  972    ReadyToDrag {
  973        selection: Selection<Anchor>,
  974        click_position: gpui::Point<Pixels>,
  975        mouse_down_time: Instant,
  976    },
  977    /// State when the mouse is dragging the selection in the editor.
  978    Dragging {
  979        selection: Selection<Anchor>,
  980        drop_cursor: Selection<Anchor>,
  981        hide_drop_cursor: bool,
  982    },
  983}
  984
  985enum ColumnarSelectionState {
  986    FromMouse {
  987        selection_tail: Anchor,
  988        display_point: Option<DisplayPoint>,
  989    },
  990    FromSelection {
  991        selection_tail: Anchor,
  992    },
  993}
  994
  995/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  996/// a breakpoint on them.
  997#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  998struct PhantomBreakpointIndicator {
  999    display_row: DisplayRow,
 1000    /// There's a small debounce between hovering over the line and showing the indicator.
 1001    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1002    is_active: bool,
 1003    collides_with_existing_breakpoint: bool,
 1004}
 1005
 1006/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1007///
 1008/// See the [module level documentation](self) for more information.
 1009pub struct Editor {
 1010    focus_handle: FocusHandle,
 1011    last_focused_descendant: Option<WeakFocusHandle>,
 1012    /// The text buffer being edited
 1013    buffer: Entity<MultiBuffer>,
 1014    /// Map of how text in the buffer should be displayed.
 1015    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1016    pub display_map: Entity<DisplayMap>,
 1017    pub selections: SelectionsCollection,
 1018    pub scroll_manager: ScrollManager,
 1019    /// When inline assist editors are linked, they all render cursors because
 1020    /// typing enters text into each of them, even the ones that aren't focused.
 1021    pub(crate) show_cursor_when_unfocused: bool,
 1022    columnar_selection_state: Option<ColumnarSelectionState>,
 1023    add_selections_state: Option<AddSelectionsState>,
 1024    select_next_state: Option<SelectNextState>,
 1025    select_prev_state: Option<SelectNextState>,
 1026    selection_history: SelectionHistory,
 1027    defer_selection_effects: bool,
 1028    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1029    autoclose_regions: Vec<AutocloseRegion>,
 1030    snippet_stack: InvalidationStack<SnippetState>,
 1031    select_syntax_node_history: SelectSyntaxNodeHistory,
 1032    ime_transaction: Option<TransactionId>,
 1033    pub diagnostics_max_severity: DiagnosticSeverity,
 1034    active_diagnostics: ActiveDiagnostic,
 1035    show_inline_diagnostics: bool,
 1036    inline_diagnostics_update: Task<()>,
 1037    inline_diagnostics_enabled: bool,
 1038    diagnostics_enabled: bool,
 1039    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1040    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1041    hard_wrap: Option<usize>,
 1042    project: Option<Entity<Project>>,
 1043    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1044    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1045    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1046    blink_manager: Entity<BlinkManager>,
 1047    show_cursor_names: bool,
 1048    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1049    pub show_local_selections: bool,
 1050    mode: EditorMode,
 1051    show_breadcrumbs: bool,
 1052    show_gutter: bool,
 1053    show_scrollbars: ScrollbarAxes,
 1054    minimap_visibility: MinimapVisibility,
 1055    offset_content: bool,
 1056    disable_expand_excerpt_buttons: bool,
 1057    show_line_numbers: Option<bool>,
 1058    use_relative_line_numbers: Option<bool>,
 1059    show_git_diff_gutter: Option<bool>,
 1060    show_code_actions: Option<bool>,
 1061    show_runnables: Option<bool>,
 1062    show_breakpoints: Option<bool>,
 1063    show_wrap_guides: Option<bool>,
 1064    show_indent_guides: Option<bool>,
 1065    placeholder_text: Option<Arc<str>>,
 1066    highlight_order: usize,
 1067    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1068    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1069    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1070    scrollbar_marker_state: ScrollbarMarkerState,
 1071    active_indent_guides_state: ActiveIndentGuidesState,
 1072    nav_history: Option<ItemNavHistory>,
 1073    context_menu: RefCell<Option<CodeContextMenu>>,
 1074    context_menu_options: Option<ContextMenuOptions>,
 1075    mouse_context_menu: Option<MouseContextMenu>,
 1076    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1077    inline_blame_popover: Option<InlineBlamePopover>,
 1078    inline_blame_popover_show_task: Option<Task<()>>,
 1079    signature_help_state: SignatureHelpState,
 1080    auto_signature_help: Option<bool>,
 1081    find_all_references_task_sources: Vec<Anchor>,
 1082    next_completion_id: CompletionId,
 1083    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1084    code_actions_task: Option<Task<Result<()>>>,
 1085    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1086    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1087    document_highlights_task: Option<Task<()>>,
 1088    linked_editing_range_task: Option<Task<Option<()>>>,
 1089    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1090    pending_rename: Option<RenameState>,
 1091    searchable: bool,
 1092    cursor_shape: CursorShape,
 1093    current_line_highlight: Option<CurrentLineHighlight>,
 1094    collapse_matches: bool,
 1095    autoindent_mode: Option<AutoindentMode>,
 1096    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1097    input_enabled: bool,
 1098    use_modal_editing: bool,
 1099    read_only: bool,
 1100    leader_id: Option<CollaboratorId>,
 1101    remote_id: Option<ViewId>,
 1102    pub hover_state: HoverState,
 1103    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1104    gutter_hovered: bool,
 1105    hovered_link_state: Option<HoveredLinkState>,
 1106    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1107    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1108    active_edit_prediction: Option<EditPredictionState>,
 1109    /// Used to prevent flickering as the user types while the menu is open
 1110    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1111    edit_prediction_settings: EditPredictionSettings,
 1112    edit_predictions_hidden_for_vim_mode: bool,
 1113    show_edit_predictions_override: Option<bool>,
 1114    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1115    edit_prediction_preview: EditPredictionPreview,
 1116    edit_prediction_indent_conflict: bool,
 1117    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1118    inlay_hint_cache: InlayHintCache,
 1119    next_inlay_id: usize,
 1120    _subscriptions: Vec<Subscription>,
 1121    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1122    gutter_dimensions: GutterDimensions,
 1123    style: Option<EditorStyle>,
 1124    text_style_refinement: Option<TextStyleRefinement>,
 1125    next_editor_action_id: EditorActionId,
 1126    editor_actions: Rc<
 1127        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1128    >,
 1129    use_autoclose: bool,
 1130    use_auto_surround: bool,
 1131    auto_replace_emoji_shortcode: bool,
 1132    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1133    show_git_blame_gutter: bool,
 1134    show_git_blame_inline: bool,
 1135    show_git_blame_inline_delay_task: Option<Task<()>>,
 1136    git_blame_inline_enabled: bool,
 1137    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1138    serialize_dirty_buffers: bool,
 1139    show_selection_menu: Option<bool>,
 1140    blame: Option<Entity<GitBlame>>,
 1141    blame_subscription: Option<Subscription>,
 1142    custom_context_menu: Option<
 1143        Box<
 1144            dyn 'static
 1145                + Fn(
 1146                    &mut Self,
 1147                    DisplayPoint,
 1148                    &mut Window,
 1149                    &mut Context<Self>,
 1150                ) -> Option<Entity<ui::ContextMenu>>,
 1151        >,
 1152    >,
 1153    last_bounds: Option<Bounds<Pixels>>,
 1154    last_position_map: Option<Rc<PositionMap>>,
 1155    expect_bounds_change: Option<Bounds<Pixels>>,
 1156    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1157    tasks_update_task: Option<Task<()>>,
 1158    breakpoint_store: Option<Entity<BreakpointStore>>,
 1159    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1160    hovered_diff_hunk_row: Option<DisplayRow>,
 1161    pull_diagnostics_task: Task<()>,
 1162    in_project_search: bool,
 1163    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1164    breadcrumb_header: Option<String>,
 1165    focused_block: Option<FocusedBlock>,
 1166    next_scroll_position: NextScrollCursorCenterTopBottom,
 1167    addons: HashMap<TypeId, Box<dyn Addon>>,
 1168    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1169    load_diff_task: Option<Shared<Task<()>>>,
 1170    /// Whether we are temporarily displaying a diff other than git's
 1171    temporary_diff_override: bool,
 1172    selection_mark_mode: bool,
 1173    toggle_fold_multiple_buffers: Task<()>,
 1174    _scroll_cursor_center_top_bottom_task: Task<()>,
 1175    serialize_selections: Task<()>,
 1176    serialize_folds: Task<()>,
 1177    mouse_cursor_hidden: bool,
 1178    minimap: Option<Entity<Self>>,
 1179    hide_mouse_mode: HideMouseMode,
 1180    pub change_list: ChangeList,
 1181    inline_value_cache: InlineValueCache,
 1182    selection_drag_state: SelectionDragState,
 1183    next_color_inlay_id: usize,
 1184    colors: Option<LspColorData>,
 1185    folding_newlines: Task<()>,
 1186}
 1187
 1188#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1189enum NextScrollCursorCenterTopBottom {
 1190    #[default]
 1191    Center,
 1192    Top,
 1193    Bottom,
 1194}
 1195
 1196impl NextScrollCursorCenterTopBottom {
 1197    fn next(&self) -> Self {
 1198        match self {
 1199            Self::Center => Self::Top,
 1200            Self::Top => Self::Bottom,
 1201            Self::Bottom => Self::Center,
 1202        }
 1203    }
 1204}
 1205
 1206#[derive(Clone)]
 1207pub struct EditorSnapshot {
 1208    pub mode: EditorMode,
 1209    show_gutter: bool,
 1210    show_line_numbers: Option<bool>,
 1211    show_git_diff_gutter: Option<bool>,
 1212    show_code_actions: Option<bool>,
 1213    show_runnables: Option<bool>,
 1214    show_breakpoints: Option<bool>,
 1215    git_blame_gutter_max_author_length: Option<usize>,
 1216    pub display_snapshot: DisplaySnapshot,
 1217    pub placeholder_text: Option<Arc<str>>,
 1218    is_focused: bool,
 1219    scroll_anchor: ScrollAnchor,
 1220    ongoing_scroll: OngoingScroll,
 1221    current_line_highlight: CurrentLineHighlight,
 1222    gutter_hovered: bool,
 1223}
 1224
 1225#[derive(Default, Debug, Clone, Copy)]
 1226pub struct GutterDimensions {
 1227    pub left_padding: Pixels,
 1228    pub right_padding: Pixels,
 1229    pub width: Pixels,
 1230    pub margin: Pixels,
 1231    pub git_blame_entries_width: Option<Pixels>,
 1232}
 1233
 1234impl GutterDimensions {
 1235    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1236        Self {
 1237            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1238            ..Default::default()
 1239        }
 1240    }
 1241
 1242    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1243        -cx.text_system().descent(font_id, font_size)
 1244    }
 1245    /// The full width of the space taken up by the gutter.
 1246    pub fn full_width(&self) -> Pixels {
 1247        self.margin + self.width
 1248    }
 1249
 1250    /// The width of the space reserved for the fold indicators,
 1251    /// use alongside 'justify_end' and `gutter_width` to
 1252    /// right align content with the line numbers
 1253    pub fn fold_area_width(&self) -> Pixels {
 1254        self.margin + self.right_padding
 1255    }
 1256}
 1257
 1258struct CharacterDimensions {
 1259    em_width: Pixels,
 1260    em_advance: Pixels,
 1261    line_height: Pixels,
 1262}
 1263
 1264#[derive(Debug)]
 1265pub struct RemoteSelection {
 1266    pub replica_id: ReplicaId,
 1267    pub selection: Selection<Anchor>,
 1268    pub cursor_shape: CursorShape,
 1269    pub collaborator_id: CollaboratorId,
 1270    pub line_mode: bool,
 1271    pub user_name: Option<SharedString>,
 1272    pub color: PlayerColor,
 1273}
 1274
 1275#[derive(Clone, Debug)]
 1276struct SelectionHistoryEntry {
 1277    selections: Arc<[Selection<Anchor>]>,
 1278    select_next_state: Option<SelectNextState>,
 1279    select_prev_state: Option<SelectNextState>,
 1280    add_selections_state: Option<AddSelectionsState>,
 1281}
 1282
 1283#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1284enum SelectionHistoryMode {
 1285    Normal,
 1286    Undoing,
 1287    Redoing,
 1288    Skipping,
 1289}
 1290
 1291#[derive(Clone, PartialEq, Eq, Hash)]
 1292struct HoveredCursor {
 1293    replica_id: u16,
 1294    selection_id: usize,
 1295}
 1296
 1297impl Default for SelectionHistoryMode {
 1298    fn default() -> Self {
 1299        Self::Normal
 1300    }
 1301}
 1302
 1303#[derive(Debug)]
 1304/// SelectionEffects controls the side-effects of updating the selection.
 1305///
 1306/// The default behaviour does "what you mostly want":
 1307/// - it pushes to the nav history if the cursor moved by >10 lines
 1308/// - it re-triggers completion requests
 1309/// - it scrolls to fit
 1310///
 1311/// You might want to modify these behaviours. For example when doing a "jump"
 1312/// like go to definition, we always want to add to nav history; but when scrolling
 1313/// in vim mode we never do.
 1314///
 1315/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1316/// move.
 1317#[derive(Clone)]
 1318pub struct SelectionEffects {
 1319    nav_history: Option<bool>,
 1320    completions: bool,
 1321    scroll: Option<Autoscroll>,
 1322}
 1323
 1324impl Default for SelectionEffects {
 1325    fn default() -> Self {
 1326        Self {
 1327            nav_history: None,
 1328            completions: true,
 1329            scroll: Some(Autoscroll::fit()),
 1330        }
 1331    }
 1332}
 1333impl SelectionEffects {
 1334    pub fn scroll(scroll: Autoscroll) -> Self {
 1335        Self {
 1336            scroll: Some(scroll),
 1337            ..Default::default()
 1338        }
 1339    }
 1340
 1341    pub fn no_scroll() -> Self {
 1342        Self {
 1343            scroll: None,
 1344            ..Default::default()
 1345        }
 1346    }
 1347
 1348    pub fn completions(self, completions: bool) -> Self {
 1349        Self {
 1350            completions,
 1351            ..self
 1352        }
 1353    }
 1354
 1355    pub fn nav_history(self, nav_history: bool) -> Self {
 1356        Self {
 1357            nav_history: Some(nav_history),
 1358            ..self
 1359        }
 1360    }
 1361}
 1362
 1363struct DeferredSelectionEffectsState {
 1364    changed: bool,
 1365    effects: SelectionEffects,
 1366    old_cursor_position: Anchor,
 1367    history_entry: SelectionHistoryEntry,
 1368}
 1369
 1370#[derive(Default)]
 1371struct SelectionHistory {
 1372    #[allow(clippy::type_complexity)]
 1373    selections_by_transaction:
 1374        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1375    mode: SelectionHistoryMode,
 1376    undo_stack: VecDeque<SelectionHistoryEntry>,
 1377    redo_stack: VecDeque<SelectionHistoryEntry>,
 1378}
 1379
 1380impl SelectionHistory {
 1381    #[track_caller]
 1382    fn insert_transaction(
 1383        &mut self,
 1384        transaction_id: TransactionId,
 1385        selections: Arc<[Selection<Anchor>]>,
 1386    ) {
 1387        if selections.is_empty() {
 1388            log::error!(
 1389                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1390                std::panic::Location::caller()
 1391            );
 1392            return;
 1393        }
 1394        self.selections_by_transaction
 1395            .insert(transaction_id, (selections, None));
 1396    }
 1397
 1398    #[allow(clippy::type_complexity)]
 1399    fn transaction(
 1400        &self,
 1401        transaction_id: TransactionId,
 1402    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1403        self.selections_by_transaction.get(&transaction_id)
 1404    }
 1405
 1406    #[allow(clippy::type_complexity)]
 1407    fn transaction_mut(
 1408        &mut self,
 1409        transaction_id: TransactionId,
 1410    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1411        self.selections_by_transaction.get_mut(&transaction_id)
 1412    }
 1413
 1414    fn push(&mut self, entry: SelectionHistoryEntry) {
 1415        if !entry.selections.is_empty() {
 1416            match self.mode {
 1417                SelectionHistoryMode::Normal => {
 1418                    self.push_undo(entry);
 1419                    self.redo_stack.clear();
 1420                }
 1421                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1422                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1423                SelectionHistoryMode::Skipping => {}
 1424            }
 1425        }
 1426    }
 1427
 1428    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1429        if self
 1430            .undo_stack
 1431            .back()
 1432            .is_none_or(|e| e.selections != entry.selections)
 1433        {
 1434            self.undo_stack.push_back(entry);
 1435            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1436                self.undo_stack.pop_front();
 1437            }
 1438        }
 1439    }
 1440
 1441    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1442        if self
 1443            .redo_stack
 1444            .back()
 1445            .is_none_or(|e| e.selections != entry.selections)
 1446        {
 1447            self.redo_stack.push_back(entry);
 1448            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1449                self.redo_stack.pop_front();
 1450            }
 1451        }
 1452    }
 1453}
 1454
 1455#[derive(Clone, Copy)]
 1456pub struct RowHighlightOptions {
 1457    pub autoscroll: bool,
 1458    pub include_gutter: bool,
 1459}
 1460
 1461impl Default for RowHighlightOptions {
 1462    fn default() -> Self {
 1463        Self {
 1464            autoscroll: Default::default(),
 1465            include_gutter: true,
 1466        }
 1467    }
 1468}
 1469
 1470struct RowHighlight {
 1471    index: usize,
 1472    range: Range<Anchor>,
 1473    color: Hsla,
 1474    options: RowHighlightOptions,
 1475    type_id: TypeId,
 1476}
 1477
 1478#[derive(Clone, Debug)]
 1479struct AddSelectionsState {
 1480    groups: Vec<AddSelectionsGroup>,
 1481}
 1482
 1483#[derive(Clone, Debug)]
 1484struct AddSelectionsGroup {
 1485    above: bool,
 1486    stack: Vec<usize>,
 1487}
 1488
 1489#[derive(Clone)]
 1490struct SelectNextState {
 1491    query: AhoCorasick,
 1492    wordwise: bool,
 1493    done: bool,
 1494}
 1495
 1496impl std::fmt::Debug for SelectNextState {
 1497    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1498        f.debug_struct(std::any::type_name::<Self>())
 1499            .field("wordwise", &self.wordwise)
 1500            .field("done", &self.done)
 1501            .finish()
 1502    }
 1503}
 1504
 1505#[derive(Debug)]
 1506struct AutocloseRegion {
 1507    selection_id: usize,
 1508    range: Range<Anchor>,
 1509    pair: BracketPair,
 1510}
 1511
 1512#[derive(Debug)]
 1513struct SnippetState {
 1514    ranges: Vec<Vec<Range<Anchor>>>,
 1515    active_index: usize,
 1516    choices: Vec<Option<Vec<String>>>,
 1517}
 1518
 1519#[doc(hidden)]
 1520pub struct RenameState {
 1521    pub range: Range<Anchor>,
 1522    pub old_name: Arc<str>,
 1523    pub editor: Entity<Editor>,
 1524    block_id: CustomBlockId,
 1525}
 1526
 1527struct InvalidationStack<T>(Vec<T>);
 1528
 1529struct RegisteredEditPredictionProvider {
 1530    provider: Arc<dyn EditPredictionProviderHandle>,
 1531    _subscription: Subscription,
 1532}
 1533
 1534#[derive(Debug, PartialEq, Eq)]
 1535pub struct ActiveDiagnosticGroup {
 1536    pub active_range: Range<Anchor>,
 1537    pub active_message: String,
 1538    pub group_id: usize,
 1539    pub blocks: HashSet<CustomBlockId>,
 1540}
 1541
 1542#[derive(Debug, PartialEq, Eq)]
 1543
 1544pub(crate) enum ActiveDiagnostic {
 1545    None,
 1546    All,
 1547    Group(ActiveDiagnosticGroup),
 1548}
 1549
 1550#[derive(Serialize, Deserialize, Clone, Debug)]
 1551pub struct ClipboardSelection {
 1552    /// The number of bytes in this selection.
 1553    pub len: usize,
 1554    /// Whether this was a full-line selection.
 1555    pub is_entire_line: bool,
 1556    /// The indentation of the first line when this content was originally copied.
 1557    pub first_line_indent: u32,
 1558}
 1559
 1560// selections, scroll behavior, was newest selection reversed
 1561type SelectSyntaxNodeHistoryState = (
 1562    Box<[Selection<usize>]>,
 1563    SelectSyntaxNodeScrollBehavior,
 1564    bool,
 1565);
 1566
 1567#[derive(Default)]
 1568struct SelectSyntaxNodeHistory {
 1569    stack: Vec<SelectSyntaxNodeHistoryState>,
 1570    // disable temporarily to allow changing selections without losing the stack
 1571    pub disable_clearing: bool,
 1572}
 1573
 1574impl SelectSyntaxNodeHistory {
 1575    pub fn try_clear(&mut self) {
 1576        if !self.disable_clearing {
 1577            self.stack.clear();
 1578        }
 1579    }
 1580
 1581    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1582        self.stack.push(selection);
 1583    }
 1584
 1585    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1586        self.stack.pop()
 1587    }
 1588}
 1589
 1590enum SelectSyntaxNodeScrollBehavior {
 1591    CursorTop,
 1592    FitSelection,
 1593    CursorBottom,
 1594}
 1595
 1596#[derive(Debug)]
 1597pub(crate) struct NavigationData {
 1598    cursor_anchor: Anchor,
 1599    cursor_position: Point,
 1600    scroll_anchor: ScrollAnchor,
 1601    scroll_top_row: u32,
 1602}
 1603
 1604#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1605pub enum GotoDefinitionKind {
 1606    Symbol,
 1607    Declaration,
 1608    Type,
 1609    Implementation,
 1610}
 1611
 1612#[derive(Debug, Clone)]
 1613enum InlayHintRefreshReason {
 1614    ModifiersChanged(bool),
 1615    Toggle(bool),
 1616    SettingsChange(InlayHintSettings),
 1617    NewLinesShown,
 1618    BufferEdited(HashSet<Arc<Language>>),
 1619    RefreshRequested,
 1620    ExcerptsRemoved(Vec<ExcerptId>),
 1621}
 1622
 1623impl InlayHintRefreshReason {
 1624    fn description(&self) -> &'static str {
 1625        match self {
 1626            Self::ModifiersChanged(_) => "modifiers changed",
 1627            Self::Toggle(_) => "toggle",
 1628            Self::SettingsChange(_) => "settings change",
 1629            Self::NewLinesShown => "new lines shown",
 1630            Self::BufferEdited(_) => "buffer edited",
 1631            Self::RefreshRequested => "refresh requested",
 1632            Self::ExcerptsRemoved(_) => "excerpts removed",
 1633        }
 1634    }
 1635}
 1636
 1637pub enum FormatTarget {
 1638    Buffers(HashSet<Entity<Buffer>>),
 1639    Ranges(Vec<Range<MultiBufferPoint>>),
 1640}
 1641
 1642pub(crate) struct FocusedBlock {
 1643    id: BlockId,
 1644    focus_handle: WeakFocusHandle,
 1645}
 1646
 1647#[derive(Clone)]
 1648enum JumpData {
 1649    MultiBufferRow {
 1650        row: MultiBufferRow,
 1651        line_offset_from_top: u32,
 1652    },
 1653    MultiBufferPoint {
 1654        excerpt_id: ExcerptId,
 1655        position: Point,
 1656        anchor: text::Anchor,
 1657        line_offset_from_top: u32,
 1658    },
 1659}
 1660
 1661pub enum MultibufferSelectionMode {
 1662    First,
 1663    All,
 1664}
 1665
 1666#[derive(Clone, Copy, Debug, Default)]
 1667pub struct RewrapOptions {
 1668    pub override_language_settings: bool,
 1669    pub preserve_existing_whitespace: bool,
 1670}
 1671
 1672impl Editor {
 1673    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1674        let buffer = cx.new(|cx| Buffer::local("", cx));
 1675        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1676        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1677    }
 1678
 1679    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1680        let buffer = cx.new(|cx| Buffer::local("", cx));
 1681        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1682        Self::new(EditorMode::full(), buffer, None, window, cx)
 1683    }
 1684
 1685    pub fn auto_height(
 1686        min_lines: usize,
 1687        max_lines: usize,
 1688        window: &mut Window,
 1689        cx: &mut Context<Self>,
 1690    ) -> Self {
 1691        let buffer = cx.new(|cx| Buffer::local("", cx));
 1692        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1693        Self::new(
 1694            EditorMode::AutoHeight {
 1695                min_lines,
 1696                max_lines: Some(max_lines),
 1697            },
 1698            buffer,
 1699            None,
 1700            window,
 1701            cx,
 1702        )
 1703    }
 1704
 1705    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1706    /// The editor grows as tall as needed to fit its content.
 1707    pub fn auto_height_unbounded(
 1708        min_lines: usize,
 1709        window: &mut Window,
 1710        cx: &mut Context<Self>,
 1711    ) -> Self {
 1712        let buffer = cx.new(|cx| Buffer::local("", cx));
 1713        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1714        Self::new(
 1715            EditorMode::AutoHeight {
 1716                min_lines,
 1717                max_lines: None,
 1718            },
 1719            buffer,
 1720            None,
 1721            window,
 1722            cx,
 1723        )
 1724    }
 1725
 1726    pub fn for_buffer(
 1727        buffer: Entity<Buffer>,
 1728        project: Option<Entity<Project>>,
 1729        window: &mut Window,
 1730        cx: &mut Context<Self>,
 1731    ) -> Self {
 1732        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1733        Self::new(EditorMode::full(), buffer, project, window, cx)
 1734    }
 1735
 1736    pub fn for_multibuffer(
 1737        buffer: Entity<MultiBuffer>,
 1738        project: Option<Entity<Project>>,
 1739        window: &mut Window,
 1740        cx: &mut Context<Self>,
 1741    ) -> Self {
 1742        Self::new(EditorMode::full(), buffer, project, window, cx)
 1743    }
 1744
 1745    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1746        let mut clone = Self::new(
 1747            self.mode.clone(),
 1748            self.buffer.clone(),
 1749            self.project.clone(),
 1750            window,
 1751            cx,
 1752        );
 1753        self.display_map.update(cx, |display_map, cx| {
 1754            let snapshot = display_map.snapshot(cx);
 1755            clone.display_map.update(cx, |display_map, cx| {
 1756                display_map.set_state(&snapshot, cx);
 1757            });
 1758        });
 1759        clone.folds_did_change(cx);
 1760        clone.selections.clone_state(&self.selections);
 1761        clone.scroll_manager.clone_state(&self.scroll_manager);
 1762        clone.searchable = self.searchable;
 1763        clone.read_only = self.read_only;
 1764        clone
 1765    }
 1766
 1767    pub fn new(
 1768        mode: EditorMode,
 1769        buffer: Entity<MultiBuffer>,
 1770        project: Option<Entity<Project>>,
 1771        window: &mut Window,
 1772        cx: &mut Context<Self>,
 1773    ) -> Self {
 1774        Editor::new_internal(mode, buffer, project, None, window, cx)
 1775    }
 1776
 1777    fn new_internal(
 1778        mode: EditorMode,
 1779        buffer: Entity<MultiBuffer>,
 1780        project: Option<Entity<Project>>,
 1781        display_map: Option<Entity<DisplayMap>>,
 1782        window: &mut Window,
 1783        cx: &mut Context<Self>,
 1784    ) -> Self {
 1785        debug_assert!(
 1786            display_map.is_none() || mode.is_minimap(),
 1787            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1788        );
 1789
 1790        let full_mode = mode.is_full();
 1791        let is_minimap = mode.is_minimap();
 1792        let diagnostics_max_severity = if full_mode {
 1793            EditorSettings::get_global(cx)
 1794                .diagnostics_max_severity
 1795                .unwrap_or(DiagnosticSeverity::Hint)
 1796        } else {
 1797            DiagnosticSeverity::Off
 1798        };
 1799        let style = window.text_style();
 1800        let font_size = style.font_size.to_pixels(window.rem_size());
 1801        let editor = cx.entity().downgrade();
 1802        let fold_placeholder = FoldPlaceholder {
 1803            constrain_width: true,
 1804            render: Arc::new(move |fold_id, fold_range, cx| {
 1805                let editor = editor.clone();
 1806                div()
 1807                    .id(fold_id)
 1808                    .bg(cx.theme().colors().ghost_element_background)
 1809                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1810                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1811                    .rounded_xs()
 1812                    .size_full()
 1813                    .cursor_pointer()
 1814                    .child("")
 1815                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1816                    .on_click(move |_, _window, cx| {
 1817                        editor
 1818                            .update(cx, |editor, cx| {
 1819                                editor.unfold_ranges(
 1820                                    &[fold_range.start..fold_range.end],
 1821                                    true,
 1822                                    false,
 1823                                    cx,
 1824                                );
 1825                                cx.stop_propagation();
 1826                            })
 1827                            .ok();
 1828                    })
 1829                    .into_any()
 1830            }),
 1831            merge_adjacent: true,
 1832            ..FoldPlaceholder::default()
 1833        };
 1834        let display_map = display_map.unwrap_or_else(|| {
 1835            cx.new(|cx| {
 1836                DisplayMap::new(
 1837                    buffer.clone(),
 1838                    style.font(),
 1839                    font_size,
 1840                    None,
 1841                    FILE_HEADER_HEIGHT,
 1842                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1843                    fold_placeholder,
 1844                    diagnostics_max_severity,
 1845                    cx,
 1846                )
 1847            })
 1848        });
 1849
 1850        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1851
 1852        let blink_manager = cx.new(|cx| {
 1853            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1854            if is_minimap {
 1855                blink_manager.disable(cx);
 1856            }
 1857            blink_manager
 1858        });
 1859
 1860        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1861            .then(|| language_settings::SoftWrap::None);
 1862
 1863        let mut project_subscriptions = Vec::new();
 1864        if full_mode && let Some(project) = project.as_ref() {
 1865            project_subscriptions.push(cx.subscribe_in(
 1866                project,
 1867                window,
 1868                |editor, _, event, window, cx| match event {
 1869                    project::Event::RefreshCodeLens => {
 1870                        // we always query lens with actions, without storing them, always refreshing them
 1871                    }
 1872                    project::Event::RefreshInlayHints => {
 1873                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1874                    }
 1875                    project::Event::LanguageServerAdded(..)
 1876                    | project::Event::LanguageServerRemoved(..) => {
 1877                        if editor.tasks_update_task.is_none() {
 1878                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1879                        }
 1880                    }
 1881                    project::Event::SnippetEdit(id, snippet_edits) => {
 1882                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1883                            let focus_handle = editor.focus_handle(cx);
 1884                            if focus_handle.is_focused(window) {
 1885                                let snapshot = buffer.read(cx).snapshot();
 1886                                for (range, snippet) in snippet_edits {
 1887                                    let editor_range =
 1888                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1889                                    editor
 1890                                        .insert_snippet(
 1891                                            &[editor_range],
 1892                                            snippet.clone(),
 1893                                            window,
 1894                                            cx,
 1895                                        )
 1896                                        .ok();
 1897                                }
 1898                            }
 1899                        }
 1900                    }
 1901                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1902                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1903                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1904                        }
 1905                    }
 1906                    _ => {}
 1907                },
 1908            ));
 1909            if let Some(task_inventory) = project
 1910                .read(cx)
 1911                .task_store()
 1912                .read(cx)
 1913                .task_inventory()
 1914                .cloned()
 1915            {
 1916                project_subscriptions.push(cx.observe_in(
 1917                    &task_inventory,
 1918                    window,
 1919                    |editor, _, window, cx| {
 1920                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1921                    },
 1922                ));
 1923            };
 1924
 1925            project_subscriptions.push(cx.subscribe_in(
 1926                &project.read(cx).breakpoint_store(),
 1927                window,
 1928                |editor, _, event, window, cx| match event {
 1929                    BreakpointStoreEvent::ClearDebugLines => {
 1930                        editor.clear_row_highlights::<ActiveDebugLine>();
 1931                        editor.refresh_inline_values(cx);
 1932                    }
 1933                    BreakpointStoreEvent::SetDebugLine => {
 1934                        if editor.go_to_active_debug_line(window, cx) {
 1935                            cx.stop_propagation();
 1936                        }
 1937
 1938                        editor.refresh_inline_values(cx);
 1939                    }
 1940                    _ => {}
 1941                },
 1942            ));
 1943            let git_store = project.read(cx).git_store().clone();
 1944            let project = project.clone();
 1945            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1946                if let GitStoreEvent::RepositoryUpdated(
 1947                    _,
 1948                    RepositoryEvent::Updated {
 1949                        new_instance: true, ..
 1950                    },
 1951                    _,
 1952                ) = event
 1953                {
 1954                    this.load_diff_task = Some(
 1955                        update_uncommitted_diff_for_buffer(
 1956                            cx.entity(),
 1957                            &project,
 1958                            this.buffer.read(cx).all_buffers(),
 1959                            this.buffer.clone(),
 1960                            cx,
 1961                        )
 1962                        .shared(),
 1963                    );
 1964                }
 1965            }));
 1966        }
 1967
 1968        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1969
 1970        let inlay_hint_settings =
 1971            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1972        let focus_handle = cx.focus_handle();
 1973        if !is_minimap {
 1974            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1975                .detach();
 1976            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1977                .detach();
 1978            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1979                .detach();
 1980            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1981                .detach();
 1982            cx.observe_pending_input(window, Self::observe_pending_input)
 1983                .detach();
 1984        }
 1985
 1986        let show_indent_guides = if matches!(
 1987            mode,
 1988            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1989        ) {
 1990            Some(false)
 1991        } else {
 1992            None
 1993        };
 1994
 1995        let breakpoint_store = match (&mode, project.as_ref()) {
 1996            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1997            _ => None,
 1998        };
 1999
 2000        let mut code_action_providers = Vec::new();
 2001        let mut load_uncommitted_diff = None;
 2002        if let Some(project) = project.clone() {
 2003            load_uncommitted_diff = Some(
 2004                update_uncommitted_diff_for_buffer(
 2005                    cx.entity(),
 2006                    &project,
 2007                    buffer.read(cx).all_buffers(),
 2008                    buffer.clone(),
 2009                    cx,
 2010                )
 2011                .shared(),
 2012            );
 2013            code_action_providers.push(Rc::new(project) as Rc<_>);
 2014        }
 2015
 2016        let mut editor = Self {
 2017            focus_handle,
 2018            show_cursor_when_unfocused: false,
 2019            last_focused_descendant: None,
 2020            buffer: buffer.clone(),
 2021            display_map: display_map.clone(),
 2022            selections,
 2023            scroll_manager: ScrollManager::new(cx),
 2024            columnar_selection_state: None,
 2025            add_selections_state: None,
 2026            select_next_state: None,
 2027            select_prev_state: None,
 2028            selection_history: SelectionHistory::default(),
 2029            defer_selection_effects: false,
 2030            deferred_selection_effects_state: None,
 2031            autoclose_regions: Vec::new(),
 2032            snippet_stack: InvalidationStack::default(),
 2033            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2034            ime_transaction: None,
 2035            active_diagnostics: ActiveDiagnostic::None,
 2036            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2037            inline_diagnostics_update: Task::ready(()),
 2038            inline_diagnostics: Vec::new(),
 2039            soft_wrap_mode_override,
 2040            diagnostics_max_severity,
 2041            hard_wrap: None,
 2042            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2043            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2044            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2045            project,
 2046            blink_manager: blink_manager.clone(),
 2047            show_local_selections: true,
 2048            show_scrollbars: ScrollbarAxes {
 2049                horizontal: full_mode,
 2050                vertical: full_mode,
 2051            },
 2052            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2053            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2054            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2055            show_gutter: full_mode,
 2056            show_line_numbers: (!full_mode).then_some(false),
 2057            use_relative_line_numbers: None,
 2058            disable_expand_excerpt_buttons: !full_mode,
 2059            show_git_diff_gutter: None,
 2060            show_code_actions: None,
 2061            show_runnables: None,
 2062            show_breakpoints: None,
 2063            show_wrap_guides: None,
 2064            show_indent_guides,
 2065            placeholder_text: None,
 2066            highlight_order: 0,
 2067            highlighted_rows: HashMap::default(),
 2068            background_highlights: TreeMap::default(),
 2069            gutter_highlights: TreeMap::default(),
 2070            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2071            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2072            nav_history: None,
 2073            context_menu: RefCell::new(None),
 2074            context_menu_options: None,
 2075            mouse_context_menu: None,
 2076            completion_tasks: Vec::new(),
 2077            inline_blame_popover: None,
 2078            inline_blame_popover_show_task: None,
 2079            signature_help_state: SignatureHelpState::default(),
 2080            auto_signature_help: None,
 2081            find_all_references_task_sources: Vec::new(),
 2082            next_completion_id: 0,
 2083            next_inlay_id: 0,
 2084            code_action_providers,
 2085            available_code_actions: None,
 2086            code_actions_task: None,
 2087            quick_selection_highlight_task: None,
 2088            debounced_selection_highlight_task: None,
 2089            document_highlights_task: None,
 2090            linked_editing_range_task: None,
 2091            pending_rename: None,
 2092            searchable: !is_minimap,
 2093            cursor_shape: EditorSettings::get_global(cx)
 2094                .cursor_shape
 2095                .unwrap_or_default(),
 2096            current_line_highlight: None,
 2097            autoindent_mode: Some(AutoindentMode::EachLine),
 2098            collapse_matches: false,
 2099            workspace: None,
 2100            input_enabled: !is_minimap,
 2101            use_modal_editing: full_mode,
 2102            read_only: is_minimap,
 2103            use_autoclose: true,
 2104            use_auto_surround: true,
 2105            auto_replace_emoji_shortcode: false,
 2106            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2107            leader_id: None,
 2108            remote_id: None,
 2109            hover_state: HoverState::default(),
 2110            pending_mouse_down: None,
 2111            hovered_link_state: None,
 2112            edit_prediction_provider: None,
 2113            active_edit_prediction: None,
 2114            stale_edit_prediction_in_menu: None,
 2115            edit_prediction_preview: EditPredictionPreview::Inactive {
 2116                released_too_fast: false,
 2117            },
 2118            inline_diagnostics_enabled: full_mode,
 2119            diagnostics_enabled: full_mode,
 2120            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2121            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2122            gutter_hovered: false,
 2123            pixel_position_of_newest_cursor: None,
 2124            last_bounds: None,
 2125            last_position_map: None,
 2126            expect_bounds_change: None,
 2127            gutter_dimensions: GutterDimensions::default(),
 2128            style: None,
 2129            show_cursor_names: false,
 2130            hovered_cursors: HashMap::default(),
 2131            next_editor_action_id: EditorActionId::default(),
 2132            editor_actions: Rc::default(),
 2133            edit_predictions_hidden_for_vim_mode: false,
 2134            show_edit_predictions_override: None,
 2135            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2136            edit_prediction_settings: EditPredictionSettings::Disabled,
 2137            edit_prediction_indent_conflict: false,
 2138            edit_prediction_requires_modifier_in_indent_conflict: true,
 2139            custom_context_menu: None,
 2140            show_git_blame_gutter: false,
 2141            show_git_blame_inline: false,
 2142            show_selection_menu: None,
 2143            show_git_blame_inline_delay_task: None,
 2144            git_blame_inline_enabled: full_mode
 2145                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2146            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2147            serialize_dirty_buffers: !is_minimap
 2148                && ProjectSettings::get_global(cx)
 2149                    .session
 2150                    .restore_unsaved_buffers,
 2151            blame: None,
 2152            blame_subscription: None,
 2153            tasks: BTreeMap::default(),
 2154
 2155            breakpoint_store,
 2156            gutter_breakpoint_indicator: (None, None),
 2157            hovered_diff_hunk_row: None,
 2158            _subscriptions: (!is_minimap)
 2159                .then(|| {
 2160                    vec![
 2161                        cx.observe(&buffer, Self::on_buffer_changed),
 2162                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2163                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2164                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2165                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2166                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2167                        cx.observe_window_activation(window, |editor, window, cx| {
 2168                            let active = window.is_window_active();
 2169                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2170                                if active {
 2171                                    blink_manager.enable(cx);
 2172                                } else {
 2173                                    blink_manager.disable(cx);
 2174                                }
 2175                            });
 2176                            if active {
 2177                                editor.show_mouse_cursor(cx);
 2178                            }
 2179                        }),
 2180                    ]
 2181                })
 2182                .unwrap_or_default(),
 2183            tasks_update_task: None,
 2184            pull_diagnostics_task: Task::ready(()),
 2185            colors: None,
 2186            next_color_inlay_id: 0,
 2187            linked_edit_ranges: Default::default(),
 2188            in_project_search: false,
 2189            previous_search_ranges: None,
 2190            breadcrumb_header: None,
 2191            focused_block: None,
 2192            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2193            addons: HashMap::default(),
 2194            registered_buffers: HashMap::default(),
 2195            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2196            selection_mark_mode: false,
 2197            toggle_fold_multiple_buffers: Task::ready(()),
 2198            serialize_selections: Task::ready(()),
 2199            serialize_folds: Task::ready(()),
 2200            text_style_refinement: None,
 2201            load_diff_task: load_uncommitted_diff,
 2202            temporary_diff_override: false,
 2203            mouse_cursor_hidden: false,
 2204            minimap: None,
 2205            hide_mouse_mode: EditorSettings::get_global(cx)
 2206                .hide_mouse
 2207                .unwrap_or_default(),
 2208            change_list: ChangeList::new(),
 2209            mode,
 2210            selection_drag_state: SelectionDragState::None,
 2211            folding_newlines: Task::ready(()),
 2212        };
 2213
 2214        if is_minimap {
 2215            return editor;
 2216        }
 2217
 2218        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2219            editor
 2220                ._subscriptions
 2221                .push(cx.observe(breakpoints, |_, _, cx| {
 2222                    cx.notify();
 2223                }));
 2224        }
 2225        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2226        editor._subscriptions.extend(project_subscriptions);
 2227
 2228        editor._subscriptions.push(cx.subscribe_in(
 2229            &cx.entity(),
 2230            window,
 2231            |editor, _, e: &EditorEvent, window, cx| match e {
 2232                EditorEvent::ScrollPositionChanged { local, .. } => {
 2233                    if *local {
 2234                        let new_anchor = editor.scroll_manager.anchor();
 2235                        let snapshot = editor.snapshot(window, cx);
 2236                        editor.update_restoration_data(cx, move |data| {
 2237                            data.scroll_position = (
 2238                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2239                                new_anchor.offset,
 2240                            );
 2241                        });
 2242                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2243                        editor.inline_blame_popover.take();
 2244                    }
 2245                }
 2246                EditorEvent::Edited { .. } => {
 2247                    if !vim_enabled(cx) {
 2248                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2249                        let pop_state = editor
 2250                            .change_list
 2251                            .last()
 2252                            .map(|previous| {
 2253                                previous.len() == selections.len()
 2254                                    && previous.iter().enumerate().all(|(ix, p)| {
 2255                                        p.to_display_point(&map).row()
 2256                                            == selections[ix].head().row()
 2257                                    })
 2258                            })
 2259                            .unwrap_or(false);
 2260                        let new_positions = selections
 2261                            .into_iter()
 2262                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2263                            .collect();
 2264                        editor
 2265                            .change_list
 2266                            .push_to_change_list(pop_state, new_positions);
 2267                    }
 2268                }
 2269                _ => (),
 2270            },
 2271        ));
 2272
 2273        if let Some(dap_store) = editor
 2274            .project
 2275            .as_ref()
 2276            .map(|project| project.read(cx).dap_store())
 2277        {
 2278            let weak_editor = cx.weak_entity();
 2279
 2280            editor
 2281                ._subscriptions
 2282                .push(
 2283                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2284                        let session_entity = cx.entity();
 2285                        weak_editor
 2286                            .update(cx, |editor, cx| {
 2287                                editor._subscriptions.push(
 2288                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2289                                );
 2290                            })
 2291                            .ok();
 2292                    }),
 2293                );
 2294
 2295            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2296                editor
 2297                    ._subscriptions
 2298                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2299            }
 2300        }
 2301
 2302        // skip adding the initial selection to selection history
 2303        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2304        editor.end_selection(window, cx);
 2305        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2306
 2307        editor.scroll_manager.show_scrollbars(window, cx);
 2308        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2309
 2310        if full_mode {
 2311            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2312            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2313
 2314            if editor.git_blame_inline_enabled {
 2315                editor.start_git_blame_inline(false, window, cx);
 2316            }
 2317
 2318            editor.go_to_active_debug_line(window, cx);
 2319
 2320            if let Some(buffer) = buffer.read(cx).as_singleton()
 2321                && let Some(project) = editor.project()
 2322            {
 2323                let handle = project.update(cx, |project, cx| {
 2324                    project.register_buffer_with_language_servers(&buffer, cx)
 2325                });
 2326                editor
 2327                    .registered_buffers
 2328                    .insert(buffer.read(cx).remote_id(), handle);
 2329            }
 2330
 2331            editor.minimap =
 2332                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2333            editor.colors = Some(LspColorData::new(cx));
 2334            editor.update_lsp_data(false, None, window, cx);
 2335        }
 2336
 2337        if editor.mode.is_full() {
 2338            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2339        }
 2340
 2341        editor
 2342    }
 2343
 2344    pub fn deploy_mouse_context_menu(
 2345        &mut self,
 2346        position: gpui::Point<Pixels>,
 2347        context_menu: Entity<ContextMenu>,
 2348        window: &mut Window,
 2349        cx: &mut Context<Self>,
 2350    ) {
 2351        self.mouse_context_menu = Some(MouseContextMenu::new(
 2352            self,
 2353            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2354            context_menu,
 2355            window,
 2356            cx,
 2357        ));
 2358    }
 2359
 2360    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2361        self.mouse_context_menu
 2362            .as_ref()
 2363            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2364    }
 2365
 2366    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2367        if self
 2368            .selections
 2369            .pending
 2370            .as_ref()
 2371            .is_some_and(|pending_selection| {
 2372                let snapshot = self.buffer().read(cx).snapshot(cx);
 2373                pending_selection
 2374                    .selection
 2375                    .range()
 2376                    .includes(range, &snapshot)
 2377            })
 2378        {
 2379            return true;
 2380        }
 2381
 2382        self.selections
 2383            .disjoint_in_range::<usize>(range.clone(), cx)
 2384            .into_iter()
 2385            .any(|selection| {
 2386                // This is needed to cover a corner case, if we just check for an existing
 2387                // selection in the fold range, having a cursor at the start of the fold
 2388                // marks it as selected. Non-empty selections don't cause this.
 2389                let length = selection.end - selection.start;
 2390                length > 0
 2391            })
 2392    }
 2393
 2394    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2395        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2396    }
 2397
 2398    fn key_context_internal(
 2399        &self,
 2400        has_active_edit_prediction: bool,
 2401        window: &Window,
 2402        cx: &App,
 2403    ) -> KeyContext {
 2404        let mut key_context = KeyContext::new_with_defaults();
 2405        key_context.add("Editor");
 2406        let mode = match self.mode {
 2407            EditorMode::SingleLine { .. } => "single_line",
 2408            EditorMode::AutoHeight { .. } => "auto_height",
 2409            EditorMode::Minimap { .. } => "minimap",
 2410            EditorMode::Full { .. } => "full",
 2411        };
 2412
 2413        if EditorSettings::jupyter_enabled(cx) {
 2414            key_context.add("jupyter");
 2415        }
 2416
 2417        key_context.set("mode", mode);
 2418        if self.pending_rename.is_some() {
 2419            key_context.add("renaming");
 2420        }
 2421
 2422        match self.context_menu.borrow().as_ref() {
 2423            Some(CodeContextMenu::Completions(menu)) => {
 2424                if menu.visible() {
 2425                    key_context.add("menu");
 2426                    key_context.add("showing_completions");
 2427                }
 2428            }
 2429            Some(CodeContextMenu::CodeActions(menu)) => {
 2430                if menu.visible() {
 2431                    key_context.add("menu");
 2432                    key_context.add("showing_code_actions")
 2433                }
 2434            }
 2435            None => {}
 2436        }
 2437
 2438        if self.signature_help_state.has_multiple_signatures() {
 2439            key_context.add("showing_signature_help");
 2440        }
 2441
 2442        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2443        if !self.focus_handle(cx).contains_focused(window, cx)
 2444            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2445        {
 2446            for addon in self.addons.values() {
 2447                addon.extend_key_context(&mut key_context, cx)
 2448            }
 2449        }
 2450
 2451        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2452            if let Some(extension) = singleton_buffer
 2453                .read(cx)
 2454                .file()
 2455                .and_then(|file| file.path().extension()?.to_str())
 2456            {
 2457                key_context.set("extension", extension.to_string());
 2458            }
 2459        } else {
 2460            key_context.add("multibuffer");
 2461        }
 2462
 2463        if has_active_edit_prediction {
 2464            if self.edit_prediction_in_conflict() {
 2465                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2466            } else {
 2467                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2468                key_context.add("copilot_suggestion");
 2469            }
 2470        }
 2471
 2472        if self.selection_mark_mode {
 2473            key_context.add("selection_mode");
 2474        }
 2475
 2476        key_context
 2477    }
 2478
 2479    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2480        if self.mouse_cursor_hidden {
 2481            self.mouse_cursor_hidden = false;
 2482            cx.notify();
 2483        }
 2484    }
 2485
 2486    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2487        let hide_mouse_cursor = match origin {
 2488            HideMouseCursorOrigin::TypingAction => {
 2489                matches!(
 2490                    self.hide_mouse_mode,
 2491                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2492                )
 2493            }
 2494            HideMouseCursorOrigin::MovementAction => {
 2495                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2496            }
 2497        };
 2498        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2499            self.mouse_cursor_hidden = hide_mouse_cursor;
 2500            cx.notify();
 2501        }
 2502    }
 2503
 2504    pub fn edit_prediction_in_conflict(&self) -> bool {
 2505        if !self.show_edit_predictions_in_menu() {
 2506            return false;
 2507        }
 2508
 2509        let showing_completions = self
 2510            .context_menu
 2511            .borrow()
 2512            .as_ref()
 2513            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2514
 2515        showing_completions
 2516            || self.edit_prediction_requires_modifier()
 2517            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2518            // bindings to insert tab characters.
 2519            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2520    }
 2521
 2522    pub fn accept_edit_prediction_keybind(
 2523        &self,
 2524        accept_partial: bool,
 2525        window: &Window,
 2526        cx: &App,
 2527    ) -> AcceptEditPredictionBinding {
 2528        let key_context = self.key_context_internal(true, window, cx);
 2529        let in_conflict = self.edit_prediction_in_conflict();
 2530
 2531        let bindings = if accept_partial {
 2532            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2533        } else {
 2534            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2535        };
 2536
 2537        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2538        // just the first one.
 2539        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2540            !in_conflict
 2541                || binding
 2542                    .keystrokes()
 2543                    .first()
 2544                    .is_some_and(|keystroke| keystroke.modifiers.modified())
 2545        }))
 2546    }
 2547
 2548    pub fn new_file(
 2549        workspace: &mut Workspace,
 2550        _: &workspace::NewFile,
 2551        window: &mut Window,
 2552        cx: &mut Context<Workspace>,
 2553    ) {
 2554        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2555            "Failed to create buffer",
 2556            window,
 2557            cx,
 2558            |e, _, _| match e.error_code() {
 2559                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2560                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2561                e.error_tag("required").unwrap_or("the latest version")
 2562            )),
 2563                _ => None,
 2564            },
 2565        );
 2566    }
 2567
 2568    pub fn new_in_workspace(
 2569        workspace: &mut Workspace,
 2570        window: &mut Window,
 2571        cx: &mut Context<Workspace>,
 2572    ) -> Task<Result<Entity<Editor>>> {
 2573        let project = workspace.project().clone();
 2574        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2575
 2576        cx.spawn_in(window, async move |workspace, cx| {
 2577            let buffer = create.await?;
 2578            workspace.update_in(cx, |workspace, window, cx| {
 2579                let editor =
 2580                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2581                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2582                editor
 2583            })
 2584        })
 2585    }
 2586
 2587    fn new_file_vertical(
 2588        workspace: &mut Workspace,
 2589        _: &workspace::NewFileSplitVertical,
 2590        window: &mut Window,
 2591        cx: &mut Context<Workspace>,
 2592    ) {
 2593        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2594    }
 2595
 2596    fn new_file_horizontal(
 2597        workspace: &mut Workspace,
 2598        _: &workspace::NewFileSplitHorizontal,
 2599        window: &mut Window,
 2600        cx: &mut Context<Workspace>,
 2601    ) {
 2602        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2603    }
 2604
 2605    fn new_file_in_direction(
 2606        workspace: &mut Workspace,
 2607        direction: SplitDirection,
 2608        window: &mut Window,
 2609        cx: &mut Context<Workspace>,
 2610    ) {
 2611        let project = workspace.project().clone();
 2612        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2613
 2614        cx.spawn_in(window, async move |workspace, cx| {
 2615            let buffer = create.await?;
 2616            workspace.update_in(cx, move |workspace, window, cx| {
 2617                workspace.split_item(
 2618                    direction,
 2619                    Box::new(
 2620                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2621                    ),
 2622                    window,
 2623                    cx,
 2624                )
 2625            })?;
 2626            anyhow::Ok(())
 2627        })
 2628        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2629            match e.error_code() {
 2630                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2631                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2632                e.error_tag("required").unwrap_or("the latest version")
 2633            )),
 2634                _ => None,
 2635            }
 2636        });
 2637    }
 2638
 2639    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2640        self.leader_id
 2641    }
 2642
 2643    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2644        &self.buffer
 2645    }
 2646
 2647    pub fn project(&self) -> Option<&Entity<Project>> {
 2648        self.project.as_ref()
 2649    }
 2650
 2651    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2652        self.workspace.as_ref()?.0.upgrade()
 2653    }
 2654
 2655    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2656        self.buffer().read(cx).title(cx)
 2657    }
 2658
 2659    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2660        let git_blame_gutter_max_author_length = self
 2661            .render_git_blame_gutter(cx)
 2662            .then(|| {
 2663                if let Some(blame) = self.blame.as_ref() {
 2664                    let max_author_length =
 2665                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2666                    Some(max_author_length)
 2667                } else {
 2668                    None
 2669                }
 2670            })
 2671            .flatten();
 2672
 2673        EditorSnapshot {
 2674            mode: self.mode.clone(),
 2675            show_gutter: self.show_gutter,
 2676            show_line_numbers: self.show_line_numbers,
 2677            show_git_diff_gutter: self.show_git_diff_gutter,
 2678            show_code_actions: self.show_code_actions,
 2679            show_runnables: self.show_runnables,
 2680            show_breakpoints: self.show_breakpoints,
 2681            git_blame_gutter_max_author_length,
 2682            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2683            scroll_anchor: self.scroll_manager.anchor(),
 2684            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2685            placeholder_text: self.placeholder_text.clone(),
 2686            is_focused: self.focus_handle.is_focused(window),
 2687            current_line_highlight: self
 2688                .current_line_highlight
 2689                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2690            gutter_hovered: self.gutter_hovered,
 2691        }
 2692    }
 2693
 2694    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2695        self.buffer.read(cx).language_at(point, cx)
 2696    }
 2697
 2698    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2699        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2700    }
 2701
 2702    pub fn active_excerpt(
 2703        &self,
 2704        cx: &App,
 2705    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2706        self.buffer
 2707            .read(cx)
 2708            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2709    }
 2710
 2711    pub fn mode(&self) -> &EditorMode {
 2712        &self.mode
 2713    }
 2714
 2715    pub fn set_mode(&mut self, mode: EditorMode) {
 2716        self.mode = mode;
 2717    }
 2718
 2719    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2720        self.collaboration_hub.as_deref()
 2721    }
 2722
 2723    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2724        self.collaboration_hub = Some(hub);
 2725    }
 2726
 2727    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2728        self.in_project_search = in_project_search;
 2729    }
 2730
 2731    pub fn set_custom_context_menu(
 2732        &mut self,
 2733        f: impl 'static
 2734        + Fn(
 2735            &mut Self,
 2736            DisplayPoint,
 2737            &mut Window,
 2738            &mut Context<Self>,
 2739        ) -> Option<Entity<ui::ContextMenu>>,
 2740    ) {
 2741        self.custom_context_menu = Some(Box::new(f))
 2742    }
 2743
 2744    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2745        self.completion_provider = provider;
 2746    }
 2747
 2748    #[cfg(any(test, feature = "test-support"))]
 2749    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2750        self.completion_provider.clone()
 2751    }
 2752
 2753    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2754        self.semantics_provider.clone()
 2755    }
 2756
 2757    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2758        self.semantics_provider = provider;
 2759    }
 2760
 2761    pub fn set_edit_prediction_provider<T>(
 2762        &mut self,
 2763        provider: Option<Entity<T>>,
 2764        window: &mut Window,
 2765        cx: &mut Context<Self>,
 2766    ) where
 2767        T: EditPredictionProvider,
 2768    {
 2769        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2770            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2771                if this.focus_handle.is_focused(window) {
 2772                    this.update_visible_edit_prediction(window, cx);
 2773                }
 2774            }),
 2775            provider: Arc::new(provider),
 2776        });
 2777        self.update_edit_prediction_settings(cx);
 2778        self.refresh_edit_prediction(false, false, window, cx);
 2779    }
 2780
 2781    pub fn placeholder_text(&self) -> Option<&str> {
 2782        self.placeholder_text.as_deref()
 2783    }
 2784
 2785    pub fn set_placeholder_text(
 2786        &mut self,
 2787        placeholder_text: impl Into<Arc<str>>,
 2788        cx: &mut Context<Self>,
 2789    ) {
 2790        let placeholder_text = Some(placeholder_text.into());
 2791        if self.placeholder_text != placeholder_text {
 2792            self.placeholder_text = placeholder_text;
 2793            cx.notify();
 2794        }
 2795    }
 2796
 2797    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2798        self.cursor_shape = cursor_shape;
 2799
 2800        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2801        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2802
 2803        cx.notify();
 2804    }
 2805
 2806    pub fn set_current_line_highlight(
 2807        &mut self,
 2808        current_line_highlight: Option<CurrentLineHighlight>,
 2809    ) {
 2810        self.current_line_highlight = current_line_highlight;
 2811    }
 2812
 2813    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2814        self.collapse_matches = collapse_matches;
 2815    }
 2816
 2817    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2818        let buffers = self.buffer.read(cx).all_buffers();
 2819        let Some(project) = self.project.as_ref() else {
 2820            return;
 2821        };
 2822        project.update(cx, |project, cx| {
 2823            for buffer in buffers {
 2824                self.registered_buffers
 2825                    .entry(buffer.read(cx).remote_id())
 2826                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2827            }
 2828        })
 2829    }
 2830
 2831    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2832        if self.collapse_matches {
 2833            return range.start..range.start;
 2834        }
 2835        range.clone()
 2836    }
 2837
 2838    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2839        if self.display_map.read(cx).clip_at_line_ends != clip {
 2840            self.display_map
 2841                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2842        }
 2843    }
 2844
 2845    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2846        self.input_enabled = input_enabled;
 2847    }
 2848
 2849    pub fn set_edit_predictions_hidden_for_vim_mode(
 2850        &mut self,
 2851        hidden: bool,
 2852        window: &mut Window,
 2853        cx: &mut Context<Self>,
 2854    ) {
 2855        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2856            self.edit_predictions_hidden_for_vim_mode = hidden;
 2857            if hidden {
 2858                self.update_visible_edit_prediction(window, cx);
 2859            } else {
 2860                self.refresh_edit_prediction(true, false, window, cx);
 2861            }
 2862        }
 2863    }
 2864
 2865    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2866        self.menu_edit_predictions_policy = value;
 2867    }
 2868
 2869    pub fn set_autoindent(&mut self, autoindent: bool) {
 2870        if autoindent {
 2871            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2872        } else {
 2873            self.autoindent_mode = None;
 2874        }
 2875    }
 2876
 2877    pub fn read_only(&self, cx: &App) -> bool {
 2878        self.read_only || self.buffer.read(cx).read_only()
 2879    }
 2880
 2881    pub fn set_read_only(&mut self, read_only: bool) {
 2882        self.read_only = read_only;
 2883    }
 2884
 2885    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2886        self.use_autoclose = autoclose;
 2887    }
 2888
 2889    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2890        self.use_auto_surround = auto_surround;
 2891    }
 2892
 2893    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2894        self.auto_replace_emoji_shortcode = auto_replace;
 2895    }
 2896
 2897    pub fn toggle_edit_predictions(
 2898        &mut self,
 2899        _: &ToggleEditPrediction,
 2900        window: &mut Window,
 2901        cx: &mut Context<Self>,
 2902    ) {
 2903        if self.show_edit_predictions_override.is_some() {
 2904            self.set_show_edit_predictions(None, window, cx);
 2905        } else {
 2906            let show_edit_predictions = !self.edit_predictions_enabled();
 2907            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2908        }
 2909    }
 2910
 2911    pub fn set_show_edit_predictions(
 2912        &mut self,
 2913        show_edit_predictions: Option<bool>,
 2914        window: &mut Window,
 2915        cx: &mut Context<Self>,
 2916    ) {
 2917        self.show_edit_predictions_override = show_edit_predictions;
 2918        self.update_edit_prediction_settings(cx);
 2919
 2920        if let Some(false) = show_edit_predictions {
 2921            self.discard_edit_prediction(false, cx);
 2922        } else {
 2923            self.refresh_edit_prediction(false, true, window, cx);
 2924        }
 2925    }
 2926
 2927    fn edit_predictions_disabled_in_scope(
 2928        &self,
 2929        buffer: &Entity<Buffer>,
 2930        buffer_position: language::Anchor,
 2931        cx: &App,
 2932    ) -> bool {
 2933        let snapshot = buffer.read(cx).snapshot();
 2934        let settings = snapshot.settings_at(buffer_position, cx);
 2935
 2936        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2937            return false;
 2938        };
 2939
 2940        scope.override_name().is_some_and(|scope_name| {
 2941            settings
 2942                .edit_predictions_disabled_in
 2943                .iter()
 2944                .any(|s| s == scope_name)
 2945        })
 2946    }
 2947
 2948    pub fn set_use_modal_editing(&mut self, to: bool) {
 2949        self.use_modal_editing = to;
 2950    }
 2951
 2952    pub fn use_modal_editing(&self) -> bool {
 2953        self.use_modal_editing
 2954    }
 2955
 2956    fn selections_did_change(
 2957        &mut self,
 2958        local: bool,
 2959        old_cursor_position: &Anchor,
 2960        effects: SelectionEffects,
 2961        window: &mut Window,
 2962        cx: &mut Context<Self>,
 2963    ) {
 2964        window.invalidate_character_coordinates();
 2965
 2966        // Copy selections to primary selection buffer
 2967        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2968        if local {
 2969            let selections = self.selections.all::<usize>(cx);
 2970            let buffer_handle = self.buffer.read(cx).read(cx);
 2971
 2972            let mut text = String::new();
 2973            for (index, selection) in selections.iter().enumerate() {
 2974                let text_for_selection = buffer_handle
 2975                    .text_for_range(selection.start..selection.end)
 2976                    .collect::<String>();
 2977
 2978                text.push_str(&text_for_selection);
 2979                if index != selections.len() - 1 {
 2980                    text.push('\n');
 2981                }
 2982            }
 2983
 2984            if !text.is_empty() {
 2985                cx.write_to_primary(ClipboardItem::new_string(text));
 2986            }
 2987        }
 2988
 2989        let selection_anchors = self.selections.disjoint_anchors();
 2990
 2991        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2992            self.buffer.update(cx, |buffer, cx| {
 2993                buffer.set_active_selections(
 2994                    &selection_anchors,
 2995                    self.selections.line_mode,
 2996                    self.cursor_shape,
 2997                    cx,
 2998                )
 2999            });
 3000        }
 3001        let display_map = self
 3002            .display_map
 3003            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3004        let buffer = &display_map.buffer_snapshot;
 3005        if self.selections.count() == 1 {
 3006            self.add_selections_state = None;
 3007        }
 3008        self.select_next_state = None;
 3009        self.select_prev_state = None;
 3010        self.select_syntax_node_history.try_clear();
 3011        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3012        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3013        self.take_rename(false, window, cx);
 3014
 3015        let newest_selection = self.selections.newest_anchor();
 3016        let new_cursor_position = newest_selection.head();
 3017        let selection_start = newest_selection.start;
 3018
 3019        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3020            self.push_to_nav_history(
 3021                *old_cursor_position,
 3022                Some(new_cursor_position.to_point(buffer)),
 3023                false,
 3024                effects.nav_history == Some(true),
 3025                cx,
 3026            );
 3027        }
 3028
 3029        if local {
 3030            if let Some(buffer_id) = new_cursor_position.buffer_id
 3031                && !self.registered_buffers.contains_key(&buffer_id)
 3032                && let Some(project) = self.project.as_ref()
 3033            {
 3034                project.update(cx, |project, cx| {
 3035                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3036                        return;
 3037                    };
 3038                    self.registered_buffers.insert(
 3039                        buffer_id,
 3040                        project.register_buffer_with_language_servers(&buffer, cx),
 3041                    );
 3042                })
 3043            }
 3044
 3045            let mut context_menu = self.context_menu.borrow_mut();
 3046            let completion_menu = match context_menu.as_ref() {
 3047                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3048                Some(CodeContextMenu::CodeActions(_)) => {
 3049                    *context_menu = None;
 3050                    None
 3051                }
 3052                None => None,
 3053            };
 3054            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3055            drop(context_menu);
 3056
 3057            if effects.completions
 3058                && let Some(completion_position) = completion_position
 3059            {
 3060                let start_offset = selection_start.to_offset(buffer);
 3061                let position_matches = start_offset == completion_position.to_offset(buffer);
 3062                let continue_showing = if position_matches {
 3063                    if self.snippet_stack.is_empty() {
 3064                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3065                    } else {
 3066                        // Snippet choices can be shown even when the cursor is in whitespace.
 3067                        // Dismissing the menu with actions like backspace is handled by
 3068                        // invalidation regions.
 3069                        true
 3070                    }
 3071                } else {
 3072                    false
 3073                };
 3074
 3075                if continue_showing {
 3076                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3077                } else {
 3078                    self.hide_context_menu(window, cx);
 3079                }
 3080            }
 3081
 3082            hide_hover(self, cx);
 3083
 3084            if old_cursor_position.to_display_point(&display_map).row()
 3085                != new_cursor_position.to_display_point(&display_map).row()
 3086            {
 3087                self.available_code_actions.take();
 3088            }
 3089            self.refresh_code_actions(window, cx);
 3090            self.refresh_document_highlights(cx);
 3091            self.refresh_selected_text_highlights(false, window, cx);
 3092            refresh_matching_bracket_highlights(self, window, cx);
 3093            self.update_visible_edit_prediction(window, cx);
 3094            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3095            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3096            self.inline_blame_popover.take();
 3097            if self.git_blame_inline_enabled {
 3098                self.start_inline_blame_timer(window, cx);
 3099            }
 3100        }
 3101
 3102        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3103        cx.emit(EditorEvent::SelectionsChanged { local });
 3104
 3105        let selections = &self.selections.disjoint;
 3106        if selections.len() == 1 {
 3107            cx.emit(SearchEvent::ActiveMatchChanged)
 3108        }
 3109        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3110            let inmemory_selections = selections
 3111                .iter()
 3112                .map(|s| {
 3113                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3114                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3115                })
 3116                .collect();
 3117            self.update_restoration_data(cx, |data| {
 3118                data.selections = inmemory_selections;
 3119            });
 3120
 3121            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3122                && let Some(workspace_id) =
 3123                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3124            {
 3125                let snapshot = self.buffer().read(cx).snapshot(cx);
 3126                let selections = selections.clone();
 3127                let background_executor = cx.background_executor().clone();
 3128                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3129                self.serialize_selections = cx.background_spawn(async move {
 3130                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3131                            let db_selections = selections
 3132                                .iter()
 3133                                .map(|selection| {
 3134                                    (
 3135                                        selection.start.to_offset(&snapshot),
 3136                                        selection.end.to_offset(&snapshot),
 3137                                    )
 3138                                })
 3139                                .collect();
 3140
 3141                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3142                                .await
 3143                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3144                                .log_err();
 3145                        });
 3146            }
 3147        }
 3148
 3149        cx.notify();
 3150    }
 3151
 3152    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3153        use text::ToOffset as _;
 3154        use text::ToPoint as _;
 3155
 3156        if self.mode.is_minimap()
 3157            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3158        {
 3159            return;
 3160        }
 3161
 3162        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3163            return;
 3164        };
 3165
 3166        let snapshot = singleton.read(cx).snapshot();
 3167        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3168            let display_snapshot = display_map.snapshot(cx);
 3169
 3170            display_snapshot
 3171                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3172                .map(|fold| {
 3173                    fold.range.start.text_anchor.to_point(&snapshot)
 3174                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3175                })
 3176                .collect()
 3177        });
 3178        self.update_restoration_data(cx, |data| {
 3179            data.folds = inmemory_folds;
 3180        });
 3181
 3182        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3183            return;
 3184        };
 3185        let background_executor = cx.background_executor().clone();
 3186        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3187        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3188            display_map
 3189                .snapshot(cx)
 3190                .folds_in_range(0..snapshot.len())
 3191                .map(|fold| {
 3192                    (
 3193                        fold.range.start.text_anchor.to_offset(&snapshot),
 3194                        fold.range.end.text_anchor.to_offset(&snapshot),
 3195                    )
 3196                })
 3197                .collect()
 3198        });
 3199        self.serialize_folds = cx.background_spawn(async move {
 3200            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3201            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3202                .await
 3203                .with_context(|| {
 3204                    format!(
 3205                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3206                    )
 3207                })
 3208                .log_err();
 3209        });
 3210    }
 3211
 3212    pub fn sync_selections(
 3213        &mut self,
 3214        other: Entity<Editor>,
 3215        cx: &mut Context<Self>,
 3216    ) -> gpui::Subscription {
 3217        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3218        self.selections.change_with(cx, |selections| {
 3219            selections.select_anchors(other_selections);
 3220        });
 3221
 3222        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3223            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3224                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3225                if other_selections.is_empty() {
 3226                    return;
 3227                }
 3228                this.selections.change_with(cx, |selections| {
 3229                    selections.select_anchors(other_selections);
 3230                });
 3231            }
 3232        });
 3233
 3234        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3235            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3236                let these_selections = this.selections.disjoint.to_vec();
 3237                if these_selections.is_empty() {
 3238                    return;
 3239                }
 3240                other.update(cx, |other_editor, cx| {
 3241                    other_editor.selections.change_with(cx, |selections| {
 3242                        selections.select_anchors(these_selections);
 3243                    })
 3244                });
 3245            }
 3246        });
 3247
 3248        Subscription::join(other_subscription, this_subscription)
 3249    }
 3250
 3251    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3252    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3253    /// effects of selection change occur at the end of the transaction.
 3254    pub fn change_selections<R>(
 3255        &mut self,
 3256        effects: SelectionEffects,
 3257        window: &mut Window,
 3258        cx: &mut Context<Self>,
 3259        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3260    ) -> R {
 3261        if let Some(state) = &mut self.deferred_selection_effects_state {
 3262            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3263            state.effects.completions = effects.completions;
 3264            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3265            let (changed, result) = self.selections.change_with(cx, change);
 3266            state.changed |= changed;
 3267            return result;
 3268        }
 3269        let mut state = DeferredSelectionEffectsState {
 3270            changed: false,
 3271            effects,
 3272            old_cursor_position: self.selections.newest_anchor().head(),
 3273            history_entry: SelectionHistoryEntry {
 3274                selections: self.selections.disjoint_anchors(),
 3275                select_next_state: self.select_next_state.clone(),
 3276                select_prev_state: self.select_prev_state.clone(),
 3277                add_selections_state: self.add_selections_state.clone(),
 3278            },
 3279        };
 3280        let (changed, result) = self.selections.change_with(cx, change);
 3281        state.changed = state.changed || changed;
 3282        if self.defer_selection_effects {
 3283            self.deferred_selection_effects_state = Some(state);
 3284        } else {
 3285            self.apply_selection_effects(state, window, cx);
 3286        }
 3287        result
 3288    }
 3289
 3290    /// Defers the effects of selection change, so that the effects of multiple calls to
 3291    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3292    /// to selection history and the state of popovers based on selection position aren't
 3293    /// erroneously updated.
 3294    pub fn with_selection_effects_deferred<R>(
 3295        &mut self,
 3296        window: &mut Window,
 3297        cx: &mut Context<Self>,
 3298        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3299    ) -> R {
 3300        let already_deferred = self.defer_selection_effects;
 3301        self.defer_selection_effects = true;
 3302        let result = update(self, window, cx);
 3303        if !already_deferred {
 3304            self.defer_selection_effects = false;
 3305            if let Some(state) = self.deferred_selection_effects_state.take() {
 3306                self.apply_selection_effects(state, window, cx);
 3307            }
 3308        }
 3309        result
 3310    }
 3311
 3312    fn apply_selection_effects(
 3313        &mut self,
 3314        state: DeferredSelectionEffectsState,
 3315        window: &mut Window,
 3316        cx: &mut Context<Self>,
 3317    ) {
 3318        if state.changed {
 3319            self.selection_history.push(state.history_entry);
 3320
 3321            if let Some(autoscroll) = state.effects.scroll {
 3322                self.request_autoscroll(autoscroll, cx);
 3323            }
 3324
 3325            let old_cursor_position = &state.old_cursor_position;
 3326
 3327            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3328
 3329            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3330                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3331            }
 3332        }
 3333    }
 3334
 3335    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3336    where
 3337        I: IntoIterator<Item = (Range<S>, T)>,
 3338        S: ToOffset,
 3339        T: Into<Arc<str>>,
 3340    {
 3341        if self.read_only(cx) {
 3342            return;
 3343        }
 3344
 3345        self.buffer
 3346            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3347    }
 3348
 3349    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3350    where
 3351        I: IntoIterator<Item = (Range<S>, T)>,
 3352        S: ToOffset,
 3353        T: Into<Arc<str>>,
 3354    {
 3355        if self.read_only(cx) {
 3356            return;
 3357        }
 3358
 3359        self.buffer.update(cx, |buffer, cx| {
 3360            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3361        });
 3362    }
 3363
 3364    pub fn edit_with_block_indent<I, S, T>(
 3365        &mut self,
 3366        edits: I,
 3367        original_indent_columns: Vec<Option<u32>>,
 3368        cx: &mut Context<Self>,
 3369    ) where
 3370        I: IntoIterator<Item = (Range<S>, T)>,
 3371        S: ToOffset,
 3372        T: Into<Arc<str>>,
 3373    {
 3374        if self.read_only(cx) {
 3375            return;
 3376        }
 3377
 3378        self.buffer.update(cx, |buffer, cx| {
 3379            buffer.edit(
 3380                edits,
 3381                Some(AutoindentMode::Block {
 3382                    original_indent_columns,
 3383                }),
 3384                cx,
 3385            )
 3386        });
 3387    }
 3388
 3389    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3390        self.hide_context_menu(window, cx);
 3391
 3392        match phase {
 3393            SelectPhase::Begin {
 3394                position,
 3395                add,
 3396                click_count,
 3397            } => self.begin_selection(position, add, click_count, window, cx),
 3398            SelectPhase::BeginColumnar {
 3399                position,
 3400                goal_column,
 3401                reset,
 3402                mode,
 3403            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3404            SelectPhase::Extend {
 3405                position,
 3406                click_count,
 3407            } => self.extend_selection(position, click_count, window, cx),
 3408            SelectPhase::Update {
 3409                position,
 3410                goal_column,
 3411                scroll_delta,
 3412            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3413            SelectPhase::End => self.end_selection(window, cx),
 3414        }
 3415    }
 3416
 3417    fn extend_selection(
 3418        &mut self,
 3419        position: DisplayPoint,
 3420        click_count: usize,
 3421        window: &mut Window,
 3422        cx: &mut Context<Self>,
 3423    ) {
 3424        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3425        let tail = self.selections.newest::<usize>(cx).tail();
 3426        self.begin_selection(position, false, click_count, window, cx);
 3427
 3428        let position = position.to_offset(&display_map, Bias::Left);
 3429        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3430
 3431        let mut pending_selection = self
 3432            .selections
 3433            .pending_anchor()
 3434            .expect("extend_selection not called with pending selection");
 3435        if position >= tail {
 3436            pending_selection.start = tail_anchor;
 3437        } else {
 3438            pending_selection.end = tail_anchor;
 3439            pending_selection.reversed = true;
 3440        }
 3441
 3442        let mut pending_mode = self.selections.pending_mode().unwrap();
 3443        match &mut pending_mode {
 3444            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3445            _ => {}
 3446        }
 3447
 3448        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3449            SelectionEffects::scroll(Autoscroll::fit())
 3450        } else {
 3451            SelectionEffects::no_scroll()
 3452        };
 3453
 3454        self.change_selections(effects, window, cx, |s| {
 3455            s.set_pending(pending_selection, pending_mode)
 3456        });
 3457    }
 3458
 3459    fn begin_selection(
 3460        &mut self,
 3461        position: DisplayPoint,
 3462        add: bool,
 3463        click_count: usize,
 3464        window: &mut Window,
 3465        cx: &mut Context<Self>,
 3466    ) {
 3467        if !self.focus_handle.is_focused(window) {
 3468            self.last_focused_descendant = None;
 3469            window.focus(&self.focus_handle);
 3470        }
 3471
 3472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3473        let buffer = &display_map.buffer_snapshot;
 3474        let position = display_map.clip_point(position, Bias::Left);
 3475
 3476        let start;
 3477        let end;
 3478        let mode;
 3479        let mut auto_scroll;
 3480        match click_count {
 3481            1 => {
 3482                start = buffer.anchor_before(position.to_point(&display_map));
 3483                end = start;
 3484                mode = SelectMode::Character;
 3485                auto_scroll = true;
 3486            }
 3487            2 => {
 3488                let position = display_map
 3489                    .clip_point(position, Bias::Left)
 3490                    .to_offset(&display_map, Bias::Left);
 3491                let (range, _) = buffer.surrounding_word(position, false);
 3492                start = buffer.anchor_before(range.start);
 3493                end = buffer.anchor_before(range.end);
 3494                mode = SelectMode::Word(start..end);
 3495                auto_scroll = true;
 3496            }
 3497            3 => {
 3498                let position = display_map
 3499                    .clip_point(position, Bias::Left)
 3500                    .to_point(&display_map);
 3501                let line_start = display_map.prev_line_boundary(position).0;
 3502                let next_line_start = buffer.clip_point(
 3503                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3504                    Bias::Left,
 3505                );
 3506                start = buffer.anchor_before(line_start);
 3507                end = buffer.anchor_before(next_line_start);
 3508                mode = SelectMode::Line(start..end);
 3509                auto_scroll = true;
 3510            }
 3511            _ => {
 3512                start = buffer.anchor_before(0);
 3513                end = buffer.anchor_before(buffer.len());
 3514                mode = SelectMode::All;
 3515                auto_scroll = false;
 3516            }
 3517        }
 3518        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3519
 3520        let point_to_delete: Option<usize> = {
 3521            let selected_points: Vec<Selection<Point>> =
 3522                self.selections.disjoint_in_range(start..end, cx);
 3523
 3524            if !add || click_count > 1 {
 3525                None
 3526            } else if !selected_points.is_empty() {
 3527                Some(selected_points[0].id)
 3528            } else {
 3529                let clicked_point_already_selected =
 3530                    self.selections.disjoint.iter().find(|selection| {
 3531                        selection.start.to_point(buffer) == start.to_point(buffer)
 3532                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3533                    });
 3534
 3535                clicked_point_already_selected.map(|selection| selection.id)
 3536            }
 3537        };
 3538
 3539        let selections_count = self.selections.count();
 3540        let effects = if auto_scroll {
 3541            SelectionEffects::default()
 3542        } else {
 3543            SelectionEffects::no_scroll()
 3544        };
 3545
 3546        self.change_selections(effects, window, cx, |s| {
 3547            if let Some(point_to_delete) = point_to_delete {
 3548                s.delete(point_to_delete);
 3549
 3550                if selections_count == 1 {
 3551                    s.set_pending_anchor_range(start..end, mode);
 3552                }
 3553            } else {
 3554                if !add {
 3555                    s.clear_disjoint();
 3556                }
 3557
 3558                s.set_pending_anchor_range(start..end, mode);
 3559            }
 3560        });
 3561    }
 3562
 3563    fn begin_columnar_selection(
 3564        &mut self,
 3565        position: DisplayPoint,
 3566        goal_column: u32,
 3567        reset: bool,
 3568        mode: ColumnarMode,
 3569        window: &mut Window,
 3570        cx: &mut Context<Self>,
 3571    ) {
 3572        if !self.focus_handle.is_focused(window) {
 3573            self.last_focused_descendant = None;
 3574            window.focus(&self.focus_handle);
 3575        }
 3576
 3577        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3578
 3579        if reset {
 3580            let pointer_position = display_map
 3581                .buffer_snapshot
 3582                .anchor_before(position.to_point(&display_map));
 3583
 3584            self.change_selections(
 3585                SelectionEffects::scroll(Autoscroll::newest()),
 3586                window,
 3587                cx,
 3588                |s| {
 3589                    s.clear_disjoint();
 3590                    s.set_pending_anchor_range(
 3591                        pointer_position..pointer_position,
 3592                        SelectMode::Character,
 3593                    );
 3594                },
 3595            );
 3596        };
 3597
 3598        let tail = self.selections.newest::<Point>(cx).tail();
 3599        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3600        self.columnar_selection_state = match mode {
 3601            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3602                selection_tail: selection_anchor,
 3603                display_point: if reset {
 3604                    if position.column() != goal_column {
 3605                        Some(DisplayPoint::new(position.row(), goal_column))
 3606                    } else {
 3607                        None
 3608                    }
 3609                } else {
 3610                    None
 3611                },
 3612            }),
 3613            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3614                selection_tail: selection_anchor,
 3615            }),
 3616        };
 3617
 3618        if !reset {
 3619            self.select_columns(position, goal_column, &display_map, window, cx);
 3620        }
 3621    }
 3622
 3623    fn update_selection(
 3624        &mut self,
 3625        position: DisplayPoint,
 3626        goal_column: u32,
 3627        scroll_delta: gpui::Point<f32>,
 3628        window: &mut Window,
 3629        cx: &mut Context<Self>,
 3630    ) {
 3631        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3632
 3633        if self.columnar_selection_state.is_some() {
 3634            self.select_columns(position, goal_column, &display_map, window, cx);
 3635        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3636            let buffer = &display_map.buffer_snapshot;
 3637            let head;
 3638            let tail;
 3639            let mode = self.selections.pending_mode().unwrap();
 3640            match &mode {
 3641                SelectMode::Character => {
 3642                    head = position.to_point(&display_map);
 3643                    tail = pending.tail().to_point(buffer);
 3644                }
 3645                SelectMode::Word(original_range) => {
 3646                    let offset = display_map
 3647                        .clip_point(position, Bias::Left)
 3648                        .to_offset(&display_map, Bias::Left);
 3649                    let original_range = original_range.to_offset(buffer);
 3650
 3651                    let head_offset = if buffer.is_inside_word(offset, false)
 3652                        || original_range.contains(&offset)
 3653                    {
 3654                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3655                        if word_range.start < original_range.start {
 3656                            word_range.start
 3657                        } else {
 3658                            word_range.end
 3659                        }
 3660                    } else {
 3661                        offset
 3662                    };
 3663
 3664                    head = head_offset.to_point(buffer);
 3665                    if head_offset <= original_range.start {
 3666                        tail = original_range.end.to_point(buffer);
 3667                    } else {
 3668                        tail = original_range.start.to_point(buffer);
 3669                    }
 3670                }
 3671                SelectMode::Line(original_range) => {
 3672                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3673
 3674                    let position = display_map
 3675                        .clip_point(position, Bias::Left)
 3676                        .to_point(&display_map);
 3677                    let line_start = display_map.prev_line_boundary(position).0;
 3678                    let next_line_start = buffer.clip_point(
 3679                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3680                        Bias::Left,
 3681                    );
 3682
 3683                    if line_start < original_range.start {
 3684                        head = line_start
 3685                    } else {
 3686                        head = next_line_start
 3687                    }
 3688
 3689                    if head <= original_range.start {
 3690                        tail = original_range.end;
 3691                    } else {
 3692                        tail = original_range.start;
 3693                    }
 3694                }
 3695                SelectMode::All => {
 3696                    return;
 3697                }
 3698            };
 3699
 3700            if head < tail {
 3701                pending.start = buffer.anchor_before(head);
 3702                pending.end = buffer.anchor_before(tail);
 3703                pending.reversed = true;
 3704            } else {
 3705                pending.start = buffer.anchor_before(tail);
 3706                pending.end = buffer.anchor_before(head);
 3707                pending.reversed = false;
 3708            }
 3709
 3710            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3711                s.set_pending(pending, mode);
 3712            });
 3713        } else {
 3714            log::error!("update_selection dispatched with no pending selection");
 3715            return;
 3716        }
 3717
 3718        self.apply_scroll_delta(scroll_delta, window, cx);
 3719        cx.notify();
 3720    }
 3721
 3722    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3723        self.columnar_selection_state.take();
 3724        if self.selections.pending_anchor().is_some() {
 3725            let selections = self.selections.all::<usize>(cx);
 3726            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3727                s.select(selections);
 3728                s.clear_pending();
 3729            });
 3730        }
 3731    }
 3732
 3733    fn select_columns(
 3734        &mut self,
 3735        head: DisplayPoint,
 3736        goal_column: u32,
 3737        display_map: &DisplaySnapshot,
 3738        window: &mut Window,
 3739        cx: &mut Context<Self>,
 3740    ) {
 3741        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3742            return;
 3743        };
 3744
 3745        let tail = match columnar_state {
 3746            ColumnarSelectionState::FromMouse {
 3747                selection_tail,
 3748                display_point,
 3749            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3750            ColumnarSelectionState::FromSelection { selection_tail } => {
 3751                selection_tail.to_display_point(display_map)
 3752            }
 3753        };
 3754
 3755        let start_row = cmp::min(tail.row(), head.row());
 3756        let end_row = cmp::max(tail.row(), head.row());
 3757        let start_column = cmp::min(tail.column(), goal_column);
 3758        let end_column = cmp::max(tail.column(), goal_column);
 3759        let reversed = start_column < tail.column();
 3760
 3761        let selection_ranges = (start_row.0..=end_row.0)
 3762            .map(DisplayRow)
 3763            .filter_map(|row| {
 3764                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3765                    || start_column <= display_map.line_len(row))
 3766                    && !display_map.is_block_line(row)
 3767                {
 3768                    let start = display_map
 3769                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3770                        .to_point(display_map);
 3771                    let end = display_map
 3772                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3773                        .to_point(display_map);
 3774                    if reversed {
 3775                        Some(end..start)
 3776                    } else {
 3777                        Some(start..end)
 3778                    }
 3779                } else {
 3780                    None
 3781                }
 3782            })
 3783            .collect::<Vec<_>>();
 3784
 3785        let ranges = match columnar_state {
 3786            ColumnarSelectionState::FromMouse { .. } => {
 3787                let mut non_empty_ranges = selection_ranges
 3788                    .iter()
 3789                    .filter(|selection_range| selection_range.start != selection_range.end)
 3790                    .peekable();
 3791                if non_empty_ranges.peek().is_some() {
 3792                    non_empty_ranges.cloned().collect()
 3793                } else {
 3794                    selection_ranges
 3795                }
 3796            }
 3797            _ => selection_ranges,
 3798        };
 3799
 3800        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3801            s.select_ranges(ranges);
 3802        });
 3803        cx.notify();
 3804    }
 3805
 3806    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3807        self.selections
 3808            .all_adjusted(cx)
 3809            .iter()
 3810            .any(|selection| !selection.is_empty())
 3811    }
 3812
 3813    pub fn has_pending_nonempty_selection(&self) -> bool {
 3814        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3815            Some(Selection { start, end, .. }) => start != end,
 3816            None => false,
 3817        };
 3818
 3819        pending_nonempty_selection
 3820            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3821    }
 3822
 3823    pub fn has_pending_selection(&self) -> bool {
 3824        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3825    }
 3826
 3827    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3828        self.selection_mark_mode = false;
 3829        self.selection_drag_state = SelectionDragState::None;
 3830
 3831        if self.clear_expanded_diff_hunks(cx) {
 3832            cx.notify();
 3833            return;
 3834        }
 3835        if self.dismiss_menus_and_popups(true, window, cx) {
 3836            return;
 3837        }
 3838
 3839        if self.mode.is_full()
 3840            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3841        {
 3842            return;
 3843        }
 3844
 3845        cx.propagate();
 3846    }
 3847
 3848    pub fn dismiss_menus_and_popups(
 3849        &mut self,
 3850        is_user_requested: bool,
 3851        window: &mut Window,
 3852        cx: &mut Context<Self>,
 3853    ) -> bool {
 3854        if self.take_rename(false, window, cx).is_some() {
 3855            return true;
 3856        }
 3857
 3858        if hide_hover(self, cx) {
 3859            return true;
 3860        }
 3861
 3862        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3863            return true;
 3864        }
 3865
 3866        if self.hide_context_menu(window, cx).is_some() {
 3867            return true;
 3868        }
 3869
 3870        if self.mouse_context_menu.take().is_some() {
 3871            return true;
 3872        }
 3873
 3874        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3875            return true;
 3876        }
 3877
 3878        if self.snippet_stack.pop().is_some() {
 3879            return true;
 3880        }
 3881
 3882        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3883            self.dismiss_diagnostics(cx);
 3884            return true;
 3885        }
 3886
 3887        false
 3888    }
 3889
 3890    fn linked_editing_ranges_for(
 3891        &self,
 3892        selection: Range<text::Anchor>,
 3893        cx: &App,
 3894    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3895        if self.linked_edit_ranges.is_empty() {
 3896            return None;
 3897        }
 3898        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3899            selection.end.buffer_id.and_then(|end_buffer_id| {
 3900                if selection.start.buffer_id != Some(end_buffer_id) {
 3901                    return None;
 3902                }
 3903                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3904                let snapshot = buffer.read(cx).snapshot();
 3905                self.linked_edit_ranges
 3906                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3907                    .map(|ranges| (ranges, snapshot, buffer))
 3908            })?;
 3909        use text::ToOffset as TO;
 3910        // find offset from the start of current range to current cursor position
 3911        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3912
 3913        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3914        let start_difference = start_offset - start_byte_offset;
 3915        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3916        let end_difference = end_offset - start_byte_offset;
 3917        // Current range has associated linked ranges.
 3918        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3919        for range in linked_ranges.iter() {
 3920            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3921            let end_offset = start_offset + end_difference;
 3922            let start_offset = start_offset + start_difference;
 3923            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3924                continue;
 3925            }
 3926            if self.selections.disjoint_anchor_ranges().any(|s| {
 3927                if s.start.buffer_id != selection.start.buffer_id
 3928                    || s.end.buffer_id != selection.end.buffer_id
 3929                {
 3930                    return false;
 3931                }
 3932                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3933                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3934            }) {
 3935                continue;
 3936            }
 3937            let start = buffer_snapshot.anchor_after(start_offset);
 3938            let end = buffer_snapshot.anchor_after(end_offset);
 3939            linked_edits
 3940                .entry(buffer.clone())
 3941                .or_default()
 3942                .push(start..end);
 3943        }
 3944        Some(linked_edits)
 3945    }
 3946
 3947    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3948        let text: Arc<str> = text.into();
 3949
 3950        if self.read_only(cx) {
 3951            return;
 3952        }
 3953
 3954        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3955
 3956        let selections = self.selections.all_adjusted(cx);
 3957        let mut bracket_inserted = false;
 3958        let mut edits = Vec::new();
 3959        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3960        let mut new_selections = Vec::with_capacity(selections.len());
 3961        let mut new_autoclose_regions = Vec::new();
 3962        let snapshot = self.buffer.read(cx).read(cx);
 3963        let mut clear_linked_edit_ranges = false;
 3964
 3965        for (selection, autoclose_region) in
 3966            self.selections_with_autoclose_regions(selections, &snapshot)
 3967        {
 3968            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3969                // Determine if the inserted text matches the opening or closing
 3970                // bracket of any of this language's bracket pairs.
 3971                let mut bracket_pair = None;
 3972                let mut is_bracket_pair_start = false;
 3973                let mut is_bracket_pair_end = false;
 3974                if !text.is_empty() {
 3975                    let mut bracket_pair_matching_end = None;
 3976                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3977                    //  and they are removing the character that triggered IME popup.
 3978                    for (pair, enabled) in scope.brackets() {
 3979                        if !pair.close && !pair.surround {
 3980                            continue;
 3981                        }
 3982
 3983                        if enabled && pair.start.ends_with(text.as_ref()) {
 3984                            let prefix_len = pair.start.len() - text.len();
 3985                            let preceding_text_matches_prefix = prefix_len == 0
 3986                                || (selection.start.column >= (prefix_len as u32)
 3987                                    && snapshot.contains_str_at(
 3988                                        Point::new(
 3989                                            selection.start.row,
 3990                                            selection.start.column - (prefix_len as u32),
 3991                                        ),
 3992                                        &pair.start[..prefix_len],
 3993                                    ));
 3994                            if preceding_text_matches_prefix {
 3995                                bracket_pair = Some(pair.clone());
 3996                                is_bracket_pair_start = true;
 3997                                break;
 3998                            }
 3999                        }
 4000                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4001                        {
 4002                            // take first bracket pair matching end, but don't break in case a later bracket
 4003                            // pair matches start
 4004                            bracket_pair_matching_end = Some(pair.clone());
 4005                        }
 4006                    }
 4007                    if let Some(end) = bracket_pair_matching_end
 4008                        && bracket_pair.is_none()
 4009                    {
 4010                        bracket_pair = Some(end);
 4011                        is_bracket_pair_end = true;
 4012                    }
 4013                }
 4014
 4015                if let Some(bracket_pair) = bracket_pair {
 4016                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4017                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4018                    let auto_surround =
 4019                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4020                    if selection.is_empty() {
 4021                        if is_bracket_pair_start {
 4022                            // If the inserted text is a suffix of an opening bracket and the
 4023                            // selection is preceded by the rest of the opening bracket, then
 4024                            // insert the closing bracket.
 4025                            let following_text_allows_autoclose = snapshot
 4026                                .chars_at(selection.start)
 4027                                .next()
 4028                                .is_none_or(|c| scope.should_autoclose_before(c));
 4029
 4030                            let preceding_text_allows_autoclose = selection.start.column == 0
 4031                                || snapshot
 4032                                    .reversed_chars_at(selection.start)
 4033                                    .next()
 4034                                    .is_none_or(|c| {
 4035                                        bracket_pair.start != bracket_pair.end
 4036                                            || !snapshot
 4037                                                .char_classifier_at(selection.start)
 4038                                                .is_word(c)
 4039                                    });
 4040
 4041                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4042                                && bracket_pair.start.len() == 1
 4043                            {
 4044                                let target = bracket_pair.start.chars().next().unwrap();
 4045                                let current_line_count = snapshot
 4046                                    .reversed_chars_at(selection.start)
 4047                                    .take_while(|&c| c != '\n')
 4048                                    .filter(|&c| c == target)
 4049                                    .count();
 4050                                current_line_count % 2 == 1
 4051                            } else {
 4052                                false
 4053                            };
 4054
 4055                            if autoclose
 4056                                && bracket_pair.close
 4057                                && following_text_allows_autoclose
 4058                                && preceding_text_allows_autoclose
 4059                                && !is_closing_quote
 4060                            {
 4061                                let anchor = snapshot.anchor_before(selection.end);
 4062                                new_selections.push((selection.map(|_| anchor), text.len()));
 4063                                new_autoclose_regions.push((
 4064                                    anchor,
 4065                                    text.len(),
 4066                                    selection.id,
 4067                                    bracket_pair.clone(),
 4068                                ));
 4069                                edits.push((
 4070                                    selection.range(),
 4071                                    format!("{}{}", text, bracket_pair.end).into(),
 4072                                ));
 4073                                bracket_inserted = true;
 4074                                continue;
 4075                            }
 4076                        }
 4077
 4078                        if let Some(region) = autoclose_region {
 4079                            // If the selection is followed by an auto-inserted closing bracket,
 4080                            // then don't insert that closing bracket again; just move the selection
 4081                            // past the closing bracket.
 4082                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4083                                && text.as_ref() == region.pair.end.as_str()
 4084                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4085                            if should_skip {
 4086                                let anchor = snapshot.anchor_after(selection.end);
 4087                                new_selections
 4088                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4089                                continue;
 4090                            }
 4091                        }
 4092
 4093                        let always_treat_brackets_as_autoclosed = snapshot
 4094                            .language_settings_at(selection.start, cx)
 4095                            .always_treat_brackets_as_autoclosed;
 4096                        if always_treat_brackets_as_autoclosed
 4097                            && is_bracket_pair_end
 4098                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4099                        {
 4100                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4101                            // and the inserted text is a closing bracket and the selection is followed
 4102                            // by the closing bracket then move the selection past the closing bracket.
 4103                            let anchor = snapshot.anchor_after(selection.end);
 4104                            new_selections.push((selection.map(|_| anchor), text.len()));
 4105                            continue;
 4106                        }
 4107                    }
 4108                    // If an opening bracket is 1 character long and is typed while
 4109                    // text is selected, then surround that text with the bracket pair.
 4110                    else if auto_surround
 4111                        && bracket_pair.surround
 4112                        && is_bracket_pair_start
 4113                        && bracket_pair.start.chars().count() == 1
 4114                    {
 4115                        edits.push((selection.start..selection.start, text.clone()));
 4116                        edits.push((
 4117                            selection.end..selection.end,
 4118                            bracket_pair.end.as_str().into(),
 4119                        ));
 4120                        bracket_inserted = true;
 4121                        new_selections.push((
 4122                            Selection {
 4123                                id: selection.id,
 4124                                start: snapshot.anchor_after(selection.start),
 4125                                end: snapshot.anchor_before(selection.end),
 4126                                reversed: selection.reversed,
 4127                                goal: selection.goal,
 4128                            },
 4129                            0,
 4130                        ));
 4131                        continue;
 4132                    }
 4133                }
 4134            }
 4135
 4136            if self.auto_replace_emoji_shortcode
 4137                && selection.is_empty()
 4138                && text.as_ref().ends_with(':')
 4139                && let Some(possible_emoji_short_code) =
 4140                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4141                && !possible_emoji_short_code.is_empty()
 4142                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4143            {
 4144                let emoji_shortcode_start = Point::new(
 4145                    selection.start.row,
 4146                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4147                );
 4148
 4149                // Remove shortcode from buffer
 4150                edits.push((
 4151                    emoji_shortcode_start..selection.start,
 4152                    "".to_string().into(),
 4153                ));
 4154                new_selections.push((
 4155                    Selection {
 4156                        id: selection.id,
 4157                        start: snapshot.anchor_after(emoji_shortcode_start),
 4158                        end: snapshot.anchor_before(selection.start),
 4159                        reversed: selection.reversed,
 4160                        goal: selection.goal,
 4161                    },
 4162                    0,
 4163                ));
 4164
 4165                // Insert emoji
 4166                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4167                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4168                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4169
 4170                continue;
 4171            }
 4172
 4173            // If not handling any auto-close operation, then just replace the selected
 4174            // text with the given input and move the selection to the end of the
 4175            // newly inserted text.
 4176            let anchor = snapshot.anchor_after(selection.end);
 4177            if !self.linked_edit_ranges.is_empty() {
 4178                let start_anchor = snapshot.anchor_before(selection.start);
 4179
 4180                let is_word_char = text.chars().next().is_none_or(|char| {
 4181                    let classifier = snapshot
 4182                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4183                        .ignore_punctuation(true);
 4184                    classifier.is_word(char)
 4185                });
 4186
 4187                if is_word_char {
 4188                    if let Some(ranges) = self
 4189                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4190                    {
 4191                        for (buffer, edits) in ranges {
 4192                            linked_edits
 4193                                .entry(buffer.clone())
 4194                                .or_default()
 4195                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4196                        }
 4197                    }
 4198                } else {
 4199                    clear_linked_edit_ranges = true;
 4200                }
 4201            }
 4202
 4203            new_selections.push((selection.map(|_| anchor), 0));
 4204            edits.push((selection.start..selection.end, text.clone()));
 4205        }
 4206
 4207        drop(snapshot);
 4208
 4209        self.transact(window, cx, |this, window, cx| {
 4210            if clear_linked_edit_ranges {
 4211                this.linked_edit_ranges.clear();
 4212            }
 4213            let initial_buffer_versions =
 4214                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4215
 4216            this.buffer.update(cx, |buffer, cx| {
 4217                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4218            });
 4219            for (buffer, edits) in linked_edits {
 4220                buffer.update(cx, |buffer, cx| {
 4221                    let snapshot = buffer.snapshot();
 4222                    let edits = edits
 4223                        .into_iter()
 4224                        .map(|(range, text)| {
 4225                            use text::ToPoint as TP;
 4226                            let end_point = TP::to_point(&range.end, &snapshot);
 4227                            let start_point = TP::to_point(&range.start, &snapshot);
 4228                            (start_point..end_point, text)
 4229                        })
 4230                        .sorted_by_key(|(range, _)| range.start);
 4231                    buffer.edit(edits, None, cx);
 4232                })
 4233            }
 4234            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4235            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4236            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4237            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4238                .zip(new_selection_deltas)
 4239                .map(|(selection, delta)| Selection {
 4240                    id: selection.id,
 4241                    start: selection.start + delta,
 4242                    end: selection.end + delta,
 4243                    reversed: selection.reversed,
 4244                    goal: SelectionGoal::None,
 4245                })
 4246                .collect::<Vec<_>>();
 4247
 4248            let mut i = 0;
 4249            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4250                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4251                let start = map.buffer_snapshot.anchor_before(position);
 4252                let end = map.buffer_snapshot.anchor_after(position);
 4253                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4254                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4255                        Ordering::Less => i += 1,
 4256                        Ordering::Greater => break,
 4257                        Ordering::Equal => {
 4258                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4259                                Ordering::Less => i += 1,
 4260                                Ordering::Equal => break,
 4261                                Ordering::Greater => break,
 4262                            }
 4263                        }
 4264                    }
 4265                }
 4266                this.autoclose_regions.insert(
 4267                    i,
 4268                    AutocloseRegion {
 4269                        selection_id,
 4270                        range: start..end,
 4271                        pair,
 4272                    },
 4273                );
 4274            }
 4275
 4276            let had_active_edit_prediction = this.has_active_edit_prediction();
 4277            this.change_selections(
 4278                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4279                window,
 4280                cx,
 4281                |s| s.select(new_selections),
 4282            );
 4283
 4284            if !bracket_inserted
 4285                && let Some(on_type_format_task) =
 4286                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4287            {
 4288                on_type_format_task.detach_and_log_err(cx);
 4289            }
 4290
 4291            let editor_settings = EditorSettings::get_global(cx);
 4292            if bracket_inserted
 4293                && (editor_settings.auto_signature_help
 4294                    || editor_settings.show_signature_help_after_edits)
 4295            {
 4296                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4297            }
 4298
 4299            let trigger_in_words =
 4300                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4301            if this.hard_wrap.is_some() {
 4302                let latest: Range<Point> = this.selections.newest(cx).range();
 4303                if latest.is_empty()
 4304                    && this
 4305                        .buffer()
 4306                        .read(cx)
 4307                        .snapshot(cx)
 4308                        .line_len(MultiBufferRow(latest.start.row))
 4309                        == latest.start.column
 4310                {
 4311                    this.rewrap_impl(
 4312                        RewrapOptions {
 4313                            override_language_settings: true,
 4314                            preserve_existing_whitespace: true,
 4315                        },
 4316                        cx,
 4317                    )
 4318                }
 4319            }
 4320            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4321            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4322            this.refresh_edit_prediction(true, false, window, cx);
 4323            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4324        });
 4325    }
 4326
 4327    fn find_possible_emoji_shortcode_at_position(
 4328        snapshot: &MultiBufferSnapshot,
 4329        position: Point,
 4330    ) -> Option<String> {
 4331        let mut chars = Vec::new();
 4332        let mut found_colon = false;
 4333        for char in snapshot.reversed_chars_at(position).take(100) {
 4334            // Found a possible emoji shortcode in the middle of the buffer
 4335            if found_colon {
 4336                if char.is_whitespace() {
 4337                    chars.reverse();
 4338                    return Some(chars.iter().collect());
 4339                }
 4340                // If the previous character is not a whitespace, we are in the middle of a word
 4341                // and we only want to complete the shortcode if the word is made up of other emojis
 4342                let mut containing_word = String::new();
 4343                for ch in snapshot
 4344                    .reversed_chars_at(position)
 4345                    .skip(chars.len() + 1)
 4346                    .take(100)
 4347                {
 4348                    if ch.is_whitespace() {
 4349                        break;
 4350                    }
 4351                    containing_word.push(ch);
 4352                }
 4353                let containing_word = containing_word.chars().rev().collect::<String>();
 4354                if util::word_consists_of_emojis(containing_word.as_str()) {
 4355                    chars.reverse();
 4356                    return Some(chars.iter().collect());
 4357                }
 4358            }
 4359
 4360            if char.is_whitespace() || !char.is_ascii() {
 4361                return None;
 4362            }
 4363            if char == ':' {
 4364                found_colon = true;
 4365            } else {
 4366                chars.push(char);
 4367            }
 4368        }
 4369        // Found a possible emoji shortcode at the beginning of the buffer
 4370        chars.reverse();
 4371        Some(chars.iter().collect())
 4372    }
 4373
 4374    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4375        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4376        self.transact(window, cx, |this, window, cx| {
 4377            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4378                let selections = this.selections.all::<usize>(cx);
 4379                let multi_buffer = this.buffer.read(cx);
 4380                let buffer = multi_buffer.snapshot(cx);
 4381                selections
 4382                    .iter()
 4383                    .map(|selection| {
 4384                        let start_point = selection.start.to_point(&buffer);
 4385                        let mut existing_indent =
 4386                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4387                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4388                        let start = selection.start;
 4389                        let end = selection.end;
 4390                        let selection_is_empty = start == end;
 4391                        let language_scope = buffer.language_scope_at(start);
 4392                        let (
 4393                            comment_delimiter,
 4394                            doc_delimiter,
 4395                            insert_extra_newline,
 4396                            indent_on_newline,
 4397                            indent_on_extra_newline,
 4398                        ) = if let Some(language) = &language_scope {
 4399                            let mut insert_extra_newline =
 4400                                insert_extra_newline_brackets(&buffer, start..end, language)
 4401                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4402
 4403                            // Comment extension on newline is allowed only for cursor selections
 4404                            let comment_delimiter = maybe!({
 4405                                if !selection_is_empty {
 4406                                    return None;
 4407                                }
 4408
 4409                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4410                                    return None;
 4411                                }
 4412
 4413                                let delimiters = language.line_comment_prefixes();
 4414                                let max_len_of_delimiter =
 4415                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4416                                let (snapshot, range) =
 4417                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4418
 4419                                let num_of_whitespaces = snapshot
 4420                                    .chars_for_range(range.clone())
 4421                                    .take_while(|c| c.is_whitespace())
 4422                                    .count();
 4423                                let comment_candidate = snapshot
 4424                                    .chars_for_range(range.clone())
 4425                                    .skip(num_of_whitespaces)
 4426                                    .take(max_len_of_delimiter)
 4427                                    .collect::<String>();
 4428                                let (delimiter, trimmed_len) = delimiters
 4429                                    .iter()
 4430                                    .filter_map(|delimiter| {
 4431                                        let prefix = delimiter.trim_end();
 4432                                        if comment_candidate.starts_with(prefix) {
 4433                                            Some((delimiter, prefix.len()))
 4434                                        } else {
 4435                                            None
 4436                                        }
 4437                                    })
 4438                                    .max_by_key(|(_, len)| *len)?;
 4439
 4440                                if let Some(BlockCommentConfig {
 4441                                    start: block_start, ..
 4442                                }) = language.block_comment()
 4443                                {
 4444                                    let block_start_trimmed = block_start.trim_end();
 4445                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4446                                        let line_content = snapshot
 4447                                            .chars_for_range(range)
 4448                                            .skip(num_of_whitespaces)
 4449                                            .take(block_start_trimmed.len())
 4450                                            .collect::<String>();
 4451
 4452                                        if line_content.starts_with(block_start_trimmed) {
 4453                                            return None;
 4454                                        }
 4455                                    }
 4456                                }
 4457
 4458                                let cursor_is_placed_after_comment_marker =
 4459                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4460                                if cursor_is_placed_after_comment_marker {
 4461                                    Some(delimiter.clone())
 4462                                } else {
 4463                                    None
 4464                                }
 4465                            });
 4466
 4467                            let mut indent_on_newline = IndentSize::spaces(0);
 4468                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4469
 4470                            let doc_delimiter = maybe!({
 4471                                if !selection_is_empty {
 4472                                    return None;
 4473                                }
 4474
 4475                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4476                                    return None;
 4477                                }
 4478
 4479                                let BlockCommentConfig {
 4480                                    start: start_tag,
 4481                                    end: end_tag,
 4482                                    prefix: delimiter,
 4483                                    tab_size: len,
 4484                                } = language.documentation_comment()?;
 4485                                let is_within_block_comment = buffer
 4486                                    .language_scope_at(start_point)
 4487                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4488                                if !is_within_block_comment {
 4489                                    return None;
 4490                                }
 4491
 4492                                let (snapshot, range) =
 4493                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4494
 4495                                let num_of_whitespaces = snapshot
 4496                                    .chars_for_range(range.clone())
 4497                                    .take_while(|c| c.is_whitespace())
 4498                                    .count();
 4499
 4500                                // 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.
 4501                                let column = start_point.column;
 4502                                let cursor_is_after_start_tag = {
 4503                                    let start_tag_len = start_tag.len();
 4504                                    let start_tag_line = snapshot
 4505                                        .chars_for_range(range.clone())
 4506                                        .skip(num_of_whitespaces)
 4507                                        .take(start_tag_len)
 4508                                        .collect::<String>();
 4509                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4510                                        num_of_whitespaces + start_tag_len <= column as usize
 4511                                    } else {
 4512                                        false
 4513                                    }
 4514                                };
 4515
 4516                                let cursor_is_after_delimiter = {
 4517                                    let delimiter_trim = delimiter.trim_end();
 4518                                    let delimiter_line = snapshot
 4519                                        .chars_for_range(range.clone())
 4520                                        .skip(num_of_whitespaces)
 4521                                        .take(delimiter_trim.len())
 4522                                        .collect::<String>();
 4523                                    if delimiter_line.starts_with(delimiter_trim) {
 4524                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4525                                    } else {
 4526                                        false
 4527                                    }
 4528                                };
 4529
 4530                                let cursor_is_before_end_tag_if_exists = {
 4531                                    let mut char_position = 0u32;
 4532                                    let mut end_tag_offset = None;
 4533
 4534                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4535                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4536                                            let chars_before_match =
 4537                                                chunk[..byte_pos].chars().count() as u32;
 4538                                            end_tag_offset =
 4539                                                Some(char_position + chars_before_match);
 4540                                            break 'outer;
 4541                                        }
 4542                                        char_position += chunk.chars().count() as u32;
 4543                                    }
 4544
 4545                                    if let Some(end_tag_offset) = end_tag_offset {
 4546                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4547                                        if cursor_is_after_start_tag {
 4548                                            if cursor_is_before_end_tag {
 4549                                                insert_extra_newline = true;
 4550                                            }
 4551                                            let cursor_is_at_start_of_end_tag =
 4552                                                column == end_tag_offset;
 4553                                            if cursor_is_at_start_of_end_tag {
 4554                                                indent_on_extra_newline.len = *len;
 4555                                            }
 4556                                        }
 4557                                        cursor_is_before_end_tag
 4558                                    } else {
 4559                                        true
 4560                                    }
 4561                                };
 4562
 4563                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4564                                    && cursor_is_before_end_tag_if_exists
 4565                                {
 4566                                    if cursor_is_after_start_tag {
 4567                                        indent_on_newline.len = *len;
 4568                                    }
 4569                                    Some(delimiter.clone())
 4570                                } else {
 4571                                    None
 4572                                }
 4573                            });
 4574
 4575                            (
 4576                                comment_delimiter,
 4577                                doc_delimiter,
 4578                                insert_extra_newline,
 4579                                indent_on_newline,
 4580                                indent_on_extra_newline,
 4581                            )
 4582                        } else {
 4583                            (
 4584                                None,
 4585                                None,
 4586                                false,
 4587                                IndentSize::default(),
 4588                                IndentSize::default(),
 4589                            )
 4590                        };
 4591
 4592                        let prevent_auto_indent = doc_delimiter.is_some();
 4593                        let delimiter = comment_delimiter.or(doc_delimiter);
 4594
 4595                        let capacity_for_delimiter =
 4596                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4597                        let mut new_text = String::with_capacity(
 4598                            1 + capacity_for_delimiter
 4599                                + existing_indent.len as usize
 4600                                + indent_on_newline.len as usize
 4601                                + indent_on_extra_newline.len as usize,
 4602                        );
 4603                        new_text.push('\n');
 4604                        new_text.extend(existing_indent.chars());
 4605                        new_text.extend(indent_on_newline.chars());
 4606
 4607                        if let Some(delimiter) = &delimiter {
 4608                            new_text.push_str(delimiter);
 4609                        }
 4610
 4611                        if insert_extra_newline {
 4612                            new_text.push('\n');
 4613                            new_text.extend(existing_indent.chars());
 4614                            new_text.extend(indent_on_extra_newline.chars());
 4615                        }
 4616
 4617                        let anchor = buffer.anchor_after(end);
 4618                        let new_selection = selection.map(|_| anchor);
 4619                        (
 4620                            ((start..end, new_text), prevent_auto_indent),
 4621                            (insert_extra_newline, new_selection),
 4622                        )
 4623                    })
 4624                    .unzip()
 4625            };
 4626
 4627            let mut auto_indent_edits = Vec::new();
 4628            let mut edits = Vec::new();
 4629            for (edit, prevent_auto_indent) in edits_with_flags {
 4630                if prevent_auto_indent {
 4631                    edits.push(edit);
 4632                } else {
 4633                    auto_indent_edits.push(edit);
 4634                }
 4635            }
 4636            if !edits.is_empty() {
 4637                this.edit(edits, cx);
 4638            }
 4639            if !auto_indent_edits.is_empty() {
 4640                this.edit_with_autoindent(auto_indent_edits, cx);
 4641            }
 4642
 4643            let buffer = this.buffer.read(cx).snapshot(cx);
 4644            let new_selections = selection_info
 4645                .into_iter()
 4646                .map(|(extra_newline_inserted, new_selection)| {
 4647                    let mut cursor = new_selection.end.to_point(&buffer);
 4648                    if extra_newline_inserted {
 4649                        cursor.row -= 1;
 4650                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4651                    }
 4652                    new_selection.map(|_| cursor)
 4653                })
 4654                .collect();
 4655
 4656            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4657            this.refresh_edit_prediction(true, false, window, cx);
 4658        });
 4659    }
 4660
 4661    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4662        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4663
 4664        let buffer = self.buffer.read(cx);
 4665        let snapshot = buffer.snapshot(cx);
 4666
 4667        let mut edits = Vec::new();
 4668        let mut rows = Vec::new();
 4669
 4670        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4671            let cursor = selection.head();
 4672            let row = cursor.row;
 4673
 4674            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4675
 4676            let newline = "\n".to_string();
 4677            edits.push((start_of_line..start_of_line, newline));
 4678
 4679            rows.push(row + rows_inserted as u32);
 4680        }
 4681
 4682        self.transact(window, cx, |editor, window, cx| {
 4683            editor.edit(edits, cx);
 4684
 4685            editor.change_selections(Default::default(), window, cx, |s| {
 4686                let mut index = 0;
 4687                s.move_cursors_with(|map, _, _| {
 4688                    let row = rows[index];
 4689                    index += 1;
 4690
 4691                    let point = Point::new(row, 0);
 4692                    let boundary = map.next_line_boundary(point).1;
 4693                    let clipped = map.clip_point(boundary, Bias::Left);
 4694
 4695                    (clipped, SelectionGoal::None)
 4696                });
 4697            });
 4698
 4699            let mut indent_edits = Vec::new();
 4700            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4701            for row in rows {
 4702                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4703                for (row, indent) in indents {
 4704                    if indent.len == 0 {
 4705                        continue;
 4706                    }
 4707
 4708                    let text = match indent.kind {
 4709                        IndentKind::Space => " ".repeat(indent.len as usize),
 4710                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4711                    };
 4712                    let point = Point::new(row.0, 0);
 4713                    indent_edits.push((point..point, text));
 4714                }
 4715            }
 4716            editor.edit(indent_edits, cx);
 4717        });
 4718    }
 4719
 4720    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4722
 4723        let buffer = self.buffer.read(cx);
 4724        let snapshot = buffer.snapshot(cx);
 4725
 4726        let mut edits = Vec::new();
 4727        let mut rows = Vec::new();
 4728        let mut rows_inserted = 0;
 4729
 4730        for selection in self.selections.all_adjusted(cx) {
 4731            let cursor = selection.head();
 4732            let row = cursor.row;
 4733
 4734            let point = Point::new(row + 1, 0);
 4735            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4736
 4737            let newline = "\n".to_string();
 4738            edits.push((start_of_line..start_of_line, newline));
 4739
 4740            rows_inserted += 1;
 4741            rows.push(row + rows_inserted);
 4742        }
 4743
 4744        self.transact(window, cx, |editor, window, cx| {
 4745            editor.edit(edits, cx);
 4746
 4747            editor.change_selections(Default::default(), window, cx, |s| {
 4748                let mut index = 0;
 4749                s.move_cursors_with(|map, _, _| {
 4750                    let row = rows[index];
 4751                    index += 1;
 4752
 4753                    let point = Point::new(row, 0);
 4754                    let boundary = map.next_line_boundary(point).1;
 4755                    let clipped = map.clip_point(boundary, Bias::Left);
 4756
 4757                    (clipped, SelectionGoal::None)
 4758                });
 4759            });
 4760
 4761            let mut indent_edits = Vec::new();
 4762            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4763            for row in rows {
 4764                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4765                for (row, indent) in indents {
 4766                    if indent.len == 0 {
 4767                        continue;
 4768                    }
 4769
 4770                    let text = match indent.kind {
 4771                        IndentKind::Space => " ".repeat(indent.len as usize),
 4772                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4773                    };
 4774                    let point = Point::new(row.0, 0);
 4775                    indent_edits.push((point..point, text));
 4776                }
 4777            }
 4778            editor.edit(indent_edits, cx);
 4779        });
 4780    }
 4781
 4782    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4783        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4784            original_indent_columns: Vec::new(),
 4785        });
 4786        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4787    }
 4788
 4789    fn insert_with_autoindent_mode(
 4790        &mut self,
 4791        text: &str,
 4792        autoindent_mode: Option<AutoindentMode>,
 4793        window: &mut Window,
 4794        cx: &mut Context<Self>,
 4795    ) {
 4796        if self.read_only(cx) {
 4797            return;
 4798        }
 4799
 4800        let text: Arc<str> = text.into();
 4801        self.transact(window, cx, |this, window, cx| {
 4802            let old_selections = this.selections.all_adjusted(cx);
 4803            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4804                let anchors = {
 4805                    let snapshot = buffer.read(cx);
 4806                    old_selections
 4807                        .iter()
 4808                        .map(|s| {
 4809                            let anchor = snapshot.anchor_after(s.head());
 4810                            s.map(|_| anchor)
 4811                        })
 4812                        .collect::<Vec<_>>()
 4813                };
 4814                buffer.edit(
 4815                    old_selections
 4816                        .iter()
 4817                        .map(|s| (s.start..s.end, text.clone())),
 4818                    autoindent_mode,
 4819                    cx,
 4820                );
 4821                anchors
 4822            });
 4823
 4824            this.change_selections(Default::default(), window, cx, |s| {
 4825                s.select_anchors(selection_anchors);
 4826            });
 4827
 4828            cx.notify();
 4829        });
 4830    }
 4831
 4832    fn trigger_completion_on_input(
 4833        &mut self,
 4834        text: &str,
 4835        trigger_in_words: bool,
 4836        window: &mut Window,
 4837        cx: &mut Context<Self>,
 4838    ) {
 4839        let completions_source = self
 4840            .context_menu
 4841            .borrow()
 4842            .as_ref()
 4843            .and_then(|menu| match menu {
 4844                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4845                CodeContextMenu::CodeActions(_) => None,
 4846            });
 4847
 4848        match completions_source {
 4849            Some(CompletionsMenuSource::Words) => {
 4850                self.show_word_completions(&ShowWordCompletions, window, cx)
 4851            }
 4852            Some(CompletionsMenuSource::Normal)
 4853            | Some(CompletionsMenuSource::SnippetChoices)
 4854            | None
 4855                if self.is_completion_trigger(
 4856                    text,
 4857                    trigger_in_words,
 4858                    completions_source.is_some(),
 4859                    cx,
 4860                ) =>
 4861            {
 4862                self.show_completions(
 4863                    &ShowCompletions {
 4864                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4865                    },
 4866                    window,
 4867                    cx,
 4868                )
 4869            }
 4870            _ => {
 4871                self.hide_context_menu(window, cx);
 4872            }
 4873        }
 4874    }
 4875
 4876    fn is_completion_trigger(
 4877        &self,
 4878        text: &str,
 4879        trigger_in_words: bool,
 4880        menu_is_open: bool,
 4881        cx: &mut Context<Self>,
 4882    ) -> bool {
 4883        let position = self.selections.newest_anchor().head();
 4884        let multibuffer = self.buffer.read(cx);
 4885        let Some(buffer) = position
 4886            .buffer_id
 4887            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4888        else {
 4889            return false;
 4890        };
 4891
 4892        if let Some(completion_provider) = &self.completion_provider {
 4893            completion_provider.is_completion_trigger(
 4894                &buffer,
 4895                position.text_anchor,
 4896                text,
 4897                trigger_in_words,
 4898                menu_is_open,
 4899                cx,
 4900            )
 4901        } else {
 4902            false
 4903        }
 4904    }
 4905
 4906    /// If any empty selections is touching the start of its innermost containing autoclose
 4907    /// region, expand it to select the brackets.
 4908    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4909        let selections = self.selections.all::<usize>(cx);
 4910        let buffer = self.buffer.read(cx).read(cx);
 4911        let new_selections = self
 4912            .selections_with_autoclose_regions(selections, &buffer)
 4913            .map(|(mut selection, region)| {
 4914                if !selection.is_empty() {
 4915                    return selection;
 4916                }
 4917
 4918                if let Some(region) = region {
 4919                    let mut range = region.range.to_offset(&buffer);
 4920                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4921                        range.start -= region.pair.start.len();
 4922                        if buffer.contains_str_at(range.start, &region.pair.start)
 4923                            && buffer.contains_str_at(range.end, &region.pair.end)
 4924                        {
 4925                            range.end += region.pair.end.len();
 4926                            selection.start = range.start;
 4927                            selection.end = range.end;
 4928
 4929                            return selection;
 4930                        }
 4931                    }
 4932                }
 4933
 4934                let always_treat_brackets_as_autoclosed = buffer
 4935                    .language_settings_at(selection.start, cx)
 4936                    .always_treat_brackets_as_autoclosed;
 4937
 4938                if !always_treat_brackets_as_autoclosed {
 4939                    return selection;
 4940                }
 4941
 4942                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4943                    for (pair, enabled) in scope.brackets() {
 4944                        if !enabled || !pair.close {
 4945                            continue;
 4946                        }
 4947
 4948                        if buffer.contains_str_at(selection.start, &pair.end) {
 4949                            let pair_start_len = pair.start.len();
 4950                            if buffer.contains_str_at(
 4951                                selection.start.saturating_sub(pair_start_len),
 4952                                &pair.start,
 4953                            ) {
 4954                                selection.start -= pair_start_len;
 4955                                selection.end += pair.end.len();
 4956
 4957                                return selection;
 4958                            }
 4959                        }
 4960                    }
 4961                }
 4962
 4963                selection
 4964            })
 4965            .collect();
 4966
 4967        drop(buffer);
 4968        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4969            selections.select(new_selections)
 4970        });
 4971    }
 4972
 4973    /// Iterate the given selections, and for each one, find the smallest surrounding
 4974    /// autoclose region. This uses the ordering of the selections and the autoclose
 4975    /// regions to avoid repeated comparisons.
 4976    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4977        &'a self,
 4978        selections: impl IntoIterator<Item = Selection<D>>,
 4979        buffer: &'a MultiBufferSnapshot,
 4980    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4981        let mut i = 0;
 4982        let mut regions = self.autoclose_regions.as_slice();
 4983        selections.into_iter().map(move |selection| {
 4984            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4985
 4986            let mut enclosing = None;
 4987            while let Some(pair_state) = regions.get(i) {
 4988                if pair_state.range.end.to_offset(buffer) < range.start {
 4989                    regions = &regions[i + 1..];
 4990                    i = 0;
 4991                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4992                    break;
 4993                } else {
 4994                    if pair_state.selection_id == selection.id {
 4995                        enclosing = Some(pair_state);
 4996                    }
 4997                    i += 1;
 4998                }
 4999            }
 5000
 5001            (selection, enclosing)
 5002        })
 5003    }
 5004
 5005    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5006    fn invalidate_autoclose_regions(
 5007        &mut self,
 5008        mut selections: &[Selection<Anchor>],
 5009        buffer: &MultiBufferSnapshot,
 5010    ) {
 5011        self.autoclose_regions.retain(|state| {
 5012            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5013                return false;
 5014            }
 5015
 5016            let mut i = 0;
 5017            while let Some(selection) = selections.get(i) {
 5018                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5019                    selections = &selections[1..];
 5020                    continue;
 5021                }
 5022                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5023                    break;
 5024                }
 5025                if selection.id == state.selection_id {
 5026                    return true;
 5027                } else {
 5028                    i += 1;
 5029                }
 5030            }
 5031            false
 5032        });
 5033    }
 5034
 5035    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5036        let offset = position.to_offset(buffer);
 5037        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5038        if offset > word_range.start && kind == Some(CharKind::Word) {
 5039            Some(
 5040                buffer
 5041                    .text_for_range(word_range.start..offset)
 5042                    .collect::<String>(),
 5043            )
 5044        } else {
 5045            None
 5046        }
 5047    }
 5048
 5049    pub fn toggle_inline_values(
 5050        &mut self,
 5051        _: &ToggleInlineValues,
 5052        _: &mut Window,
 5053        cx: &mut Context<Self>,
 5054    ) {
 5055        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5056
 5057        self.refresh_inline_values(cx);
 5058    }
 5059
 5060    pub fn toggle_inlay_hints(
 5061        &mut self,
 5062        _: &ToggleInlayHints,
 5063        _: &mut Window,
 5064        cx: &mut Context<Self>,
 5065    ) {
 5066        self.refresh_inlay_hints(
 5067            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5068            cx,
 5069        );
 5070    }
 5071
 5072    pub fn inlay_hints_enabled(&self) -> bool {
 5073        self.inlay_hint_cache.enabled
 5074    }
 5075
 5076    pub fn inline_values_enabled(&self) -> bool {
 5077        self.inline_value_cache.enabled
 5078    }
 5079
 5080    #[cfg(any(test, feature = "test-support"))]
 5081    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5082        self.display_map
 5083            .read(cx)
 5084            .current_inlays()
 5085            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5086            .cloned()
 5087            .collect()
 5088    }
 5089
 5090    #[cfg(any(test, feature = "test-support"))]
 5091    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5092        self.display_map
 5093            .read(cx)
 5094            .current_inlays()
 5095            .cloned()
 5096            .collect()
 5097    }
 5098
 5099    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5100        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5101            return;
 5102        }
 5103
 5104        let reason_description = reason.description();
 5105        let ignore_debounce = matches!(
 5106            reason,
 5107            InlayHintRefreshReason::SettingsChange(_)
 5108                | InlayHintRefreshReason::Toggle(_)
 5109                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5110                | InlayHintRefreshReason::ModifiersChanged(_)
 5111        );
 5112        let (invalidate_cache, required_languages) = match reason {
 5113            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5114                match self.inlay_hint_cache.modifiers_override(enabled) {
 5115                    Some(enabled) => {
 5116                        if enabled {
 5117                            (InvalidationStrategy::RefreshRequested, None)
 5118                        } else {
 5119                            self.splice_inlays(
 5120                                &self
 5121                                    .visible_inlay_hints(cx)
 5122                                    .iter()
 5123                                    .map(|inlay| inlay.id)
 5124                                    .collect::<Vec<InlayId>>(),
 5125                                Vec::new(),
 5126                                cx,
 5127                            );
 5128                            return;
 5129                        }
 5130                    }
 5131                    None => return,
 5132                }
 5133            }
 5134            InlayHintRefreshReason::Toggle(enabled) => {
 5135                if self.inlay_hint_cache.toggle(enabled) {
 5136                    if enabled {
 5137                        (InvalidationStrategy::RefreshRequested, None)
 5138                    } else {
 5139                        self.splice_inlays(
 5140                            &self
 5141                                .visible_inlay_hints(cx)
 5142                                .iter()
 5143                                .map(|inlay| inlay.id)
 5144                                .collect::<Vec<InlayId>>(),
 5145                            Vec::new(),
 5146                            cx,
 5147                        );
 5148                        return;
 5149                    }
 5150                } else {
 5151                    return;
 5152                }
 5153            }
 5154            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5155                match self.inlay_hint_cache.update_settings(
 5156                    &self.buffer,
 5157                    new_settings,
 5158                    self.visible_inlay_hints(cx),
 5159                    cx,
 5160                ) {
 5161                    ControlFlow::Break(Some(InlaySplice {
 5162                        to_remove,
 5163                        to_insert,
 5164                    })) => {
 5165                        self.splice_inlays(&to_remove, to_insert, cx);
 5166                        return;
 5167                    }
 5168                    ControlFlow::Break(None) => return,
 5169                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5170                }
 5171            }
 5172            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5173                if let Some(InlaySplice {
 5174                    to_remove,
 5175                    to_insert,
 5176                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5177                {
 5178                    self.splice_inlays(&to_remove, to_insert, cx);
 5179                }
 5180                self.display_map.update(cx, |display_map, _| {
 5181                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5182                });
 5183                return;
 5184            }
 5185            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5186            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5187                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5188            }
 5189            InlayHintRefreshReason::RefreshRequested => {
 5190                (InvalidationStrategy::RefreshRequested, None)
 5191            }
 5192        };
 5193
 5194        if let Some(InlaySplice {
 5195            to_remove,
 5196            to_insert,
 5197        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5198            reason_description,
 5199            self.visible_excerpts(required_languages.as_ref(), cx),
 5200            invalidate_cache,
 5201            ignore_debounce,
 5202            cx,
 5203        ) {
 5204            self.splice_inlays(&to_remove, to_insert, cx);
 5205        }
 5206    }
 5207
 5208    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5209        self.display_map
 5210            .read(cx)
 5211            .current_inlays()
 5212            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5213            .cloned()
 5214            .collect()
 5215    }
 5216
 5217    pub fn visible_excerpts(
 5218        &self,
 5219        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5220        cx: &mut Context<Editor>,
 5221    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5222        let Some(project) = self.project() else {
 5223            return HashMap::default();
 5224        };
 5225        let project = project.read(cx);
 5226        let multi_buffer = self.buffer().read(cx);
 5227        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5228        let multi_buffer_visible_start = self
 5229            .scroll_manager
 5230            .anchor()
 5231            .anchor
 5232            .to_point(&multi_buffer_snapshot);
 5233        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5234            multi_buffer_visible_start
 5235                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5236            Bias::Left,
 5237        );
 5238        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5239        multi_buffer_snapshot
 5240            .range_to_buffer_ranges(multi_buffer_visible_range)
 5241            .into_iter()
 5242            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5243            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5244                let buffer_file = project::File::from_dyn(buffer.file())?;
 5245                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5246                let worktree_entry = buffer_worktree
 5247                    .read(cx)
 5248                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5249                if worktree_entry.is_ignored {
 5250                    return None;
 5251                }
 5252
 5253                let language = buffer.language()?;
 5254                if let Some(restrict_to_languages) = restrict_to_languages
 5255                    && !restrict_to_languages.contains(language)
 5256                {
 5257                    return None;
 5258                }
 5259                Some((
 5260                    excerpt_id,
 5261                    (
 5262                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5263                        buffer.version().clone(),
 5264                        excerpt_visible_range,
 5265                    ),
 5266                ))
 5267            })
 5268            .collect()
 5269    }
 5270
 5271    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5272        TextLayoutDetails {
 5273            text_system: window.text_system().clone(),
 5274            editor_style: self.style.clone().unwrap(),
 5275            rem_size: window.rem_size(),
 5276            scroll_anchor: self.scroll_manager.anchor(),
 5277            visible_rows: self.visible_line_count(),
 5278            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5279        }
 5280    }
 5281
 5282    pub fn splice_inlays(
 5283        &self,
 5284        to_remove: &[InlayId],
 5285        to_insert: Vec<Inlay>,
 5286        cx: &mut Context<Self>,
 5287    ) {
 5288        self.display_map.update(cx, |display_map, cx| {
 5289            display_map.splice_inlays(to_remove, to_insert, cx)
 5290        });
 5291        cx.notify();
 5292    }
 5293
 5294    fn trigger_on_type_formatting(
 5295        &self,
 5296        input: String,
 5297        window: &mut Window,
 5298        cx: &mut Context<Self>,
 5299    ) -> Option<Task<Result<()>>> {
 5300        if input.len() != 1 {
 5301            return None;
 5302        }
 5303
 5304        let project = self.project()?;
 5305        let position = self.selections.newest_anchor().head();
 5306        let (buffer, buffer_position) = self
 5307            .buffer
 5308            .read(cx)
 5309            .text_anchor_for_position(position, cx)?;
 5310
 5311        let settings = language_settings::language_settings(
 5312            buffer
 5313                .read(cx)
 5314                .language_at(buffer_position)
 5315                .map(|l| l.name()),
 5316            buffer.read(cx).file(),
 5317            cx,
 5318        );
 5319        if !settings.use_on_type_format {
 5320            return None;
 5321        }
 5322
 5323        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5324        // hence we do LSP request & edit on host side only — add formats to host's history.
 5325        let push_to_lsp_host_history = true;
 5326        // If this is not the host, append its history with new edits.
 5327        let push_to_client_history = project.read(cx).is_via_collab();
 5328
 5329        let on_type_formatting = project.update(cx, |project, cx| {
 5330            project.on_type_format(
 5331                buffer.clone(),
 5332                buffer_position,
 5333                input,
 5334                push_to_lsp_host_history,
 5335                cx,
 5336            )
 5337        });
 5338        Some(cx.spawn_in(window, async move |editor, cx| {
 5339            if let Some(transaction) = on_type_formatting.await? {
 5340                if push_to_client_history {
 5341                    buffer
 5342                        .update(cx, |buffer, _| {
 5343                            buffer.push_transaction(transaction, Instant::now());
 5344                            buffer.finalize_last_transaction();
 5345                        })
 5346                        .ok();
 5347                }
 5348                editor.update(cx, |editor, cx| {
 5349                    editor.refresh_document_highlights(cx);
 5350                })?;
 5351            }
 5352            Ok(())
 5353        }))
 5354    }
 5355
 5356    pub fn show_word_completions(
 5357        &mut self,
 5358        _: &ShowWordCompletions,
 5359        window: &mut Window,
 5360        cx: &mut Context<Self>,
 5361    ) {
 5362        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5363    }
 5364
 5365    pub fn show_completions(
 5366        &mut self,
 5367        options: &ShowCompletions,
 5368        window: &mut Window,
 5369        cx: &mut Context<Self>,
 5370    ) {
 5371        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5372    }
 5373
 5374    fn open_or_update_completions_menu(
 5375        &mut self,
 5376        requested_source: Option<CompletionsMenuSource>,
 5377        trigger: Option<&str>,
 5378        window: &mut Window,
 5379        cx: &mut Context<Self>,
 5380    ) {
 5381        if self.pending_rename.is_some() {
 5382            return;
 5383        }
 5384
 5385        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5386
 5387        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5388        // inserted and selected. To handle that case, the start of the selection is used so that
 5389        // the menu starts with all choices.
 5390        let position = self
 5391            .selections
 5392            .newest_anchor()
 5393            .start
 5394            .bias_right(&multibuffer_snapshot);
 5395        if position.diff_base_anchor.is_some() {
 5396            return;
 5397        }
 5398        let (buffer, buffer_position) =
 5399            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5400                output
 5401            } else {
 5402                return;
 5403            };
 5404        let buffer_snapshot = buffer.read(cx).snapshot();
 5405
 5406        let query: Option<Arc<String>> =
 5407            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5408
 5409        drop(multibuffer_snapshot);
 5410
 5411        let provider = match requested_source {
 5412            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5413            Some(CompletionsMenuSource::Words) => None,
 5414            Some(CompletionsMenuSource::SnippetChoices) => {
 5415                log::error!("bug: SnippetChoices requested_source is not handled");
 5416                None
 5417            }
 5418        };
 5419
 5420        let sort_completions = provider
 5421            .as_ref()
 5422            .is_some_and(|provider| provider.sort_completions());
 5423
 5424        let filter_completions = provider
 5425            .as_ref()
 5426            .is_none_or(|provider| provider.filter_completions());
 5427
 5428        let trigger_kind = match trigger {
 5429            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5430                CompletionTriggerKind::TRIGGER_CHARACTER
 5431            }
 5432            _ => CompletionTriggerKind::INVOKED,
 5433        };
 5434        let completion_context = CompletionContext {
 5435            trigger_character: trigger.and_then(|trigger| {
 5436                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5437                    Some(String::from(trigger))
 5438                } else {
 5439                    None
 5440                }
 5441            }),
 5442            trigger_kind,
 5443        };
 5444
 5445        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5446        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5447        // involve trigger chars, so this is skipped in that case.
 5448        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5449        {
 5450            let menu_is_open = matches!(
 5451                self.context_menu.borrow().as_ref(),
 5452                Some(CodeContextMenu::Completions(_))
 5453            );
 5454            if menu_is_open {
 5455                self.hide_context_menu(window, cx);
 5456            }
 5457        }
 5458
 5459        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5460            if filter_completions {
 5461                menu.filter(query.clone(), provider.clone(), window, cx);
 5462            }
 5463            // When `is_incomplete` is false, no need to re-query completions when the current query
 5464            // is a suffix of the initial query.
 5465            if !menu.is_incomplete {
 5466                // If the new query is a suffix of the old query (typing more characters) and
 5467                // the previous result was complete, the existing completions can be filtered.
 5468                //
 5469                // Note that this is always true for snippet completions.
 5470                let query_matches = match (&menu.initial_query, &query) {
 5471                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5472                    (None, _) => true,
 5473                    _ => false,
 5474                };
 5475                if query_matches {
 5476                    let position_matches = if menu.initial_position == position {
 5477                        true
 5478                    } else {
 5479                        let snapshot = self.buffer.read(cx).read(cx);
 5480                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5481                    };
 5482                    if position_matches {
 5483                        return;
 5484                    }
 5485                }
 5486            }
 5487        };
 5488
 5489        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5490            buffer_snapshot.surrounding_word(buffer_position, false)
 5491        {
 5492            let word_to_exclude = buffer_snapshot
 5493                .text_for_range(word_range.clone())
 5494                .collect::<String>();
 5495            (
 5496                buffer_snapshot.anchor_before(word_range.start)
 5497                    ..buffer_snapshot.anchor_after(buffer_position),
 5498                Some(word_to_exclude),
 5499            )
 5500        } else {
 5501            (buffer_position..buffer_position, None)
 5502        };
 5503
 5504        let language = buffer_snapshot
 5505            .language_at(buffer_position)
 5506            .map(|language| language.name());
 5507
 5508        let completion_settings =
 5509            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5510
 5511        let show_completion_documentation = buffer_snapshot
 5512            .settings_at(buffer_position, cx)
 5513            .show_completion_documentation;
 5514
 5515        // The document can be large, so stay in reasonable bounds when searching for words,
 5516        // otherwise completion pop-up might be slow to appear.
 5517        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5518        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5519        let min_word_search = buffer_snapshot.clip_point(
 5520            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5521            Bias::Left,
 5522        );
 5523        let max_word_search = buffer_snapshot.clip_point(
 5524            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5525            Bias::Right,
 5526        );
 5527        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5528            ..buffer_snapshot.point_to_offset(max_word_search);
 5529
 5530        let skip_digits = query
 5531            .as_ref()
 5532            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5533
 5534        let (mut words, provider_responses) = match &provider {
 5535            Some(provider) => {
 5536                let provider_responses = provider.completions(
 5537                    position.excerpt_id,
 5538                    &buffer,
 5539                    buffer_position,
 5540                    completion_context,
 5541                    window,
 5542                    cx,
 5543                );
 5544
 5545                let words = match completion_settings.words {
 5546                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5547                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5548                        .background_spawn(async move {
 5549                            buffer_snapshot.words_in_range(WordsQuery {
 5550                                fuzzy_contents: None,
 5551                                range: word_search_range,
 5552                                skip_digits,
 5553                            })
 5554                        }),
 5555                };
 5556
 5557                (words, provider_responses)
 5558            }
 5559            None => (
 5560                cx.background_spawn(async move {
 5561                    buffer_snapshot.words_in_range(WordsQuery {
 5562                        fuzzy_contents: None,
 5563                        range: word_search_range,
 5564                        skip_digits,
 5565                    })
 5566                }),
 5567                Task::ready(Ok(Vec::new())),
 5568            ),
 5569        };
 5570
 5571        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5572
 5573        let id = post_inc(&mut self.next_completion_id);
 5574        let task = cx.spawn_in(window, async move |editor, cx| {
 5575            let Ok(()) = editor.update(cx, |this, _| {
 5576                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5577            }) else {
 5578                return;
 5579            };
 5580
 5581            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5582            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5583            let mut completions = Vec::new();
 5584            let mut is_incomplete = false;
 5585            if let Some(provider_responses) = provider_responses.await.log_err()
 5586                && !provider_responses.is_empty()
 5587            {
 5588                for response in provider_responses {
 5589                    completions.extend(response.completions);
 5590                    is_incomplete = is_incomplete || response.is_incomplete;
 5591                }
 5592                if completion_settings.words == WordsCompletionMode::Fallback {
 5593                    words = Task::ready(BTreeMap::default());
 5594                }
 5595            }
 5596
 5597            let mut words = words.await;
 5598            if let Some(word_to_exclude) = &word_to_exclude {
 5599                words.remove(word_to_exclude);
 5600            }
 5601            for lsp_completion in &completions {
 5602                words.remove(&lsp_completion.new_text);
 5603            }
 5604            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5605                replace_range: word_replace_range.clone(),
 5606                new_text: word.clone(),
 5607                label: CodeLabel::plain(word, None),
 5608                icon_path: None,
 5609                documentation: None,
 5610                source: CompletionSource::BufferWord {
 5611                    word_range,
 5612                    resolved: false,
 5613                },
 5614                insert_text_mode: Some(InsertTextMode::AS_IS),
 5615                confirm: None,
 5616            }));
 5617
 5618            let menu = if completions.is_empty() {
 5619                None
 5620            } else {
 5621                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5622                    let languages = editor
 5623                        .workspace
 5624                        .as_ref()
 5625                        .and_then(|(workspace, _)| workspace.upgrade())
 5626                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5627                    let menu = CompletionsMenu::new(
 5628                        id,
 5629                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5630                        sort_completions,
 5631                        show_completion_documentation,
 5632                        position,
 5633                        query.clone(),
 5634                        is_incomplete,
 5635                        buffer.clone(),
 5636                        completions.into(),
 5637                        snippet_sort_order,
 5638                        languages,
 5639                        language,
 5640                        cx,
 5641                    );
 5642
 5643                    let query = if filter_completions { query } else { None };
 5644                    let matches_task = if let Some(query) = query {
 5645                        menu.do_async_filtering(query, cx)
 5646                    } else {
 5647                        Task::ready(menu.unfiltered_matches())
 5648                    };
 5649                    (menu, matches_task)
 5650                }) else {
 5651                    return;
 5652                };
 5653
 5654                let matches = matches_task.await;
 5655
 5656                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5657                    // Newer menu already set, so exit.
 5658                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5659                        editor.context_menu.borrow().as_ref()
 5660                        && prev_menu.id > id
 5661                    {
 5662                        return;
 5663                    };
 5664
 5665                    // Only valid to take prev_menu because it the new menu is immediately set
 5666                    // below, or the menu is hidden.
 5667                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5668                        editor.context_menu.borrow_mut().take()
 5669                    {
 5670                        let position_matches =
 5671                            if prev_menu.initial_position == menu.initial_position {
 5672                                true
 5673                            } else {
 5674                                let snapshot = editor.buffer.read(cx).read(cx);
 5675                                prev_menu.initial_position.to_offset(&snapshot)
 5676                                    == menu.initial_position.to_offset(&snapshot)
 5677                            };
 5678                        if position_matches {
 5679                            // Preserve markdown cache before `set_filter_results` because it will
 5680                            // try to populate the documentation cache.
 5681                            menu.preserve_markdown_cache(prev_menu);
 5682                        }
 5683                    };
 5684
 5685                    menu.set_filter_results(matches, provider, window, cx);
 5686                }) else {
 5687                    return;
 5688                };
 5689
 5690                menu.visible().then_some(menu)
 5691            };
 5692
 5693            editor
 5694                .update_in(cx, |editor, window, cx| {
 5695                    if editor.focus_handle.is_focused(window)
 5696                        && let Some(menu) = menu
 5697                    {
 5698                        *editor.context_menu.borrow_mut() =
 5699                            Some(CodeContextMenu::Completions(menu));
 5700
 5701                        crate::hover_popover::hide_hover(editor, cx);
 5702                        if editor.show_edit_predictions_in_menu() {
 5703                            editor.update_visible_edit_prediction(window, cx);
 5704                        } else {
 5705                            editor.discard_edit_prediction(false, cx);
 5706                        }
 5707
 5708                        cx.notify();
 5709                        return;
 5710                    }
 5711
 5712                    if editor.completion_tasks.len() <= 1 {
 5713                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5714                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5715                        // If it was already hidden and we don't show edit predictions in the menu,
 5716                        // we should also show the edit prediction when available.
 5717                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5718                            editor.update_visible_edit_prediction(window, cx);
 5719                        }
 5720                    }
 5721                })
 5722                .ok();
 5723        });
 5724
 5725        self.completion_tasks.push((id, task));
 5726    }
 5727
 5728    #[cfg(feature = "test-support")]
 5729    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5730        let menu = self.context_menu.borrow();
 5731        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5732            let completions = menu.completions.borrow();
 5733            Some(completions.to_vec())
 5734        } else {
 5735            None
 5736        }
 5737    }
 5738
 5739    pub fn with_completions_menu_matching_id<R>(
 5740        &self,
 5741        id: CompletionId,
 5742        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5743    ) -> R {
 5744        let mut context_menu = self.context_menu.borrow_mut();
 5745        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5746            return f(None);
 5747        };
 5748        if completions_menu.id != id {
 5749            return f(None);
 5750        }
 5751        f(Some(completions_menu))
 5752    }
 5753
 5754    pub fn confirm_completion(
 5755        &mut self,
 5756        action: &ConfirmCompletion,
 5757        window: &mut Window,
 5758        cx: &mut Context<Self>,
 5759    ) -> Option<Task<Result<()>>> {
 5760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5761        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5762    }
 5763
 5764    pub fn confirm_completion_insert(
 5765        &mut self,
 5766        _: &ConfirmCompletionInsert,
 5767        window: &mut Window,
 5768        cx: &mut Context<Self>,
 5769    ) -> Option<Task<Result<()>>> {
 5770        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5771        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5772    }
 5773
 5774    pub fn confirm_completion_replace(
 5775        &mut self,
 5776        _: &ConfirmCompletionReplace,
 5777        window: &mut Window,
 5778        cx: &mut Context<Self>,
 5779    ) -> Option<Task<Result<()>>> {
 5780        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5781        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5782    }
 5783
 5784    pub fn compose_completion(
 5785        &mut self,
 5786        action: &ComposeCompletion,
 5787        window: &mut Window,
 5788        cx: &mut Context<Self>,
 5789    ) -> Option<Task<Result<()>>> {
 5790        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5791        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5792    }
 5793
 5794    fn do_completion(
 5795        &mut self,
 5796        item_ix: Option<usize>,
 5797        intent: CompletionIntent,
 5798        window: &mut Window,
 5799        cx: &mut Context<Editor>,
 5800    ) -> Option<Task<Result<()>>> {
 5801        use language::ToOffset as _;
 5802
 5803        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5804        else {
 5805            return None;
 5806        };
 5807
 5808        let candidate_id = {
 5809            let entries = completions_menu.entries.borrow();
 5810            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5811            if self.show_edit_predictions_in_menu() {
 5812                self.discard_edit_prediction(true, cx);
 5813            }
 5814            mat.candidate_id
 5815        };
 5816
 5817        let completion = completions_menu
 5818            .completions
 5819            .borrow()
 5820            .get(candidate_id)?
 5821            .clone();
 5822        cx.stop_propagation();
 5823
 5824        let buffer_handle = completions_menu.buffer.clone();
 5825
 5826        let CompletionEdit {
 5827            new_text,
 5828            snippet,
 5829            replace_range,
 5830        } = process_completion_for_edit(
 5831            &completion,
 5832            intent,
 5833            &buffer_handle,
 5834            &completions_menu.initial_position.text_anchor,
 5835            cx,
 5836        );
 5837
 5838        let buffer = buffer_handle.read(cx);
 5839        let snapshot = self.buffer.read(cx).snapshot(cx);
 5840        let newest_anchor = self.selections.newest_anchor();
 5841        let replace_range_multibuffer = {
 5842            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5843            let multibuffer_anchor = snapshot
 5844                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5845                .unwrap()
 5846                ..snapshot
 5847                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5848                    .unwrap();
 5849            multibuffer_anchor.start.to_offset(&snapshot)
 5850                ..multibuffer_anchor.end.to_offset(&snapshot)
 5851        };
 5852        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5853            return None;
 5854        }
 5855
 5856        let old_text = buffer
 5857            .text_for_range(replace_range.clone())
 5858            .collect::<String>();
 5859        let lookbehind = newest_anchor
 5860            .start
 5861            .text_anchor
 5862            .to_offset(buffer)
 5863            .saturating_sub(replace_range.start);
 5864        let lookahead = replace_range
 5865            .end
 5866            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5867        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5868        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5869
 5870        let selections = self.selections.all::<usize>(cx);
 5871        let mut ranges = Vec::new();
 5872        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5873
 5874        for selection in &selections {
 5875            let range = if selection.id == newest_anchor.id {
 5876                replace_range_multibuffer.clone()
 5877            } else {
 5878                let mut range = selection.range();
 5879
 5880                // if prefix is present, don't duplicate it
 5881                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5882                    range.start = range.start.saturating_sub(lookbehind);
 5883
 5884                    // if suffix is also present, mimic the newest cursor and replace it
 5885                    if selection.id != newest_anchor.id
 5886                        && snapshot.contains_str_at(range.end, suffix)
 5887                    {
 5888                        range.end += lookahead;
 5889                    }
 5890                }
 5891                range
 5892            };
 5893
 5894            ranges.push(range.clone());
 5895
 5896            if !self.linked_edit_ranges.is_empty() {
 5897                let start_anchor = snapshot.anchor_before(range.start);
 5898                let end_anchor = snapshot.anchor_after(range.end);
 5899                if let Some(ranges) = self
 5900                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5901                {
 5902                    for (buffer, edits) in ranges {
 5903                        linked_edits
 5904                            .entry(buffer.clone())
 5905                            .or_default()
 5906                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5907                    }
 5908                }
 5909            }
 5910        }
 5911
 5912        let common_prefix_len = old_text
 5913            .chars()
 5914            .zip(new_text.chars())
 5915            .take_while(|(a, b)| a == b)
 5916            .map(|(a, _)| a.len_utf8())
 5917            .sum::<usize>();
 5918
 5919        cx.emit(EditorEvent::InputHandled {
 5920            utf16_range_to_replace: None,
 5921            text: new_text[common_prefix_len..].into(),
 5922        });
 5923
 5924        self.transact(window, cx, |editor, window, cx| {
 5925            if let Some(mut snippet) = snippet {
 5926                snippet.text = new_text.to_string();
 5927                editor
 5928                    .insert_snippet(&ranges, snippet, window, cx)
 5929                    .log_err();
 5930            } else {
 5931                editor.buffer.update(cx, |multi_buffer, cx| {
 5932                    let auto_indent = match completion.insert_text_mode {
 5933                        Some(InsertTextMode::AS_IS) => None,
 5934                        _ => editor.autoindent_mode.clone(),
 5935                    };
 5936                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5937                    multi_buffer.edit(edits, auto_indent, cx);
 5938                });
 5939            }
 5940            for (buffer, edits) in linked_edits {
 5941                buffer.update(cx, |buffer, cx| {
 5942                    let snapshot = buffer.snapshot();
 5943                    let edits = edits
 5944                        .into_iter()
 5945                        .map(|(range, text)| {
 5946                            use text::ToPoint as TP;
 5947                            let end_point = TP::to_point(&range.end, &snapshot);
 5948                            let start_point = TP::to_point(&range.start, &snapshot);
 5949                            (start_point..end_point, text)
 5950                        })
 5951                        .sorted_by_key(|(range, _)| range.start);
 5952                    buffer.edit(edits, None, cx);
 5953                })
 5954            }
 5955
 5956            editor.refresh_edit_prediction(true, false, window, cx);
 5957        });
 5958        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5959
 5960        let show_new_completions_on_confirm = completion
 5961            .confirm
 5962            .as_ref()
 5963            .is_some_and(|confirm| confirm(intent, window, cx));
 5964        if show_new_completions_on_confirm {
 5965            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5966        }
 5967
 5968        let provider = self.completion_provider.as_ref()?;
 5969        drop(completion);
 5970        let apply_edits = provider.apply_additional_edits_for_completion(
 5971            buffer_handle,
 5972            completions_menu.completions.clone(),
 5973            candidate_id,
 5974            true,
 5975            cx,
 5976        );
 5977
 5978        let editor_settings = EditorSettings::get_global(cx);
 5979        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5980            // After the code completion is finished, users often want to know what signatures are needed.
 5981            // so we should automatically call signature_help
 5982            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5983        }
 5984
 5985        Some(cx.foreground_executor().spawn(async move {
 5986            apply_edits.await?;
 5987            Ok(())
 5988        }))
 5989    }
 5990
 5991    pub fn toggle_code_actions(
 5992        &mut self,
 5993        action: &ToggleCodeActions,
 5994        window: &mut Window,
 5995        cx: &mut Context<Self>,
 5996    ) {
 5997        let quick_launch = action.quick_launch;
 5998        let mut context_menu = self.context_menu.borrow_mut();
 5999        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6000            if code_actions.deployed_from == action.deployed_from {
 6001                // Toggle if we're selecting the same one
 6002                *context_menu = None;
 6003                cx.notify();
 6004                return;
 6005            } else {
 6006                // Otherwise, clear it and start a new one
 6007                *context_menu = None;
 6008                cx.notify();
 6009            }
 6010        }
 6011        drop(context_menu);
 6012        let snapshot = self.snapshot(window, cx);
 6013        let deployed_from = action.deployed_from.clone();
 6014        let action = action.clone();
 6015        self.completion_tasks.clear();
 6016        self.discard_edit_prediction(false, cx);
 6017
 6018        let multibuffer_point = match &action.deployed_from {
 6019            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6020                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6021            }
 6022            _ => self.selections.newest::<Point>(cx).head(),
 6023        };
 6024        let Some((buffer, buffer_row)) = snapshot
 6025            .buffer_snapshot
 6026            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6027            .and_then(|(buffer_snapshot, range)| {
 6028                self.buffer()
 6029                    .read(cx)
 6030                    .buffer(buffer_snapshot.remote_id())
 6031                    .map(|buffer| (buffer, range.start.row))
 6032            })
 6033        else {
 6034            return;
 6035        };
 6036        let buffer_id = buffer.read(cx).remote_id();
 6037        let tasks = self
 6038            .tasks
 6039            .get(&(buffer_id, buffer_row))
 6040            .map(|t| Arc::new(t.to_owned()));
 6041
 6042        if !self.focus_handle.is_focused(window) {
 6043            return;
 6044        }
 6045        let project = self.project.clone();
 6046
 6047        let code_actions_task = match deployed_from {
 6048            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6049            _ => self.code_actions(buffer_row, window, cx),
 6050        };
 6051
 6052        let runnable_task = match deployed_from {
 6053            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6054            _ => {
 6055                let mut task_context_task = Task::ready(None);
 6056                if let Some(tasks) = &tasks
 6057                    && let Some(project) = project
 6058                {
 6059                    task_context_task =
 6060                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6061                }
 6062
 6063                cx.spawn_in(window, {
 6064                    let buffer = buffer.clone();
 6065                    async move |editor, cx| {
 6066                        let task_context = task_context_task.await;
 6067
 6068                        let resolved_tasks =
 6069                            tasks
 6070                                .zip(task_context.clone())
 6071                                .map(|(tasks, task_context)| ResolvedTasks {
 6072                                    templates: tasks.resolve(&task_context).collect(),
 6073                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6074                                        multibuffer_point.row,
 6075                                        tasks.column,
 6076                                    )),
 6077                                });
 6078                        let debug_scenarios = editor
 6079                            .update(cx, |editor, cx| {
 6080                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6081                            })?
 6082                            .await;
 6083                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6084                    }
 6085                })
 6086            }
 6087        };
 6088
 6089        cx.spawn_in(window, async move |editor, cx| {
 6090            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6091            let code_actions = code_actions_task.await;
 6092            let spawn_straight_away = quick_launch
 6093                && resolved_tasks
 6094                    .as_ref()
 6095                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6096                && code_actions
 6097                    .as_ref()
 6098                    .is_none_or(|actions| actions.is_empty())
 6099                && debug_scenarios.is_empty();
 6100
 6101            editor.update_in(cx, |editor, window, cx| {
 6102                crate::hover_popover::hide_hover(editor, cx);
 6103                let actions = CodeActionContents::new(
 6104                    resolved_tasks,
 6105                    code_actions,
 6106                    debug_scenarios,
 6107                    task_context.unwrap_or_default(),
 6108                );
 6109
 6110                // Don't show the menu if there are no actions available
 6111                if actions.is_empty() {
 6112                    cx.notify();
 6113                    return Task::ready(Ok(()));
 6114                }
 6115
 6116                *editor.context_menu.borrow_mut() =
 6117                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6118                        buffer,
 6119                        actions,
 6120                        selected_item: Default::default(),
 6121                        scroll_handle: UniformListScrollHandle::default(),
 6122                        deployed_from,
 6123                    }));
 6124                cx.notify();
 6125                if spawn_straight_away
 6126                    && let Some(task) = editor.confirm_code_action(
 6127                        &ConfirmCodeAction { item_ix: Some(0) },
 6128                        window,
 6129                        cx,
 6130                    )
 6131                {
 6132                    return task;
 6133                }
 6134
 6135                Task::ready(Ok(()))
 6136            })
 6137        })
 6138        .detach_and_log_err(cx);
 6139    }
 6140
 6141    fn debug_scenarios(
 6142        &mut self,
 6143        resolved_tasks: &Option<ResolvedTasks>,
 6144        buffer: &Entity<Buffer>,
 6145        cx: &mut App,
 6146    ) -> Task<Vec<task::DebugScenario>> {
 6147        maybe!({
 6148            let project = self.project()?;
 6149            let dap_store = project.read(cx).dap_store();
 6150            let mut scenarios = vec![];
 6151            let resolved_tasks = resolved_tasks.as_ref()?;
 6152            let buffer = buffer.read(cx);
 6153            let language = buffer.language()?;
 6154            let file = buffer.file();
 6155            let debug_adapter = language_settings(language.name().into(), file, cx)
 6156                .debuggers
 6157                .first()
 6158                .map(SharedString::from)
 6159                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6160
 6161            dap_store.update(cx, |dap_store, cx| {
 6162                for (_, task) in &resolved_tasks.templates {
 6163                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6164                        task.original_task().clone(),
 6165                        debug_adapter.clone().into(),
 6166                        task.display_label().to_owned().into(),
 6167                        cx,
 6168                    );
 6169                    scenarios.push(maybe_scenario);
 6170                }
 6171            });
 6172            Some(cx.background_spawn(async move {
 6173                futures::future::join_all(scenarios)
 6174                    .await
 6175                    .into_iter()
 6176                    .flatten()
 6177                    .collect::<Vec<_>>()
 6178            }))
 6179        })
 6180        .unwrap_or_else(|| Task::ready(vec![]))
 6181    }
 6182
 6183    fn code_actions(
 6184        &mut self,
 6185        buffer_row: u32,
 6186        window: &mut Window,
 6187        cx: &mut Context<Self>,
 6188    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6189        let mut task = self.code_actions_task.take();
 6190        cx.spawn_in(window, async move |editor, cx| {
 6191            while let Some(prev_task) = task {
 6192                prev_task.await.log_err();
 6193                task = editor
 6194                    .update(cx, |this, _| this.code_actions_task.take())
 6195                    .ok()?;
 6196            }
 6197
 6198            editor
 6199                .update(cx, |editor, cx| {
 6200                    editor
 6201                        .available_code_actions
 6202                        .clone()
 6203                        .and_then(|(location, code_actions)| {
 6204                            let snapshot = location.buffer.read(cx).snapshot();
 6205                            let point_range = location.range.to_point(&snapshot);
 6206                            let point_range = point_range.start.row..=point_range.end.row;
 6207                            if point_range.contains(&buffer_row) {
 6208                                Some(code_actions)
 6209                            } else {
 6210                                None
 6211                            }
 6212                        })
 6213                })
 6214                .ok()
 6215                .flatten()
 6216        })
 6217    }
 6218
 6219    pub fn confirm_code_action(
 6220        &mut self,
 6221        action: &ConfirmCodeAction,
 6222        window: &mut Window,
 6223        cx: &mut Context<Self>,
 6224    ) -> Option<Task<Result<()>>> {
 6225        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6226
 6227        let actions_menu =
 6228            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6229                menu
 6230            } else {
 6231                return None;
 6232            };
 6233
 6234        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6235        let action = actions_menu.actions.get(action_ix)?;
 6236        let title = action.label();
 6237        let buffer = actions_menu.buffer;
 6238        let workspace = self.workspace()?;
 6239
 6240        match action {
 6241            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6242                workspace.update(cx, |workspace, cx| {
 6243                    workspace.schedule_resolved_task(
 6244                        task_source_kind,
 6245                        resolved_task,
 6246                        false,
 6247                        window,
 6248                        cx,
 6249                    );
 6250
 6251                    Some(Task::ready(Ok(())))
 6252                })
 6253            }
 6254            CodeActionsItem::CodeAction {
 6255                excerpt_id,
 6256                action,
 6257                provider,
 6258            } => {
 6259                let apply_code_action =
 6260                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6261                let workspace = workspace.downgrade();
 6262                Some(cx.spawn_in(window, async move |editor, cx| {
 6263                    let project_transaction = apply_code_action.await?;
 6264                    Self::open_project_transaction(
 6265                        &editor,
 6266                        workspace,
 6267                        project_transaction,
 6268                        title,
 6269                        cx,
 6270                    )
 6271                    .await
 6272                }))
 6273            }
 6274            CodeActionsItem::DebugScenario(scenario) => {
 6275                let context = actions_menu.actions.context.clone();
 6276
 6277                workspace.update(cx, |workspace, cx| {
 6278                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6279                    workspace.start_debug_session(
 6280                        scenario,
 6281                        context,
 6282                        Some(buffer),
 6283                        None,
 6284                        window,
 6285                        cx,
 6286                    );
 6287                });
 6288                Some(Task::ready(Ok(())))
 6289            }
 6290        }
 6291    }
 6292
 6293    pub async fn open_project_transaction(
 6294        this: &WeakEntity<Editor>,
 6295        workspace: WeakEntity<Workspace>,
 6296        transaction: ProjectTransaction,
 6297        title: String,
 6298        cx: &mut AsyncWindowContext,
 6299    ) -> Result<()> {
 6300        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6301        cx.update(|_, cx| {
 6302            entries.sort_unstable_by_key(|(buffer, _)| {
 6303                buffer.read(cx).file().map(|f| f.path().clone())
 6304            });
 6305        })?;
 6306
 6307        // If the project transaction's edits are all contained within this editor, then
 6308        // avoid opening a new editor to display them.
 6309
 6310        if let Some((buffer, transaction)) = entries.first() {
 6311            if entries.len() == 1 {
 6312                let excerpt = this.update(cx, |editor, cx| {
 6313                    editor
 6314                        .buffer()
 6315                        .read(cx)
 6316                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6317                })?;
 6318                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6319                    && excerpted_buffer == *buffer
 6320                {
 6321                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6322                        let excerpt_range = excerpt_range.to_offset(buffer);
 6323                        buffer
 6324                            .edited_ranges_for_transaction::<usize>(transaction)
 6325                            .all(|range| {
 6326                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6327                            })
 6328                    })?;
 6329
 6330                    if all_edits_within_excerpt {
 6331                        return Ok(());
 6332                    }
 6333                }
 6334            }
 6335        } else {
 6336            return Ok(());
 6337        }
 6338
 6339        let mut ranges_to_highlight = Vec::new();
 6340        let excerpt_buffer = cx.new(|cx| {
 6341            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6342            for (buffer_handle, transaction) in &entries {
 6343                let edited_ranges = buffer_handle
 6344                    .read(cx)
 6345                    .edited_ranges_for_transaction::<Point>(transaction)
 6346                    .collect::<Vec<_>>();
 6347                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6348                    PathKey::for_buffer(buffer_handle, cx),
 6349                    buffer_handle.clone(),
 6350                    edited_ranges,
 6351                    DEFAULT_MULTIBUFFER_CONTEXT,
 6352                    cx,
 6353                );
 6354
 6355                ranges_to_highlight.extend(ranges);
 6356            }
 6357            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6358            multibuffer
 6359        })?;
 6360
 6361        workspace.update_in(cx, |workspace, window, cx| {
 6362            let project = workspace.project().clone();
 6363            let editor =
 6364                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6365            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6366            editor.update(cx, |editor, cx| {
 6367                editor.highlight_background::<Self>(
 6368                    &ranges_to_highlight,
 6369                    |theme| theme.colors().editor_highlighted_line_background,
 6370                    cx,
 6371                );
 6372            });
 6373        })?;
 6374
 6375        Ok(())
 6376    }
 6377
 6378    pub fn clear_code_action_providers(&mut self) {
 6379        self.code_action_providers.clear();
 6380        self.available_code_actions.take();
 6381    }
 6382
 6383    pub fn add_code_action_provider(
 6384        &mut self,
 6385        provider: Rc<dyn CodeActionProvider>,
 6386        window: &mut Window,
 6387        cx: &mut Context<Self>,
 6388    ) {
 6389        if self
 6390            .code_action_providers
 6391            .iter()
 6392            .any(|existing_provider| existing_provider.id() == provider.id())
 6393        {
 6394            return;
 6395        }
 6396
 6397        self.code_action_providers.push(provider);
 6398        self.refresh_code_actions(window, cx);
 6399    }
 6400
 6401    pub fn remove_code_action_provider(
 6402        &mut self,
 6403        id: Arc<str>,
 6404        window: &mut Window,
 6405        cx: &mut Context<Self>,
 6406    ) {
 6407        self.code_action_providers
 6408            .retain(|provider| provider.id() != id);
 6409        self.refresh_code_actions(window, cx);
 6410    }
 6411
 6412    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6413        !self.code_action_providers.is_empty()
 6414            && EditorSettings::get_global(cx).toolbar.code_actions
 6415    }
 6416
 6417    pub fn has_available_code_actions(&self) -> bool {
 6418        self.available_code_actions
 6419            .as_ref()
 6420            .is_some_and(|(_, actions)| !actions.is_empty())
 6421    }
 6422
 6423    fn render_inline_code_actions(
 6424        &self,
 6425        icon_size: ui::IconSize,
 6426        display_row: DisplayRow,
 6427        is_active: bool,
 6428        cx: &mut Context<Self>,
 6429    ) -> AnyElement {
 6430        let show_tooltip = !self.context_menu_visible();
 6431        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6432            .icon_size(icon_size)
 6433            .shape(ui::IconButtonShape::Square)
 6434            .icon_color(ui::Color::Hidden)
 6435            .toggle_state(is_active)
 6436            .when(show_tooltip, |this| {
 6437                this.tooltip({
 6438                    let focus_handle = self.focus_handle.clone();
 6439                    move |window, cx| {
 6440                        Tooltip::for_action_in(
 6441                            "Toggle Code Actions",
 6442                            &ToggleCodeActions {
 6443                                deployed_from: None,
 6444                                quick_launch: false,
 6445                            },
 6446                            &focus_handle,
 6447                            window,
 6448                            cx,
 6449                        )
 6450                    }
 6451                })
 6452            })
 6453            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6454                window.focus(&editor.focus_handle(cx));
 6455                editor.toggle_code_actions(
 6456                    &crate::actions::ToggleCodeActions {
 6457                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6458                            display_row,
 6459                        )),
 6460                        quick_launch: false,
 6461                    },
 6462                    window,
 6463                    cx,
 6464                );
 6465            }))
 6466            .into_any_element()
 6467    }
 6468
 6469    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6470        &self.context_menu
 6471    }
 6472
 6473    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6474        let newest_selection = self.selections.newest_anchor().clone();
 6475        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6476        let buffer = self.buffer.read(cx);
 6477        if newest_selection.head().diff_base_anchor.is_some() {
 6478            return None;
 6479        }
 6480        let (start_buffer, start) =
 6481            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6482        let (end_buffer, end) =
 6483            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6484        if start_buffer != end_buffer {
 6485            return None;
 6486        }
 6487
 6488        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6489            cx.background_executor()
 6490                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6491                .await;
 6492
 6493            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6494                let providers = this.code_action_providers.clone();
 6495                let tasks = this
 6496                    .code_action_providers
 6497                    .iter()
 6498                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6499                    .collect::<Vec<_>>();
 6500                (providers, tasks)
 6501            })?;
 6502
 6503            let mut actions = Vec::new();
 6504            for (provider, provider_actions) in
 6505                providers.into_iter().zip(future::join_all(tasks).await)
 6506            {
 6507                if let Some(provider_actions) = provider_actions.log_err() {
 6508                    actions.extend(provider_actions.into_iter().map(|action| {
 6509                        AvailableCodeAction {
 6510                            excerpt_id: newest_selection.start.excerpt_id,
 6511                            action,
 6512                            provider: provider.clone(),
 6513                        }
 6514                    }));
 6515                }
 6516            }
 6517
 6518            this.update(cx, |this, cx| {
 6519                this.available_code_actions = if actions.is_empty() {
 6520                    None
 6521                } else {
 6522                    Some((
 6523                        Location {
 6524                            buffer: start_buffer,
 6525                            range: start..end,
 6526                        },
 6527                        actions.into(),
 6528                    ))
 6529                };
 6530                cx.notify();
 6531            })
 6532        }));
 6533        None
 6534    }
 6535
 6536    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6537        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6538            self.show_git_blame_inline = false;
 6539
 6540            self.show_git_blame_inline_delay_task =
 6541                Some(cx.spawn_in(window, async move |this, cx| {
 6542                    cx.background_executor().timer(delay).await;
 6543
 6544                    this.update(cx, |this, cx| {
 6545                        this.show_git_blame_inline = true;
 6546                        cx.notify();
 6547                    })
 6548                    .log_err();
 6549                }));
 6550        }
 6551    }
 6552
 6553    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6554        let snapshot = self.snapshot(window, cx);
 6555        let cursor = self.selections.newest::<Point>(cx).head();
 6556        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6557        else {
 6558            return;
 6559        };
 6560
 6561        let Some(blame) = self.blame.as_ref() else {
 6562            return;
 6563        };
 6564
 6565        let row_info = RowInfo {
 6566            buffer_id: Some(buffer.remote_id()),
 6567            buffer_row: Some(point.row),
 6568            ..Default::default()
 6569        };
 6570        let Some(blame_entry) = blame
 6571            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6572            .flatten()
 6573        else {
 6574            return;
 6575        };
 6576
 6577        let anchor = self.selections.newest_anchor().head();
 6578        let position = self.to_pixel_point(anchor, &snapshot, window);
 6579        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6580            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6581        };
 6582    }
 6583
 6584    fn show_blame_popover(
 6585        &mut self,
 6586        blame_entry: &BlameEntry,
 6587        position: gpui::Point<Pixels>,
 6588        ignore_timeout: bool,
 6589        cx: &mut Context<Self>,
 6590    ) {
 6591        if let Some(state) = &mut self.inline_blame_popover {
 6592            state.hide_task.take();
 6593        } else {
 6594            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6595            let blame_entry = blame_entry.clone();
 6596            let show_task = cx.spawn(async move |editor, cx| {
 6597                if !ignore_timeout {
 6598                    cx.background_executor()
 6599                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6600                        .await;
 6601                }
 6602                editor
 6603                    .update(cx, |editor, cx| {
 6604                        editor.inline_blame_popover_show_task.take();
 6605                        let Some(blame) = editor.blame.as_ref() else {
 6606                            return;
 6607                        };
 6608                        let blame = blame.read(cx);
 6609                        let details = blame.details_for_entry(&blame_entry);
 6610                        let markdown = cx.new(|cx| {
 6611                            Markdown::new(
 6612                                details
 6613                                    .as_ref()
 6614                                    .map(|message| message.message.clone())
 6615                                    .unwrap_or_default(),
 6616                                None,
 6617                                None,
 6618                                cx,
 6619                            )
 6620                        });
 6621                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6622                            position,
 6623                            hide_task: None,
 6624                            popover_bounds: None,
 6625                            popover_state: InlineBlamePopoverState {
 6626                                scroll_handle: ScrollHandle::new(),
 6627                                commit_message: details,
 6628                                markdown,
 6629                            },
 6630                            keyboard_grace: ignore_timeout,
 6631                        });
 6632                        cx.notify();
 6633                    })
 6634                    .ok();
 6635            });
 6636            self.inline_blame_popover_show_task = Some(show_task);
 6637        }
 6638    }
 6639
 6640    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6641        self.inline_blame_popover_show_task.take();
 6642        if let Some(state) = &mut self.inline_blame_popover {
 6643            let hide_task = cx.spawn(async move |editor, cx| {
 6644                cx.background_executor()
 6645                    .timer(std::time::Duration::from_millis(100))
 6646                    .await;
 6647                editor
 6648                    .update(cx, |editor, cx| {
 6649                        editor.inline_blame_popover.take();
 6650                        cx.notify();
 6651                    })
 6652                    .ok();
 6653            });
 6654            state.hide_task = Some(hide_task);
 6655        }
 6656    }
 6657
 6658    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6659        if self.pending_rename.is_some() {
 6660            return None;
 6661        }
 6662
 6663        let provider = self.semantics_provider.clone()?;
 6664        let buffer = self.buffer.read(cx);
 6665        let newest_selection = self.selections.newest_anchor().clone();
 6666        let cursor_position = newest_selection.head();
 6667        let (cursor_buffer, cursor_buffer_position) =
 6668            buffer.text_anchor_for_position(cursor_position, cx)?;
 6669        let (tail_buffer, tail_buffer_position) =
 6670            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6671        if cursor_buffer != tail_buffer {
 6672            return None;
 6673        }
 6674
 6675        let snapshot = cursor_buffer.read(cx).snapshot();
 6676        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6677        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6678        if start_word_range != end_word_range {
 6679            self.document_highlights_task.take();
 6680            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6681            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6682            return None;
 6683        }
 6684
 6685        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6686        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6687            cx.background_executor()
 6688                .timer(Duration::from_millis(debounce))
 6689                .await;
 6690
 6691            let highlights = if let Some(highlights) = cx
 6692                .update(|cx| {
 6693                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6694                })
 6695                .ok()
 6696                .flatten()
 6697            {
 6698                highlights.await.log_err()
 6699            } else {
 6700                None
 6701            };
 6702
 6703            if let Some(highlights) = highlights {
 6704                this.update(cx, |this, cx| {
 6705                    if this.pending_rename.is_some() {
 6706                        return;
 6707                    }
 6708
 6709                    let buffer_id = cursor_position.buffer_id;
 6710                    let buffer = this.buffer.read(cx);
 6711                    if buffer
 6712                        .text_anchor_for_position(cursor_position, cx)
 6713                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6714                    {
 6715                        return;
 6716                    }
 6717
 6718                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6719                    let mut write_ranges = Vec::new();
 6720                    let mut read_ranges = Vec::new();
 6721                    for highlight in highlights {
 6722                        for (excerpt_id, excerpt_range) in
 6723                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6724                        {
 6725                            let start = highlight
 6726                                .range
 6727                                .start
 6728                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6729                            let end = highlight
 6730                                .range
 6731                                .end
 6732                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6733                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6734                                continue;
 6735                            }
 6736
 6737                            let range = Anchor {
 6738                                buffer_id,
 6739                                excerpt_id,
 6740                                text_anchor: start,
 6741                                diff_base_anchor: None,
 6742                            }..Anchor {
 6743                                buffer_id,
 6744                                excerpt_id,
 6745                                text_anchor: end,
 6746                                diff_base_anchor: None,
 6747                            };
 6748                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6749                                write_ranges.push(range);
 6750                            } else {
 6751                                read_ranges.push(range);
 6752                            }
 6753                        }
 6754                    }
 6755
 6756                    this.highlight_background::<DocumentHighlightRead>(
 6757                        &read_ranges,
 6758                        |theme| theme.colors().editor_document_highlight_read_background,
 6759                        cx,
 6760                    );
 6761                    this.highlight_background::<DocumentHighlightWrite>(
 6762                        &write_ranges,
 6763                        |theme| theme.colors().editor_document_highlight_write_background,
 6764                        cx,
 6765                    );
 6766                    cx.notify();
 6767                })
 6768                .log_err();
 6769            }
 6770        }));
 6771        None
 6772    }
 6773
 6774    fn prepare_highlight_query_from_selection(
 6775        &mut self,
 6776        cx: &mut Context<Editor>,
 6777    ) -> Option<(String, Range<Anchor>)> {
 6778        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6779            return None;
 6780        }
 6781        if !EditorSettings::get_global(cx).selection_highlight {
 6782            return None;
 6783        }
 6784        if self.selections.count() != 1 || self.selections.line_mode {
 6785            return None;
 6786        }
 6787        let selection = self.selections.newest::<Point>(cx);
 6788        if selection.is_empty() || selection.start.row != selection.end.row {
 6789            return None;
 6790        }
 6791        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6792        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6793        let query = multi_buffer_snapshot
 6794            .text_for_range(selection_anchor_range.clone())
 6795            .collect::<String>();
 6796        if query.trim().is_empty() {
 6797            return None;
 6798        }
 6799        Some((query, selection_anchor_range))
 6800    }
 6801
 6802    fn update_selection_occurrence_highlights(
 6803        &mut self,
 6804        query_text: String,
 6805        query_range: Range<Anchor>,
 6806        multi_buffer_range_to_query: Range<Point>,
 6807        use_debounce: bool,
 6808        window: &mut Window,
 6809        cx: &mut Context<Editor>,
 6810    ) -> Task<()> {
 6811        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6812        cx.spawn_in(window, async move |editor, cx| {
 6813            if use_debounce {
 6814                cx.background_executor()
 6815                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6816                    .await;
 6817            }
 6818            let match_task = cx.background_spawn(async move {
 6819                let buffer_ranges = multi_buffer_snapshot
 6820                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6821                    .into_iter()
 6822                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6823                let mut match_ranges = Vec::new();
 6824                let Ok(regex) = project::search::SearchQuery::text(
 6825                    query_text.clone(),
 6826                    false,
 6827                    false,
 6828                    false,
 6829                    Default::default(),
 6830                    Default::default(),
 6831                    false,
 6832                    None,
 6833                ) else {
 6834                    return Vec::default();
 6835                };
 6836                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6837                    match_ranges.extend(
 6838                        regex
 6839                            .search(buffer_snapshot, Some(search_range.clone()))
 6840                            .await
 6841                            .into_iter()
 6842                            .filter_map(|match_range| {
 6843                                let match_start = buffer_snapshot
 6844                                    .anchor_after(search_range.start + match_range.start);
 6845                                let match_end = buffer_snapshot
 6846                                    .anchor_before(search_range.start + match_range.end);
 6847                                let match_anchor_range = Anchor::range_in_buffer(
 6848                                    excerpt_id,
 6849                                    buffer_snapshot.remote_id(),
 6850                                    match_start..match_end,
 6851                                );
 6852                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6853                            }),
 6854                    );
 6855                }
 6856                match_ranges
 6857            });
 6858            let match_ranges = match_task.await;
 6859            editor
 6860                .update_in(cx, |editor, _, cx| {
 6861                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6862                    if !match_ranges.is_empty() {
 6863                        editor.highlight_background::<SelectedTextHighlight>(
 6864                            &match_ranges,
 6865                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6866                            cx,
 6867                        )
 6868                    }
 6869                })
 6870                .log_err();
 6871        })
 6872    }
 6873
 6874    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6875        struct NewlineFold;
 6876        let type_id = std::any::TypeId::of::<NewlineFold>();
 6877        if !self.mode.is_single_line() {
 6878            return;
 6879        }
 6880        let snapshot = self.snapshot(window, cx);
 6881        if snapshot.buffer_snapshot.max_point().row == 0 {
 6882            return;
 6883        }
 6884        let task = cx.background_spawn(async move {
 6885            let new_newlines = snapshot
 6886                .buffer_chars_at(0)
 6887                .filter_map(|(c, i)| {
 6888                    if c == '\n' {
 6889                        Some(
 6890                            snapshot.buffer_snapshot.anchor_after(i)
 6891                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6892                        )
 6893                    } else {
 6894                        None
 6895                    }
 6896                })
 6897                .collect::<Vec<_>>();
 6898            let existing_newlines = snapshot
 6899                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6900                .filter_map(|fold| {
 6901                    if fold.placeholder.type_tag == Some(type_id) {
 6902                        Some(fold.range.start..fold.range.end)
 6903                    } else {
 6904                        None
 6905                    }
 6906                })
 6907                .collect::<Vec<_>>();
 6908
 6909            (new_newlines, existing_newlines)
 6910        });
 6911        self.folding_newlines = cx.spawn(async move |this, cx| {
 6912            let (new_newlines, existing_newlines) = task.await;
 6913            if new_newlines == existing_newlines {
 6914                return;
 6915            }
 6916            let placeholder = FoldPlaceholder {
 6917                render: Arc::new(move |_, _, cx| {
 6918                    div()
 6919                        .bg(cx.theme().status().hint_background)
 6920                        .border_b_1()
 6921                        .size_full()
 6922                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6923                        .border_color(cx.theme().status().hint)
 6924                        .child("\\n")
 6925                        .into_any()
 6926                }),
 6927                constrain_width: false,
 6928                merge_adjacent: false,
 6929                type_tag: Some(type_id),
 6930            };
 6931            let creases = new_newlines
 6932                .into_iter()
 6933                .map(|range| Crease::simple(range, placeholder.clone()))
 6934                .collect();
 6935            this.update(cx, |this, cx| {
 6936                this.display_map.update(cx, |display_map, cx| {
 6937                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6938                    display_map.fold(creases, cx);
 6939                });
 6940            })
 6941            .ok();
 6942        });
 6943    }
 6944
 6945    fn refresh_selected_text_highlights(
 6946        &mut self,
 6947        on_buffer_edit: bool,
 6948        window: &mut Window,
 6949        cx: &mut Context<Editor>,
 6950    ) {
 6951        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6952        else {
 6953            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6954            self.quick_selection_highlight_task.take();
 6955            self.debounced_selection_highlight_task.take();
 6956            return;
 6957        };
 6958        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6959        if on_buffer_edit
 6960            || self
 6961                .quick_selection_highlight_task
 6962                .as_ref()
 6963                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6964        {
 6965            let multi_buffer_visible_start = self
 6966                .scroll_manager
 6967                .anchor()
 6968                .anchor
 6969                .to_point(&multi_buffer_snapshot);
 6970            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6971                multi_buffer_visible_start
 6972                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6973                Bias::Left,
 6974            );
 6975            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6976            self.quick_selection_highlight_task = Some((
 6977                query_range.clone(),
 6978                self.update_selection_occurrence_highlights(
 6979                    query_text.clone(),
 6980                    query_range.clone(),
 6981                    multi_buffer_visible_range,
 6982                    false,
 6983                    window,
 6984                    cx,
 6985                ),
 6986            ));
 6987        }
 6988        if on_buffer_edit
 6989            || self
 6990                .debounced_selection_highlight_task
 6991                .as_ref()
 6992                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6993        {
 6994            let multi_buffer_start = multi_buffer_snapshot
 6995                .anchor_before(0)
 6996                .to_point(&multi_buffer_snapshot);
 6997            let multi_buffer_end = multi_buffer_snapshot
 6998                .anchor_after(multi_buffer_snapshot.len())
 6999                .to_point(&multi_buffer_snapshot);
 7000            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7001            self.debounced_selection_highlight_task = Some((
 7002                query_range.clone(),
 7003                self.update_selection_occurrence_highlights(
 7004                    query_text,
 7005                    query_range,
 7006                    multi_buffer_full_range,
 7007                    true,
 7008                    window,
 7009                    cx,
 7010                ),
 7011            ));
 7012        }
 7013    }
 7014
 7015    pub fn refresh_edit_prediction(
 7016        &mut self,
 7017        debounce: bool,
 7018        user_requested: bool,
 7019        window: &mut Window,
 7020        cx: &mut Context<Self>,
 7021    ) -> Option<()> {
 7022        if DisableAiSettings::get_global(cx).disable_ai {
 7023            return None;
 7024        }
 7025
 7026        let provider = self.edit_prediction_provider()?;
 7027        let cursor = self.selections.newest_anchor().head();
 7028        let (buffer, cursor_buffer_position) =
 7029            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7030
 7031        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7032            self.discard_edit_prediction(false, cx);
 7033            return None;
 7034        }
 7035
 7036        if !user_requested
 7037            && (!self.should_show_edit_predictions()
 7038                || !self.is_focused(window)
 7039                || buffer.read(cx).is_empty())
 7040        {
 7041            self.discard_edit_prediction(false, cx);
 7042            return None;
 7043        }
 7044
 7045        self.update_visible_edit_prediction(window, cx);
 7046        provider.refresh(
 7047            self.project.clone(),
 7048            buffer,
 7049            cursor_buffer_position,
 7050            debounce,
 7051            cx,
 7052        );
 7053        Some(())
 7054    }
 7055
 7056    fn show_edit_predictions_in_menu(&self) -> bool {
 7057        match self.edit_prediction_settings {
 7058            EditPredictionSettings::Disabled => false,
 7059            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7060        }
 7061    }
 7062
 7063    pub fn edit_predictions_enabled(&self) -> bool {
 7064        match self.edit_prediction_settings {
 7065            EditPredictionSettings::Disabled => false,
 7066            EditPredictionSettings::Enabled { .. } => true,
 7067        }
 7068    }
 7069
 7070    fn edit_prediction_requires_modifier(&self) -> bool {
 7071        match self.edit_prediction_settings {
 7072            EditPredictionSettings::Disabled => false,
 7073            EditPredictionSettings::Enabled {
 7074                preview_requires_modifier,
 7075                ..
 7076            } => preview_requires_modifier,
 7077        }
 7078    }
 7079
 7080    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7081        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7082            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7083            self.discard_edit_prediction(false, cx);
 7084        } else {
 7085            let selection = self.selections.newest_anchor();
 7086            let cursor = selection.head();
 7087
 7088            if let Some((buffer, cursor_buffer_position)) =
 7089                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7090            {
 7091                self.edit_prediction_settings =
 7092                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7093            }
 7094        }
 7095    }
 7096
 7097    fn edit_prediction_settings_at_position(
 7098        &self,
 7099        buffer: &Entity<Buffer>,
 7100        buffer_position: language::Anchor,
 7101        cx: &App,
 7102    ) -> EditPredictionSettings {
 7103        if !self.mode.is_full()
 7104            || !self.show_edit_predictions_override.unwrap_or(true)
 7105            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7106        {
 7107            return EditPredictionSettings::Disabled;
 7108        }
 7109
 7110        let buffer = buffer.read(cx);
 7111
 7112        let file = buffer.file();
 7113
 7114        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7115            return EditPredictionSettings::Disabled;
 7116        };
 7117
 7118        let by_provider = matches!(
 7119            self.menu_edit_predictions_policy,
 7120            MenuEditPredictionsPolicy::ByProvider
 7121        );
 7122
 7123        let show_in_menu = by_provider
 7124            && self
 7125                .edit_prediction_provider
 7126                .as_ref()
 7127                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7128
 7129        let preview_requires_modifier =
 7130            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7131
 7132        EditPredictionSettings::Enabled {
 7133            show_in_menu,
 7134            preview_requires_modifier,
 7135        }
 7136    }
 7137
 7138    fn should_show_edit_predictions(&self) -> bool {
 7139        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7140    }
 7141
 7142    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7143        matches!(
 7144            self.edit_prediction_preview,
 7145            EditPredictionPreview::Active { .. }
 7146        )
 7147    }
 7148
 7149    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7150        let cursor = self.selections.newest_anchor().head();
 7151        if let Some((buffer, cursor_position)) =
 7152            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7153        {
 7154            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7155        } else {
 7156            false
 7157        }
 7158    }
 7159
 7160    pub fn supports_minimap(&self, cx: &App) -> bool {
 7161        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7162    }
 7163
 7164    fn edit_predictions_enabled_in_buffer(
 7165        &self,
 7166        buffer: &Entity<Buffer>,
 7167        buffer_position: language::Anchor,
 7168        cx: &App,
 7169    ) -> bool {
 7170        maybe!({
 7171            if self.read_only(cx) {
 7172                return Some(false);
 7173            }
 7174            let provider = self.edit_prediction_provider()?;
 7175            if !provider.is_enabled(buffer, buffer_position, cx) {
 7176                return Some(false);
 7177            }
 7178            let buffer = buffer.read(cx);
 7179            let Some(file) = buffer.file() else {
 7180                return Some(true);
 7181            };
 7182            let settings = all_language_settings(Some(file), cx);
 7183            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7184        })
 7185        .unwrap_or(false)
 7186    }
 7187
 7188    fn cycle_edit_prediction(
 7189        &mut self,
 7190        direction: Direction,
 7191        window: &mut Window,
 7192        cx: &mut Context<Self>,
 7193    ) -> Option<()> {
 7194        let provider = self.edit_prediction_provider()?;
 7195        let cursor = self.selections.newest_anchor().head();
 7196        let (buffer, cursor_buffer_position) =
 7197            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7198        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7199            return None;
 7200        }
 7201
 7202        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7203        self.update_visible_edit_prediction(window, cx);
 7204
 7205        Some(())
 7206    }
 7207
 7208    pub fn show_edit_prediction(
 7209        &mut self,
 7210        _: &ShowEditPrediction,
 7211        window: &mut Window,
 7212        cx: &mut Context<Self>,
 7213    ) {
 7214        if !self.has_active_edit_prediction() {
 7215            self.refresh_edit_prediction(false, true, window, cx);
 7216            return;
 7217        }
 7218
 7219        self.update_visible_edit_prediction(window, cx);
 7220    }
 7221
 7222    pub fn display_cursor_names(
 7223        &mut self,
 7224        _: &DisplayCursorNames,
 7225        window: &mut Window,
 7226        cx: &mut Context<Self>,
 7227    ) {
 7228        self.show_cursor_names(window, cx);
 7229    }
 7230
 7231    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7232        self.show_cursor_names = true;
 7233        cx.notify();
 7234        cx.spawn_in(window, async move |this, cx| {
 7235            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7236            this.update(cx, |this, cx| {
 7237                this.show_cursor_names = false;
 7238                cx.notify()
 7239            })
 7240            .ok()
 7241        })
 7242        .detach();
 7243    }
 7244
 7245    pub fn next_edit_prediction(
 7246        &mut self,
 7247        _: &NextEditPrediction,
 7248        window: &mut Window,
 7249        cx: &mut Context<Self>,
 7250    ) {
 7251        if self.has_active_edit_prediction() {
 7252            self.cycle_edit_prediction(Direction::Next, window, cx);
 7253        } else {
 7254            let is_copilot_disabled = self
 7255                .refresh_edit_prediction(false, true, window, cx)
 7256                .is_none();
 7257            if is_copilot_disabled {
 7258                cx.propagate();
 7259            }
 7260        }
 7261    }
 7262
 7263    pub fn previous_edit_prediction(
 7264        &mut self,
 7265        _: &PreviousEditPrediction,
 7266        window: &mut Window,
 7267        cx: &mut Context<Self>,
 7268    ) {
 7269        if self.has_active_edit_prediction() {
 7270            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7271        } else {
 7272            let is_copilot_disabled = self
 7273                .refresh_edit_prediction(false, true, window, cx)
 7274                .is_none();
 7275            if is_copilot_disabled {
 7276                cx.propagate();
 7277            }
 7278        }
 7279    }
 7280
 7281    pub fn accept_edit_prediction(
 7282        &mut self,
 7283        _: &AcceptEditPrediction,
 7284        window: &mut Window,
 7285        cx: &mut Context<Self>,
 7286    ) {
 7287        if self.show_edit_predictions_in_menu() {
 7288            self.hide_context_menu(window, cx);
 7289        }
 7290
 7291        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7292            return;
 7293        };
 7294
 7295        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7296
 7297        match &active_edit_prediction.completion {
 7298            EditPrediction::Move { target, .. } => {
 7299                let target = *target;
 7300
 7301                if let Some(position_map) = &self.last_position_map {
 7302                    if position_map
 7303                        .visible_row_range
 7304                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7305                        || !self.edit_prediction_requires_modifier()
 7306                    {
 7307                        self.unfold_ranges(&[target..target], true, false, cx);
 7308                        // Note that this is also done in vim's handler of the Tab action.
 7309                        self.change_selections(
 7310                            SelectionEffects::scroll(Autoscroll::newest()),
 7311                            window,
 7312                            cx,
 7313                            |selections| {
 7314                                selections.select_anchor_ranges([target..target]);
 7315                            },
 7316                        );
 7317                        self.clear_row_highlights::<EditPredictionPreview>();
 7318
 7319                        self.edit_prediction_preview
 7320                            .set_previous_scroll_position(None);
 7321                    } else {
 7322                        self.edit_prediction_preview
 7323                            .set_previous_scroll_position(Some(
 7324                                position_map.snapshot.scroll_anchor,
 7325                            ));
 7326
 7327                        self.highlight_rows::<EditPredictionPreview>(
 7328                            target..target,
 7329                            cx.theme().colors().editor_highlighted_line_background,
 7330                            RowHighlightOptions {
 7331                                autoscroll: true,
 7332                                ..Default::default()
 7333                            },
 7334                            cx,
 7335                        );
 7336                        self.request_autoscroll(Autoscroll::fit(), cx);
 7337                    }
 7338                }
 7339            }
 7340            EditPrediction::Edit { edits, .. } => {
 7341                if let Some(provider) = self.edit_prediction_provider() {
 7342                    provider.accept(cx);
 7343                }
 7344
 7345                // Store the transaction ID and selections before applying the edit
 7346                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7347
 7348                let snapshot = self.buffer.read(cx).snapshot(cx);
 7349                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7350
 7351                self.buffer.update(cx, |buffer, cx| {
 7352                    buffer.edit(edits.iter().cloned(), None, cx)
 7353                });
 7354
 7355                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7356                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7357                });
 7358
 7359                let selections = self.selections.disjoint_anchors();
 7360                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7361                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7362                    if has_new_transaction {
 7363                        self.selection_history
 7364                            .insert_transaction(transaction_id_now, selections);
 7365                    }
 7366                }
 7367
 7368                self.update_visible_edit_prediction(window, cx);
 7369                if self.active_edit_prediction.is_none() {
 7370                    self.refresh_edit_prediction(true, true, window, cx);
 7371                }
 7372
 7373                cx.notify();
 7374            }
 7375        }
 7376
 7377        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7378    }
 7379
 7380    pub fn accept_partial_edit_prediction(
 7381        &mut self,
 7382        _: &AcceptPartialEditPrediction,
 7383        window: &mut Window,
 7384        cx: &mut Context<Self>,
 7385    ) {
 7386        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7387            return;
 7388        };
 7389        if self.selections.count() != 1 {
 7390            return;
 7391        }
 7392
 7393        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7394
 7395        match &active_edit_prediction.completion {
 7396            EditPrediction::Move { target, .. } => {
 7397                let target = *target;
 7398                self.change_selections(
 7399                    SelectionEffects::scroll(Autoscroll::newest()),
 7400                    window,
 7401                    cx,
 7402                    |selections| {
 7403                        selections.select_anchor_ranges([target..target]);
 7404                    },
 7405                );
 7406            }
 7407            EditPrediction::Edit { edits, .. } => {
 7408                // Find an insertion that starts at the cursor position.
 7409                let snapshot = self.buffer.read(cx).snapshot(cx);
 7410                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7411                let insertion = edits.iter().find_map(|(range, text)| {
 7412                    let range = range.to_offset(&snapshot);
 7413                    if range.is_empty() && range.start == cursor_offset {
 7414                        Some(text)
 7415                    } else {
 7416                        None
 7417                    }
 7418                });
 7419
 7420                if let Some(text) = insertion {
 7421                    let mut partial_completion = text
 7422                        .chars()
 7423                        .by_ref()
 7424                        .take_while(|c| c.is_alphabetic())
 7425                        .collect::<String>();
 7426                    if partial_completion.is_empty() {
 7427                        partial_completion = text
 7428                            .chars()
 7429                            .by_ref()
 7430                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7431                            .collect::<String>();
 7432                    }
 7433
 7434                    cx.emit(EditorEvent::InputHandled {
 7435                        utf16_range_to_replace: None,
 7436                        text: partial_completion.clone().into(),
 7437                    });
 7438
 7439                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7440
 7441                    self.refresh_edit_prediction(true, true, window, cx);
 7442                    cx.notify();
 7443                } else {
 7444                    self.accept_edit_prediction(&Default::default(), window, cx);
 7445                }
 7446            }
 7447        }
 7448    }
 7449
 7450    fn discard_edit_prediction(
 7451        &mut self,
 7452        should_report_edit_prediction_event: bool,
 7453        cx: &mut Context<Self>,
 7454    ) -> bool {
 7455        if should_report_edit_prediction_event {
 7456            let completion_id = self
 7457                .active_edit_prediction
 7458                .as_ref()
 7459                .and_then(|active_completion| active_completion.completion_id.clone());
 7460
 7461            self.report_edit_prediction_event(completion_id, false, cx);
 7462        }
 7463
 7464        if let Some(provider) = self.edit_prediction_provider() {
 7465            provider.discard(cx);
 7466        }
 7467
 7468        self.take_active_edit_prediction(cx)
 7469    }
 7470
 7471    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7472        let Some(provider) = self.edit_prediction_provider() else {
 7473            return;
 7474        };
 7475
 7476        let Some((_, buffer, _)) = self
 7477            .buffer
 7478            .read(cx)
 7479            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7480        else {
 7481            return;
 7482        };
 7483
 7484        let extension = buffer
 7485            .read(cx)
 7486            .file()
 7487            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7488
 7489        let event_type = match accepted {
 7490            true => "Edit Prediction Accepted",
 7491            false => "Edit Prediction Discarded",
 7492        };
 7493        telemetry::event!(
 7494            event_type,
 7495            provider = provider.name(),
 7496            prediction_id = id,
 7497            suggestion_accepted = accepted,
 7498            file_extension = extension,
 7499        );
 7500    }
 7501
 7502    pub fn has_active_edit_prediction(&self) -> bool {
 7503        self.active_edit_prediction.is_some()
 7504    }
 7505
 7506    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7507        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7508            return false;
 7509        };
 7510
 7511        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7512        self.clear_highlights::<EditPredictionHighlight>(cx);
 7513        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7514        true
 7515    }
 7516
 7517    /// Returns true when we're displaying the edit prediction popover below the cursor
 7518    /// like we are not previewing and the LSP autocomplete menu is visible
 7519    /// or we are in `when_holding_modifier` mode.
 7520    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7521        if self.edit_prediction_preview_is_active()
 7522            || !self.show_edit_predictions_in_menu()
 7523            || !self.edit_predictions_enabled()
 7524        {
 7525            return false;
 7526        }
 7527
 7528        if self.has_visible_completions_menu() {
 7529            return true;
 7530        }
 7531
 7532        has_completion && self.edit_prediction_requires_modifier()
 7533    }
 7534
 7535    fn handle_modifiers_changed(
 7536        &mut self,
 7537        modifiers: Modifiers,
 7538        position_map: &PositionMap,
 7539        window: &mut Window,
 7540        cx: &mut Context<Self>,
 7541    ) {
 7542        if self.show_edit_predictions_in_menu() {
 7543            self.update_edit_prediction_preview(&modifiers, window, cx);
 7544        }
 7545
 7546        self.update_selection_mode(&modifiers, position_map, window, cx);
 7547
 7548        let mouse_position = window.mouse_position();
 7549        if !position_map.text_hitbox.is_hovered(window) {
 7550            return;
 7551        }
 7552
 7553        self.update_hovered_link(
 7554            position_map.point_for_position(mouse_position),
 7555            &position_map.snapshot,
 7556            modifiers,
 7557            window,
 7558            cx,
 7559        )
 7560    }
 7561
 7562    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7563        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7564        if invert {
 7565            match multi_cursor_setting {
 7566                MultiCursorModifier::Alt => modifiers.alt,
 7567                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7568            }
 7569        } else {
 7570            match multi_cursor_setting {
 7571                MultiCursorModifier::Alt => modifiers.secondary(),
 7572                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7573            }
 7574        }
 7575    }
 7576
 7577    fn columnar_selection_mode(
 7578        modifiers: &Modifiers,
 7579        cx: &mut Context<Self>,
 7580    ) -> Option<ColumnarMode> {
 7581        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7582            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7583                Some(ColumnarMode::FromMouse)
 7584            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7585                Some(ColumnarMode::FromSelection)
 7586            } else {
 7587                None
 7588            }
 7589        } else {
 7590            None
 7591        }
 7592    }
 7593
 7594    fn update_selection_mode(
 7595        &mut self,
 7596        modifiers: &Modifiers,
 7597        position_map: &PositionMap,
 7598        window: &mut Window,
 7599        cx: &mut Context<Self>,
 7600    ) {
 7601        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7602            return;
 7603        };
 7604        if self.selections.pending.is_none() {
 7605            return;
 7606        }
 7607
 7608        let mouse_position = window.mouse_position();
 7609        let point_for_position = position_map.point_for_position(mouse_position);
 7610        let position = point_for_position.previous_valid;
 7611
 7612        self.select(
 7613            SelectPhase::BeginColumnar {
 7614                position,
 7615                reset: false,
 7616                mode,
 7617                goal_column: point_for_position.exact_unclipped.column(),
 7618            },
 7619            window,
 7620            cx,
 7621        );
 7622    }
 7623
 7624    fn update_edit_prediction_preview(
 7625        &mut self,
 7626        modifiers: &Modifiers,
 7627        window: &mut Window,
 7628        cx: &mut Context<Self>,
 7629    ) {
 7630        let mut modifiers_held = false;
 7631        if let Some(accept_keystroke) = self
 7632            .accept_edit_prediction_keybind(false, window, cx)
 7633            .keystroke()
 7634        {
 7635            modifiers_held = modifiers_held
 7636                || (&accept_keystroke.modifiers == modifiers
 7637                    && accept_keystroke.modifiers.modified());
 7638        };
 7639        if let Some(accept_partial_keystroke) = self
 7640            .accept_edit_prediction_keybind(true, window, cx)
 7641            .keystroke()
 7642        {
 7643            modifiers_held = modifiers_held
 7644                || (&accept_partial_keystroke.modifiers == modifiers
 7645                    && accept_partial_keystroke.modifiers.modified());
 7646        }
 7647
 7648        if modifiers_held {
 7649            if matches!(
 7650                self.edit_prediction_preview,
 7651                EditPredictionPreview::Inactive { .. }
 7652            ) {
 7653                self.edit_prediction_preview = EditPredictionPreview::Active {
 7654                    previous_scroll_position: None,
 7655                    since: Instant::now(),
 7656                };
 7657
 7658                self.update_visible_edit_prediction(window, cx);
 7659                cx.notify();
 7660            }
 7661        } else if let EditPredictionPreview::Active {
 7662            previous_scroll_position,
 7663            since,
 7664        } = self.edit_prediction_preview
 7665        {
 7666            if let (Some(previous_scroll_position), Some(position_map)) =
 7667                (previous_scroll_position, self.last_position_map.as_ref())
 7668            {
 7669                self.set_scroll_position(
 7670                    previous_scroll_position
 7671                        .scroll_position(&position_map.snapshot.display_snapshot),
 7672                    window,
 7673                    cx,
 7674                );
 7675            }
 7676
 7677            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7678                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7679            };
 7680            self.clear_row_highlights::<EditPredictionPreview>();
 7681            self.update_visible_edit_prediction(window, cx);
 7682            cx.notify();
 7683        }
 7684    }
 7685
 7686    fn update_visible_edit_prediction(
 7687        &mut self,
 7688        _window: &mut Window,
 7689        cx: &mut Context<Self>,
 7690    ) -> Option<()> {
 7691        if DisableAiSettings::get_global(cx).disable_ai {
 7692            return None;
 7693        }
 7694
 7695        let selection = self.selections.newest_anchor();
 7696        let cursor = selection.head();
 7697        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7698        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7699        let excerpt_id = cursor.excerpt_id;
 7700
 7701        let show_in_menu = self.show_edit_predictions_in_menu();
 7702        let completions_menu_has_precedence = !show_in_menu
 7703            && (self.context_menu.borrow().is_some()
 7704                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7705
 7706        if completions_menu_has_precedence
 7707            || !offset_selection.is_empty()
 7708            || self
 7709                .active_edit_prediction
 7710                .as_ref()
 7711                .is_some_and(|completion| {
 7712                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7713                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7714                    !invalidation_range.contains(&offset_selection.head())
 7715                })
 7716        {
 7717            self.discard_edit_prediction(false, cx);
 7718            return None;
 7719        }
 7720
 7721        self.take_active_edit_prediction(cx);
 7722        let Some(provider) = self.edit_prediction_provider() else {
 7723            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7724            return None;
 7725        };
 7726
 7727        let (buffer, cursor_buffer_position) =
 7728            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7729
 7730        self.edit_prediction_settings =
 7731            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7732
 7733        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7734            self.discard_edit_prediction(false, cx);
 7735            return None;
 7736        };
 7737
 7738        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7739
 7740        if self.edit_prediction_indent_conflict {
 7741            let cursor_point = cursor.to_point(&multibuffer);
 7742
 7743            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7744
 7745            if let Some((_, indent)) = indents.iter().next()
 7746                && indent.len == cursor_point.column
 7747            {
 7748                self.edit_prediction_indent_conflict = false;
 7749            }
 7750        }
 7751
 7752        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7753        let edits = edit_prediction
 7754            .edits
 7755            .into_iter()
 7756            .flat_map(|(range, new_text)| {
 7757                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7758                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7759                Some((start..end, new_text))
 7760            })
 7761            .collect::<Vec<_>>();
 7762        if edits.is_empty() {
 7763            return None;
 7764        }
 7765
 7766        let first_edit_start = edits.first().unwrap().0.start;
 7767        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7768        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7769
 7770        let last_edit_end = edits.last().unwrap().0.end;
 7771        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7772        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7773
 7774        let cursor_row = cursor.to_point(&multibuffer).row;
 7775
 7776        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7777
 7778        let mut inlay_ids = Vec::new();
 7779        let invalidation_row_range;
 7780        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7781            Some(cursor_row..edit_end_row)
 7782        } else if cursor_row > edit_end_row {
 7783            Some(edit_start_row..cursor_row)
 7784        } else {
 7785            None
 7786        };
 7787        let supports_jump = self
 7788            .edit_prediction_provider
 7789            .as_ref()
 7790            .map(|provider| provider.provider.supports_jump_to_edit())
 7791            .unwrap_or(true);
 7792
 7793        let is_move = supports_jump
 7794            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7795        let completion = if is_move {
 7796            invalidation_row_range =
 7797                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7798            let target = first_edit_start;
 7799            EditPrediction::Move { target, snapshot }
 7800        } else {
 7801            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7802                && !self.edit_predictions_hidden_for_vim_mode;
 7803
 7804            if show_completions_in_buffer {
 7805                if edits
 7806                    .iter()
 7807                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7808                {
 7809                    let mut inlays = Vec::new();
 7810                    for (range, new_text) in &edits {
 7811                        let inlay = Inlay::edit_prediction(
 7812                            post_inc(&mut self.next_inlay_id),
 7813                            range.start,
 7814                            new_text.as_str(),
 7815                        );
 7816                        inlay_ids.push(inlay.id);
 7817                        inlays.push(inlay);
 7818                    }
 7819
 7820                    self.splice_inlays(&[], inlays, cx);
 7821                } else {
 7822                    let background_color = cx.theme().status().deleted_background;
 7823                    self.highlight_text::<EditPredictionHighlight>(
 7824                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7825                        HighlightStyle {
 7826                            background_color: Some(background_color),
 7827                            ..Default::default()
 7828                        },
 7829                        cx,
 7830                    );
 7831                }
 7832            }
 7833
 7834            invalidation_row_range = edit_start_row..edit_end_row;
 7835
 7836            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7837                if provider.show_tab_accept_marker() {
 7838                    EditDisplayMode::TabAccept
 7839                } else {
 7840                    EditDisplayMode::Inline
 7841                }
 7842            } else {
 7843                EditDisplayMode::DiffPopover
 7844            };
 7845
 7846            EditPrediction::Edit {
 7847                edits,
 7848                edit_preview: edit_prediction.edit_preview,
 7849                display_mode,
 7850                snapshot,
 7851            }
 7852        };
 7853
 7854        let invalidation_range = multibuffer
 7855            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7856            ..multibuffer.anchor_after(Point::new(
 7857                invalidation_row_range.end,
 7858                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7859            ));
 7860
 7861        self.stale_edit_prediction_in_menu = None;
 7862        self.active_edit_prediction = Some(EditPredictionState {
 7863            inlay_ids,
 7864            completion,
 7865            completion_id: edit_prediction.id,
 7866            invalidation_range,
 7867        });
 7868
 7869        cx.notify();
 7870
 7871        Some(())
 7872    }
 7873
 7874    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7875        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7876    }
 7877
 7878    fn clear_tasks(&mut self) {
 7879        self.tasks.clear()
 7880    }
 7881
 7882    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7883        if self.tasks.insert(key, value).is_some() {
 7884            // This case should hopefully be rare, but just in case...
 7885            log::error!(
 7886                "multiple different run targets found on a single line, only the last target will be rendered"
 7887            )
 7888        }
 7889    }
 7890
 7891    /// Get all display points of breakpoints that will be rendered within editor
 7892    ///
 7893    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7894    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7895    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7896    fn active_breakpoints(
 7897        &self,
 7898        range: Range<DisplayRow>,
 7899        window: &mut Window,
 7900        cx: &mut Context<Self>,
 7901    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7902        let mut breakpoint_display_points = HashMap::default();
 7903
 7904        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7905            return breakpoint_display_points;
 7906        };
 7907
 7908        let snapshot = self.snapshot(window, cx);
 7909
 7910        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7911        let Some(project) = self.project() else {
 7912            return breakpoint_display_points;
 7913        };
 7914
 7915        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7916            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7917
 7918        for (buffer_snapshot, range, excerpt_id) in
 7919            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7920        {
 7921            let Some(buffer) = project
 7922                .read(cx)
 7923                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7924            else {
 7925                continue;
 7926            };
 7927            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7928                &buffer,
 7929                Some(
 7930                    buffer_snapshot.anchor_before(range.start)
 7931                        ..buffer_snapshot.anchor_after(range.end),
 7932                ),
 7933                buffer_snapshot,
 7934                cx,
 7935            );
 7936            for (breakpoint, state) in breakpoints {
 7937                let multi_buffer_anchor =
 7938                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7939                let position = multi_buffer_anchor
 7940                    .to_point(multi_buffer_snapshot)
 7941                    .to_display_point(&snapshot);
 7942
 7943                breakpoint_display_points.insert(
 7944                    position.row(),
 7945                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7946                );
 7947            }
 7948        }
 7949
 7950        breakpoint_display_points
 7951    }
 7952
 7953    fn breakpoint_context_menu(
 7954        &self,
 7955        anchor: Anchor,
 7956        window: &mut Window,
 7957        cx: &mut Context<Self>,
 7958    ) -> Entity<ui::ContextMenu> {
 7959        let weak_editor = cx.weak_entity();
 7960        let focus_handle = self.focus_handle(cx);
 7961
 7962        let row = self
 7963            .buffer
 7964            .read(cx)
 7965            .snapshot(cx)
 7966            .summary_for_anchor::<Point>(&anchor)
 7967            .row;
 7968
 7969        let breakpoint = self
 7970            .breakpoint_at_row(row, window, cx)
 7971            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7972
 7973        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7974            "Edit Log Breakpoint"
 7975        } else {
 7976            "Set Log Breakpoint"
 7977        };
 7978
 7979        let condition_breakpoint_msg = if breakpoint
 7980            .as_ref()
 7981            .is_some_and(|bp| bp.1.condition.is_some())
 7982        {
 7983            "Edit Condition Breakpoint"
 7984        } else {
 7985            "Set Condition Breakpoint"
 7986        };
 7987
 7988        let hit_condition_breakpoint_msg = if breakpoint
 7989            .as_ref()
 7990            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7991        {
 7992            "Edit Hit Condition Breakpoint"
 7993        } else {
 7994            "Set Hit Condition Breakpoint"
 7995        };
 7996
 7997        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7998            "Unset Breakpoint"
 7999        } else {
 8000            "Set Breakpoint"
 8001        };
 8002
 8003        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8004
 8005        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8006            BreakpointState::Enabled => Some("Disable"),
 8007            BreakpointState::Disabled => Some("Enable"),
 8008        });
 8009
 8010        let (anchor, breakpoint) =
 8011            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8012
 8013        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8014            menu.on_blur_subscription(Subscription::new(|| {}))
 8015                .context(focus_handle)
 8016                .when(run_to_cursor, |this| {
 8017                    let weak_editor = weak_editor.clone();
 8018                    this.entry("Run to cursor", None, move |window, cx| {
 8019                        weak_editor
 8020                            .update(cx, |editor, cx| {
 8021                                editor.change_selections(
 8022                                    SelectionEffects::no_scroll(),
 8023                                    window,
 8024                                    cx,
 8025                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8026                                );
 8027                            })
 8028                            .ok();
 8029
 8030                        window.dispatch_action(Box::new(RunToCursor), cx);
 8031                    })
 8032                    .separator()
 8033                })
 8034                .when_some(toggle_state_msg, |this, msg| {
 8035                    this.entry(msg, None, {
 8036                        let weak_editor = weak_editor.clone();
 8037                        let breakpoint = breakpoint.clone();
 8038                        move |_window, cx| {
 8039                            weak_editor
 8040                                .update(cx, |this, cx| {
 8041                                    this.edit_breakpoint_at_anchor(
 8042                                        anchor,
 8043                                        breakpoint.as_ref().clone(),
 8044                                        BreakpointEditAction::InvertState,
 8045                                        cx,
 8046                                    );
 8047                                })
 8048                                .log_err();
 8049                        }
 8050                    })
 8051                })
 8052                .entry(set_breakpoint_msg, None, {
 8053                    let weak_editor = weak_editor.clone();
 8054                    let breakpoint = breakpoint.clone();
 8055                    move |_window, cx| {
 8056                        weak_editor
 8057                            .update(cx, |this, cx| {
 8058                                this.edit_breakpoint_at_anchor(
 8059                                    anchor,
 8060                                    breakpoint.as_ref().clone(),
 8061                                    BreakpointEditAction::Toggle,
 8062                                    cx,
 8063                                );
 8064                            })
 8065                            .log_err();
 8066                    }
 8067                })
 8068                .entry(log_breakpoint_msg, None, {
 8069                    let breakpoint = breakpoint.clone();
 8070                    let weak_editor = weak_editor.clone();
 8071                    move |window, cx| {
 8072                        weak_editor
 8073                            .update(cx, |this, cx| {
 8074                                this.add_edit_breakpoint_block(
 8075                                    anchor,
 8076                                    breakpoint.as_ref(),
 8077                                    BreakpointPromptEditAction::Log,
 8078                                    window,
 8079                                    cx,
 8080                                );
 8081                            })
 8082                            .log_err();
 8083                    }
 8084                })
 8085                .entry(condition_breakpoint_msg, None, {
 8086                    let breakpoint = breakpoint.clone();
 8087                    let weak_editor = weak_editor.clone();
 8088                    move |window, cx| {
 8089                        weak_editor
 8090                            .update(cx, |this, cx| {
 8091                                this.add_edit_breakpoint_block(
 8092                                    anchor,
 8093                                    breakpoint.as_ref(),
 8094                                    BreakpointPromptEditAction::Condition,
 8095                                    window,
 8096                                    cx,
 8097                                );
 8098                            })
 8099                            .log_err();
 8100                    }
 8101                })
 8102                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8103                    weak_editor
 8104                        .update(cx, |this, cx| {
 8105                            this.add_edit_breakpoint_block(
 8106                                anchor,
 8107                                breakpoint.as_ref(),
 8108                                BreakpointPromptEditAction::HitCondition,
 8109                                window,
 8110                                cx,
 8111                            );
 8112                        })
 8113                        .log_err();
 8114                })
 8115        })
 8116    }
 8117
 8118    fn render_breakpoint(
 8119        &self,
 8120        position: Anchor,
 8121        row: DisplayRow,
 8122        breakpoint: &Breakpoint,
 8123        state: Option<BreakpointSessionState>,
 8124        cx: &mut Context<Self>,
 8125    ) -> IconButton {
 8126        let is_rejected = state.is_some_and(|s| !s.verified);
 8127        // Is it a breakpoint that shows up when hovering over gutter?
 8128        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8129            (false, false),
 8130            |PhantomBreakpointIndicator {
 8131                 is_active,
 8132                 display_row,
 8133                 collides_with_existing_breakpoint,
 8134             }| {
 8135                (
 8136                    is_active && display_row == row,
 8137                    collides_with_existing_breakpoint,
 8138                )
 8139            },
 8140        );
 8141
 8142        let (color, icon) = {
 8143            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8144                (false, false) => ui::IconName::DebugBreakpoint,
 8145                (true, false) => ui::IconName::DebugLogBreakpoint,
 8146                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8147                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8148            };
 8149
 8150            let color = if is_phantom {
 8151                Color::Hint
 8152            } else if is_rejected {
 8153                Color::Disabled
 8154            } else {
 8155                Color::Debugger
 8156            };
 8157
 8158            (color, icon)
 8159        };
 8160
 8161        let breakpoint = Arc::from(breakpoint.clone());
 8162
 8163        let alt_as_text = gpui::Keystroke {
 8164            modifiers: Modifiers::secondary_key(),
 8165            ..Default::default()
 8166        };
 8167        let primary_action_text = if breakpoint.is_disabled() {
 8168            "Enable breakpoint"
 8169        } else if is_phantom && !collides_with_existing {
 8170            "Set breakpoint"
 8171        } else {
 8172            "Unset breakpoint"
 8173        };
 8174        let focus_handle = self.focus_handle.clone();
 8175
 8176        let meta = if is_rejected {
 8177            SharedString::from("No executable code is associated with this line.")
 8178        } else if collides_with_existing && !breakpoint.is_disabled() {
 8179            SharedString::from(format!(
 8180                "{alt_as_text}-click to disable,\nright-click for more options."
 8181            ))
 8182        } else {
 8183            SharedString::from("Right-click for more options.")
 8184        };
 8185        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8186            .icon_size(IconSize::XSmall)
 8187            .size(ui::ButtonSize::None)
 8188            .when(is_rejected, |this| {
 8189                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8190            })
 8191            .icon_color(color)
 8192            .style(ButtonStyle::Transparent)
 8193            .on_click(cx.listener({
 8194                let breakpoint = breakpoint.clone();
 8195
 8196                move |editor, event: &ClickEvent, window, cx| {
 8197                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8198                        BreakpointEditAction::InvertState
 8199                    } else {
 8200                        BreakpointEditAction::Toggle
 8201                    };
 8202
 8203                    window.focus(&editor.focus_handle(cx));
 8204                    editor.edit_breakpoint_at_anchor(
 8205                        position,
 8206                        breakpoint.as_ref().clone(),
 8207                        edit_action,
 8208                        cx,
 8209                    );
 8210                }
 8211            }))
 8212            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8213                editor.set_breakpoint_context_menu(
 8214                    row,
 8215                    Some(position),
 8216                    event.position(),
 8217                    window,
 8218                    cx,
 8219                );
 8220            }))
 8221            .tooltip(move |window, cx| {
 8222                Tooltip::with_meta_in(
 8223                    primary_action_text,
 8224                    Some(&ToggleBreakpoint),
 8225                    meta.clone(),
 8226                    &focus_handle,
 8227                    window,
 8228                    cx,
 8229                )
 8230            })
 8231    }
 8232
 8233    fn build_tasks_context(
 8234        project: &Entity<Project>,
 8235        buffer: &Entity<Buffer>,
 8236        buffer_row: u32,
 8237        tasks: &Arc<RunnableTasks>,
 8238        cx: &mut Context<Self>,
 8239    ) -> Task<Option<task::TaskContext>> {
 8240        let position = Point::new(buffer_row, tasks.column);
 8241        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8242        let location = Location {
 8243            buffer: buffer.clone(),
 8244            range: range_start..range_start,
 8245        };
 8246        // Fill in the environmental variables from the tree-sitter captures
 8247        let mut captured_task_variables = TaskVariables::default();
 8248        for (capture_name, value) in tasks.extra_variables.clone() {
 8249            captured_task_variables.insert(
 8250                task::VariableName::Custom(capture_name.into()),
 8251                value.clone(),
 8252            );
 8253        }
 8254        project.update(cx, |project, cx| {
 8255            project.task_store().update(cx, |task_store, cx| {
 8256                task_store.task_context_for_location(captured_task_variables, location, cx)
 8257            })
 8258        })
 8259    }
 8260
 8261    pub fn spawn_nearest_task(
 8262        &mut self,
 8263        action: &SpawnNearestTask,
 8264        window: &mut Window,
 8265        cx: &mut Context<Self>,
 8266    ) {
 8267        let Some((workspace, _)) = self.workspace.clone() else {
 8268            return;
 8269        };
 8270        let Some(project) = self.project.clone() else {
 8271            return;
 8272        };
 8273
 8274        // Try to find a closest, enclosing node using tree-sitter that has a task
 8275        let Some((buffer, buffer_row, tasks)) = self
 8276            .find_enclosing_node_task(cx)
 8277            // Or find the task that's closest in row-distance.
 8278            .or_else(|| self.find_closest_task(cx))
 8279        else {
 8280            return;
 8281        };
 8282
 8283        let reveal_strategy = action.reveal;
 8284        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8285        cx.spawn_in(window, async move |_, cx| {
 8286            let context = task_context.await?;
 8287            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8288
 8289            let resolved = &mut resolved_task.resolved;
 8290            resolved.reveal = reveal_strategy;
 8291
 8292            workspace
 8293                .update_in(cx, |workspace, window, cx| {
 8294                    workspace.schedule_resolved_task(
 8295                        task_source_kind,
 8296                        resolved_task,
 8297                        false,
 8298                        window,
 8299                        cx,
 8300                    );
 8301                })
 8302                .ok()
 8303        })
 8304        .detach();
 8305    }
 8306
 8307    fn find_closest_task(
 8308        &mut self,
 8309        cx: &mut Context<Self>,
 8310    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8311        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8312
 8313        let ((buffer_id, row), tasks) = self
 8314            .tasks
 8315            .iter()
 8316            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8317
 8318        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8319        let tasks = Arc::new(tasks.to_owned());
 8320        Some((buffer, *row, tasks))
 8321    }
 8322
 8323    fn find_enclosing_node_task(
 8324        &mut self,
 8325        cx: &mut Context<Self>,
 8326    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8327        let snapshot = self.buffer.read(cx).snapshot(cx);
 8328        let offset = self.selections.newest::<usize>(cx).head();
 8329        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8330        let buffer_id = excerpt.buffer().remote_id();
 8331
 8332        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8333        let mut cursor = layer.node().walk();
 8334
 8335        while cursor.goto_first_child_for_byte(offset).is_some() {
 8336            if cursor.node().end_byte() == offset {
 8337                cursor.goto_next_sibling();
 8338            }
 8339        }
 8340
 8341        // Ascend to the smallest ancestor that contains the range and has a task.
 8342        loop {
 8343            let node = cursor.node();
 8344            let node_range = node.byte_range();
 8345            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8346
 8347            // Check if this node contains our offset
 8348            if node_range.start <= offset && node_range.end >= offset {
 8349                // If it contains offset, check for task
 8350                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8351                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8352                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8353                }
 8354            }
 8355
 8356            if !cursor.goto_parent() {
 8357                break;
 8358            }
 8359        }
 8360        None
 8361    }
 8362
 8363    fn render_run_indicator(
 8364        &self,
 8365        _style: &EditorStyle,
 8366        is_active: bool,
 8367        row: DisplayRow,
 8368        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8369        cx: &mut Context<Self>,
 8370    ) -> IconButton {
 8371        let color = Color::Muted;
 8372        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8373
 8374        IconButton::new(
 8375            ("run_indicator", row.0 as usize),
 8376            ui::IconName::PlayOutlined,
 8377        )
 8378        .shape(ui::IconButtonShape::Square)
 8379        .icon_size(IconSize::XSmall)
 8380        .icon_color(color)
 8381        .toggle_state(is_active)
 8382        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8383            let quick_launch = match e {
 8384                ClickEvent::Keyboard(_) => true,
 8385                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8386            };
 8387
 8388            window.focus(&editor.focus_handle(cx));
 8389            editor.toggle_code_actions(
 8390                &ToggleCodeActions {
 8391                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8392                    quick_launch,
 8393                },
 8394                window,
 8395                cx,
 8396            );
 8397        }))
 8398        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8399            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8400        }))
 8401    }
 8402
 8403    pub fn context_menu_visible(&self) -> bool {
 8404        !self.edit_prediction_preview_is_active()
 8405            && self
 8406                .context_menu
 8407                .borrow()
 8408                .as_ref()
 8409                .is_some_and(|menu| menu.visible())
 8410    }
 8411
 8412    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8413        self.context_menu
 8414            .borrow()
 8415            .as_ref()
 8416            .map(|menu| menu.origin())
 8417    }
 8418
 8419    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8420        self.context_menu_options = Some(options);
 8421    }
 8422
 8423    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8424    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8425
 8426    fn render_edit_prediction_popover(
 8427        &mut self,
 8428        text_bounds: &Bounds<Pixels>,
 8429        content_origin: gpui::Point<Pixels>,
 8430        right_margin: Pixels,
 8431        editor_snapshot: &EditorSnapshot,
 8432        visible_row_range: Range<DisplayRow>,
 8433        scroll_top: f32,
 8434        scroll_bottom: f32,
 8435        line_layouts: &[LineWithInvisibles],
 8436        line_height: Pixels,
 8437        scroll_pixel_position: gpui::Point<Pixels>,
 8438        newest_selection_head: Option<DisplayPoint>,
 8439        editor_width: Pixels,
 8440        style: &EditorStyle,
 8441        window: &mut Window,
 8442        cx: &mut App,
 8443    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8444        if self.mode().is_minimap() {
 8445            return None;
 8446        }
 8447        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8448
 8449        if self.edit_prediction_visible_in_cursor_popover(true) {
 8450            return None;
 8451        }
 8452
 8453        match &active_edit_prediction.completion {
 8454            EditPrediction::Move { target, .. } => {
 8455                let target_display_point = target.to_display_point(editor_snapshot);
 8456
 8457                if self.edit_prediction_requires_modifier() {
 8458                    if !self.edit_prediction_preview_is_active() {
 8459                        return None;
 8460                    }
 8461
 8462                    self.render_edit_prediction_modifier_jump_popover(
 8463                        text_bounds,
 8464                        content_origin,
 8465                        visible_row_range,
 8466                        line_layouts,
 8467                        line_height,
 8468                        scroll_pixel_position,
 8469                        newest_selection_head,
 8470                        target_display_point,
 8471                        window,
 8472                        cx,
 8473                    )
 8474                } else {
 8475                    self.render_edit_prediction_eager_jump_popover(
 8476                        text_bounds,
 8477                        content_origin,
 8478                        editor_snapshot,
 8479                        visible_row_range,
 8480                        scroll_top,
 8481                        scroll_bottom,
 8482                        line_height,
 8483                        scroll_pixel_position,
 8484                        target_display_point,
 8485                        editor_width,
 8486                        window,
 8487                        cx,
 8488                    )
 8489                }
 8490            }
 8491            EditPrediction::Edit {
 8492                display_mode: EditDisplayMode::Inline,
 8493                ..
 8494            } => None,
 8495            EditPrediction::Edit {
 8496                display_mode: EditDisplayMode::TabAccept,
 8497                edits,
 8498                ..
 8499            } => {
 8500                let range = &edits.first()?.0;
 8501                let target_display_point = range.end.to_display_point(editor_snapshot);
 8502
 8503                self.render_edit_prediction_end_of_line_popover(
 8504                    "Accept",
 8505                    editor_snapshot,
 8506                    visible_row_range,
 8507                    target_display_point,
 8508                    line_height,
 8509                    scroll_pixel_position,
 8510                    content_origin,
 8511                    editor_width,
 8512                    window,
 8513                    cx,
 8514                )
 8515            }
 8516            EditPrediction::Edit {
 8517                edits,
 8518                edit_preview,
 8519                display_mode: EditDisplayMode::DiffPopover,
 8520                snapshot,
 8521            } => self.render_edit_prediction_diff_popover(
 8522                text_bounds,
 8523                content_origin,
 8524                right_margin,
 8525                editor_snapshot,
 8526                visible_row_range,
 8527                line_layouts,
 8528                line_height,
 8529                scroll_pixel_position,
 8530                newest_selection_head,
 8531                editor_width,
 8532                style,
 8533                edits,
 8534                edit_preview,
 8535                snapshot,
 8536                window,
 8537                cx,
 8538            ),
 8539        }
 8540    }
 8541
 8542    fn render_edit_prediction_modifier_jump_popover(
 8543        &mut self,
 8544        text_bounds: &Bounds<Pixels>,
 8545        content_origin: gpui::Point<Pixels>,
 8546        visible_row_range: Range<DisplayRow>,
 8547        line_layouts: &[LineWithInvisibles],
 8548        line_height: Pixels,
 8549        scroll_pixel_position: gpui::Point<Pixels>,
 8550        newest_selection_head: Option<DisplayPoint>,
 8551        target_display_point: DisplayPoint,
 8552        window: &mut Window,
 8553        cx: &mut App,
 8554    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8555        let scrolled_content_origin =
 8556            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8557
 8558        const SCROLL_PADDING_Y: Pixels = px(12.);
 8559
 8560        if target_display_point.row() < visible_row_range.start {
 8561            return self.render_edit_prediction_scroll_popover(
 8562                |_| SCROLL_PADDING_Y,
 8563                IconName::ArrowUp,
 8564                visible_row_range,
 8565                line_layouts,
 8566                newest_selection_head,
 8567                scrolled_content_origin,
 8568                window,
 8569                cx,
 8570            );
 8571        } else if target_display_point.row() >= visible_row_range.end {
 8572            return self.render_edit_prediction_scroll_popover(
 8573                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8574                IconName::ArrowDown,
 8575                visible_row_range,
 8576                line_layouts,
 8577                newest_selection_head,
 8578                scrolled_content_origin,
 8579                window,
 8580                cx,
 8581            );
 8582        }
 8583
 8584        const POLE_WIDTH: Pixels = px(2.);
 8585
 8586        let line_layout =
 8587            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8588        let target_column = target_display_point.column() as usize;
 8589
 8590        let target_x = line_layout.x_for_index(target_column);
 8591        let target_y =
 8592            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8593
 8594        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8595
 8596        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8597        border_color.l += 0.001;
 8598
 8599        let mut element = v_flex()
 8600            .items_end()
 8601            .when(flag_on_right, |el| el.items_start())
 8602            .child(if flag_on_right {
 8603                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8604                    .rounded_bl(px(0.))
 8605                    .rounded_tl(px(0.))
 8606                    .border_l_2()
 8607                    .border_color(border_color)
 8608            } else {
 8609                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8610                    .rounded_br(px(0.))
 8611                    .rounded_tr(px(0.))
 8612                    .border_r_2()
 8613                    .border_color(border_color)
 8614            })
 8615            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8616            .into_any();
 8617
 8618        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8619
 8620        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8621            - point(
 8622                if flag_on_right {
 8623                    POLE_WIDTH
 8624                } else {
 8625                    size.width - POLE_WIDTH
 8626                },
 8627                size.height - line_height,
 8628            );
 8629
 8630        origin.x = origin.x.max(content_origin.x);
 8631
 8632        element.prepaint_at(origin, window, cx);
 8633
 8634        Some((element, origin))
 8635    }
 8636
 8637    fn render_edit_prediction_scroll_popover(
 8638        &mut self,
 8639        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8640        scroll_icon: IconName,
 8641        visible_row_range: Range<DisplayRow>,
 8642        line_layouts: &[LineWithInvisibles],
 8643        newest_selection_head: Option<DisplayPoint>,
 8644        scrolled_content_origin: gpui::Point<Pixels>,
 8645        window: &mut Window,
 8646        cx: &mut App,
 8647    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8648        let mut element = self
 8649            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8650            .into_any();
 8651
 8652        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8653
 8654        let cursor = newest_selection_head?;
 8655        let cursor_row_layout =
 8656            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8657        let cursor_column = cursor.column() as usize;
 8658
 8659        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8660
 8661        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8662
 8663        element.prepaint_at(origin, window, cx);
 8664        Some((element, origin))
 8665    }
 8666
 8667    fn render_edit_prediction_eager_jump_popover(
 8668        &mut self,
 8669        text_bounds: &Bounds<Pixels>,
 8670        content_origin: gpui::Point<Pixels>,
 8671        editor_snapshot: &EditorSnapshot,
 8672        visible_row_range: Range<DisplayRow>,
 8673        scroll_top: f32,
 8674        scroll_bottom: f32,
 8675        line_height: Pixels,
 8676        scroll_pixel_position: gpui::Point<Pixels>,
 8677        target_display_point: DisplayPoint,
 8678        editor_width: Pixels,
 8679        window: &mut Window,
 8680        cx: &mut App,
 8681    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8682        if target_display_point.row().as_f32() < scroll_top {
 8683            let mut element = self
 8684                .render_edit_prediction_line_popover(
 8685                    "Jump to Edit",
 8686                    Some(IconName::ArrowUp),
 8687                    window,
 8688                    cx,
 8689                )?
 8690                .into_any();
 8691
 8692            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8693            let offset = point(
 8694                (text_bounds.size.width - size.width) / 2.,
 8695                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8696            );
 8697
 8698            let origin = text_bounds.origin + offset;
 8699            element.prepaint_at(origin, window, cx);
 8700            Some((element, origin))
 8701        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8702            let mut element = self
 8703                .render_edit_prediction_line_popover(
 8704                    "Jump to Edit",
 8705                    Some(IconName::ArrowDown),
 8706                    window,
 8707                    cx,
 8708                )?
 8709                .into_any();
 8710
 8711            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8712            let offset = point(
 8713                (text_bounds.size.width - size.width) / 2.,
 8714                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8715            );
 8716
 8717            let origin = text_bounds.origin + offset;
 8718            element.prepaint_at(origin, window, cx);
 8719            Some((element, origin))
 8720        } else {
 8721            self.render_edit_prediction_end_of_line_popover(
 8722                "Jump to Edit",
 8723                editor_snapshot,
 8724                visible_row_range,
 8725                target_display_point,
 8726                line_height,
 8727                scroll_pixel_position,
 8728                content_origin,
 8729                editor_width,
 8730                window,
 8731                cx,
 8732            )
 8733        }
 8734    }
 8735
 8736    fn render_edit_prediction_end_of_line_popover(
 8737        self: &mut Editor,
 8738        label: &'static str,
 8739        editor_snapshot: &EditorSnapshot,
 8740        visible_row_range: Range<DisplayRow>,
 8741        target_display_point: DisplayPoint,
 8742        line_height: Pixels,
 8743        scroll_pixel_position: gpui::Point<Pixels>,
 8744        content_origin: gpui::Point<Pixels>,
 8745        editor_width: Pixels,
 8746        window: &mut Window,
 8747        cx: &mut App,
 8748    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8749        let target_line_end = DisplayPoint::new(
 8750            target_display_point.row(),
 8751            editor_snapshot.line_len(target_display_point.row()),
 8752        );
 8753
 8754        let mut element = self
 8755            .render_edit_prediction_line_popover(label, None, window, cx)?
 8756            .into_any();
 8757
 8758        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8759
 8760        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8761
 8762        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8763        let mut origin = start_point
 8764            + line_origin
 8765            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8766        origin.x = origin.x.max(content_origin.x);
 8767
 8768        let max_x = content_origin.x + editor_width - size.width;
 8769
 8770        if origin.x > max_x {
 8771            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8772
 8773            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8774                origin.y += offset;
 8775                IconName::ArrowUp
 8776            } else {
 8777                origin.y -= offset;
 8778                IconName::ArrowDown
 8779            };
 8780
 8781            element = self
 8782                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8783                .into_any();
 8784
 8785            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8786
 8787            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8788        }
 8789
 8790        element.prepaint_at(origin, window, cx);
 8791        Some((element, origin))
 8792    }
 8793
 8794    fn render_edit_prediction_diff_popover(
 8795        self: &Editor,
 8796        text_bounds: &Bounds<Pixels>,
 8797        content_origin: gpui::Point<Pixels>,
 8798        right_margin: Pixels,
 8799        editor_snapshot: &EditorSnapshot,
 8800        visible_row_range: Range<DisplayRow>,
 8801        line_layouts: &[LineWithInvisibles],
 8802        line_height: Pixels,
 8803        scroll_pixel_position: gpui::Point<Pixels>,
 8804        newest_selection_head: Option<DisplayPoint>,
 8805        editor_width: Pixels,
 8806        style: &EditorStyle,
 8807        edits: &Vec<(Range<Anchor>, String)>,
 8808        edit_preview: &Option<language::EditPreview>,
 8809        snapshot: &language::BufferSnapshot,
 8810        window: &mut Window,
 8811        cx: &mut App,
 8812    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8813        let edit_start = edits
 8814            .first()
 8815            .unwrap()
 8816            .0
 8817            .start
 8818            .to_display_point(editor_snapshot);
 8819        let edit_end = edits
 8820            .last()
 8821            .unwrap()
 8822            .0
 8823            .end
 8824            .to_display_point(editor_snapshot);
 8825
 8826        let is_visible = visible_row_range.contains(&edit_start.row())
 8827            || visible_row_range.contains(&edit_end.row());
 8828        if !is_visible {
 8829            return None;
 8830        }
 8831
 8832        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8833            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8834        } else {
 8835            // Fallback for providers without edit_preview
 8836            crate::edit_prediction_fallback_text(edits, cx)
 8837        };
 8838
 8839        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8840        let line_count = highlighted_edits.text.lines().count();
 8841
 8842        const BORDER_WIDTH: Pixels = px(1.);
 8843
 8844        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8845        let has_keybind = keybind.is_some();
 8846
 8847        let mut element = h_flex()
 8848            .items_start()
 8849            .child(
 8850                h_flex()
 8851                    .bg(cx.theme().colors().editor_background)
 8852                    .border(BORDER_WIDTH)
 8853                    .shadow_xs()
 8854                    .border_color(cx.theme().colors().border)
 8855                    .rounded_l_lg()
 8856                    .when(line_count > 1, |el| el.rounded_br_lg())
 8857                    .pr_1()
 8858                    .child(styled_text),
 8859            )
 8860            .child(
 8861                h_flex()
 8862                    .h(line_height + BORDER_WIDTH * 2.)
 8863                    .px_1p5()
 8864                    .gap_1()
 8865                    // Workaround: For some reason, there's a gap if we don't do this
 8866                    .ml(-BORDER_WIDTH)
 8867                    .shadow(vec![gpui::BoxShadow {
 8868                        color: gpui::black().opacity(0.05),
 8869                        offset: point(px(1.), px(1.)),
 8870                        blur_radius: px(2.),
 8871                        spread_radius: px(0.),
 8872                    }])
 8873                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8874                    .border(BORDER_WIDTH)
 8875                    .border_color(cx.theme().colors().border)
 8876                    .rounded_r_lg()
 8877                    .id("edit_prediction_diff_popover_keybind")
 8878                    .when(!has_keybind, |el| {
 8879                        let status_colors = cx.theme().status();
 8880
 8881                        el.bg(status_colors.error_background)
 8882                            .border_color(status_colors.error.opacity(0.6))
 8883                            .child(Icon::new(IconName::Info).color(Color::Error))
 8884                            .cursor_default()
 8885                            .hoverable_tooltip(move |_window, cx| {
 8886                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8887                            })
 8888                    })
 8889                    .children(keybind),
 8890            )
 8891            .into_any();
 8892
 8893        let longest_row =
 8894            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8895        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8896            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8897        } else {
 8898            layout_line(
 8899                longest_row,
 8900                editor_snapshot,
 8901                style,
 8902                editor_width,
 8903                |_| false,
 8904                window,
 8905                cx,
 8906            )
 8907            .width
 8908        };
 8909
 8910        let viewport_bounds =
 8911            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8912                right: -right_margin,
 8913                ..Default::default()
 8914            });
 8915
 8916        let x_after_longest =
 8917            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8918                - scroll_pixel_position.x;
 8919
 8920        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8921
 8922        // Fully visible if it can be displayed within the window (allow overlapping other
 8923        // panes). However, this is only allowed if the popover starts within text_bounds.
 8924        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8925            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8926
 8927        let mut origin = if can_position_to_the_right {
 8928            point(
 8929                x_after_longest,
 8930                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8931                    - scroll_pixel_position.y,
 8932            )
 8933        } else {
 8934            let cursor_row = newest_selection_head.map(|head| head.row());
 8935            let above_edit = edit_start
 8936                .row()
 8937                .0
 8938                .checked_sub(line_count as u32)
 8939                .map(DisplayRow);
 8940            let below_edit = Some(edit_end.row() + 1);
 8941            let above_cursor =
 8942                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8943            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8944
 8945            // Place the edit popover adjacent to the edit if there is a location
 8946            // available that is onscreen and does not obscure the cursor. Otherwise,
 8947            // place it adjacent to the cursor.
 8948            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8949                .into_iter()
 8950                .flatten()
 8951                .find(|&start_row| {
 8952                    let end_row = start_row + line_count as u32;
 8953                    visible_row_range.contains(&start_row)
 8954                        && visible_row_range.contains(&end_row)
 8955                        && cursor_row
 8956                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 8957                })?;
 8958
 8959            content_origin
 8960                + point(
 8961                    -scroll_pixel_position.x,
 8962                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8963                )
 8964        };
 8965
 8966        origin.x -= BORDER_WIDTH;
 8967
 8968        window.defer_draw(element, origin, 1);
 8969
 8970        // Do not return an element, since it will already be drawn due to defer_draw.
 8971        None
 8972    }
 8973
 8974    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8975        px(30.)
 8976    }
 8977
 8978    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8979        if self.read_only(cx) {
 8980            cx.theme().players().read_only()
 8981        } else {
 8982            self.style.as_ref().unwrap().local_player
 8983        }
 8984    }
 8985
 8986    fn render_edit_prediction_accept_keybind(
 8987        &self,
 8988        window: &mut Window,
 8989        cx: &App,
 8990    ) -> Option<AnyElement> {
 8991        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8992        let accept_keystroke = accept_binding.keystroke()?;
 8993
 8994        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8995
 8996        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8997            Color::Accent
 8998        } else {
 8999            Color::Muted
 9000        };
 9001
 9002        h_flex()
 9003            .px_0p5()
 9004            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9005            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9006            .text_size(TextSize::XSmall.rems(cx))
 9007            .child(h_flex().children(ui::render_modifiers(
 9008                &accept_keystroke.modifiers,
 9009                PlatformStyle::platform(),
 9010                Some(modifiers_color),
 9011                Some(IconSize::XSmall.rems().into()),
 9012                true,
 9013            )))
 9014            .when(is_platform_style_mac, |parent| {
 9015                parent.child(accept_keystroke.key.clone())
 9016            })
 9017            .when(!is_platform_style_mac, |parent| {
 9018                parent.child(
 9019                    Key::new(
 9020                        util::capitalize(&accept_keystroke.key),
 9021                        Some(Color::Default),
 9022                    )
 9023                    .size(Some(IconSize::XSmall.rems().into())),
 9024                )
 9025            })
 9026            .into_any()
 9027            .into()
 9028    }
 9029
 9030    fn render_edit_prediction_line_popover(
 9031        &self,
 9032        label: impl Into<SharedString>,
 9033        icon: Option<IconName>,
 9034        window: &mut Window,
 9035        cx: &App,
 9036    ) -> Option<Stateful<Div>> {
 9037        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9038
 9039        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9040        let has_keybind = keybind.is_some();
 9041
 9042        let result = h_flex()
 9043            .id("ep-line-popover")
 9044            .py_0p5()
 9045            .pl_1()
 9046            .pr(padding_right)
 9047            .gap_1()
 9048            .rounded_md()
 9049            .border_1()
 9050            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9051            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9052            .shadow_xs()
 9053            .when(!has_keybind, |el| {
 9054                let status_colors = cx.theme().status();
 9055
 9056                el.bg(status_colors.error_background)
 9057                    .border_color(status_colors.error.opacity(0.6))
 9058                    .pl_2()
 9059                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9060                    .cursor_default()
 9061                    .hoverable_tooltip(move |_window, cx| {
 9062                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9063                    })
 9064            })
 9065            .children(keybind)
 9066            .child(
 9067                Label::new(label)
 9068                    .size(LabelSize::Small)
 9069                    .when(!has_keybind, |el| {
 9070                        el.color(cx.theme().status().error.into()).strikethrough()
 9071                    }),
 9072            )
 9073            .when(!has_keybind, |el| {
 9074                el.child(
 9075                    h_flex().ml_1().child(
 9076                        Icon::new(IconName::Info)
 9077                            .size(IconSize::Small)
 9078                            .color(cx.theme().status().error.into()),
 9079                    ),
 9080                )
 9081            })
 9082            .when_some(icon, |element, icon| {
 9083                element.child(
 9084                    div()
 9085                        .mt(px(1.5))
 9086                        .child(Icon::new(icon).size(IconSize::Small)),
 9087                )
 9088            });
 9089
 9090        Some(result)
 9091    }
 9092
 9093    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9094        let accent_color = cx.theme().colors().text_accent;
 9095        let editor_bg_color = cx.theme().colors().editor_background;
 9096        editor_bg_color.blend(accent_color.opacity(0.1))
 9097    }
 9098
 9099    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9100        let accent_color = cx.theme().colors().text_accent;
 9101        let editor_bg_color = cx.theme().colors().editor_background;
 9102        editor_bg_color.blend(accent_color.opacity(0.6))
 9103    }
 9104    fn get_prediction_provider_icon_name(
 9105        provider: &Option<RegisteredEditPredictionProvider>,
 9106    ) -> IconName {
 9107        match provider {
 9108            Some(provider) => match provider.provider.name() {
 9109                "copilot" => IconName::Copilot,
 9110                "supermaven" => IconName::Supermaven,
 9111                _ => IconName::ZedPredict,
 9112            },
 9113            None => IconName::ZedPredict,
 9114        }
 9115    }
 9116
 9117    fn render_edit_prediction_cursor_popover(
 9118        &self,
 9119        min_width: Pixels,
 9120        max_width: Pixels,
 9121        cursor_point: Point,
 9122        style: &EditorStyle,
 9123        accept_keystroke: Option<&gpui::Keystroke>,
 9124        _window: &Window,
 9125        cx: &mut Context<Editor>,
 9126    ) -> Option<AnyElement> {
 9127        let provider = self.edit_prediction_provider.as_ref()?;
 9128        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9129
 9130        if provider.provider.needs_terms_acceptance(cx) {
 9131            return Some(
 9132                h_flex()
 9133                    .min_w(min_width)
 9134                    .flex_1()
 9135                    .px_2()
 9136                    .py_1()
 9137                    .gap_3()
 9138                    .elevation_2(cx)
 9139                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9140                    .id("accept-terms")
 9141                    .cursor_pointer()
 9142                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9143                    .on_click(cx.listener(|this, _event, window, cx| {
 9144                        cx.stop_propagation();
 9145                        this.report_editor_event(ReportEditorEvent::ZetaTosClicked, None, cx);
 9146                        window.dispatch_action(
 9147                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9148                            cx,
 9149                        );
 9150                    }))
 9151                    .child(
 9152                        h_flex()
 9153                            .flex_1()
 9154                            .gap_2()
 9155                            .child(Icon::new(provider_icon))
 9156                            .child(Label::new("Accept Terms of Service"))
 9157                            .child(div().w_full())
 9158                            .child(
 9159                                Icon::new(IconName::ArrowUpRight)
 9160                                    .color(Color::Muted)
 9161                                    .size(IconSize::Small),
 9162                            )
 9163                            .into_any_element(),
 9164                    )
 9165                    .into_any(),
 9166            );
 9167        }
 9168
 9169        let is_refreshing = provider.provider.is_refreshing(cx);
 9170
 9171        fn pending_completion_container(icon: IconName) -> Div {
 9172            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9173        }
 9174
 9175        let completion = match &self.active_edit_prediction {
 9176            Some(prediction) => {
 9177                if !self.has_visible_completions_menu() {
 9178                    const RADIUS: Pixels = px(6.);
 9179                    const BORDER_WIDTH: Pixels = px(1.);
 9180
 9181                    return Some(
 9182                        h_flex()
 9183                            .elevation_2(cx)
 9184                            .border(BORDER_WIDTH)
 9185                            .border_color(cx.theme().colors().border)
 9186                            .when(accept_keystroke.is_none(), |el| {
 9187                                el.border_color(cx.theme().status().error)
 9188                            })
 9189                            .rounded(RADIUS)
 9190                            .rounded_tl(px(0.))
 9191                            .overflow_hidden()
 9192                            .child(div().px_1p5().child(match &prediction.completion {
 9193                                EditPrediction::Move { target, snapshot } => {
 9194                                    use text::ToPoint as _;
 9195                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9196                                    {
 9197                                        Icon::new(IconName::ZedPredictDown)
 9198                                    } else {
 9199                                        Icon::new(IconName::ZedPredictUp)
 9200                                    }
 9201                                }
 9202                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9203                            }))
 9204                            .child(
 9205                                h_flex()
 9206                                    .gap_1()
 9207                                    .py_1()
 9208                                    .px_2()
 9209                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9210                                    .border_l_1()
 9211                                    .border_color(cx.theme().colors().border)
 9212                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9213                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9214                                        el.child(
 9215                                            Label::new("Hold")
 9216                                                .size(LabelSize::Small)
 9217                                                .when(accept_keystroke.is_none(), |el| {
 9218                                                    el.strikethrough()
 9219                                                })
 9220                                                .line_height_style(LineHeightStyle::UiLabel),
 9221                                        )
 9222                                    })
 9223                                    .id("edit_prediction_cursor_popover_keybind")
 9224                                    .when(accept_keystroke.is_none(), |el| {
 9225                                        let status_colors = cx.theme().status();
 9226
 9227                                        el.bg(status_colors.error_background)
 9228                                            .border_color(status_colors.error.opacity(0.6))
 9229                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9230                                            .cursor_default()
 9231                                            .hoverable_tooltip(move |_window, cx| {
 9232                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9233                                                    .into()
 9234                                            })
 9235                                    })
 9236                                    .when_some(
 9237                                        accept_keystroke.as_ref(),
 9238                                        |el, accept_keystroke| {
 9239                                            el.child(h_flex().children(ui::render_modifiers(
 9240                                                &accept_keystroke.modifiers,
 9241                                                PlatformStyle::platform(),
 9242                                                Some(Color::Default),
 9243                                                Some(IconSize::XSmall.rems().into()),
 9244                                                false,
 9245                                            )))
 9246                                        },
 9247                                    ),
 9248                            )
 9249                            .into_any(),
 9250                    );
 9251                }
 9252
 9253                self.render_edit_prediction_cursor_popover_preview(
 9254                    prediction,
 9255                    cursor_point,
 9256                    style,
 9257                    cx,
 9258                )?
 9259            }
 9260
 9261            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9262                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9263                    stale_completion,
 9264                    cursor_point,
 9265                    style,
 9266                    cx,
 9267                )?,
 9268
 9269                None => pending_completion_container(provider_icon)
 9270                    .child(Label::new("...").size(LabelSize::Small)),
 9271            },
 9272
 9273            None => pending_completion_container(provider_icon)
 9274                .child(Label::new("...").size(LabelSize::Small)),
 9275        };
 9276
 9277        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9278            completion
 9279                .with_animation(
 9280                    "loading-completion",
 9281                    Animation::new(Duration::from_secs(2))
 9282                        .repeat()
 9283                        .with_easing(pulsating_between(0.4, 0.8)),
 9284                    |label, delta| label.opacity(delta),
 9285                )
 9286                .into_any_element()
 9287        } else {
 9288            completion.into_any_element()
 9289        };
 9290
 9291        let has_completion = self.active_edit_prediction.is_some();
 9292
 9293        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9294        Some(
 9295            h_flex()
 9296                .min_w(min_width)
 9297                .max_w(max_width)
 9298                .flex_1()
 9299                .elevation_2(cx)
 9300                .border_color(cx.theme().colors().border)
 9301                .child(
 9302                    div()
 9303                        .flex_1()
 9304                        .py_1()
 9305                        .px_2()
 9306                        .overflow_hidden()
 9307                        .child(completion),
 9308                )
 9309                .when_some(accept_keystroke, |el, accept_keystroke| {
 9310                    if !accept_keystroke.modifiers.modified() {
 9311                        return el;
 9312                    }
 9313
 9314                    el.child(
 9315                        h_flex()
 9316                            .h_full()
 9317                            .border_l_1()
 9318                            .rounded_r_lg()
 9319                            .border_color(cx.theme().colors().border)
 9320                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9321                            .gap_1()
 9322                            .py_1()
 9323                            .px_2()
 9324                            .child(
 9325                                h_flex()
 9326                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9327                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9328                                    .child(h_flex().children(ui::render_modifiers(
 9329                                        &accept_keystroke.modifiers,
 9330                                        PlatformStyle::platform(),
 9331                                        Some(if !has_completion {
 9332                                            Color::Muted
 9333                                        } else {
 9334                                            Color::Default
 9335                                        }),
 9336                                        None,
 9337                                        false,
 9338                                    ))),
 9339                            )
 9340                            .child(Label::new("Preview").into_any_element())
 9341                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9342                    )
 9343                })
 9344                .into_any(),
 9345        )
 9346    }
 9347
 9348    fn render_edit_prediction_cursor_popover_preview(
 9349        &self,
 9350        completion: &EditPredictionState,
 9351        cursor_point: Point,
 9352        style: &EditorStyle,
 9353        cx: &mut Context<Editor>,
 9354    ) -> Option<Div> {
 9355        use text::ToPoint as _;
 9356
 9357        fn render_relative_row_jump(
 9358            prefix: impl Into<String>,
 9359            current_row: u32,
 9360            target_row: u32,
 9361        ) -> Div {
 9362            let (row_diff, arrow) = if target_row < current_row {
 9363                (current_row - target_row, IconName::ArrowUp)
 9364            } else {
 9365                (target_row - current_row, IconName::ArrowDown)
 9366            };
 9367
 9368            h_flex()
 9369                .child(
 9370                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9371                        .color(Color::Muted)
 9372                        .size(LabelSize::Small),
 9373                )
 9374                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9375        }
 9376
 9377        let supports_jump = self
 9378            .edit_prediction_provider
 9379            .as_ref()
 9380            .map(|provider| provider.provider.supports_jump_to_edit())
 9381            .unwrap_or(true);
 9382
 9383        match &completion.completion {
 9384            EditPrediction::Move {
 9385                target, snapshot, ..
 9386            } => {
 9387                if !supports_jump {
 9388                    return None;
 9389                }
 9390
 9391                Some(
 9392                    h_flex()
 9393                        .px_2()
 9394                        .gap_2()
 9395                        .flex_1()
 9396                        .child(
 9397                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9398                                Icon::new(IconName::ZedPredictDown)
 9399                            } else {
 9400                                Icon::new(IconName::ZedPredictUp)
 9401                            },
 9402                        )
 9403                        .child(Label::new("Jump to Edit")),
 9404                )
 9405            }
 9406
 9407            EditPrediction::Edit {
 9408                edits,
 9409                edit_preview,
 9410                snapshot,
 9411                display_mode: _,
 9412            } => {
 9413                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9414
 9415                let (highlighted_edits, has_more_lines) =
 9416                    if let Some(edit_preview) = edit_preview.as_ref() {
 9417                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9418                            .first_line_preview()
 9419                    } else {
 9420                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9421                    };
 9422
 9423                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9424                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9425
 9426                let preview = h_flex()
 9427                    .gap_1()
 9428                    .min_w_16()
 9429                    .child(styled_text)
 9430                    .when(has_more_lines, |parent| parent.child(""));
 9431
 9432                let left = if supports_jump && first_edit_row != cursor_point.row {
 9433                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9434                        .into_any_element()
 9435                } else {
 9436                    let icon_name =
 9437                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9438                    Icon::new(icon_name).into_any_element()
 9439                };
 9440
 9441                Some(
 9442                    h_flex()
 9443                        .h_full()
 9444                        .flex_1()
 9445                        .gap_2()
 9446                        .pr_1()
 9447                        .overflow_x_hidden()
 9448                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9449                        .child(left)
 9450                        .child(preview),
 9451                )
 9452            }
 9453        }
 9454    }
 9455
 9456    pub fn render_context_menu(
 9457        &self,
 9458        style: &EditorStyle,
 9459        max_height_in_lines: u32,
 9460        window: &mut Window,
 9461        cx: &mut Context<Editor>,
 9462    ) -> Option<AnyElement> {
 9463        let menu = self.context_menu.borrow();
 9464        let menu = menu.as_ref()?;
 9465        if !menu.visible() {
 9466            return None;
 9467        };
 9468        Some(menu.render(style, max_height_in_lines, window, cx))
 9469    }
 9470
 9471    fn render_context_menu_aside(
 9472        &mut self,
 9473        max_size: Size<Pixels>,
 9474        window: &mut Window,
 9475        cx: &mut Context<Editor>,
 9476    ) -> Option<AnyElement> {
 9477        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9478            if menu.visible() {
 9479                menu.render_aside(max_size, window, cx)
 9480            } else {
 9481                None
 9482            }
 9483        })
 9484    }
 9485
 9486    fn hide_context_menu(
 9487        &mut self,
 9488        window: &mut Window,
 9489        cx: &mut Context<Self>,
 9490    ) -> Option<CodeContextMenu> {
 9491        cx.notify();
 9492        self.completion_tasks.clear();
 9493        let context_menu = self.context_menu.borrow_mut().take();
 9494        self.stale_edit_prediction_in_menu.take();
 9495        self.update_visible_edit_prediction(window, cx);
 9496        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9497            && let Some(completion_provider) = &self.completion_provider
 9498        {
 9499            completion_provider.selection_changed(None, window, cx);
 9500        }
 9501        context_menu
 9502    }
 9503
 9504    fn show_snippet_choices(
 9505        &mut self,
 9506        choices: &Vec<String>,
 9507        selection: Range<Anchor>,
 9508        cx: &mut Context<Self>,
 9509    ) {
 9510        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9511            (Some(a), Some(b)) if a == b => a,
 9512            _ => {
 9513                log::error!("expected anchor range to have matching buffer IDs");
 9514                return;
 9515            }
 9516        };
 9517        let multi_buffer = self.buffer().read(cx);
 9518        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9519            return;
 9520        };
 9521
 9522        let id = post_inc(&mut self.next_completion_id);
 9523        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9524        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9525            CompletionsMenu::new_snippet_choices(
 9526                id,
 9527                true,
 9528                choices,
 9529                selection,
 9530                buffer,
 9531                snippet_sort_order,
 9532            ),
 9533        ));
 9534    }
 9535
 9536    pub fn insert_snippet(
 9537        &mut self,
 9538        insertion_ranges: &[Range<usize>],
 9539        snippet: Snippet,
 9540        window: &mut Window,
 9541        cx: &mut Context<Self>,
 9542    ) -> Result<()> {
 9543        struct Tabstop<T> {
 9544            is_end_tabstop: bool,
 9545            ranges: Vec<Range<T>>,
 9546            choices: Option<Vec<String>>,
 9547        }
 9548
 9549        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9550            let snippet_text: Arc<str> = snippet.text.clone().into();
 9551            let edits = insertion_ranges
 9552                .iter()
 9553                .cloned()
 9554                .map(|range| (range, snippet_text.clone()));
 9555            let autoindent_mode = AutoindentMode::Block {
 9556                original_indent_columns: Vec::new(),
 9557            };
 9558            buffer.edit(edits, Some(autoindent_mode), cx);
 9559
 9560            let snapshot = &*buffer.read(cx);
 9561            let snippet = &snippet;
 9562            snippet
 9563                .tabstops
 9564                .iter()
 9565                .map(|tabstop| {
 9566                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9567                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9568                    });
 9569                    let mut tabstop_ranges = tabstop
 9570                        .ranges
 9571                        .iter()
 9572                        .flat_map(|tabstop_range| {
 9573                            let mut delta = 0_isize;
 9574                            insertion_ranges.iter().map(move |insertion_range| {
 9575                                let insertion_start = insertion_range.start as isize + delta;
 9576                                delta +=
 9577                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9578
 9579                                let start = ((insertion_start + tabstop_range.start) as usize)
 9580                                    .min(snapshot.len());
 9581                                let end = ((insertion_start + tabstop_range.end) as usize)
 9582                                    .min(snapshot.len());
 9583                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9584                            })
 9585                        })
 9586                        .collect::<Vec<_>>();
 9587                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9588
 9589                    Tabstop {
 9590                        is_end_tabstop,
 9591                        ranges: tabstop_ranges,
 9592                        choices: tabstop.choices.clone(),
 9593                    }
 9594                })
 9595                .collect::<Vec<_>>()
 9596        });
 9597        if let Some(tabstop) = tabstops.first() {
 9598            self.change_selections(Default::default(), window, cx, |s| {
 9599                // Reverse order so that the first range is the newest created selection.
 9600                // Completions will use it and autoscroll will prioritize it.
 9601                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9602            });
 9603
 9604            if let Some(choices) = &tabstop.choices
 9605                && let Some(selection) = tabstop.ranges.first()
 9606            {
 9607                self.show_snippet_choices(choices, selection.clone(), cx)
 9608            }
 9609
 9610            // If we're already at the last tabstop and it's at the end of the snippet,
 9611            // we're done, we don't need to keep the state around.
 9612            if !tabstop.is_end_tabstop {
 9613                let choices = tabstops
 9614                    .iter()
 9615                    .map(|tabstop| tabstop.choices.clone())
 9616                    .collect();
 9617
 9618                let ranges = tabstops
 9619                    .into_iter()
 9620                    .map(|tabstop| tabstop.ranges)
 9621                    .collect::<Vec<_>>();
 9622
 9623                self.snippet_stack.push(SnippetState {
 9624                    active_index: 0,
 9625                    ranges,
 9626                    choices,
 9627                });
 9628            }
 9629
 9630            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9631            if self.autoclose_regions.is_empty() {
 9632                let snapshot = self.buffer.read(cx).snapshot(cx);
 9633                let mut all_selections = self.selections.all::<Point>(cx);
 9634                for selection in &mut all_selections {
 9635                    let selection_head = selection.head();
 9636                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9637                        continue;
 9638                    };
 9639
 9640                    let mut bracket_pair = None;
 9641                    let max_lookup_length = scope
 9642                        .brackets()
 9643                        .map(|(pair, _)| {
 9644                            pair.start
 9645                                .as_str()
 9646                                .chars()
 9647                                .count()
 9648                                .max(pair.end.as_str().chars().count())
 9649                        })
 9650                        .max();
 9651                    if let Some(max_lookup_length) = max_lookup_length {
 9652                        let next_text = snapshot
 9653                            .chars_at(selection_head)
 9654                            .take(max_lookup_length)
 9655                            .collect::<String>();
 9656                        let prev_text = snapshot
 9657                            .reversed_chars_at(selection_head)
 9658                            .take(max_lookup_length)
 9659                            .collect::<String>();
 9660
 9661                        for (pair, enabled) in scope.brackets() {
 9662                            if enabled
 9663                                && pair.close
 9664                                && prev_text.starts_with(pair.start.as_str())
 9665                                && next_text.starts_with(pair.end.as_str())
 9666                            {
 9667                                bracket_pair = Some(pair.clone());
 9668                                break;
 9669                            }
 9670                        }
 9671                    }
 9672
 9673                    if let Some(pair) = bracket_pair {
 9674                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9675                        let autoclose_enabled =
 9676                            self.use_autoclose && snapshot_settings.use_autoclose;
 9677                        if autoclose_enabled {
 9678                            let start = snapshot.anchor_after(selection_head);
 9679                            let end = snapshot.anchor_after(selection_head);
 9680                            self.autoclose_regions.push(AutocloseRegion {
 9681                                selection_id: selection.id,
 9682                                range: start..end,
 9683                                pair,
 9684                            });
 9685                        }
 9686                    }
 9687                }
 9688            }
 9689        }
 9690        Ok(())
 9691    }
 9692
 9693    pub fn move_to_next_snippet_tabstop(
 9694        &mut self,
 9695        window: &mut Window,
 9696        cx: &mut Context<Self>,
 9697    ) -> bool {
 9698        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9699    }
 9700
 9701    pub fn move_to_prev_snippet_tabstop(
 9702        &mut self,
 9703        window: &mut Window,
 9704        cx: &mut Context<Self>,
 9705    ) -> bool {
 9706        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9707    }
 9708
 9709    pub fn move_to_snippet_tabstop(
 9710        &mut self,
 9711        bias: Bias,
 9712        window: &mut Window,
 9713        cx: &mut Context<Self>,
 9714    ) -> bool {
 9715        if let Some(mut snippet) = self.snippet_stack.pop() {
 9716            match bias {
 9717                Bias::Left => {
 9718                    if snippet.active_index > 0 {
 9719                        snippet.active_index -= 1;
 9720                    } else {
 9721                        self.snippet_stack.push(snippet);
 9722                        return false;
 9723                    }
 9724                }
 9725                Bias::Right => {
 9726                    if snippet.active_index + 1 < snippet.ranges.len() {
 9727                        snippet.active_index += 1;
 9728                    } else {
 9729                        self.snippet_stack.push(snippet);
 9730                        return false;
 9731                    }
 9732                }
 9733            }
 9734            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9735                self.change_selections(Default::default(), window, cx, |s| {
 9736                    // Reverse order so that the first range is the newest created selection.
 9737                    // Completions will use it and autoscroll will prioritize it.
 9738                    s.select_ranges(current_ranges.iter().rev().cloned())
 9739                });
 9740
 9741                if let Some(choices) = &snippet.choices[snippet.active_index]
 9742                    && let Some(selection) = current_ranges.first()
 9743                {
 9744                    self.show_snippet_choices(choices, selection.clone(), cx);
 9745                }
 9746
 9747                // If snippet state is not at the last tabstop, push it back on the stack
 9748                if snippet.active_index + 1 < snippet.ranges.len() {
 9749                    self.snippet_stack.push(snippet);
 9750                }
 9751                return true;
 9752            }
 9753        }
 9754
 9755        false
 9756    }
 9757
 9758    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9759        self.transact(window, cx, |this, window, cx| {
 9760            this.select_all(&SelectAll, window, cx);
 9761            this.insert("", window, cx);
 9762        });
 9763    }
 9764
 9765    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9767        self.transact(window, cx, |this, window, cx| {
 9768            this.select_autoclose_pair(window, cx);
 9769            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9770            if !this.linked_edit_ranges.is_empty() {
 9771                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9772                let snapshot = this.buffer.read(cx).snapshot(cx);
 9773
 9774                for selection in selections.iter() {
 9775                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9776                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9777                    if selection_start.buffer_id != selection_end.buffer_id {
 9778                        continue;
 9779                    }
 9780                    if let Some(ranges) =
 9781                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9782                    {
 9783                        for (buffer, entries) in ranges {
 9784                            linked_ranges.entry(buffer).or_default().extend(entries);
 9785                        }
 9786                    }
 9787                }
 9788            }
 9789
 9790            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9791            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9792            for selection in &mut selections {
 9793                if selection.is_empty() {
 9794                    let old_head = selection.head();
 9795                    let mut new_head =
 9796                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9797                            .to_point(&display_map);
 9798                    if let Some((buffer, line_buffer_range)) = display_map
 9799                        .buffer_snapshot
 9800                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9801                    {
 9802                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9803                        let indent_len = match indent_size.kind {
 9804                            IndentKind::Space => {
 9805                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9806                            }
 9807                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9808                        };
 9809                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9810                            let indent_len = indent_len.get();
 9811                            new_head = cmp::min(
 9812                                new_head,
 9813                                MultiBufferPoint::new(
 9814                                    old_head.row,
 9815                                    ((old_head.column - 1) / indent_len) * indent_len,
 9816                                ),
 9817                            );
 9818                        }
 9819                    }
 9820
 9821                    selection.set_head(new_head, SelectionGoal::None);
 9822                }
 9823            }
 9824
 9825            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9826            this.insert("", window, cx);
 9827            let empty_str: Arc<str> = Arc::from("");
 9828            for (buffer, edits) in linked_ranges {
 9829                let snapshot = buffer.read(cx).snapshot();
 9830                use text::ToPoint as TP;
 9831
 9832                let edits = edits
 9833                    .into_iter()
 9834                    .map(|range| {
 9835                        let end_point = TP::to_point(&range.end, &snapshot);
 9836                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9837
 9838                        if end_point == start_point {
 9839                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9840                                .saturating_sub(1);
 9841                            start_point =
 9842                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9843                        };
 9844
 9845                        (start_point..end_point, empty_str.clone())
 9846                    })
 9847                    .sorted_by_key(|(range, _)| range.start)
 9848                    .collect::<Vec<_>>();
 9849                buffer.update(cx, |this, cx| {
 9850                    this.edit(edits, None, cx);
 9851                })
 9852            }
 9853            this.refresh_edit_prediction(true, false, window, cx);
 9854            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9855        });
 9856    }
 9857
 9858    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9860        self.transact(window, cx, |this, window, cx| {
 9861            this.change_selections(Default::default(), window, cx, |s| {
 9862                s.move_with(|map, selection| {
 9863                    if selection.is_empty() {
 9864                        let cursor = movement::right(map, selection.head());
 9865                        selection.end = cursor;
 9866                        selection.reversed = true;
 9867                        selection.goal = SelectionGoal::None;
 9868                    }
 9869                })
 9870            });
 9871            this.insert("", window, cx);
 9872            this.refresh_edit_prediction(true, false, window, cx);
 9873        });
 9874    }
 9875
 9876    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9877        if self.mode.is_single_line() {
 9878            cx.propagate();
 9879            return;
 9880        }
 9881
 9882        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9883        if self.move_to_prev_snippet_tabstop(window, cx) {
 9884            return;
 9885        }
 9886        self.outdent(&Outdent, window, cx);
 9887    }
 9888
 9889    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9890        if self.mode.is_single_line() {
 9891            cx.propagate();
 9892            return;
 9893        }
 9894
 9895        if self.move_to_next_snippet_tabstop(window, cx) {
 9896            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9897            return;
 9898        }
 9899        if self.read_only(cx) {
 9900            return;
 9901        }
 9902        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9903        let mut selections = self.selections.all_adjusted(cx);
 9904        let buffer = self.buffer.read(cx);
 9905        let snapshot = buffer.snapshot(cx);
 9906        let rows_iter = selections.iter().map(|s| s.head().row);
 9907        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9908
 9909        let has_some_cursor_in_whitespace = selections
 9910            .iter()
 9911            .filter(|selection| selection.is_empty())
 9912            .any(|selection| {
 9913                let cursor = selection.head();
 9914                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9915                cursor.column < current_indent.len
 9916            });
 9917
 9918        let mut edits = Vec::new();
 9919        let mut prev_edited_row = 0;
 9920        let mut row_delta = 0;
 9921        for selection in &mut selections {
 9922            if selection.start.row != prev_edited_row {
 9923                row_delta = 0;
 9924            }
 9925            prev_edited_row = selection.end.row;
 9926
 9927            // If the selection is non-empty, then increase the indentation of the selected lines.
 9928            if !selection.is_empty() {
 9929                row_delta =
 9930                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9931                continue;
 9932            }
 9933
 9934            let cursor = selection.head();
 9935            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9936            if let Some(suggested_indent) =
 9937                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9938            {
 9939                // Don't do anything if already at suggested indent
 9940                // and there is any other cursor which is not
 9941                if has_some_cursor_in_whitespace
 9942                    && cursor.column == current_indent.len
 9943                    && current_indent.len == suggested_indent.len
 9944                {
 9945                    continue;
 9946                }
 9947
 9948                // Adjust line and move cursor to suggested indent
 9949                // if cursor is not at suggested indent
 9950                if cursor.column < suggested_indent.len
 9951                    && cursor.column <= current_indent.len
 9952                    && current_indent.len <= suggested_indent.len
 9953                {
 9954                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9955                    selection.end = selection.start;
 9956                    if row_delta == 0 {
 9957                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9958                            cursor.row,
 9959                            current_indent,
 9960                            suggested_indent,
 9961                        ));
 9962                        row_delta = suggested_indent.len - current_indent.len;
 9963                    }
 9964                    continue;
 9965                }
 9966
 9967                // If current indent is more than suggested indent
 9968                // only move cursor to current indent and skip indent
 9969                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9970                    selection.start = Point::new(cursor.row, current_indent.len);
 9971                    selection.end = selection.start;
 9972                    continue;
 9973                }
 9974            }
 9975
 9976            // Otherwise, insert a hard or soft tab.
 9977            let settings = buffer.language_settings_at(cursor, cx);
 9978            let tab_size = if settings.hard_tabs {
 9979                IndentSize::tab()
 9980            } else {
 9981                let tab_size = settings.tab_size.get();
 9982                let indent_remainder = snapshot
 9983                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9984                    .flat_map(str::chars)
 9985                    .fold(row_delta % tab_size, |counter: u32, c| {
 9986                        if c == '\t' {
 9987                            0
 9988                        } else {
 9989                            (counter + 1) % tab_size
 9990                        }
 9991                    });
 9992
 9993                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9994                IndentSize::spaces(chars_to_next_tab_stop)
 9995            };
 9996            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9997            selection.end = selection.start;
 9998            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9999            row_delta += tab_size.len;
10000        }
10001
10002        self.transact(window, cx, |this, window, cx| {
10003            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10004            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10005            this.refresh_edit_prediction(true, false, window, cx);
10006        });
10007    }
10008
10009    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10010        if self.read_only(cx) {
10011            return;
10012        }
10013        if self.mode.is_single_line() {
10014            cx.propagate();
10015            return;
10016        }
10017
10018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10019        let mut selections = self.selections.all::<Point>(cx);
10020        let mut prev_edited_row = 0;
10021        let mut row_delta = 0;
10022        let mut edits = Vec::new();
10023        let buffer = self.buffer.read(cx);
10024        let snapshot = buffer.snapshot(cx);
10025        for selection in &mut selections {
10026            if selection.start.row != prev_edited_row {
10027                row_delta = 0;
10028            }
10029            prev_edited_row = selection.end.row;
10030
10031            row_delta =
10032                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10033        }
10034
10035        self.transact(window, cx, |this, window, cx| {
10036            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10037            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10038        });
10039    }
10040
10041    fn indent_selection(
10042        buffer: &MultiBuffer,
10043        snapshot: &MultiBufferSnapshot,
10044        selection: &mut Selection<Point>,
10045        edits: &mut Vec<(Range<Point>, String)>,
10046        delta_for_start_row: u32,
10047        cx: &App,
10048    ) -> u32 {
10049        let settings = buffer.language_settings_at(selection.start, cx);
10050        let tab_size = settings.tab_size.get();
10051        let indent_kind = if settings.hard_tabs {
10052            IndentKind::Tab
10053        } else {
10054            IndentKind::Space
10055        };
10056        let mut start_row = selection.start.row;
10057        let mut end_row = selection.end.row + 1;
10058
10059        // If a selection ends at the beginning of a line, don't indent
10060        // that last line.
10061        if selection.end.column == 0 && selection.end.row > selection.start.row {
10062            end_row -= 1;
10063        }
10064
10065        // Avoid re-indenting a row that has already been indented by a
10066        // previous selection, but still update this selection's column
10067        // to reflect that indentation.
10068        if delta_for_start_row > 0 {
10069            start_row += 1;
10070            selection.start.column += delta_for_start_row;
10071            if selection.end.row == selection.start.row {
10072                selection.end.column += delta_for_start_row;
10073            }
10074        }
10075
10076        let mut delta_for_end_row = 0;
10077        let has_multiple_rows = start_row + 1 != end_row;
10078        for row in start_row..end_row {
10079            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10080            let indent_delta = match (current_indent.kind, indent_kind) {
10081                (IndentKind::Space, IndentKind::Space) => {
10082                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10083                    IndentSize::spaces(columns_to_next_tab_stop)
10084                }
10085                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10086                (_, IndentKind::Tab) => IndentSize::tab(),
10087            };
10088
10089            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10090                0
10091            } else {
10092                selection.start.column
10093            };
10094            let row_start = Point::new(row, start);
10095            edits.push((
10096                row_start..row_start,
10097                indent_delta.chars().collect::<String>(),
10098            ));
10099
10100            // Update this selection's endpoints to reflect the indentation.
10101            if row == selection.start.row {
10102                selection.start.column += indent_delta.len;
10103            }
10104            if row == selection.end.row {
10105                selection.end.column += indent_delta.len;
10106                delta_for_end_row = indent_delta.len;
10107            }
10108        }
10109
10110        if selection.start.row == selection.end.row {
10111            delta_for_start_row + delta_for_end_row
10112        } else {
10113            delta_for_end_row
10114        }
10115    }
10116
10117    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10118        if self.read_only(cx) {
10119            return;
10120        }
10121        if self.mode.is_single_line() {
10122            cx.propagate();
10123            return;
10124        }
10125
10126        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10127        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10128        let selections = self.selections.all::<Point>(cx);
10129        let mut deletion_ranges = Vec::new();
10130        let mut last_outdent = None;
10131        {
10132            let buffer = self.buffer.read(cx);
10133            let snapshot = buffer.snapshot(cx);
10134            for selection in &selections {
10135                let settings = buffer.language_settings_at(selection.start, cx);
10136                let tab_size = settings.tab_size.get();
10137                let mut rows = selection.spanned_rows(false, &display_map);
10138
10139                // Avoid re-outdenting a row that has already been outdented by a
10140                // previous selection.
10141                if let Some(last_row) = last_outdent
10142                    && last_row == rows.start
10143                {
10144                    rows.start = rows.start.next_row();
10145                }
10146                let has_multiple_rows = rows.len() > 1;
10147                for row in rows.iter_rows() {
10148                    let indent_size = snapshot.indent_size_for_line(row);
10149                    if indent_size.len > 0 {
10150                        let deletion_len = match indent_size.kind {
10151                            IndentKind::Space => {
10152                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10153                                if columns_to_prev_tab_stop == 0 {
10154                                    tab_size
10155                                } else {
10156                                    columns_to_prev_tab_stop
10157                                }
10158                            }
10159                            IndentKind::Tab => 1,
10160                        };
10161                        let start = if has_multiple_rows
10162                            || deletion_len > selection.start.column
10163                            || indent_size.len < selection.start.column
10164                        {
10165                            0
10166                        } else {
10167                            selection.start.column - deletion_len
10168                        };
10169                        deletion_ranges.push(
10170                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10171                        );
10172                        last_outdent = Some(row);
10173                    }
10174                }
10175            }
10176        }
10177
10178        self.transact(window, cx, |this, window, cx| {
10179            this.buffer.update(cx, |buffer, cx| {
10180                let empty_str: Arc<str> = Arc::default();
10181                buffer.edit(
10182                    deletion_ranges
10183                        .into_iter()
10184                        .map(|range| (range, empty_str.clone())),
10185                    None,
10186                    cx,
10187                );
10188            });
10189            let selections = this.selections.all::<usize>(cx);
10190            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10191        });
10192    }
10193
10194    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10195        if self.read_only(cx) {
10196            return;
10197        }
10198        if self.mode.is_single_line() {
10199            cx.propagate();
10200            return;
10201        }
10202
10203        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10204        let selections = self
10205            .selections
10206            .all::<usize>(cx)
10207            .into_iter()
10208            .map(|s| s.range());
10209
10210        self.transact(window, cx, |this, window, cx| {
10211            this.buffer.update(cx, |buffer, cx| {
10212                buffer.autoindent_ranges(selections, cx);
10213            });
10214            let selections = this.selections.all::<usize>(cx);
10215            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10216        });
10217    }
10218
10219    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10220        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10221        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10222        let selections = self.selections.all::<Point>(cx);
10223
10224        let mut new_cursors = Vec::new();
10225        let mut edit_ranges = Vec::new();
10226        let mut selections = selections.iter().peekable();
10227        while let Some(selection) = selections.next() {
10228            let mut rows = selection.spanned_rows(false, &display_map);
10229            let goal_display_column = selection.head().to_display_point(&display_map).column();
10230
10231            // Accumulate contiguous regions of rows that we want to delete.
10232            while let Some(next_selection) = selections.peek() {
10233                let next_rows = next_selection.spanned_rows(false, &display_map);
10234                if next_rows.start <= rows.end {
10235                    rows.end = next_rows.end;
10236                    selections.next().unwrap();
10237                } else {
10238                    break;
10239                }
10240            }
10241
10242            let buffer = &display_map.buffer_snapshot;
10243            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10244            let edit_end;
10245            let cursor_buffer_row;
10246            if buffer.max_point().row >= rows.end.0 {
10247                // If there's a line after the range, delete the \n from the end of the row range
10248                // and position the cursor on the next line.
10249                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10250                cursor_buffer_row = rows.end;
10251            } else {
10252                // If there isn't a line after the range, delete the \n from the line before the
10253                // start of the row range and position the cursor there.
10254                edit_start = edit_start.saturating_sub(1);
10255                edit_end = buffer.len();
10256                cursor_buffer_row = rows.start.previous_row();
10257            }
10258
10259            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10260            *cursor.column_mut() =
10261                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10262
10263            new_cursors.push((
10264                selection.id,
10265                buffer.anchor_after(cursor.to_point(&display_map)),
10266            ));
10267            edit_ranges.push(edit_start..edit_end);
10268        }
10269
10270        self.transact(window, cx, |this, window, cx| {
10271            let buffer = this.buffer.update(cx, |buffer, cx| {
10272                let empty_str: Arc<str> = Arc::default();
10273                buffer.edit(
10274                    edit_ranges
10275                        .into_iter()
10276                        .map(|range| (range, empty_str.clone())),
10277                    None,
10278                    cx,
10279                );
10280                buffer.snapshot(cx)
10281            });
10282            let new_selections = new_cursors
10283                .into_iter()
10284                .map(|(id, cursor)| {
10285                    let cursor = cursor.to_point(&buffer);
10286                    Selection {
10287                        id,
10288                        start: cursor,
10289                        end: cursor,
10290                        reversed: false,
10291                        goal: SelectionGoal::None,
10292                    }
10293                })
10294                .collect();
10295
10296            this.change_selections(Default::default(), window, cx, |s| {
10297                s.select(new_selections);
10298            });
10299        });
10300    }
10301
10302    pub fn join_lines_impl(
10303        &mut self,
10304        insert_whitespace: bool,
10305        window: &mut Window,
10306        cx: &mut Context<Self>,
10307    ) {
10308        if self.read_only(cx) {
10309            return;
10310        }
10311        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10312        for selection in self.selections.all::<Point>(cx) {
10313            let start = MultiBufferRow(selection.start.row);
10314            // Treat single line selections as if they include the next line. Otherwise this action
10315            // would do nothing for single line selections individual cursors.
10316            let end = if selection.start.row == selection.end.row {
10317                MultiBufferRow(selection.start.row + 1)
10318            } else {
10319                MultiBufferRow(selection.end.row)
10320            };
10321
10322            if let Some(last_row_range) = row_ranges.last_mut()
10323                && start <= last_row_range.end
10324            {
10325                last_row_range.end = end;
10326                continue;
10327            }
10328            row_ranges.push(start..end);
10329        }
10330
10331        let snapshot = self.buffer.read(cx).snapshot(cx);
10332        let mut cursor_positions = Vec::new();
10333        for row_range in &row_ranges {
10334            let anchor = snapshot.anchor_before(Point::new(
10335                row_range.end.previous_row().0,
10336                snapshot.line_len(row_range.end.previous_row()),
10337            ));
10338            cursor_positions.push(anchor..anchor);
10339        }
10340
10341        self.transact(window, cx, |this, window, cx| {
10342            for row_range in row_ranges.into_iter().rev() {
10343                for row in row_range.iter_rows().rev() {
10344                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10345                    let next_line_row = row.next_row();
10346                    let indent = snapshot.indent_size_for_line(next_line_row);
10347                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10348
10349                    let replace =
10350                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10351                            " "
10352                        } else {
10353                            ""
10354                        };
10355
10356                    this.buffer.update(cx, |buffer, cx| {
10357                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10358                    });
10359                }
10360            }
10361
10362            this.change_selections(Default::default(), window, cx, |s| {
10363                s.select_anchor_ranges(cursor_positions)
10364            });
10365        });
10366    }
10367
10368    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10369        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10370        self.join_lines_impl(true, window, cx);
10371    }
10372
10373    pub fn sort_lines_case_sensitive(
10374        &mut self,
10375        _: &SortLinesCaseSensitive,
10376        window: &mut Window,
10377        cx: &mut Context<Self>,
10378    ) {
10379        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10380    }
10381
10382    pub fn sort_lines_by_length(
10383        &mut self,
10384        _: &SortLinesByLength,
10385        window: &mut Window,
10386        cx: &mut Context<Self>,
10387    ) {
10388        self.manipulate_immutable_lines(window, cx, |lines| {
10389            lines.sort_by_key(|&line| line.chars().count())
10390        })
10391    }
10392
10393    pub fn sort_lines_case_insensitive(
10394        &mut self,
10395        _: &SortLinesCaseInsensitive,
10396        window: &mut Window,
10397        cx: &mut Context<Self>,
10398    ) {
10399        self.manipulate_immutable_lines(window, cx, |lines| {
10400            lines.sort_by_key(|line| line.to_lowercase())
10401        })
10402    }
10403
10404    pub fn unique_lines_case_insensitive(
10405        &mut self,
10406        _: &UniqueLinesCaseInsensitive,
10407        window: &mut Window,
10408        cx: &mut Context<Self>,
10409    ) {
10410        self.manipulate_immutable_lines(window, cx, |lines| {
10411            let mut seen = HashSet::default();
10412            lines.retain(|line| seen.insert(line.to_lowercase()));
10413        })
10414    }
10415
10416    pub fn unique_lines_case_sensitive(
10417        &mut self,
10418        _: &UniqueLinesCaseSensitive,
10419        window: &mut Window,
10420        cx: &mut Context<Self>,
10421    ) {
10422        self.manipulate_immutable_lines(window, cx, |lines| {
10423            let mut seen = HashSet::default();
10424            lines.retain(|line| seen.insert(*line));
10425        })
10426    }
10427
10428    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10429        let Some(project) = self.project.clone() else {
10430            return;
10431        };
10432        self.reload(project, window, cx)
10433            .detach_and_notify_err(window, cx);
10434    }
10435
10436    pub fn restore_file(
10437        &mut self,
10438        _: &::git::RestoreFile,
10439        window: &mut Window,
10440        cx: &mut Context<Self>,
10441    ) {
10442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10443        let mut buffer_ids = HashSet::default();
10444        let snapshot = self.buffer().read(cx).snapshot(cx);
10445        for selection in self.selections.all::<usize>(cx) {
10446            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10447        }
10448
10449        let buffer = self.buffer().read(cx);
10450        let ranges = buffer_ids
10451            .into_iter()
10452            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10453            .collect::<Vec<_>>();
10454
10455        self.restore_hunks_in_ranges(ranges, window, cx);
10456    }
10457
10458    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10459        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10460        let selections = self
10461            .selections
10462            .all(cx)
10463            .into_iter()
10464            .map(|s| s.range())
10465            .collect();
10466        self.restore_hunks_in_ranges(selections, window, cx);
10467    }
10468
10469    pub fn restore_hunks_in_ranges(
10470        &mut self,
10471        ranges: Vec<Range<Point>>,
10472        window: &mut Window,
10473        cx: &mut Context<Editor>,
10474    ) {
10475        let mut revert_changes = HashMap::default();
10476        let chunk_by = self
10477            .snapshot(window, cx)
10478            .hunks_for_ranges(ranges)
10479            .into_iter()
10480            .chunk_by(|hunk| hunk.buffer_id);
10481        for (buffer_id, hunks) in &chunk_by {
10482            let hunks = hunks.collect::<Vec<_>>();
10483            for hunk in &hunks {
10484                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10485            }
10486            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10487        }
10488        drop(chunk_by);
10489        if !revert_changes.is_empty() {
10490            self.transact(window, cx, |editor, window, cx| {
10491                editor.restore(revert_changes, window, cx);
10492            });
10493        }
10494    }
10495
10496    pub fn open_active_item_in_terminal(
10497        &mut self,
10498        _: &OpenInTerminal,
10499        window: &mut Window,
10500        cx: &mut Context<Self>,
10501    ) {
10502        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10503            let project_path = buffer.read(cx).project_path(cx)?;
10504            let project = self.project()?.read(cx);
10505            let entry = project.entry_for_path(&project_path, cx)?;
10506            let parent = match &entry.canonical_path {
10507                Some(canonical_path) => canonical_path.to_path_buf(),
10508                None => project.absolute_path(&project_path, cx)?,
10509            }
10510            .parent()?
10511            .to_path_buf();
10512            Some(parent)
10513        }) {
10514            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10515        }
10516    }
10517
10518    fn set_breakpoint_context_menu(
10519        &mut self,
10520        display_row: DisplayRow,
10521        position: Option<Anchor>,
10522        clicked_point: gpui::Point<Pixels>,
10523        window: &mut Window,
10524        cx: &mut Context<Self>,
10525    ) {
10526        let source = self
10527            .buffer
10528            .read(cx)
10529            .snapshot(cx)
10530            .anchor_before(Point::new(display_row.0, 0u32));
10531
10532        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10533
10534        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10535            self,
10536            source,
10537            clicked_point,
10538            context_menu,
10539            window,
10540            cx,
10541        );
10542    }
10543
10544    fn add_edit_breakpoint_block(
10545        &mut self,
10546        anchor: Anchor,
10547        breakpoint: &Breakpoint,
10548        edit_action: BreakpointPromptEditAction,
10549        window: &mut Window,
10550        cx: &mut Context<Self>,
10551    ) {
10552        let weak_editor = cx.weak_entity();
10553        let bp_prompt = cx.new(|cx| {
10554            BreakpointPromptEditor::new(
10555                weak_editor,
10556                anchor,
10557                breakpoint.clone(),
10558                edit_action,
10559                window,
10560                cx,
10561            )
10562        });
10563
10564        let height = bp_prompt.update(cx, |this, cx| {
10565            this.prompt
10566                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10567        });
10568        let cloned_prompt = bp_prompt.clone();
10569        let blocks = vec![BlockProperties {
10570            style: BlockStyle::Sticky,
10571            placement: BlockPlacement::Above(anchor),
10572            height: Some(height),
10573            render: Arc::new(move |cx| {
10574                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10575                cloned_prompt.clone().into_any_element()
10576            }),
10577            priority: 0,
10578        }];
10579
10580        let focus_handle = bp_prompt.focus_handle(cx);
10581        window.focus(&focus_handle);
10582
10583        let block_ids = self.insert_blocks(blocks, None, cx);
10584        bp_prompt.update(cx, |prompt, _| {
10585            prompt.add_block_ids(block_ids);
10586        });
10587    }
10588
10589    pub(crate) fn breakpoint_at_row(
10590        &self,
10591        row: u32,
10592        window: &mut Window,
10593        cx: &mut Context<Self>,
10594    ) -> Option<(Anchor, Breakpoint)> {
10595        let snapshot = self.snapshot(window, cx);
10596        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10597
10598        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10599    }
10600
10601    pub(crate) fn breakpoint_at_anchor(
10602        &self,
10603        breakpoint_position: Anchor,
10604        snapshot: &EditorSnapshot,
10605        cx: &mut Context<Self>,
10606    ) -> Option<(Anchor, Breakpoint)> {
10607        let project = self.project.clone()?;
10608
10609        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10610            snapshot
10611                .buffer_snapshot
10612                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10613        })?;
10614
10615        let enclosing_excerpt = breakpoint_position.excerpt_id;
10616        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10617        let buffer_snapshot = buffer.read(cx).snapshot();
10618
10619        let row = buffer_snapshot
10620            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10621            .row;
10622
10623        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10624        let anchor_end = snapshot
10625            .buffer_snapshot
10626            .anchor_after(Point::new(row, line_len));
10627
10628        self.breakpoint_store
10629            .as_ref()?
10630            .read_with(cx, |breakpoint_store, cx| {
10631                breakpoint_store
10632                    .breakpoints(
10633                        &buffer,
10634                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10635                        &buffer_snapshot,
10636                        cx,
10637                    )
10638                    .next()
10639                    .and_then(|(bp, _)| {
10640                        let breakpoint_row = buffer_snapshot
10641                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10642                            .row;
10643
10644                        if breakpoint_row == row {
10645                            snapshot
10646                                .buffer_snapshot
10647                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10648                                .map(|position| (position, bp.bp.clone()))
10649                        } else {
10650                            None
10651                        }
10652                    })
10653            })
10654    }
10655
10656    pub fn edit_log_breakpoint(
10657        &mut self,
10658        _: &EditLogBreakpoint,
10659        window: &mut Window,
10660        cx: &mut Context<Self>,
10661    ) {
10662        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10663            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10664                message: None,
10665                state: BreakpointState::Enabled,
10666                condition: None,
10667                hit_condition: None,
10668            });
10669
10670            self.add_edit_breakpoint_block(
10671                anchor,
10672                &breakpoint,
10673                BreakpointPromptEditAction::Log,
10674                window,
10675                cx,
10676            );
10677        }
10678    }
10679
10680    fn breakpoints_at_cursors(
10681        &self,
10682        window: &mut Window,
10683        cx: &mut Context<Self>,
10684    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10685        let snapshot = self.snapshot(window, cx);
10686        let cursors = self
10687            .selections
10688            .disjoint_anchors()
10689            .iter()
10690            .map(|selection| {
10691                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10692
10693                let breakpoint_position = self
10694                    .breakpoint_at_row(cursor_position.row, window, cx)
10695                    .map(|bp| bp.0)
10696                    .unwrap_or_else(|| {
10697                        snapshot
10698                            .display_snapshot
10699                            .buffer_snapshot
10700                            .anchor_after(Point::new(cursor_position.row, 0))
10701                    });
10702
10703                let breakpoint = self
10704                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10705                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10706
10707                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10708            })
10709            // 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.
10710            .collect::<HashMap<Anchor, _>>();
10711
10712        cursors.into_iter().collect()
10713    }
10714
10715    pub fn enable_breakpoint(
10716        &mut self,
10717        _: &crate::actions::EnableBreakpoint,
10718        window: &mut Window,
10719        cx: &mut Context<Self>,
10720    ) {
10721        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10722            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10723                continue;
10724            };
10725            self.edit_breakpoint_at_anchor(
10726                anchor,
10727                breakpoint,
10728                BreakpointEditAction::InvertState,
10729                cx,
10730            );
10731        }
10732    }
10733
10734    pub fn disable_breakpoint(
10735        &mut self,
10736        _: &crate::actions::DisableBreakpoint,
10737        window: &mut Window,
10738        cx: &mut Context<Self>,
10739    ) {
10740        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10741            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10742                continue;
10743            };
10744            self.edit_breakpoint_at_anchor(
10745                anchor,
10746                breakpoint,
10747                BreakpointEditAction::InvertState,
10748                cx,
10749            );
10750        }
10751    }
10752
10753    pub fn toggle_breakpoint(
10754        &mut self,
10755        _: &crate::actions::ToggleBreakpoint,
10756        window: &mut Window,
10757        cx: &mut Context<Self>,
10758    ) {
10759        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10760            if let Some(breakpoint) = breakpoint {
10761                self.edit_breakpoint_at_anchor(
10762                    anchor,
10763                    breakpoint,
10764                    BreakpointEditAction::Toggle,
10765                    cx,
10766                );
10767            } else {
10768                self.edit_breakpoint_at_anchor(
10769                    anchor,
10770                    Breakpoint::new_standard(),
10771                    BreakpointEditAction::Toggle,
10772                    cx,
10773                );
10774            }
10775        }
10776    }
10777
10778    pub fn edit_breakpoint_at_anchor(
10779        &mut self,
10780        breakpoint_position: Anchor,
10781        breakpoint: Breakpoint,
10782        edit_action: BreakpointEditAction,
10783        cx: &mut Context<Self>,
10784    ) {
10785        let Some(breakpoint_store) = &self.breakpoint_store else {
10786            return;
10787        };
10788
10789        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10790            if breakpoint_position == Anchor::min() {
10791                self.buffer()
10792                    .read(cx)
10793                    .excerpt_buffer_ids()
10794                    .into_iter()
10795                    .next()
10796            } else {
10797                None
10798            }
10799        }) else {
10800            return;
10801        };
10802
10803        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10804            return;
10805        };
10806
10807        breakpoint_store.update(cx, |breakpoint_store, cx| {
10808            breakpoint_store.toggle_breakpoint(
10809                buffer,
10810                BreakpointWithPosition {
10811                    position: breakpoint_position.text_anchor,
10812                    bp: breakpoint,
10813                },
10814                edit_action,
10815                cx,
10816            );
10817        });
10818
10819        cx.notify();
10820    }
10821
10822    #[cfg(any(test, feature = "test-support"))]
10823    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10824        self.breakpoint_store.clone()
10825    }
10826
10827    pub fn prepare_restore_change(
10828        &self,
10829        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10830        hunk: &MultiBufferDiffHunk,
10831        cx: &mut App,
10832    ) -> Option<()> {
10833        if hunk.is_created_file() {
10834            return None;
10835        }
10836        let buffer = self.buffer.read(cx);
10837        let diff = buffer.diff_for(hunk.buffer_id)?;
10838        let buffer = buffer.buffer(hunk.buffer_id)?;
10839        let buffer = buffer.read(cx);
10840        let original_text = diff
10841            .read(cx)
10842            .base_text()
10843            .as_rope()
10844            .slice(hunk.diff_base_byte_range.clone());
10845        let buffer_snapshot = buffer.snapshot();
10846        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10847        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10848            probe
10849                .0
10850                .start
10851                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10852                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10853        }) {
10854            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10855            Some(())
10856        } else {
10857            None
10858        }
10859    }
10860
10861    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10862        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10863    }
10864
10865    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10866        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10867    }
10868
10869    fn manipulate_lines<M>(
10870        &mut self,
10871        window: &mut Window,
10872        cx: &mut Context<Self>,
10873        mut manipulate: M,
10874    ) where
10875        M: FnMut(&str) -> LineManipulationResult,
10876    {
10877        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10878
10879        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10880        let buffer = self.buffer.read(cx).snapshot(cx);
10881
10882        let mut edits = Vec::new();
10883
10884        let selections = self.selections.all::<Point>(cx);
10885        let mut selections = selections.iter().peekable();
10886        let mut contiguous_row_selections = Vec::new();
10887        let mut new_selections = Vec::new();
10888        let mut added_lines = 0;
10889        let mut removed_lines = 0;
10890
10891        while let Some(selection) = selections.next() {
10892            let (start_row, end_row) = consume_contiguous_rows(
10893                &mut contiguous_row_selections,
10894                selection,
10895                &display_map,
10896                &mut selections,
10897            );
10898
10899            let start_point = Point::new(start_row.0, 0);
10900            let end_point = Point::new(
10901                end_row.previous_row().0,
10902                buffer.line_len(end_row.previous_row()),
10903            );
10904            let text = buffer
10905                .text_for_range(start_point..end_point)
10906                .collect::<String>();
10907
10908            let LineManipulationResult {
10909                new_text,
10910                line_count_before,
10911                line_count_after,
10912            } = manipulate(&text);
10913
10914            edits.push((start_point..end_point, new_text));
10915
10916            // Selections must change based on added and removed line count
10917            let start_row =
10918                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10919            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10920            new_selections.push(Selection {
10921                id: selection.id,
10922                start: start_row,
10923                end: end_row,
10924                goal: SelectionGoal::None,
10925                reversed: selection.reversed,
10926            });
10927
10928            if line_count_after > line_count_before {
10929                added_lines += line_count_after - line_count_before;
10930            } else if line_count_before > line_count_after {
10931                removed_lines += line_count_before - line_count_after;
10932            }
10933        }
10934
10935        self.transact(window, cx, |this, window, cx| {
10936            let buffer = this.buffer.update(cx, |buffer, cx| {
10937                buffer.edit(edits, None, cx);
10938                buffer.snapshot(cx)
10939            });
10940
10941            // Recalculate offsets on newly edited buffer
10942            let new_selections = new_selections
10943                .iter()
10944                .map(|s| {
10945                    let start_point = Point::new(s.start.0, 0);
10946                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10947                    Selection {
10948                        id: s.id,
10949                        start: buffer.point_to_offset(start_point),
10950                        end: buffer.point_to_offset(end_point),
10951                        goal: s.goal,
10952                        reversed: s.reversed,
10953                    }
10954                })
10955                .collect();
10956
10957            this.change_selections(Default::default(), window, cx, |s| {
10958                s.select(new_selections);
10959            });
10960
10961            this.request_autoscroll(Autoscroll::fit(), cx);
10962        });
10963    }
10964
10965    fn manipulate_immutable_lines<Fn>(
10966        &mut self,
10967        window: &mut Window,
10968        cx: &mut Context<Self>,
10969        mut callback: Fn,
10970    ) where
10971        Fn: FnMut(&mut Vec<&str>),
10972    {
10973        self.manipulate_lines(window, cx, |text| {
10974            let mut lines: Vec<&str> = text.split('\n').collect();
10975            let line_count_before = lines.len();
10976
10977            callback(&mut lines);
10978
10979            LineManipulationResult {
10980                new_text: lines.join("\n"),
10981                line_count_before,
10982                line_count_after: lines.len(),
10983            }
10984        });
10985    }
10986
10987    fn manipulate_mutable_lines<Fn>(
10988        &mut self,
10989        window: &mut Window,
10990        cx: &mut Context<Self>,
10991        mut callback: Fn,
10992    ) where
10993        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10994    {
10995        self.manipulate_lines(window, cx, |text| {
10996            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10997            let line_count_before = lines.len();
10998
10999            callback(&mut lines);
11000
11001            LineManipulationResult {
11002                new_text: lines.join("\n"),
11003                line_count_before,
11004                line_count_after: lines.len(),
11005            }
11006        });
11007    }
11008
11009    pub fn convert_indentation_to_spaces(
11010        &mut self,
11011        _: &ConvertIndentationToSpaces,
11012        window: &mut Window,
11013        cx: &mut Context<Self>,
11014    ) {
11015        let settings = self.buffer.read(cx).language_settings(cx);
11016        let tab_size = settings.tab_size.get() as usize;
11017
11018        self.manipulate_mutable_lines(window, cx, |lines| {
11019            // Allocates a reasonably sized scratch buffer once for the whole loop
11020            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11021            // Avoids recomputing spaces that could be inserted many times
11022            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11023                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11024                .collect();
11025
11026            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11027                let mut chars = line.as_ref().chars();
11028                let mut col = 0;
11029                let mut changed = false;
11030
11031                while let Some(ch) = chars.next() {
11032                    match ch {
11033                        ' ' => {
11034                            reindented_line.push(' ');
11035                            col += 1;
11036                        }
11037                        '\t' => {
11038                            // \t are converted to spaces depending on the current column
11039                            let spaces_len = tab_size - (col % tab_size);
11040                            reindented_line.extend(&space_cache[spaces_len - 1]);
11041                            col += spaces_len;
11042                            changed = true;
11043                        }
11044                        _ => {
11045                            // If we dont append before break, the character is consumed
11046                            reindented_line.push(ch);
11047                            break;
11048                        }
11049                    }
11050                }
11051
11052                if !changed {
11053                    reindented_line.clear();
11054                    continue;
11055                }
11056                // Append the rest of the line and replace old reference with new one
11057                reindented_line.extend(chars);
11058                *line = Cow::Owned(reindented_line.clone());
11059                reindented_line.clear();
11060            }
11061        });
11062    }
11063
11064    pub fn convert_indentation_to_tabs(
11065        &mut self,
11066        _: &ConvertIndentationToTabs,
11067        window: &mut Window,
11068        cx: &mut Context<Self>,
11069    ) {
11070        let settings = self.buffer.read(cx).language_settings(cx);
11071        let tab_size = settings.tab_size.get() as usize;
11072
11073        self.manipulate_mutable_lines(window, cx, |lines| {
11074            // Allocates a reasonably sized buffer once for the whole loop
11075            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11076            // Avoids recomputing spaces that could be inserted many times
11077            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11078                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11079                .collect();
11080
11081            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11082                let mut chars = line.chars();
11083                let mut spaces_count = 0;
11084                let mut first_non_indent_char = None;
11085                let mut changed = false;
11086
11087                while let Some(ch) = chars.next() {
11088                    match ch {
11089                        ' ' => {
11090                            // Keep track of spaces. Append \t when we reach tab_size
11091                            spaces_count += 1;
11092                            changed = true;
11093                            if spaces_count == tab_size {
11094                                reindented_line.push('\t');
11095                                spaces_count = 0;
11096                            }
11097                        }
11098                        '\t' => {
11099                            reindented_line.push('\t');
11100                            spaces_count = 0;
11101                        }
11102                        _ => {
11103                            // Dont append it yet, we might have remaining spaces
11104                            first_non_indent_char = Some(ch);
11105                            break;
11106                        }
11107                    }
11108                }
11109
11110                if !changed {
11111                    reindented_line.clear();
11112                    continue;
11113                }
11114                // Remaining spaces that didn't make a full tab stop
11115                if spaces_count > 0 {
11116                    reindented_line.extend(&space_cache[spaces_count - 1]);
11117                }
11118                // If we consume an extra character that was not indentation, add it back
11119                if let Some(extra_char) = first_non_indent_char {
11120                    reindented_line.push(extra_char);
11121                }
11122                // Append the rest of the line and replace old reference with new one
11123                reindented_line.extend(chars);
11124                *line = Cow::Owned(reindented_line.clone());
11125                reindented_line.clear();
11126            }
11127        });
11128    }
11129
11130    pub fn convert_to_upper_case(
11131        &mut self,
11132        _: &ConvertToUpperCase,
11133        window: &mut Window,
11134        cx: &mut Context<Self>,
11135    ) {
11136        self.manipulate_text(window, cx, |text| text.to_uppercase())
11137    }
11138
11139    pub fn convert_to_lower_case(
11140        &mut self,
11141        _: &ConvertToLowerCase,
11142        window: &mut Window,
11143        cx: &mut Context<Self>,
11144    ) {
11145        self.manipulate_text(window, cx, |text| text.to_lowercase())
11146    }
11147
11148    pub fn convert_to_title_case(
11149        &mut self,
11150        _: &ConvertToTitleCase,
11151        window: &mut Window,
11152        cx: &mut Context<Self>,
11153    ) {
11154        self.manipulate_text(window, cx, |text| {
11155            text.split('\n')
11156                .map(|line| line.to_case(Case::Title))
11157                .join("\n")
11158        })
11159    }
11160
11161    pub fn convert_to_snake_case(
11162        &mut self,
11163        _: &ConvertToSnakeCase,
11164        window: &mut Window,
11165        cx: &mut Context<Self>,
11166    ) {
11167        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11168    }
11169
11170    pub fn convert_to_kebab_case(
11171        &mut self,
11172        _: &ConvertToKebabCase,
11173        window: &mut Window,
11174        cx: &mut Context<Self>,
11175    ) {
11176        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11177    }
11178
11179    pub fn convert_to_upper_camel_case(
11180        &mut self,
11181        _: &ConvertToUpperCamelCase,
11182        window: &mut Window,
11183        cx: &mut Context<Self>,
11184    ) {
11185        self.manipulate_text(window, cx, |text| {
11186            text.split('\n')
11187                .map(|line| line.to_case(Case::UpperCamel))
11188                .join("\n")
11189        })
11190    }
11191
11192    pub fn convert_to_lower_camel_case(
11193        &mut self,
11194        _: &ConvertToLowerCamelCase,
11195        window: &mut Window,
11196        cx: &mut Context<Self>,
11197    ) {
11198        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11199    }
11200
11201    pub fn convert_to_opposite_case(
11202        &mut self,
11203        _: &ConvertToOppositeCase,
11204        window: &mut Window,
11205        cx: &mut Context<Self>,
11206    ) {
11207        self.manipulate_text(window, cx, |text| {
11208            text.chars()
11209                .fold(String::with_capacity(text.len()), |mut t, c| {
11210                    if c.is_uppercase() {
11211                        t.extend(c.to_lowercase());
11212                    } else {
11213                        t.extend(c.to_uppercase());
11214                    }
11215                    t
11216                })
11217        })
11218    }
11219
11220    pub fn convert_to_sentence_case(
11221        &mut self,
11222        _: &ConvertToSentenceCase,
11223        window: &mut Window,
11224        cx: &mut Context<Self>,
11225    ) {
11226        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11227    }
11228
11229    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11230        self.manipulate_text(window, cx, |text| {
11231            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11232            if has_upper_case_characters {
11233                text.to_lowercase()
11234            } else {
11235                text.to_uppercase()
11236            }
11237        })
11238    }
11239
11240    pub fn convert_to_rot13(
11241        &mut self,
11242        _: &ConvertToRot13,
11243        window: &mut Window,
11244        cx: &mut Context<Self>,
11245    ) {
11246        self.manipulate_text(window, cx, |text| {
11247            text.chars()
11248                .map(|c| match c {
11249                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11250                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11251                    _ => c,
11252                })
11253                .collect()
11254        })
11255    }
11256
11257    pub fn convert_to_rot47(
11258        &mut self,
11259        _: &ConvertToRot47,
11260        window: &mut Window,
11261        cx: &mut Context<Self>,
11262    ) {
11263        self.manipulate_text(window, cx, |text| {
11264            text.chars()
11265                .map(|c| {
11266                    let code_point = c as u32;
11267                    if code_point >= 33 && code_point <= 126 {
11268                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11269                    }
11270                    c
11271                })
11272                .collect()
11273        })
11274    }
11275
11276    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11277    where
11278        Fn: FnMut(&str) -> String,
11279    {
11280        let buffer = self.buffer.read(cx).snapshot(cx);
11281
11282        let mut new_selections = Vec::new();
11283        let mut edits = Vec::new();
11284        let mut selection_adjustment = 0i32;
11285
11286        for selection in self.selections.all::<usize>(cx) {
11287            let selection_is_empty = selection.is_empty();
11288
11289            let (start, end) = if selection_is_empty {
11290                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11291                (word_range.start, word_range.end)
11292            } else {
11293                (selection.start, selection.end)
11294            };
11295
11296            let text = buffer.text_for_range(start..end).collect::<String>();
11297            let old_length = text.len() as i32;
11298            let text = callback(&text);
11299
11300            new_selections.push(Selection {
11301                start: (start as i32 - selection_adjustment) as usize,
11302                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11303                goal: SelectionGoal::None,
11304                ..selection
11305            });
11306
11307            selection_adjustment += old_length - text.len() as i32;
11308
11309            edits.push((start..end, text));
11310        }
11311
11312        self.transact(window, cx, |this, window, cx| {
11313            this.buffer.update(cx, |buffer, cx| {
11314                buffer.edit(edits, None, cx);
11315            });
11316
11317            this.change_selections(Default::default(), window, cx, |s| {
11318                s.select(new_selections);
11319            });
11320
11321            this.request_autoscroll(Autoscroll::fit(), cx);
11322        });
11323    }
11324
11325    pub fn move_selection_on_drop(
11326        &mut self,
11327        selection: &Selection<Anchor>,
11328        target: DisplayPoint,
11329        is_cut: bool,
11330        window: &mut Window,
11331        cx: &mut Context<Self>,
11332    ) {
11333        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11334        let buffer = &display_map.buffer_snapshot;
11335        let mut edits = Vec::new();
11336        let insert_point = display_map
11337            .clip_point(target, Bias::Left)
11338            .to_point(&display_map);
11339        let text = buffer
11340            .text_for_range(selection.start..selection.end)
11341            .collect::<String>();
11342        if is_cut {
11343            edits.push(((selection.start..selection.end), String::new()));
11344        }
11345        let insert_anchor = buffer.anchor_before(insert_point);
11346        edits.push(((insert_anchor..insert_anchor), text));
11347        let last_edit_start = insert_anchor.bias_left(buffer);
11348        let last_edit_end = insert_anchor.bias_right(buffer);
11349        self.transact(window, cx, |this, window, cx| {
11350            this.buffer.update(cx, |buffer, cx| {
11351                buffer.edit(edits, None, cx);
11352            });
11353            this.change_selections(Default::default(), window, cx, |s| {
11354                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11355            });
11356        });
11357    }
11358
11359    pub fn clear_selection_drag_state(&mut self) {
11360        self.selection_drag_state = SelectionDragState::None;
11361    }
11362
11363    pub fn duplicate(
11364        &mut self,
11365        upwards: bool,
11366        whole_lines: bool,
11367        window: &mut Window,
11368        cx: &mut Context<Self>,
11369    ) {
11370        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11371
11372        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11373        let buffer = &display_map.buffer_snapshot;
11374        let selections = self.selections.all::<Point>(cx);
11375
11376        let mut edits = Vec::new();
11377        let mut selections_iter = selections.iter().peekable();
11378        while let Some(selection) = selections_iter.next() {
11379            let mut rows = selection.spanned_rows(false, &display_map);
11380            // duplicate line-wise
11381            if whole_lines || selection.start == selection.end {
11382                // Avoid duplicating the same lines twice.
11383                while let Some(next_selection) = selections_iter.peek() {
11384                    let next_rows = next_selection.spanned_rows(false, &display_map);
11385                    if next_rows.start < rows.end {
11386                        rows.end = next_rows.end;
11387                        selections_iter.next().unwrap();
11388                    } else {
11389                        break;
11390                    }
11391                }
11392
11393                // Copy the text from the selected row region and splice it either at the start
11394                // or end of the region.
11395                let start = Point::new(rows.start.0, 0);
11396                let end = Point::new(
11397                    rows.end.previous_row().0,
11398                    buffer.line_len(rows.end.previous_row()),
11399                );
11400                let text = buffer
11401                    .text_for_range(start..end)
11402                    .chain(Some("\n"))
11403                    .collect::<String>();
11404                let insert_location = if upwards {
11405                    Point::new(rows.end.0, 0)
11406                } else {
11407                    start
11408                };
11409                edits.push((insert_location..insert_location, text));
11410            } else {
11411                // duplicate character-wise
11412                let start = selection.start;
11413                let end = selection.end;
11414                let text = buffer.text_for_range(start..end).collect::<String>();
11415                edits.push((selection.end..selection.end, text));
11416            }
11417        }
11418
11419        self.transact(window, cx, |this, _, cx| {
11420            this.buffer.update(cx, |buffer, cx| {
11421                buffer.edit(edits, None, cx);
11422            });
11423
11424            this.request_autoscroll(Autoscroll::fit(), cx);
11425        });
11426    }
11427
11428    pub fn duplicate_line_up(
11429        &mut self,
11430        _: &DuplicateLineUp,
11431        window: &mut Window,
11432        cx: &mut Context<Self>,
11433    ) {
11434        self.duplicate(true, true, window, cx);
11435    }
11436
11437    pub fn duplicate_line_down(
11438        &mut self,
11439        _: &DuplicateLineDown,
11440        window: &mut Window,
11441        cx: &mut Context<Self>,
11442    ) {
11443        self.duplicate(false, true, window, cx);
11444    }
11445
11446    pub fn duplicate_selection(
11447        &mut self,
11448        _: &DuplicateSelection,
11449        window: &mut Window,
11450        cx: &mut Context<Self>,
11451    ) {
11452        self.duplicate(false, false, window, cx);
11453    }
11454
11455    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11456        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11457        if self.mode.is_single_line() {
11458            cx.propagate();
11459            return;
11460        }
11461
11462        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11463        let buffer = self.buffer.read(cx).snapshot(cx);
11464
11465        let mut edits = Vec::new();
11466        let mut unfold_ranges = Vec::new();
11467        let mut refold_creases = Vec::new();
11468
11469        let selections = self.selections.all::<Point>(cx);
11470        let mut selections = selections.iter().peekable();
11471        let mut contiguous_row_selections = Vec::new();
11472        let mut new_selections = Vec::new();
11473
11474        while let Some(selection) = selections.next() {
11475            // Find all the selections that span a contiguous row range
11476            let (start_row, end_row) = consume_contiguous_rows(
11477                &mut contiguous_row_selections,
11478                selection,
11479                &display_map,
11480                &mut selections,
11481            );
11482
11483            // Move the text spanned by the row range to be before the line preceding the row range
11484            if start_row.0 > 0 {
11485                let range_to_move = Point::new(
11486                    start_row.previous_row().0,
11487                    buffer.line_len(start_row.previous_row()),
11488                )
11489                    ..Point::new(
11490                        end_row.previous_row().0,
11491                        buffer.line_len(end_row.previous_row()),
11492                    );
11493                let insertion_point = display_map
11494                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11495                    .0;
11496
11497                // Don't move lines across excerpts
11498                if buffer
11499                    .excerpt_containing(insertion_point..range_to_move.end)
11500                    .is_some()
11501                {
11502                    let text = buffer
11503                        .text_for_range(range_to_move.clone())
11504                        .flat_map(|s| s.chars())
11505                        .skip(1)
11506                        .chain(['\n'])
11507                        .collect::<String>();
11508
11509                    edits.push((
11510                        buffer.anchor_after(range_to_move.start)
11511                            ..buffer.anchor_before(range_to_move.end),
11512                        String::new(),
11513                    ));
11514                    let insertion_anchor = buffer.anchor_after(insertion_point);
11515                    edits.push((insertion_anchor..insertion_anchor, text));
11516
11517                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11518
11519                    // Move selections up
11520                    new_selections.extend(contiguous_row_selections.drain(..).map(
11521                        |mut selection| {
11522                            selection.start.row -= row_delta;
11523                            selection.end.row -= row_delta;
11524                            selection
11525                        },
11526                    ));
11527
11528                    // Move folds up
11529                    unfold_ranges.push(range_to_move.clone());
11530                    for fold in display_map.folds_in_range(
11531                        buffer.anchor_before(range_to_move.start)
11532                            ..buffer.anchor_after(range_to_move.end),
11533                    ) {
11534                        let mut start = fold.range.start.to_point(&buffer);
11535                        let mut end = fold.range.end.to_point(&buffer);
11536                        start.row -= row_delta;
11537                        end.row -= row_delta;
11538                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11539                    }
11540                }
11541            }
11542
11543            // If we didn't move line(s), preserve the existing selections
11544            new_selections.append(&mut contiguous_row_selections);
11545        }
11546
11547        self.transact(window, cx, |this, window, cx| {
11548            this.unfold_ranges(&unfold_ranges, true, true, cx);
11549            this.buffer.update(cx, |buffer, cx| {
11550                for (range, text) in edits {
11551                    buffer.edit([(range, text)], None, cx);
11552                }
11553            });
11554            this.fold_creases(refold_creases, true, window, cx);
11555            this.change_selections(Default::default(), window, cx, |s| {
11556                s.select(new_selections);
11557            })
11558        });
11559    }
11560
11561    pub fn move_line_down(
11562        &mut self,
11563        _: &MoveLineDown,
11564        window: &mut Window,
11565        cx: &mut Context<Self>,
11566    ) {
11567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11568        if self.mode.is_single_line() {
11569            cx.propagate();
11570            return;
11571        }
11572
11573        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11574        let buffer = self.buffer.read(cx).snapshot(cx);
11575
11576        let mut edits = Vec::new();
11577        let mut unfold_ranges = Vec::new();
11578        let mut refold_creases = Vec::new();
11579
11580        let selections = self.selections.all::<Point>(cx);
11581        let mut selections = selections.iter().peekable();
11582        let mut contiguous_row_selections = Vec::new();
11583        let mut new_selections = Vec::new();
11584
11585        while let Some(selection) = selections.next() {
11586            // Find all the selections that span a contiguous row range
11587            let (start_row, end_row) = consume_contiguous_rows(
11588                &mut contiguous_row_selections,
11589                selection,
11590                &display_map,
11591                &mut selections,
11592            );
11593
11594            // Move the text spanned by the row range to be after the last line of the row range
11595            if end_row.0 <= buffer.max_point().row {
11596                let range_to_move =
11597                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11598                let insertion_point = display_map
11599                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11600                    .0;
11601
11602                // Don't move lines across excerpt boundaries
11603                if buffer
11604                    .excerpt_containing(range_to_move.start..insertion_point)
11605                    .is_some()
11606                {
11607                    let mut text = String::from("\n");
11608                    text.extend(buffer.text_for_range(range_to_move.clone()));
11609                    text.pop(); // Drop trailing newline
11610                    edits.push((
11611                        buffer.anchor_after(range_to_move.start)
11612                            ..buffer.anchor_before(range_to_move.end),
11613                        String::new(),
11614                    ));
11615                    let insertion_anchor = buffer.anchor_after(insertion_point);
11616                    edits.push((insertion_anchor..insertion_anchor, text));
11617
11618                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11619
11620                    // Move selections down
11621                    new_selections.extend(contiguous_row_selections.drain(..).map(
11622                        |mut selection| {
11623                            selection.start.row += row_delta;
11624                            selection.end.row += row_delta;
11625                            selection
11626                        },
11627                    ));
11628
11629                    // Move folds down
11630                    unfold_ranges.push(range_to_move.clone());
11631                    for fold in display_map.folds_in_range(
11632                        buffer.anchor_before(range_to_move.start)
11633                            ..buffer.anchor_after(range_to_move.end),
11634                    ) {
11635                        let mut start = fold.range.start.to_point(&buffer);
11636                        let mut end = fold.range.end.to_point(&buffer);
11637                        start.row += row_delta;
11638                        end.row += row_delta;
11639                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11640                    }
11641                }
11642            }
11643
11644            // If we didn't move line(s), preserve the existing selections
11645            new_selections.append(&mut contiguous_row_selections);
11646        }
11647
11648        self.transact(window, cx, |this, window, cx| {
11649            this.unfold_ranges(&unfold_ranges, true, true, cx);
11650            this.buffer.update(cx, |buffer, cx| {
11651                for (range, text) in edits {
11652                    buffer.edit([(range, text)], None, cx);
11653                }
11654            });
11655            this.fold_creases(refold_creases, true, window, cx);
11656            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11657        });
11658    }
11659
11660    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11661        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11662        let text_layout_details = &self.text_layout_details(window);
11663        self.transact(window, cx, |this, window, cx| {
11664            let edits = this.change_selections(Default::default(), window, cx, |s| {
11665                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11666                s.move_with(|display_map, selection| {
11667                    if !selection.is_empty() {
11668                        return;
11669                    }
11670
11671                    let mut head = selection.head();
11672                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11673                    if head.column() == display_map.line_len(head.row()) {
11674                        transpose_offset = display_map
11675                            .buffer_snapshot
11676                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11677                    }
11678
11679                    if transpose_offset == 0 {
11680                        return;
11681                    }
11682
11683                    *head.column_mut() += 1;
11684                    head = display_map.clip_point(head, Bias::Right);
11685                    let goal = SelectionGoal::HorizontalPosition(
11686                        display_map
11687                            .x_for_display_point(head, text_layout_details)
11688                            .into(),
11689                    );
11690                    selection.collapse_to(head, goal);
11691
11692                    let transpose_start = display_map
11693                        .buffer_snapshot
11694                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11695                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11696                        let transpose_end = display_map
11697                            .buffer_snapshot
11698                            .clip_offset(transpose_offset + 1, Bias::Right);
11699                        if let Some(ch) =
11700                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11701                        {
11702                            edits.push((transpose_start..transpose_offset, String::new()));
11703                            edits.push((transpose_end..transpose_end, ch.to_string()));
11704                        }
11705                    }
11706                });
11707                edits
11708            });
11709            this.buffer
11710                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11711            let selections = this.selections.all::<usize>(cx);
11712            this.change_selections(Default::default(), window, cx, |s| {
11713                s.select(selections);
11714            });
11715        });
11716    }
11717
11718    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11719        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11720        if self.mode.is_single_line() {
11721            cx.propagate();
11722            return;
11723        }
11724
11725        self.rewrap_impl(RewrapOptions::default(), cx)
11726    }
11727
11728    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11729        let buffer = self.buffer.read(cx).snapshot(cx);
11730        let selections = self.selections.all::<Point>(cx);
11731
11732        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11733        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11734            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11735                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11736                .peekable();
11737
11738            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11739                row
11740            } else {
11741                return Vec::new();
11742            };
11743
11744            let language_settings = buffer.language_settings_at(selection.head(), cx);
11745            let language_scope = buffer.language_scope_at(selection.head());
11746
11747            let indent_and_prefix_for_row =
11748                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11749                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11750                    let (comment_prefix, rewrap_prefix) =
11751                        if let Some(language_scope) = &language_scope {
11752                            let indent_end = Point::new(row, indent.len);
11753                            let comment_prefix = language_scope
11754                                .line_comment_prefixes()
11755                                .iter()
11756                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11757                                .map(|prefix| prefix.to_string());
11758                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11759                            let line_text_after_indent = buffer
11760                                .text_for_range(indent_end..line_end)
11761                                .collect::<String>();
11762                            let rewrap_prefix = language_scope
11763                                .rewrap_prefixes()
11764                                .iter()
11765                                .find_map(|prefix_regex| {
11766                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11767                                        if mat.start() == 0 {
11768                                            Some(mat.as_str().to_string())
11769                                        } else {
11770                                            None
11771                                        }
11772                                    })
11773                                })
11774                                .flatten();
11775                            (comment_prefix, rewrap_prefix)
11776                        } else {
11777                            (None, None)
11778                        };
11779                    (indent, comment_prefix, rewrap_prefix)
11780                };
11781
11782            let mut ranges = Vec::new();
11783            let from_empty_selection = selection.is_empty();
11784
11785            let mut current_range_start = first_row;
11786            let mut prev_row = first_row;
11787            let (
11788                mut current_range_indent,
11789                mut current_range_comment_prefix,
11790                mut current_range_rewrap_prefix,
11791            ) = indent_and_prefix_for_row(first_row);
11792
11793            for row in non_blank_rows_iter.skip(1) {
11794                let has_paragraph_break = row > prev_row + 1;
11795
11796                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11797                    indent_and_prefix_for_row(row);
11798
11799                let has_indent_change = row_indent != current_range_indent;
11800                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11801
11802                let has_boundary_change = has_comment_change
11803                    || row_rewrap_prefix.is_some()
11804                    || (has_indent_change && current_range_comment_prefix.is_some());
11805
11806                if has_paragraph_break || has_boundary_change {
11807                    ranges.push((
11808                        language_settings.clone(),
11809                        Point::new(current_range_start, 0)
11810                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11811                        current_range_indent,
11812                        current_range_comment_prefix.clone(),
11813                        current_range_rewrap_prefix.clone(),
11814                        from_empty_selection,
11815                    ));
11816                    current_range_start = row;
11817                    current_range_indent = row_indent;
11818                    current_range_comment_prefix = row_comment_prefix;
11819                    current_range_rewrap_prefix = row_rewrap_prefix;
11820                }
11821                prev_row = row;
11822            }
11823
11824            ranges.push((
11825                language_settings.clone(),
11826                Point::new(current_range_start, 0)
11827                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11828                current_range_indent,
11829                current_range_comment_prefix,
11830                current_range_rewrap_prefix,
11831                from_empty_selection,
11832            ));
11833
11834            ranges
11835        });
11836
11837        let mut edits = Vec::new();
11838        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11839
11840        for (
11841            language_settings,
11842            wrap_range,
11843            indent_size,
11844            comment_prefix,
11845            rewrap_prefix,
11846            from_empty_selection,
11847        ) in wrap_ranges
11848        {
11849            let mut start_row = wrap_range.start.row;
11850            let mut end_row = wrap_range.end.row;
11851
11852            // Skip selections that overlap with a range that has already been rewrapped.
11853            let selection_range = start_row..end_row;
11854            if rewrapped_row_ranges
11855                .iter()
11856                .any(|range| range.overlaps(&selection_range))
11857            {
11858                continue;
11859            }
11860
11861            let tab_size = language_settings.tab_size;
11862
11863            let indent_prefix = indent_size.chars().collect::<String>();
11864            let mut line_prefix = indent_prefix.clone();
11865            let mut inside_comment = false;
11866            if let Some(prefix) = &comment_prefix {
11867                line_prefix.push_str(prefix);
11868                inside_comment = true;
11869            }
11870            if let Some(prefix) = &rewrap_prefix {
11871                line_prefix.push_str(prefix);
11872            }
11873
11874            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11875                RewrapBehavior::InComments => inside_comment,
11876                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11877                RewrapBehavior::Anywhere => true,
11878            };
11879
11880            let should_rewrap = options.override_language_settings
11881                || allow_rewrap_based_on_language
11882                || self.hard_wrap.is_some();
11883            if !should_rewrap {
11884                continue;
11885            }
11886
11887            if from_empty_selection {
11888                'expand_upwards: while start_row > 0 {
11889                    let prev_row = start_row - 1;
11890                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11891                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11892                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11893                    {
11894                        start_row = prev_row;
11895                    } else {
11896                        break 'expand_upwards;
11897                    }
11898                }
11899
11900                'expand_downwards: while end_row < buffer.max_point().row {
11901                    let next_row = end_row + 1;
11902                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11903                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11904                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11905                    {
11906                        end_row = next_row;
11907                    } else {
11908                        break 'expand_downwards;
11909                    }
11910                }
11911            }
11912
11913            let start = Point::new(start_row, 0);
11914            let start_offset = start.to_offset(&buffer);
11915            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11916            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11917            let Some(lines_without_prefixes) = selection_text
11918                .lines()
11919                .enumerate()
11920                .map(|(ix, line)| {
11921                    let line_trimmed = line.trim_start();
11922                    if rewrap_prefix.is_some() && ix > 0 {
11923                        Ok(line_trimmed)
11924                    } else {
11925                        line_trimmed
11926                            .strip_prefix(&line_prefix.trim_start())
11927                            .with_context(|| {
11928                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11929                            })
11930                    }
11931                })
11932                .collect::<Result<Vec<_>, _>>()
11933                .log_err()
11934            else {
11935                continue;
11936            };
11937
11938            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11939                buffer
11940                    .language_settings_at(Point::new(start_row, 0), cx)
11941                    .preferred_line_length as usize
11942            });
11943
11944            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11945                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11946            } else {
11947                line_prefix.clone()
11948            };
11949
11950            let wrapped_text = wrap_with_prefix(
11951                line_prefix,
11952                subsequent_lines_prefix,
11953                lines_without_prefixes.join("\n"),
11954                wrap_column,
11955                tab_size,
11956                options.preserve_existing_whitespace,
11957            );
11958
11959            // TODO: should always use char-based diff while still supporting cursor behavior that
11960            // matches vim.
11961            let mut diff_options = DiffOptions::default();
11962            if options.override_language_settings {
11963                diff_options.max_word_diff_len = 0;
11964                diff_options.max_word_diff_line_count = 0;
11965            } else {
11966                diff_options.max_word_diff_len = usize::MAX;
11967                diff_options.max_word_diff_line_count = usize::MAX;
11968            }
11969
11970            for (old_range, new_text) in
11971                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11972            {
11973                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11974                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11975                edits.push((edit_start..edit_end, new_text));
11976            }
11977
11978            rewrapped_row_ranges.push(start_row..=end_row);
11979        }
11980
11981        self.buffer
11982            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11983    }
11984
11985    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11986        let mut text = String::new();
11987        let buffer = self.buffer.read(cx).snapshot(cx);
11988        let mut selections = self.selections.all::<Point>(cx);
11989        let mut clipboard_selections = Vec::with_capacity(selections.len());
11990        {
11991            let max_point = buffer.max_point();
11992            let mut is_first = true;
11993            for selection in &mut selections {
11994                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11995                if is_entire_line {
11996                    selection.start = Point::new(selection.start.row, 0);
11997                    if !selection.is_empty() && selection.end.column == 0 {
11998                        selection.end = cmp::min(max_point, selection.end);
11999                    } else {
12000                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12001                    }
12002                    selection.goal = SelectionGoal::None;
12003                }
12004                if is_first {
12005                    is_first = false;
12006                } else {
12007                    text += "\n";
12008                }
12009                let mut len = 0;
12010                for chunk in buffer.text_for_range(selection.start..selection.end) {
12011                    text.push_str(chunk);
12012                    len += chunk.len();
12013                }
12014                clipboard_selections.push(ClipboardSelection {
12015                    len,
12016                    is_entire_line,
12017                    first_line_indent: buffer
12018                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12019                        .len,
12020                });
12021            }
12022        }
12023
12024        self.transact(window, cx, |this, window, cx| {
12025            this.change_selections(Default::default(), window, cx, |s| {
12026                s.select(selections);
12027            });
12028            this.insert("", window, cx);
12029        });
12030        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12031    }
12032
12033    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12034        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12035        let item = self.cut_common(window, cx);
12036        cx.write_to_clipboard(item);
12037    }
12038
12039    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12040        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12041        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12042            s.move_with(|snapshot, sel| {
12043                if sel.is_empty() {
12044                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12045                }
12046            });
12047        });
12048        let item = self.cut_common(window, cx);
12049        cx.set_global(KillRing(item))
12050    }
12051
12052    pub fn kill_ring_yank(
12053        &mut self,
12054        _: &KillRingYank,
12055        window: &mut Window,
12056        cx: &mut Context<Self>,
12057    ) {
12058        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12059        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12060            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12061                (kill_ring.text().to_string(), kill_ring.metadata_json())
12062            } else {
12063                return;
12064            }
12065        } else {
12066            return;
12067        };
12068        self.do_paste(&text, metadata, false, window, cx);
12069    }
12070
12071    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12072        self.do_copy(true, cx);
12073    }
12074
12075    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12076        self.do_copy(false, cx);
12077    }
12078
12079    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12080        let selections = self.selections.all::<Point>(cx);
12081        let buffer = self.buffer.read(cx).read(cx);
12082        let mut text = String::new();
12083
12084        let mut clipboard_selections = Vec::with_capacity(selections.len());
12085        {
12086            let max_point = buffer.max_point();
12087            let mut is_first = true;
12088            for selection in &selections {
12089                let mut start = selection.start;
12090                let mut end = selection.end;
12091                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12092                if is_entire_line {
12093                    start = Point::new(start.row, 0);
12094                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12095                }
12096
12097                let mut trimmed_selections = Vec::new();
12098                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12099                    let row = MultiBufferRow(start.row);
12100                    let first_indent = buffer.indent_size_for_line(row);
12101                    if first_indent.len == 0 || start.column > first_indent.len {
12102                        trimmed_selections.push(start..end);
12103                    } else {
12104                        trimmed_selections.push(
12105                            Point::new(row.0, first_indent.len)
12106                                ..Point::new(row.0, buffer.line_len(row)),
12107                        );
12108                        for row in start.row + 1..=end.row {
12109                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12110                            if row == end.row {
12111                                line_len = end.column;
12112                            }
12113                            if line_len == 0 {
12114                                trimmed_selections
12115                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12116                                continue;
12117                            }
12118                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12119                            if row_indent_size.len >= first_indent.len {
12120                                trimmed_selections.push(
12121                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12122                                );
12123                            } else {
12124                                trimmed_selections.clear();
12125                                trimmed_selections.push(start..end);
12126                                break;
12127                            }
12128                        }
12129                    }
12130                } else {
12131                    trimmed_selections.push(start..end);
12132                }
12133
12134                for trimmed_range in trimmed_selections {
12135                    if is_first {
12136                        is_first = false;
12137                    } else {
12138                        text += "\n";
12139                    }
12140                    let mut len = 0;
12141                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12142                        text.push_str(chunk);
12143                        len += chunk.len();
12144                    }
12145                    clipboard_selections.push(ClipboardSelection {
12146                        len,
12147                        is_entire_line,
12148                        first_line_indent: buffer
12149                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12150                            .len,
12151                    });
12152                }
12153            }
12154        }
12155
12156        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12157            text,
12158            clipboard_selections,
12159        ));
12160    }
12161
12162    pub fn do_paste(
12163        &mut self,
12164        text: &String,
12165        clipboard_selections: Option<Vec<ClipboardSelection>>,
12166        handle_entire_lines: bool,
12167        window: &mut Window,
12168        cx: &mut Context<Self>,
12169    ) {
12170        if self.read_only(cx) {
12171            return;
12172        }
12173
12174        let clipboard_text = Cow::Borrowed(text);
12175
12176        self.transact(window, cx, |this, window, cx| {
12177            let had_active_edit_prediction = this.has_active_edit_prediction();
12178
12179            if let Some(mut clipboard_selections) = clipboard_selections {
12180                let old_selections = this.selections.all::<usize>(cx);
12181                let all_selections_were_entire_line =
12182                    clipboard_selections.iter().all(|s| s.is_entire_line);
12183                let first_selection_indent_column =
12184                    clipboard_selections.first().map(|s| s.first_line_indent);
12185                if clipboard_selections.len() != old_selections.len() {
12186                    clipboard_selections.drain(..);
12187                }
12188                let cursor_offset = this.selections.last::<usize>(cx).head();
12189                let mut auto_indent_on_paste = true;
12190
12191                this.buffer.update(cx, |buffer, cx| {
12192                    let snapshot = buffer.read(cx);
12193                    auto_indent_on_paste = snapshot
12194                        .language_settings_at(cursor_offset, cx)
12195                        .auto_indent_on_paste;
12196
12197                    let mut start_offset = 0;
12198                    let mut edits = Vec::new();
12199                    let mut original_indent_columns = Vec::new();
12200                    for (ix, selection) in old_selections.iter().enumerate() {
12201                        let to_insert;
12202                        let entire_line;
12203                        let original_indent_column;
12204                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12205                            let end_offset = start_offset + clipboard_selection.len;
12206                            to_insert = &clipboard_text[start_offset..end_offset];
12207                            entire_line = clipboard_selection.is_entire_line;
12208                            start_offset = end_offset + 1;
12209                            original_indent_column = Some(clipboard_selection.first_line_indent);
12210                        } else {
12211                            to_insert = clipboard_text.as_str();
12212                            entire_line = all_selections_were_entire_line;
12213                            original_indent_column = first_selection_indent_column
12214                        }
12215
12216                        // If the corresponding selection was empty when this slice of the
12217                        // clipboard text was written, then the entire line containing the
12218                        // selection was copied. If this selection is also currently empty,
12219                        // then paste the line before the current line of the buffer.
12220                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12221                            let column = selection.start.to_point(&snapshot).column as usize;
12222                            let line_start = selection.start - column;
12223                            line_start..line_start
12224                        } else {
12225                            selection.range()
12226                        };
12227
12228                        edits.push((range, to_insert));
12229                        original_indent_columns.push(original_indent_column);
12230                    }
12231                    drop(snapshot);
12232
12233                    buffer.edit(
12234                        edits,
12235                        if auto_indent_on_paste {
12236                            Some(AutoindentMode::Block {
12237                                original_indent_columns,
12238                            })
12239                        } else {
12240                            None
12241                        },
12242                        cx,
12243                    );
12244                });
12245
12246                let selections = this.selections.all::<usize>(cx);
12247                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12248            } else {
12249                this.insert(&clipboard_text, window, cx);
12250            }
12251
12252            let trigger_in_words =
12253                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12254
12255            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12256        });
12257    }
12258
12259    pub fn diff_clipboard_with_selection(
12260        &mut self,
12261        _: &DiffClipboardWithSelection,
12262        window: &mut Window,
12263        cx: &mut Context<Self>,
12264    ) {
12265        let selections = self.selections.all::<usize>(cx);
12266
12267        if selections.is_empty() {
12268            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12269            return;
12270        };
12271
12272        let clipboard_text = match cx.read_from_clipboard() {
12273            Some(item) => match item.entries().first() {
12274                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12275                _ => None,
12276            },
12277            None => None,
12278        };
12279
12280        let Some(clipboard_text) = clipboard_text else {
12281            log::warn!("Clipboard doesn't contain text.");
12282            return;
12283        };
12284
12285        window.dispatch_action(
12286            Box::new(DiffClipboardWithSelectionData {
12287                clipboard_text,
12288                editor: cx.entity(),
12289            }),
12290            cx,
12291        );
12292    }
12293
12294    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12295        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12296        if let Some(item) = cx.read_from_clipboard() {
12297            let entries = item.entries();
12298
12299            match entries.first() {
12300                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12301                // of all the pasted entries.
12302                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12303                    .do_paste(
12304                        clipboard_string.text(),
12305                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12306                        true,
12307                        window,
12308                        cx,
12309                    ),
12310                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12311            }
12312        }
12313    }
12314
12315    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12316        if self.read_only(cx) {
12317            return;
12318        }
12319
12320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12321
12322        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12323            if let Some((selections, _)) =
12324                self.selection_history.transaction(transaction_id).cloned()
12325            {
12326                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12327                    s.select_anchors(selections.to_vec());
12328                });
12329            } else {
12330                log::error!(
12331                    "No entry in selection_history found for undo. \
12332                     This may correspond to a bug where undo does not update the selection. \
12333                     If this is occurring, please add details to \
12334                     https://github.com/zed-industries/zed/issues/22692"
12335                );
12336            }
12337            self.request_autoscroll(Autoscroll::fit(), cx);
12338            self.unmark_text(window, cx);
12339            self.refresh_edit_prediction(true, false, window, cx);
12340            cx.emit(EditorEvent::Edited { transaction_id });
12341            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12342        }
12343    }
12344
12345    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12346        if self.read_only(cx) {
12347            return;
12348        }
12349
12350        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12351
12352        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12353            if let Some((_, Some(selections))) =
12354                self.selection_history.transaction(transaction_id).cloned()
12355            {
12356                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12357                    s.select_anchors(selections.to_vec());
12358                });
12359            } else {
12360                log::error!(
12361                    "No entry in selection_history found for redo. \
12362                     This may correspond to a bug where undo does not update the selection. \
12363                     If this is occurring, please add details to \
12364                     https://github.com/zed-industries/zed/issues/22692"
12365                );
12366            }
12367            self.request_autoscroll(Autoscroll::fit(), cx);
12368            self.unmark_text(window, cx);
12369            self.refresh_edit_prediction(true, false, window, cx);
12370            cx.emit(EditorEvent::Edited { transaction_id });
12371        }
12372    }
12373
12374    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12375        self.buffer
12376            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12377    }
12378
12379    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12380        self.buffer
12381            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12382    }
12383
12384    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12385        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12386        self.change_selections(Default::default(), window, cx, |s| {
12387            s.move_with(|map, selection| {
12388                let cursor = if selection.is_empty() {
12389                    movement::left(map, selection.start)
12390                } else {
12391                    selection.start
12392                };
12393                selection.collapse_to(cursor, SelectionGoal::None);
12394            });
12395        })
12396    }
12397
12398    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12400        self.change_selections(Default::default(), window, cx, |s| {
12401            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12402        })
12403    }
12404
12405    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12406        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12407        self.change_selections(Default::default(), window, cx, |s| {
12408            s.move_with(|map, selection| {
12409                let cursor = if selection.is_empty() {
12410                    movement::right(map, selection.end)
12411                } else {
12412                    selection.end
12413                };
12414                selection.collapse_to(cursor, SelectionGoal::None)
12415            });
12416        })
12417    }
12418
12419    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12420        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12421        self.change_selections(Default::default(), window, cx, |s| {
12422            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12423        })
12424    }
12425
12426    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12427        if self.take_rename(true, window, cx).is_some() {
12428            return;
12429        }
12430
12431        if self.mode.is_single_line() {
12432            cx.propagate();
12433            return;
12434        }
12435
12436        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12437
12438        let text_layout_details = &self.text_layout_details(window);
12439        let selection_count = self.selections.count();
12440        let first_selection = self.selections.first_anchor();
12441
12442        self.change_selections(Default::default(), window, cx, |s| {
12443            s.move_with(|map, selection| {
12444                if !selection.is_empty() {
12445                    selection.goal = SelectionGoal::None;
12446                }
12447                let (cursor, goal) = movement::up(
12448                    map,
12449                    selection.start,
12450                    selection.goal,
12451                    false,
12452                    text_layout_details,
12453                );
12454                selection.collapse_to(cursor, goal);
12455            });
12456        });
12457
12458        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12459        {
12460            cx.propagate();
12461        }
12462    }
12463
12464    pub fn move_up_by_lines(
12465        &mut self,
12466        action: &MoveUpByLines,
12467        window: &mut Window,
12468        cx: &mut Context<Self>,
12469    ) {
12470        if self.take_rename(true, window, cx).is_some() {
12471            return;
12472        }
12473
12474        if self.mode.is_single_line() {
12475            cx.propagate();
12476            return;
12477        }
12478
12479        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12480
12481        let text_layout_details = &self.text_layout_details(window);
12482
12483        self.change_selections(Default::default(), window, cx, |s| {
12484            s.move_with(|map, selection| {
12485                if !selection.is_empty() {
12486                    selection.goal = SelectionGoal::None;
12487                }
12488                let (cursor, goal) = movement::up_by_rows(
12489                    map,
12490                    selection.start,
12491                    action.lines,
12492                    selection.goal,
12493                    false,
12494                    text_layout_details,
12495                );
12496                selection.collapse_to(cursor, goal);
12497            });
12498        })
12499    }
12500
12501    pub fn move_down_by_lines(
12502        &mut self,
12503        action: &MoveDownByLines,
12504        window: &mut Window,
12505        cx: &mut Context<Self>,
12506    ) {
12507        if self.take_rename(true, window, cx).is_some() {
12508            return;
12509        }
12510
12511        if self.mode.is_single_line() {
12512            cx.propagate();
12513            return;
12514        }
12515
12516        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12517
12518        let text_layout_details = &self.text_layout_details(window);
12519
12520        self.change_selections(Default::default(), window, cx, |s| {
12521            s.move_with(|map, selection| {
12522                if !selection.is_empty() {
12523                    selection.goal = SelectionGoal::None;
12524                }
12525                let (cursor, goal) = movement::down_by_rows(
12526                    map,
12527                    selection.start,
12528                    action.lines,
12529                    selection.goal,
12530                    false,
12531                    text_layout_details,
12532                );
12533                selection.collapse_to(cursor, goal);
12534            });
12535        })
12536    }
12537
12538    pub fn select_down_by_lines(
12539        &mut self,
12540        action: &SelectDownByLines,
12541        window: &mut Window,
12542        cx: &mut Context<Self>,
12543    ) {
12544        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12545        let text_layout_details = &self.text_layout_details(window);
12546        self.change_selections(Default::default(), window, cx, |s| {
12547            s.move_heads_with(|map, head, goal| {
12548                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12549            })
12550        })
12551    }
12552
12553    pub fn select_up_by_lines(
12554        &mut self,
12555        action: &SelectUpByLines,
12556        window: &mut Window,
12557        cx: &mut Context<Self>,
12558    ) {
12559        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12560        let text_layout_details = &self.text_layout_details(window);
12561        self.change_selections(Default::default(), window, cx, |s| {
12562            s.move_heads_with(|map, head, goal| {
12563                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12564            })
12565        })
12566    }
12567
12568    pub fn select_page_up(
12569        &mut self,
12570        _: &SelectPageUp,
12571        window: &mut Window,
12572        cx: &mut Context<Self>,
12573    ) {
12574        let Some(row_count) = self.visible_row_count() else {
12575            return;
12576        };
12577
12578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12579
12580        let text_layout_details = &self.text_layout_details(window);
12581
12582        self.change_selections(Default::default(), window, cx, |s| {
12583            s.move_heads_with(|map, head, goal| {
12584                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12585            })
12586        })
12587    }
12588
12589    pub fn move_page_up(
12590        &mut self,
12591        action: &MovePageUp,
12592        window: &mut Window,
12593        cx: &mut Context<Self>,
12594    ) {
12595        if self.take_rename(true, window, cx).is_some() {
12596            return;
12597        }
12598
12599        if self
12600            .context_menu
12601            .borrow_mut()
12602            .as_mut()
12603            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12604            .unwrap_or(false)
12605        {
12606            return;
12607        }
12608
12609        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12610            cx.propagate();
12611            return;
12612        }
12613
12614        let Some(row_count) = self.visible_row_count() else {
12615            return;
12616        };
12617
12618        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12619
12620        let effects = if action.center_cursor {
12621            SelectionEffects::scroll(Autoscroll::center())
12622        } else {
12623            SelectionEffects::default()
12624        };
12625
12626        let text_layout_details = &self.text_layout_details(window);
12627
12628        self.change_selections(effects, window, cx, |s| {
12629            s.move_with(|map, selection| {
12630                if !selection.is_empty() {
12631                    selection.goal = SelectionGoal::None;
12632                }
12633                let (cursor, goal) = movement::up_by_rows(
12634                    map,
12635                    selection.end,
12636                    row_count,
12637                    selection.goal,
12638                    false,
12639                    text_layout_details,
12640                );
12641                selection.collapse_to(cursor, goal);
12642            });
12643        });
12644    }
12645
12646    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12648        let text_layout_details = &self.text_layout_details(window);
12649        self.change_selections(Default::default(), window, cx, |s| {
12650            s.move_heads_with(|map, head, goal| {
12651                movement::up(map, head, goal, false, text_layout_details)
12652            })
12653        })
12654    }
12655
12656    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12657        self.take_rename(true, window, cx);
12658
12659        if self.mode.is_single_line() {
12660            cx.propagate();
12661            return;
12662        }
12663
12664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12665
12666        let text_layout_details = &self.text_layout_details(window);
12667        let selection_count = self.selections.count();
12668        let first_selection = self.selections.first_anchor();
12669
12670        self.change_selections(Default::default(), window, cx, |s| {
12671            s.move_with(|map, selection| {
12672                if !selection.is_empty() {
12673                    selection.goal = SelectionGoal::None;
12674                }
12675                let (cursor, goal) = movement::down(
12676                    map,
12677                    selection.end,
12678                    selection.goal,
12679                    false,
12680                    text_layout_details,
12681                );
12682                selection.collapse_to(cursor, goal);
12683            });
12684        });
12685
12686        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12687        {
12688            cx.propagate();
12689        }
12690    }
12691
12692    pub fn select_page_down(
12693        &mut self,
12694        _: &SelectPageDown,
12695        window: &mut Window,
12696        cx: &mut Context<Self>,
12697    ) {
12698        let Some(row_count) = self.visible_row_count() else {
12699            return;
12700        };
12701
12702        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12703
12704        let text_layout_details = &self.text_layout_details(window);
12705
12706        self.change_selections(Default::default(), window, cx, |s| {
12707            s.move_heads_with(|map, head, goal| {
12708                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12709            })
12710        })
12711    }
12712
12713    pub fn move_page_down(
12714        &mut self,
12715        action: &MovePageDown,
12716        window: &mut Window,
12717        cx: &mut Context<Self>,
12718    ) {
12719        if self.take_rename(true, window, cx).is_some() {
12720            return;
12721        }
12722
12723        if self
12724            .context_menu
12725            .borrow_mut()
12726            .as_mut()
12727            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12728            .unwrap_or(false)
12729        {
12730            return;
12731        }
12732
12733        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12734            cx.propagate();
12735            return;
12736        }
12737
12738        let Some(row_count) = self.visible_row_count() else {
12739            return;
12740        };
12741
12742        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12743
12744        let effects = if action.center_cursor {
12745            SelectionEffects::scroll(Autoscroll::center())
12746        } else {
12747            SelectionEffects::default()
12748        };
12749
12750        let text_layout_details = &self.text_layout_details(window);
12751        self.change_selections(effects, window, cx, |s| {
12752            s.move_with(|map, selection| {
12753                if !selection.is_empty() {
12754                    selection.goal = SelectionGoal::None;
12755                }
12756                let (cursor, goal) = movement::down_by_rows(
12757                    map,
12758                    selection.end,
12759                    row_count,
12760                    selection.goal,
12761                    false,
12762                    text_layout_details,
12763                );
12764                selection.collapse_to(cursor, goal);
12765            });
12766        });
12767    }
12768
12769    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12770        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12771        let text_layout_details = &self.text_layout_details(window);
12772        self.change_selections(Default::default(), window, cx, |s| {
12773            s.move_heads_with(|map, head, goal| {
12774                movement::down(map, head, goal, false, text_layout_details)
12775            })
12776        });
12777    }
12778
12779    pub fn context_menu_first(
12780        &mut self,
12781        _: &ContextMenuFirst,
12782        window: &mut Window,
12783        cx: &mut Context<Self>,
12784    ) {
12785        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12786            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12787        }
12788    }
12789
12790    pub fn context_menu_prev(
12791        &mut self,
12792        _: &ContextMenuPrevious,
12793        window: &mut Window,
12794        cx: &mut Context<Self>,
12795    ) {
12796        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12797            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12798        }
12799    }
12800
12801    pub fn context_menu_next(
12802        &mut self,
12803        _: &ContextMenuNext,
12804        window: &mut Window,
12805        cx: &mut Context<Self>,
12806    ) {
12807        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12808            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12809        }
12810    }
12811
12812    pub fn context_menu_last(
12813        &mut self,
12814        _: &ContextMenuLast,
12815        window: &mut Window,
12816        cx: &mut Context<Self>,
12817    ) {
12818        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12819            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12820        }
12821    }
12822
12823    pub fn signature_help_prev(
12824        &mut self,
12825        _: &SignatureHelpPrevious,
12826        _: &mut Window,
12827        cx: &mut Context<Self>,
12828    ) {
12829        if let Some(popover) = self.signature_help_state.popover_mut() {
12830            if popover.current_signature == 0 {
12831                popover.current_signature = popover.signatures.len() - 1;
12832            } else {
12833                popover.current_signature -= 1;
12834            }
12835            cx.notify();
12836        }
12837    }
12838
12839    pub fn signature_help_next(
12840        &mut self,
12841        _: &SignatureHelpNext,
12842        _: &mut Window,
12843        cx: &mut Context<Self>,
12844    ) {
12845        if let Some(popover) = self.signature_help_state.popover_mut() {
12846            if popover.current_signature + 1 == popover.signatures.len() {
12847                popover.current_signature = 0;
12848            } else {
12849                popover.current_signature += 1;
12850            }
12851            cx.notify();
12852        }
12853    }
12854
12855    pub fn move_to_previous_word_start(
12856        &mut self,
12857        _: &MoveToPreviousWordStart,
12858        window: &mut Window,
12859        cx: &mut Context<Self>,
12860    ) {
12861        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12862        self.change_selections(Default::default(), window, cx, |s| {
12863            s.move_cursors_with(|map, head, _| {
12864                (
12865                    movement::previous_word_start(map, head),
12866                    SelectionGoal::None,
12867                )
12868            });
12869        })
12870    }
12871
12872    pub fn move_to_previous_subword_start(
12873        &mut self,
12874        _: &MoveToPreviousSubwordStart,
12875        window: &mut Window,
12876        cx: &mut Context<Self>,
12877    ) {
12878        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12879        self.change_selections(Default::default(), window, cx, |s| {
12880            s.move_cursors_with(|map, head, _| {
12881                (
12882                    movement::previous_subword_start(map, head),
12883                    SelectionGoal::None,
12884                )
12885            });
12886        })
12887    }
12888
12889    pub fn select_to_previous_word_start(
12890        &mut self,
12891        _: &SelectToPreviousWordStart,
12892        window: &mut Window,
12893        cx: &mut Context<Self>,
12894    ) {
12895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12896        self.change_selections(Default::default(), window, cx, |s| {
12897            s.move_heads_with(|map, head, _| {
12898                (
12899                    movement::previous_word_start(map, head),
12900                    SelectionGoal::None,
12901                )
12902            });
12903        })
12904    }
12905
12906    pub fn select_to_previous_subword_start(
12907        &mut self,
12908        _: &SelectToPreviousSubwordStart,
12909        window: &mut Window,
12910        cx: &mut Context<Self>,
12911    ) {
12912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12913        self.change_selections(Default::default(), window, cx, |s| {
12914            s.move_heads_with(|map, head, _| {
12915                (
12916                    movement::previous_subword_start(map, head),
12917                    SelectionGoal::None,
12918                )
12919            });
12920        })
12921    }
12922
12923    pub fn delete_to_previous_word_start(
12924        &mut self,
12925        action: &DeleteToPreviousWordStart,
12926        window: &mut Window,
12927        cx: &mut Context<Self>,
12928    ) {
12929        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12930        self.transact(window, cx, |this, window, cx| {
12931            this.select_autoclose_pair(window, cx);
12932            this.change_selections(Default::default(), window, cx, |s| {
12933                s.move_with(|map, selection| {
12934                    if selection.is_empty() {
12935                        let cursor = if action.ignore_newlines {
12936                            movement::previous_word_start(map, selection.head())
12937                        } else {
12938                            movement::previous_word_start_or_newline(map, selection.head())
12939                        };
12940                        selection.set_head(cursor, SelectionGoal::None);
12941                    }
12942                });
12943            });
12944            this.insert("", window, cx);
12945        });
12946    }
12947
12948    pub fn delete_to_previous_subword_start(
12949        &mut self,
12950        _: &DeleteToPreviousSubwordStart,
12951        window: &mut Window,
12952        cx: &mut Context<Self>,
12953    ) {
12954        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12955        self.transact(window, cx, |this, window, cx| {
12956            this.select_autoclose_pair(window, cx);
12957            this.change_selections(Default::default(), window, cx, |s| {
12958                s.move_with(|map, selection| {
12959                    if selection.is_empty() {
12960                        let cursor = movement::previous_subword_start(map, selection.head());
12961                        selection.set_head(cursor, SelectionGoal::None);
12962                    }
12963                });
12964            });
12965            this.insert("", window, cx);
12966        });
12967    }
12968
12969    pub fn move_to_next_word_end(
12970        &mut self,
12971        _: &MoveToNextWordEnd,
12972        window: &mut Window,
12973        cx: &mut Context<Self>,
12974    ) {
12975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12976        self.change_selections(Default::default(), window, cx, |s| {
12977            s.move_cursors_with(|map, head, _| {
12978                (movement::next_word_end(map, head), SelectionGoal::None)
12979            });
12980        })
12981    }
12982
12983    pub fn move_to_next_subword_end(
12984        &mut self,
12985        _: &MoveToNextSubwordEnd,
12986        window: &mut Window,
12987        cx: &mut Context<Self>,
12988    ) {
12989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12990        self.change_selections(Default::default(), window, cx, |s| {
12991            s.move_cursors_with(|map, head, _| {
12992                (movement::next_subword_end(map, head), SelectionGoal::None)
12993            });
12994        })
12995    }
12996
12997    pub fn select_to_next_word_end(
12998        &mut self,
12999        _: &SelectToNextWordEnd,
13000        window: &mut Window,
13001        cx: &mut Context<Self>,
13002    ) {
13003        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13004        self.change_selections(Default::default(), window, cx, |s| {
13005            s.move_heads_with(|map, head, _| {
13006                (movement::next_word_end(map, head), SelectionGoal::None)
13007            });
13008        })
13009    }
13010
13011    pub fn select_to_next_subword_end(
13012        &mut self,
13013        _: &SelectToNextSubwordEnd,
13014        window: &mut Window,
13015        cx: &mut Context<Self>,
13016    ) {
13017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13018        self.change_selections(Default::default(), window, cx, |s| {
13019            s.move_heads_with(|map, head, _| {
13020                (movement::next_subword_end(map, head), SelectionGoal::None)
13021            });
13022        })
13023    }
13024
13025    pub fn delete_to_next_word_end(
13026        &mut self,
13027        action: &DeleteToNextWordEnd,
13028        window: &mut Window,
13029        cx: &mut Context<Self>,
13030    ) {
13031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13032        self.transact(window, cx, |this, window, cx| {
13033            this.change_selections(Default::default(), window, cx, |s| {
13034                s.move_with(|map, selection| {
13035                    if selection.is_empty() {
13036                        let cursor = if action.ignore_newlines {
13037                            movement::next_word_end(map, selection.head())
13038                        } else {
13039                            movement::next_word_end_or_newline(map, selection.head())
13040                        };
13041                        selection.set_head(cursor, SelectionGoal::None);
13042                    }
13043                });
13044            });
13045            this.insert("", window, cx);
13046        });
13047    }
13048
13049    pub fn delete_to_next_subword_end(
13050        &mut self,
13051        _: &DeleteToNextSubwordEnd,
13052        window: &mut Window,
13053        cx: &mut Context<Self>,
13054    ) {
13055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13056        self.transact(window, cx, |this, window, cx| {
13057            this.change_selections(Default::default(), window, cx, |s| {
13058                s.move_with(|map, selection| {
13059                    if selection.is_empty() {
13060                        let cursor = movement::next_subword_end(map, selection.head());
13061                        selection.set_head(cursor, SelectionGoal::None);
13062                    }
13063                });
13064            });
13065            this.insert("", window, cx);
13066        });
13067    }
13068
13069    pub fn move_to_beginning_of_line(
13070        &mut self,
13071        action: &MoveToBeginningOfLine,
13072        window: &mut Window,
13073        cx: &mut Context<Self>,
13074    ) {
13075        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13076        self.change_selections(Default::default(), window, cx, |s| {
13077            s.move_cursors_with(|map, head, _| {
13078                (
13079                    movement::indented_line_beginning(
13080                        map,
13081                        head,
13082                        action.stop_at_soft_wraps,
13083                        action.stop_at_indent,
13084                    ),
13085                    SelectionGoal::None,
13086                )
13087            });
13088        })
13089    }
13090
13091    pub fn select_to_beginning_of_line(
13092        &mut self,
13093        action: &SelectToBeginningOfLine,
13094        window: &mut Window,
13095        cx: &mut Context<Self>,
13096    ) {
13097        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13098        self.change_selections(Default::default(), window, cx, |s| {
13099            s.move_heads_with(|map, head, _| {
13100                (
13101                    movement::indented_line_beginning(
13102                        map,
13103                        head,
13104                        action.stop_at_soft_wraps,
13105                        action.stop_at_indent,
13106                    ),
13107                    SelectionGoal::None,
13108                )
13109            });
13110        });
13111    }
13112
13113    pub fn delete_to_beginning_of_line(
13114        &mut self,
13115        action: &DeleteToBeginningOfLine,
13116        window: &mut Window,
13117        cx: &mut Context<Self>,
13118    ) {
13119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13120        self.transact(window, cx, |this, window, cx| {
13121            this.change_selections(Default::default(), window, cx, |s| {
13122                s.move_with(|_, selection| {
13123                    selection.reversed = true;
13124                });
13125            });
13126
13127            this.select_to_beginning_of_line(
13128                &SelectToBeginningOfLine {
13129                    stop_at_soft_wraps: false,
13130                    stop_at_indent: action.stop_at_indent,
13131                },
13132                window,
13133                cx,
13134            );
13135            this.backspace(&Backspace, window, cx);
13136        });
13137    }
13138
13139    pub fn move_to_end_of_line(
13140        &mut self,
13141        action: &MoveToEndOfLine,
13142        window: &mut Window,
13143        cx: &mut Context<Self>,
13144    ) {
13145        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13146        self.change_selections(Default::default(), window, cx, |s| {
13147            s.move_cursors_with(|map, head, _| {
13148                (
13149                    movement::line_end(map, head, action.stop_at_soft_wraps),
13150                    SelectionGoal::None,
13151                )
13152            });
13153        })
13154    }
13155
13156    pub fn select_to_end_of_line(
13157        &mut self,
13158        action: &SelectToEndOfLine,
13159        window: &mut Window,
13160        cx: &mut Context<Self>,
13161    ) {
13162        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13163        self.change_selections(Default::default(), window, cx, |s| {
13164            s.move_heads_with(|map, head, _| {
13165                (
13166                    movement::line_end(map, head, action.stop_at_soft_wraps),
13167                    SelectionGoal::None,
13168                )
13169            });
13170        })
13171    }
13172
13173    pub fn delete_to_end_of_line(
13174        &mut self,
13175        _: &DeleteToEndOfLine,
13176        window: &mut Window,
13177        cx: &mut Context<Self>,
13178    ) {
13179        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13180        self.transact(window, cx, |this, window, cx| {
13181            this.select_to_end_of_line(
13182                &SelectToEndOfLine {
13183                    stop_at_soft_wraps: false,
13184                },
13185                window,
13186                cx,
13187            );
13188            this.delete(&Delete, window, cx);
13189        });
13190    }
13191
13192    pub fn cut_to_end_of_line(
13193        &mut self,
13194        _: &CutToEndOfLine,
13195        window: &mut Window,
13196        cx: &mut Context<Self>,
13197    ) {
13198        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13199        self.transact(window, cx, |this, window, cx| {
13200            this.select_to_end_of_line(
13201                &SelectToEndOfLine {
13202                    stop_at_soft_wraps: false,
13203                },
13204                window,
13205                cx,
13206            );
13207            this.cut(&Cut, window, cx);
13208        });
13209    }
13210
13211    pub fn move_to_start_of_paragraph(
13212        &mut self,
13213        _: &MoveToStartOfParagraph,
13214        window: &mut Window,
13215        cx: &mut Context<Self>,
13216    ) {
13217        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13218            cx.propagate();
13219            return;
13220        }
13221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13222        self.change_selections(Default::default(), window, cx, |s| {
13223            s.move_with(|map, selection| {
13224                selection.collapse_to(
13225                    movement::start_of_paragraph(map, selection.head(), 1),
13226                    SelectionGoal::None,
13227                )
13228            });
13229        })
13230    }
13231
13232    pub fn move_to_end_of_paragraph(
13233        &mut self,
13234        _: &MoveToEndOfParagraph,
13235        window: &mut Window,
13236        cx: &mut Context<Self>,
13237    ) {
13238        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13239            cx.propagate();
13240            return;
13241        }
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243        self.change_selections(Default::default(), window, cx, |s| {
13244            s.move_with(|map, selection| {
13245                selection.collapse_to(
13246                    movement::end_of_paragraph(map, selection.head(), 1),
13247                    SelectionGoal::None,
13248                )
13249            });
13250        })
13251    }
13252
13253    pub fn select_to_start_of_paragraph(
13254        &mut self,
13255        _: &SelectToStartOfParagraph,
13256        window: &mut Window,
13257        cx: &mut Context<Self>,
13258    ) {
13259        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13260            cx.propagate();
13261            return;
13262        }
13263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13264        self.change_selections(Default::default(), window, cx, |s| {
13265            s.move_heads_with(|map, head, _| {
13266                (
13267                    movement::start_of_paragraph(map, head, 1),
13268                    SelectionGoal::None,
13269                )
13270            });
13271        })
13272    }
13273
13274    pub fn select_to_end_of_paragraph(
13275        &mut self,
13276        _: &SelectToEndOfParagraph,
13277        window: &mut Window,
13278        cx: &mut Context<Self>,
13279    ) {
13280        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13281            cx.propagate();
13282            return;
13283        }
13284        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13285        self.change_selections(Default::default(), window, cx, |s| {
13286            s.move_heads_with(|map, head, _| {
13287                (
13288                    movement::end_of_paragraph(map, head, 1),
13289                    SelectionGoal::None,
13290                )
13291            });
13292        })
13293    }
13294
13295    pub fn move_to_start_of_excerpt(
13296        &mut self,
13297        _: &MoveToStartOfExcerpt,
13298        window: &mut Window,
13299        cx: &mut Context<Self>,
13300    ) {
13301        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13302            cx.propagate();
13303            return;
13304        }
13305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13306        self.change_selections(Default::default(), window, cx, |s| {
13307            s.move_with(|map, selection| {
13308                selection.collapse_to(
13309                    movement::start_of_excerpt(
13310                        map,
13311                        selection.head(),
13312                        workspace::searchable::Direction::Prev,
13313                    ),
13314                    SelectionGoal::None,
13315                )
13316            });
13317        })
13318    }
13319
13320    pub fn move_to_start_of_next_excerpt(
13321        &mut self,
13322        _: &MoveToStartOfNextExcerpt,
13323        window: &mut Window,
13324        cx: &mut Context<Self>,
13325    ) {
13326        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13327            cx.propagate();
13328            return;
13329        }
13330
13331        self.change_selections(Default::default(), window, cx, |s| {
13332            s.move_with(|map, selection| {
13333                selection.collapse_to(
13334                    movement::start_of_excerpt(
13335                        map,
13336                        selection.head(),
13337                        workspace::searchable::Direction::Next,
13338                    ),
13339                    SelectionGoal::None,
13340                )
13341            });
13342        })
13343    }
13344
13345    pub fn move_to_end_of_excerpt(
13346        &mut self,
13347        _: &MoveToEndOfExcerpt,
13348        window: &mut Window,
13349        cx: &mut Context<Self>,
13350    ) {
13351        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13352            cx.propagate();
13353            return;
13354        }
13355        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13356        self.change_selections(Default::default(), window, cx, |s| {
13357            s.move_with(|map, selection| {
13358                selection.collapse_to(
13359                    movement::end_of_excerpt(
13360                        map,
13361                        selection.head(),
13362                        workspace::searchable::Direction::Next,
13363                    ),
13364                    SelectionGoal::None,
13365                )
13366            });
13367        })
13368    }
13369
13370    pub fn move_to_end_of_previous_excerpt(
13371        &mut self,
13372        _: &MoveToEndOfPreviousExcerpt,
13373        window: &mut Window,
13374        cx: &mut Context<Self>,
13375    ) {
13376        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13377            cx.propagate();
13378            return;
13379        }
13380        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13381        self.change_selections(Default::default(), window, cx, |s| {
13382            s.move_with(|map, selection| {
13383                selection.collapse_to(
13384                    movement::end_of_excerpt(
13385                        map,
13386                        selection.head(),
13387                        workspace::searchable::Direction::Prev,
13388                    ),
13389                    SelectionGoal::None,
13390                )
13391            });
13392        })
13393    }
13394
13395    pub fn select_to_start_of_excerpt(
13396        &mut self,
13397        _: &SelectToStartOfExcerpt,
13398        window: &mut Window,
13399        cx: &mut Context<Self>,
13400    ) {
13401        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13402            cx.propagate();
13403            return;
13404        }
13405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13406        self.change_selections(Default::default(), window, cx, |s| {
13407            s.move_heads_with(|map, head, _| {
13408                (
13409                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13410                    SelectionGoal::None,
13411                )
13412            });
13413        })
13414    }
13415
13416    pub fn select_to_start_of_next_excerpt(
13417        &mut self,
13418        _: &SelectToStartOfNextExcerpt,
13419        window: &mut Window,
13420        cx: &mut Context<Self>,
13421    ) {
13422        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13423            cx.propagate();
13424            return;
13425        }
13426        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13427        self.change_selections(Default::default(), window, cx, |s| {
13428            s.move_heads_with(|map, head, _| {
13429                (
13430                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13431                    SelectionGoal::None,
13432                )
13433            });
13434        })
13435    }
13436
13437    pub fn select_to_end_of_excerpt(
13438        &mut self,
13439        _: &SelectToEndOfExcerpt,
13440        window: &mut Window,
13441        cx: &mut Context<Self>,
13442    ) {
13443        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13444            cx.propagate();
13445            return;
13446        }
13447        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13448        self.change_selections(Default::default(), window, cx, |s| {
13449            s.move_heads_with(|map, head, _| {
13450                (
13451                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13452                    SelectionGoal::None,
13453                )
13454            });
13455        })
13456    }
13457
13458    pub fn select_to_end_of_previous_excerpt(
13459        &mut self,
13460        _: &SelectToEndOfPreviousExcerpt,
13461        window: &mut Window,
13462        cx: &mut Context<Self>,
13463    ) {
13464        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13465            cx.propagate();
13466            return;
13467        }
13468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13469        self.change_selections(Default::default(), window, cx, |s| {
13470            s.move_heads_with(|map, head, _| {
13471                (
13472                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13473                    SelectionGoal::None,
13474                )
13475            });
13476        })
13477    }
13478
13479    pub fn move_to_beginning(
13480        &mut self,
13481        _: &MoveToBeginning,
13482        window: &mut Window,
13483        cx: &mut Context<Self>,
13484    ) {
13485        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13486            cx.propagate();
13487            return;
13488        }
13489        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13490        self.change_selections(Default::default(), window, cx, |s| {
13491            s.select_ranges(vec![0..0]);
13492        });
13493    }
13494
13495    pub fn select_to_beginning(
13496        &mut self,
13497        _: &SelectToBeginning,
13498        window: &mut Window,
13499        cx: &mut Context<Self>,
13500    ) {
13501        let mut selection = self.selections.last::<Point>(cx);
13502        selection.set_head(Point::zero(), SelectionGoal::None);
13503        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13504        self.change_selections(Default::default(), window, cx, |s| {
13505            s.select(vec![selection]);
13506        });
13507    }
13508
13509    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13510        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13511            cx.propagate();
13512            return;
13513        }
13514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13515        let cursor = self.buffer.read(cx).read(cx).len();
13516        self.change_selections(Default::default(), window, cx, |s| {
13517            s.select_ranges(vec![cursor..cursor])
13518        });
13519    }
13520
13521    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13522        self.nav_history = nav_history;
13523    }
13524
13525    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13526        self.nav_history.as_ref()
13527    }
13528
13529    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13530        self.push_to_nav_history(
13531            self.selections.newest_anchor().head(),
13532            None,
13533            false,
13534            true,
13535            cx,
13536        );
13537    }
13538
13539    fn push_to_nav_history(
13540        &mut self,
13541        cursor_anchor: Anchor,
13542        new_position: Option<Point>,
13543        is_deactivate: bool,
13544        always: bool,
13545        cx: &mut Context<Self>,
13546    ) {
13547        if let Some(nav_history) = self.nav_history.as_mut() {
13548            let buffer = self.buffer.read(cx).read(cx);
13549            let cursor_position = cursor_anchor.to_point(&buffer);
13550            let scroll_state = self.scroll_manager.anchor();
13551            let scroll_top_row = scroll_state.top_row(&buffer);
13552            drop(buffer);
13553
13554            if let Some(new_position) = new_position {
13555                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13556                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13557                    return;
13558                }
13559            }
13560
13561            nav_history.push(
13562                Some(NavigationData {
13563                    cursor_anchor,
13564                    cursor_position,
13565                    scroll_anchor: scroll_state,
13566                    scroll_top_row,
13567                }),
13568                cx,
13569            );
13570            cx.emit(EditorEvent::PushedToNavHistory {
13571                anchor: cursor_anchor,
13572                is_deactivate,
13573            })
13574        }
13575    }
13576
13577    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13579        let buffer = self.buffer.read(cx).snapshot(cx);
13580        let mut selection = self.selections.first::<usize>(cx);
13581        selection.set_head(buffer.len(), SelectionGoal::None);
13582        self.change_selections(Default::default(), window, cx, |s| {
13583            s.select(vec![selection]);
13584        });
13585    }
13586
13587    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13589        let end = self.buffer.read(cx).read(cx).len();
13590        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13591            s.select_ranges(vec![0..end]);
13592        });
13593    }
13594
13595    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13596        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13597        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13598        let mut selections = self.selections.all::<Point>(cx);
13599        let max_point = display_map.buffer_snapshot.max_point();
13600        for selection in &mut selections {
13601            let rows = selection.spanned_rows(true, &display_map);
13602            selection.start = Point::new(rows.start.0, 0);
13603            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13604            selection.reversed = false;
13605        }
13606        self.change_selections(Default::default(), window, cx, |s| {
13607            s.select(selections);
13608        });
13609    }
13610
13611    pub fn split_selection_into_lines(
13612        &mut self,
13613        action: &SplitSelectionIntoLines,
13614        window: &mut Window,
13615        cx: &mut Context<Self>,
13616    ) {
13617        let selections = self
13618            .selections
13619            .all::<Point>(cx)
13620            .into_iter()
13621            .map(|selection| selection.start..selection.end)
13622            .collect::<Vec<_>>();
13623        self.unfold_ranges(&selections, true, true, cx);
13624
13625        let mut new_selection_ranges = Vec::new();
13626        {
13627            let buffer = self.buffer.read(cx).read(cx);
13628            for selection in selections {
13629                for row in selection.start.row..selection.end.row {
13630                    let line_start = Point::new(row, 0);
13631                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13632
13633                    if action.keep_selections {
13634                        // Keep the selection range for each line
13635                        let selection_start = if row == selection.start.row {
13636                            selection.start
13637                        } else {
13638                            line_start
13639                        };
13640                        new_selection_ranges.push(selection_start..line_end);
13641                    } else {
13642                        // Collapse to cursor at end of line
13643                        new_selection_ranges.push(line_end..line_end);
13644                    }
13645                }
13646
13647                let is_multiline_selection = selection.start.row != selection.end.row;
13648                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13649                // so this action feels more ergonomic when paired with other selection operations
13650                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13651                if !should_skip_last {
13652                    if action.keep_selections {
13653                        if is_multiline_selection {
13654                            let line_start = Point::new(selection.end.row, 0);
13655                            new_selection_ranges.push(line_start..selection.end);
13656                        } else {
13657                            new_selection_ranges.push(selection.start..selection.end);
13658                        }
13659                    } else {
13660                        new_selection_ranges.push(selection.end..selection.end);
13661                    }
13662                }
13663            }
13664        }
13665        self.change_selections(Default::default(), window, cx, |s| {
13666            s.select_ranges(new_selection_ranges);
13667        });
13668    }
13669
13670    pub fn add_selection_above(
13671        &mut self,
13672        _: &AddSelectionAbove,
13673        window: &mut Window,
13674        cx: &mut Context<Self>,
13675    ) {
13676        self.add_selection(true, window, cx);
13677    }
13678
13679    pub fn add_selection_below(
13680        &mut self,
13681        _: &AddSelectionBelow,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        self.add_selection(false, window, cx);
13686    }
13687
13688    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13690
13691        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13692        let all_selections = self.selections.all::<Point>(cx);
13693        let text_layout_details = self.text_layout_details(window);
13694
13695        let (mut columnar_selections, new_selections_to_columnarize) = {
13696            if let Some(state) = self.add_selections_state.as_ref() {
13697                let columnar_selection_ids: HashSet<_> = state
13698                    .groups
13699                    .iter()
13700                    .flat_map(|group| group.stack.iter())
13701                    .copied()
13702                    .collect();
13703
13704                all_selections
13705                    .into_iter()
13706                    .partition(|s| columnar_selection_ids.contains(&s.id))
13707            } else {
13708                (Vec::new(), all_selections)
13709            }
13710        };
13711
13712        let mut state = self
13713            .add_selections_state
13714            .take()
13715            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13716
13717        for selection in new_selections_to_columnarize {
13718            let range = selection.display_range(&display_map).sorted();
13719            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13720            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13721            let positions = start_x.min(end_x)..start_x.max(end_x);
13722            let mut stack = Vec::new();
13723            for row in range.start.row().0..=range.end.row().0 {
13724                if let Some(selection) = self.selections.build_columnar_selection(
13725                    &display_map,
13726                    DisplayRow(row),
13727                    &positions,
13728                    selection.reversed,
13729                    &text_layout_details,
13730                ) {
13731                    stack.push(selection.id);
13732                    columnar_selections.push(selection);
13733                }
13734            }
13735            if !stack.is_empty() {
13736                if above {
13737                    stack.reverse();
13738                }
13739                state.groups.push(AddSelectionsGroup { above, stack });
13740            }
13741        }
13742
13743        let mut final_selections = Vec::new();
13744        let end_row = if above {
13745            DisplayRow(0)
13746        } else {
13747            display_map.max_point().row()
13748        };
13749
13750        let mut last_added_item_per_group = HashMap::default();
13751        for group in state.groups.iter_mut() {
13752            if let Some(last_id) = group.stack.last() {
13753                last_added_item_per_group.insert(*last_id, group);
13754            }
13755        }
13756
13757        for selection in columnar_selections {
13758            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13759                if above == group.above {
13760                    let range = selection.display_range(&display_map).sorted();
13761                    debug_assert_eq!(range.start.row(), range.end.row());
13762                    let mut row = range.start.row();
13763                    let positions =
13764                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13765                            px(start)..px(end)
13766                        } else {
13767                            let start_x =
13768                                display_map.x_for_display_point(range.start, &text_layout_details);
13769                            let end_x =
13770                                display_map.x_for_display_point(range.end, &text_layout_details);
13771                            start_x.min(end_x)..start_x.max(end_x)
13772                        };
13773
13774                    let mut maybe_new_selection = None;
13775                    while row != end_row {
13776                        if above {
13777                            row.0 -= 1;
13778                        } else {
13779                            row.0 += 1;
13780                        }
13781                        if let Some(new_selection) = self.selections.build_columnar_selection(
13782                            &display_map,
13783                            row,
13784                            &positions,
13785                            selection.reversed,
13786                            &text_layout_details,
13787                        ) {
13788                            maybe_new_selection = Some(new_selection);
13789                            break;
13790                        }
13791                    }
13792
13793                    if let Some(new_selection) = maybe_new_selection {
13794                        group.stack.push(new_selection.id);
13795                        if above {
13796                            final_selections.push(new_selection);
13797                            final_selections.push(selection);
13798                        } else {
13799                            final_selections.push(selection);
13800                            final_selections.push(new_selection);
13801                        }
13802                    } else {
13803                        final_selections.push(selection);
13804                    }
13805                } else {
13806                    group.stack.pop();
13807                }
13808            } else {
13809                final_selections.push(selection);
13810            }
13811        }
13812
13813        self.change_selections(Default::default(), window, cx, |s| {
13814            s.select(final_selections);
13815        });
13816
13817        let final_selection_ids: HashSet<_> = self
13818            .selections
13819            .all::<Point>(cx)
13820            .iter()
13821            .map(|s| s.id)
13822            .collect();
13823        state.groups.retain_mut(|group| {
13824            // selections might get merged above so we remove invalid items from stacks
13825            group.stack.retain(|id| final_selection_ids.contains(id));
13826
13827            // single selection in stack can be treated as initial state
13828            group.stack.len() > 1
13829        });
13830
13831        if !state.groups.is_empty() {
13832            self.add_selections_state = Some(state);
13833        }
13834    }
13835
13836    fn select_match_ranges(
13837        &mut self,
13838        range: Range<usize>,
13839        reversed: bool,
13840        replace_newest: bool,
13841        auto_scroll: Option<Autoscroll>,
13842        window: &mut Window,
13843        cx: &mut Context<Editor>,
13844    ) {
13845        self.unfold_ranges(
13846            std::slice::from_ref(&range),
13847            false,
13848            auto_scroll.is_some(),
13849            cx,
13850        );
13851        let effects = if let Some(scroll) = auto_scroll {
13852            SelectionEffects::scroll(scroll)
13853        } else {
13854            SelectionEffects::no_scroll()
13855        };
13856        self.change_selections(effects, window, cx, |s| {
13857            if replace_newest {
13858                s.delete(s.newest_anchor().id);
13859            }
13860            if reversed {
13861                s.insert_range(range.end..range.start);
13862            } else {
13863                s.insert_range(range);
13864            }
13865        });
13866    }
13867
13868    pub fn select_next_match_internal(
13869        &mut self,
13870        display_map: &DisplaySnapshot,
13871        replace_newest: bool,
13872        autoscroll: Option<Autoscroll>,
13873        window: &mut Window,
13874        cx: &mut Context<Self>,
13875    ) -> Result<()> {
13876        let buffer = &display_map.buffer_snapshot;
13877        let mut selections = self.selections.all::<usize>(cx);
13878        if let Some(mut select_next_state) = self.select_next_state.take() {
13879            let query = &select_next_state.query;
13880            if !select_next_state.done {
13881                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13882                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13883                let mut next_selected_range = None;
13884
13885                let bytes_after_last_selection =
13886                    buffer.bytes_in_range(last_selection.end..buffer.len());
13887                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13888                let query_matches = query
13889                    .stream_find_iter(bytes_after_last_selection)
13890                    .map(|result| (last_selection.end, result))
13891                    .chain(
13892                        query
13893                            .stream_find_iter(bytes_before_first_selection)
13894                            .map(|result| (0, result)),
13895                    );
13896
13897                for (start_offset, query_match) in query_matches {
13898                    let query_match = query_match.unwrap(); // can only fail due to I/O
13899                    let offset_range =
13900                        start_offset + query_match.start()..start_offset + query_match.end();
13901
13902                    if !select_next_state.wordwise
13903                        || (!buffer.is_inside_word(offset_range.start, false)
13904                            && !buffer.is_inside_word(offset_range.end, false))
13905                    {
13906                        // TODO: This is n^2, because we might check all the selections
13907                        if !selections
13908                            .iter()
13909                            .any(|selection| selection.range().overlaps(&offset_range))
13910                        {
13911                            next_selected_range = Some(offset_range);
13912                            break;
13913                        }
13914                    }
13915                }
13916
13917                if let Some(next_selected_range) = next_selected_range {
13918                    self.select_match_ranges(
13919                        next_selected_range,
13920                        last_selection.reversed,
13921                        replace_newest,
13922                        autoscroll,
13923                        window,
13924                        cx,
13925                    );
13926                } else {
13927                    select_next_state.done = true;
13928                }
13929            }
13930
13931            self.select_next_state = Some(select_next_state);
13932        } else {
13933            let mut only_carets = true;
13934            let mut same_text_selected = true;
13935            let mut selected_text = None;
13936
13937            let mut selections_iter = selections.iter().peekable();
13938            while let Some(selection) = selections_iter.next() {
13939                if selection.start != selection.end {
13940                    only_carets = false;
13941                }
13942
13943                if same_text_selected {
13944                    if selected_text.is_none() {
13945                        selected_text =
13946                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13947                    }
13948
13949                    if let Some(next_selection) = selections_iter.peek() {
13950                        if next_selection.range().len() == selection.range().len() {
13951                            let next_selected_text = buffer
13952                                .text_for_range(next_selection.range())
13953                                .collect::<String>();
13954                            if Some(next_selected_text) != selected_text {
13955                                same_text_selected = false;
13956                                selected_text = None;
13957                            }
13958                        } else {
13959                            same_text_selected = false;
13960                            selected_text = None;
13961                        }
13962                    }
13963                }
13964            }
13965
13966            if only_carets {
13967                for selection in &mut selections {
13968                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13969                    selection.start = word_range.start;
13970                    selection.end = word_range.end;
13971                    selection.goal = SelectionGoal::None;
13972                    selection.reversed = false;
13973                    self.select_match_ranges(
13974                        selection.start..selection.end,
13975                        selection.reversed,
13976                        replace_newest,
13977                        autoscroll,
13978                        window,
13979                        cx,
13980                    );
13981                }
13982
13983                if selections.len() == 1 {
13984                    let selection = selections
13985                        .last()
13986                        .expect("ensured that there's only one selection");
13987                    let query = buffer
13988                        .text_for_range(selection.start..selection.end)
13989                        .collect::<String>();
13990                    let is_empty = query.is_empty();
13991                    let select_state = SelectNextState {
13992                        query: AhoCorasick::new(&[query])?,
13993                        wordwise: true,
13994                        done: is_empty,
13995                    };
13996                    self.select_next_state = Some(select_state);
13997                } else {
13998                    self.select_next_state = None;
13999                }
14000            } else if let Some(selected_text) = selected_text {
14001                self.select_next_state = Some(SelectNextState {
14002                    query: AhoCorasick::new(&[selected_text])?,
14003                    wordwise: false,
14004                    done: false,
14005                });
14006                self.select_next_match_internal(
14007                    display_map,
14008                    replace_newest,
14009                    autoscroll,
14010                    window,
14011                    cx,
14012                )?;
14013            }
14014        }
14015        Ok(())
14016    }
14017
14018    pub fn select_all_matches(
14019        &mut self,
14020        _action: &SelectAllMatches,
14021        window: &mut Window,
14022        cx: &mut Context<Self>,
14023    ) -> Result<()> {
14024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14025
14026        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14027
14028        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14029        let Some(select_next_state) = self.select_next_state.as_mut() else {
14030            return Ok(());
14031        };
14032        if select_next_state.done {
14033            return Ok(());
14034        }
14035
14036        let mut new_selections = Vec::new();
14037
14038        let reversed = self.selections.oldest::<usize>(cx).reversed;
14039        let buffer = &display_map.buffer_snapshot;
14040        let query_matches = select_next_state
14041            .query
14042            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14043
14044        for query_match in query_matches.into_iter() {
14045            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14046            let offset_range = if reversed {
14047                query_match.end()..query_match.start()
14048            } else {
14049                query_match.start()..query_match.end()
14050            };
14051
14052            if !select_next_state.wordwise
14053                || (!buffer.is_inside_word(offset_range.start, false)
14054                    && !buffer.is_inside_word(offset_range.end, false))
14055            {
14056                new_selections.push(offset_range.start..offset_range.end);
14057            }
14058        }
14059
14060        select_next_state.done = true;
14061
14062        if new_selections.is_empty() {
14063            log::error!("bug: new_selections is empty in select_all_matches");
14064            return Ok(());
14065        }
14066
14067        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14068        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14069            selections.select_ranges(new_selections)
14070        });
14071
14072        Ok(())
14073    }
14074
14075    pub fn select_next(
14076        &mut self,
14077        action: &SelectNext,
14078        window: &mut Window,
14079        cx: &mut Context<Self>,
14080    ) -> Result<()> {
14081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14082        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14083        self.select_next_match_internal(
14084            &display_map,
14085            action.replace_newest,
14086            Some(Autoscroll::newest()),
14087            window,
14088            cx,
14089        )?;
14090        Ok(())
14091    }
14092
14093    pub fn select_previous(
14094        &mut self,
14095        action: &SelectPrevious,
14096        window: &mut Window,
14097        cx: &mut Context<Self>,
14098    ) -> Result<()> {
14099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14100        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14101        let buffer = &display_map.buffer_snapshot;
14102        let mut selections = self.selections.all::<usize>(cx);
14103        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14104            let query = &select_prev_state.query;
14105            if !select_prev_state.done {
14106                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14107                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14108                let mut next_selected_range = None;
14109                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14110                let bytes_before_last_selection =
14111                    buffer.reversed_bytes_in_range(0..last_selection.start);
14112                let bytes_after_first_selection =
14113                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14114                let query_matches = query
14115                    .stream_find_iter(bytes_before_last_selection)
14116                    .map(|result| (last_selection.start, result))
14117                    .chain(
14118                        query
14119                            .stream_find_iter(bytes_after_first_selection)
14120                            .map(|result| (buffer.len(), result)),
14121                    );
14122                for (end_offset, query_match) in query_matches {
14123                    let query_match = query_match.unwrap(); // can only fail due to I/O
14124                    let offset_range =
14125                        end_offset - query_match.end()..end_offset - query_match.start();
14126
14127                    if !select_prev_state.wordwise
14128                        || (!buffer.is_inside_word(offset_range.start, false)
14129                            && !buffer.is_inside_word(offset_range.end, false))
14130                    {
14131                        next_selected_range = Some(offset_range);
14132                        break;
14133                    }
14134                }
14135
14136                if let Some(next_selected_range) = next_selected_range {
14137                    self.select_match_ranges(
14138                        next_selected_range,
14139                        last_selection.reversed,
14140                        action.replace_newest,
14141                        Some(Autoscroll::newest()),
14142                        window,
14143                        cx,
14144                    );
14145                } else {
14146                    select_prev_state.done = true;
14147                }
14148            }
14149
14150            self.select_prev_state = Some(select_prev_state);
14151        } else {
14152            let mut only_carets = true;
14153            let mut same_text_selected = true;
14154            let mut selected_text = None;
14155
14156            let mut selections_iter = selections.iter().peekable();
14157            while let Some(selection) = selections_iter.next() {
14158                if selection.start != selection.end {
14159                    only_carets = false;
14160                }
14161
14162                if same_text_selected {
14163                    if selected_text.is_none() {
14164                        selected_text =
14165                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14166                    }
14167
14168                    if let Some(next_selection) = selections_iter.peek() {
14169                        if next_selection.range().len() == selection.range().len() {
14170                            let next_selected_text = buffer
14171                                .text_for_range(next_selection.range())
14172                                .collect::<String>();
14173                            if Some(next_selected_text) != selected_text {
14174                                same_text_selected = false;
14175                                selected_text = None;
14176                            }
14177                        } else {
14178                            same_text_selected = false;
14179                            selected_text = None;
14180                        }
14181                    }
14182                }
14183            }
14184
14185            if only_carets {
14186                for selection in &mut selections {
14187                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14188                    selection.start = word_range.start;
14189                    selection.end = word_range.end;
14190                    selection.goal = SelectionGoal::None;
14191                    selection.reversed = false;
14192                    self.select_match_ranges(
14193                        selection.start..selection.end,
14194                        selection.reversed,
14195                        action.replace_newest,
14196                        Some(Autoscroll::newest()),
14197                        window,
14198                        cx,
14199                    );
14200                }
14201                if selections.len() == 1 {
14202                    let selection = selections
14203                        .last()
14204                        .expect("ensured that there's only one selection");
14205                    let query = buffer
14206                        .text_for_range(selection.start..selection.end)
14207                        .collect::<String>();
14208                    let is_empty = query.is_empty();
14209                    let select_state = SelectNextState {
14210                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14211                        wordwise: true,
14212                        done: is_empty,
14213                    };
14214                    self.select_prev_state = Some(select_state);
14215                } else {
14216                    self.select_prev_state = None;
14217                }
14218            } else if let Some(selected_text) = selected_text {
14219                self.select_prev_state = Some(SelectNextState {
14220                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14221                    wordwise: false,
14222                    done: false,
14223                });
14224                self.select_previous(action, window, cx)?;
14225            }
14226        }
14227        Ok(())
14228    }
14229
14230    pub fn find_next_match(
14231        &mut self,
14232        _: &FindNextMatch,
14233        window: &mut Window,
14234        cx: &mut Context<Self>,
14235    ) -> Result<()> {
14236        let selections = self.selections.disjoint_anchors();
14237        match selections.first() {
14238            Some(first) if selections.len() >= 2 => {
14239                self.change_selections(Default::default(), window, cx, |s| {
14240                    s.select_ranges([first.range()]);
14241                });
14242            }
14243            _ => self.select_next(
14244                &SelectNext {
14245                    replace_newest: true,
14246                },
14247                window,
14248                cx,
14249            )?,
14250        }
14251        Ok(())
14252    }
14253
14254    pub fn find_previous_match(
14255        &mut self,
14256        _: &FindPreviousMatch,
14257        window: &mut Window,
14258        cx: &mut Context<Self>,
14259    ) -> Result<()> {
14260        let selections = self.selections.disjoint_anchors();
14261        match selections.last() {
14262            Some(last) if selections.len() >= 2 => {
14263                self.change_selections(Default::default(), window, cx, |s| {
14264                    s.select_ranges([last.range()]);
14265                });
14266            }
14267            _ => self.select_previous(
14268                &SelectPrevious {
14269                    replace_newest: true,
14270                },
14271                window,
14272                cx,
14273            )?,
14274        }
14275        Ok(())
14276    }
14277
14278    pub fn toggle_comments(
14279        &mut self,
14280        action: &ToggleComments,
14281        window: &mut Window,
14282        cx: &mut Context<Self>,
14283    ) {
14284        if self.read_only(cx) {
14285            return;
14286        }
14287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14288        let text_layout_details = &self.text_layout_details(window);
14289        self.transact(window, cx, |this, window, cx| {
14290            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14291            let mut edits = Vec::new();
14292            let mut selection_edit_ranges = Vec::new();
14293            let mut last_toggled_row = None;
14294            let snapshot = this.buffer.read(cx).read(cx);
14295            let empty_str: Arc<str> = Arc::default();
14296            let mut suffixes_inserted = Vec::new();
14297            let ignore_indent = action.ignore_indent;
14298
14299            fn comment_prefix_range(
14300                snapshot: &MultiBufferSnapshot,
14301                row: MultiBufferRow,
14302                comment_prefix: &str,
14303                comment_prefix_whitespace: &str,
14304                ignore_indent: bool,
14305            ) -> Range<Point> {
14306                let indent_size = if ignore_indent {
14307                    0
14308                } else {
14309                    snapshot.indent_size_for_line(row).len
14310                };
14311
14312                let start = Point::new(row.0, indent_size);
14313
14314                let mut line_bytes = snapshot
14315                    .bytes_in_range(start..snapshot.max_point())
14316                    .flatten()
14317                    .copied();
14318
14319                // If this line currently begins with the line comment prefix, then record
14320                // the range containing the prefix.
14321                if line_bytes
14322                    .by_ref()
14323                    .take(comment_prefix.len())
14324                    .eq(comment_prefix.bytes())
14325                {
14326                    // Include any whitespace that matches the comment prefix.
14327                    let matching_whitespace_len = line_bytes
14328                        .zip(comment_prefix_whitespace.bytes())
14329                        .take_while(|(a, b)| a == b)
14330                        .count() as u32;
14331                    let end = Point::new(
14332                        start.row,
14333                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14334                    );
14335                    start..end
14336                } else {
14337                    start..start
14338                }
14339            }
14340
14341            fn comment_suffix_range(
14342                snapshot: &MultiBufferSnapshot,
14343                row: MultiBufferRow,
14344                comment_suffix: &str,
14345                comment_suffix_has_leading_space: bool,
14346            ) -> Range<Point> {
14347                let end = Point::new(row.0, snapshot.line_len(row));
14348                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14349
14350                let mut line_end_bytes = snapshot
14351                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14352                    .flatten()
14353                    .copied();
14354
14355                let leading_space_len = if suffix_start_column > 0
14356                    && line_end_bytes.next() == Some(b' ')
14357                    && comment_suffix_has_leading_space
14358                {
14359                    1
14360                } else {
14361                    0
14362                };
14363
14364                // If this line currently begins with the line comment prefix, then record
14365                // the range containing the prefix.
14366                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14367                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14368                    start..end
14369                } else {
14370                    end..end
14371                }
14372            }
14373
14374            // TODO: Handle selections that cross excerpts
14375            for selection in &mut selections {
14376                let start_column = snapshot
14377                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14378                    .len;
14379                let language = if let Some(language) =
14380                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14381                {
14382                    language
14383                } else {
14384                    continue;
14385                };
14386
14387                selection_edit_ranges.clear();
14388
14389                // If multiple selections contain a given row, avoid processing that
14390                // row more than once.
14391                let mut start_row = MultiBufferRow(selection.start.row);
14392                if last_toggled_row == Some(start_row) {
14393                    start_row = start_row.next_row();
14394                }
14395                let end_row =
14396                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14397                        MultiBufferRow(selection.end.row - 1)
14398                    } else {
14399                        MultiBufferRow(selection.end.row)
14400                    };
14401                last_toggled_row = Some(end_row);
14402
14403                if start_row > end_row {
14404                    continue;
14405                }
14406
14407                // If the language has line comments, toggle those.
14408                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14409
14410                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14411                if ignore_indent {
14412                    full_comment_prefixes = full_comment_prefixes
14413                        .into_iter()
14414                        .map(|s| Arc::from(s.trim_end()))
14415                        .collect();
14416                }
14417
14418                if !full_comment_prefixes.is_empty() {
14419                    let first_prefix = full_comment_prefixes
14420                        .first()
14421                        .expect("prefixes is non-empty");
14422                    let prefix_trimmed_lengths = full_comment_prefixes
14423                        .iter()
14424                        .map(|p| p.trim_end_matches(' ').len())
14425                        .collect::<SmallVec<[usize; 4]>>();
14426
14427                    let mut all_selection_lines_are_comments = true;
14428
14429                    for row in start_row.0..=end_row.0 {
14430                        let row = MultiBufferRow(row);
14431                        if start_row < end_row && snapshot.is_line_blank(row) {
14432                            continue;
14433                        }
14434
14435                        let prefix_range = full_comment_prefixes
14436                            .iter()
14437                            .zip(prefix_trimmed_lengths.iter().copied())
14438                            .map(|(prefix, trimmed_prefix_len)| {
14439                                comment_prefix_range(
14440                                    snapshot.deref(),
14441                                    row,
14442                                    &prefix[..trimmed_prefix_len],
14443                                    &prefix[trimmed_prefix_len..],
14444                                    ignore_indent,
14445                                )
14446                            })
14447                            .max_by_key(|range| range.end.column - range.start.column)
14448                            .expect("prefixes is non-empty");
14449
14450                        if prefix_range.is_empty() {
14451                            all_selection_lines_are_comments = false;
14452                        }
14453
14454                        selection_edit_ranges.push(prefix_range);
14455                    }
14456
14457                    if all_selection_lines_are_comments {
14458                        edits.extend(
14459                            selection_edit_ranges
14460                                .iter()
14461                                .cloned()
14462                                .map(|range| (range, empty_str.clone())),
14463                        );
14464                    } else {
14465                        let min_column = selection_edit_ranges
14466                            .iter()
14467                            .map(|range| range.start.column)
14468                            .min()
14469                            .unwrap_or(0);
14470                        edits.extend(selection_edit_ranges.iter().map(|range| {
14471                            let position = Point::new(range.start.row, min_column);
14472                            (position..position, first_prefix.clone())
14473                        }));
14474                    }
14475                } else if let Some(BlockCommentConfig {
14476                    start: full_comment_prefix,
14477                    end: comment_suffix,
14478                    ..
14479                }) = language.block_comment()
14480                {
14481                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14482                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14483                    let prefix_range = comment_prefix_range(
14484                        snapshot.deref(),
14485                        start_row,
14486                        comment_prefix,
14487                        comment_prefix_whitespace,
14488                        ignore_indent,
14489                    );
14490                    let suffix_range = comment_suffix_range(
14491                        snapshot.deref(),
14492                        end_row,
14493                        comment_suffix.trim_start_matches(' '),
14494                        comment_suffix.starts_with(' '),
14495                    );
14496
14497                    if prefix_range.is_empty() || suffix_range.is_empty() {
14498                        edits.push((
14499                            prefix_range.start..prefix_range.start,
14500                            full_comment_prefix.clone(),
14501                        ));
14502                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14503                        suffixes_inserted.push((end_row, comment_suffix.len()));
14504                    } else {
14505                        edits.push((prefix_range, empty_str.clone()));
14506                        edits.push((suffix_range, empty_str.clone()));
14507                    }
14508                } else {
14509                    continue;
14510                }
14511            }
14512
14513            drop(snapshot);
14514            this.buffer.update(cx, |buffer, cx| {
14515                buffer.edit(edits, None, cx);
14516            });
14517
14518            // Adjust selections so that they end before any comment suffixes that
14519            // were inserted.
14520            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14521            let mut selections = this.selections.all::<Point>(cx);
14522            let snapshot = this.buffer.read(cx).read(cx);
14523            for selection in &mut selections {
14524                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14525                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14526                        Ordering::Less => {
14527                            suffixes_inserted.next();
14528                            continue;
14529                        }
14530                        Ordering::Greater => break,
14531                        Ordering::Equal => {
14532                            if selection.end.column == snapshot.line_len(row) {
14533                                if selection.is_empty() {
14534                                    selection.start.column -= suffix_len as u32;
14535                                }
14536                                selection.end.column -= suffix_len as u32;
14537                            }
14538                            break;
14539                        }
14540                    }
14541                }
14542            }
14543
14544            drop(snapshot);
14545            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14546
14547            let selections = this.selections.all::<Point>(cx);
14548            let selections_on_single_row = selections.windows(2).all(|selections| {
14549                selections[0].start.row == selections[1].start.row
14550                    && selections[0].end.row == selections[1].end.row
14551                    && selections[0].start.row == selections[0].end.row
14552            });
14553            let selections_selecting = selections
14554                .iter()
14555                .any(|selection| selection.start != selection.end);
14556            let advance_downwards = action.advance_downwards
14557                && selections_on_single_row
14558                && !selections_selecting
14559                && !matches!(this.mode, EditorMode::SingleLine { .. });
14560
14561            if advance_downwards {
14562                let snapshot = this.buffer.read(cx).snapshot(cx);
14563
14564                this.change_selections(Default::default(), window, cx, |s| {
14565                    s.move_cursors_with(|display_snapshot, display_point, _| {
14566                        let mut point = display_point.to_point(display_snapshot);
14567                        point.row += 1;
14568                        point = snapshot.clip_point(point, Bias::Left);
14569                        let display_point = point.to_display_point(display_snapshot);
14570                        let goal = SelectionGoal::HorizontalPosition(
14571                            display_snapshot
14572                                .x_for_display_point(display_point, text_layout_details)
14573                                .into(),
14574                        );
14575                        (display_point, goal)
14576                    })
14577                });
14578            }
14579        });
14580    }
14581
14582    pub fn select_enclosing_symbol(
14583        &mut self,
14584        _: &SelectEnclosingSymbol,
14585        window: &mut Window,
14586        cx: &mut Context<Self>,
14587    ) {
14588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14589
14590        let buffer = self.buffer.read(cx).snapshot(cx);
14591        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14592
14593        fn update_selection(
14594            selection: &Selection<usize>,
14595            buffer_snap: &MultiBufferSnapshot,
14596        ) -> Option<Selection<usize>> {
14597            let cursor = selection.head();
14598            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14599            for symbol in symbols.iter().rev() {
14600                let start = symbol.range.start.to_offset(buffer_snap);
14601                let end = symbol.range.end.to_offset(buffer_snap);
14602                let new_range = start..end;
14603                if start < selection.start || end > selection.end {
14604                    return Some(Selection {
14605                        id: selection.id,
14606                        start: new_range.start,
14607                        end: new_range.end,
14608                        goal: SelectionGoal::None,
14609                        reversed: selection.reversed,
14610                    });
14611                }
14612            }
14613            None
14614        }
14615
14616        let mut selected_larger_symbol = false;
14617        let new_selections = old_selections
14618            .iter()
14619            .map(|selection| match update_selection(selection, &buffer) {
14620                Some(new_selection) => {
14621                    if new_selection.range() != selection.range() {
14622                        selected_larger_symbol = true;
14623                    }
14624                    new_selection
14625                }
14626                None => selection.clone(),
14627            })
14628            .collect::<Vec<_>>();
14629
14630        if selected_larger_symbol {
14631            self.change_selections(Default::default(), window, cx, |s| {
14632                s.select(new_selections);
14633            });
14634        }
14635    }
14636
14637    pub fn select_larger_syntax_node(
14638        &mut self,
14639        _: &SelectLargerSyntaxNode,
14640        window: &mut Window,
14641        cx: &mut Context<Self>,
14642    ) {
14643        let Some(visible_row_count) = self.visible_row_count() else {
14644            return;
14645        };
14646        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14647        if old_selections.is_empty() {
14648            return;
14649        }
14650
14651        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14652
14653        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14654        let buffer = self.buffer.read(cx).snapshot(cx);
14655
14656        let mut selected_larger_node = false;
14657        let mut new_selections = old_selections
14658            .iter()
14659            .map(|selection| {
14660                let old_range = selection.start..selection.end;
14661
14662                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14663                    // manually select word at selection
14664                    if ["string_content", "inline"].contains(&node.kind()) {
14665                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14666                        // ignore if word is already selected
14667                        if !word_range.is_empty() && old_range != word_range {
14668                            let (last_word_range, _) =
14669                                buffer.surrounding_word(old_range.end, false);
14670                            // only select word if start and end point belongs to same word
14671                            if word_range == last_word_range {
14672                                selected_larger_node = true;
14673                                return Selection {
14674                                    id: selection.id,
14675                                    start: word_range.start,
14676                                    end: word_range.end,
14677                                    goal: SelectionGoal::None,
14678                                    reversed: selection.reversed,
14679                                };
14680                            }
14681                        }
14682                    }
14683                }
14684
14685                let mut new_range = old_range.clone();
14686                while let Some((_node, containing_range)) =
14687                    buffer.syntax_ancestor(new_range.clone())
14688                {
14689                    new_range = match containing_range {
14690                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14691                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14692                    };
14693                    if !display_map.intersects_fold(new_range.start)
14694                        && !display_map.intersects_fold(new_range.end)
14695                    {
14696                        break;
14697                    }
14698                }
14699
14700                selected_larger_node |= new_range != old_range;
14701                Selection {
14702                    id: selection.id,
14703                    start: new_range.start,
14704                    end: new_range.end,
14705                    goal: SelectionGoal::None,
14706                    reversed: selection.reversed,
14707                }
14708            })
14709            .collect::<Vec<_>>();
14710
14711        if !selected_larger_node {
14712            return; // don't put this call in the history
14713        }
14714
14715        // scroll based on transformation done to the last selection created by the user
14716        let (last_old, last_new) = old_selections
14717            .last()
14718            .zip(new_selections.last().cloned())
14719            .expect("old_selections isn't empty");
14720
14721        // revert selection
14722        let is_selection_reversed = {
14723            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14724            new_selections.last_mut().expect("checked above").reversed =
14725                should_newest_selection_be_reversed;
14726            should_newest_selection_be_reversed
14727        };
14728
14729        if selected_larger_node {
14730            self.select_syntax_node_history.disable_clearing = true;
14731            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14732                s.select(new_selections.clone());
14733            });
14734            self.select_syntax_node_history.disable_clearing = false;
14735        }
14736
14737        let start_row = last_new.start.to_display_point(&display_map).row().0;
14738        let end_row = last_new.end.to_display_point(&display_map).row().0;
14739        let selection_height = end_row - start_row + 1;
14740        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14741
14742        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14743        let scroll_behavior = if fits_on_the_screen {
14744            self.request_autoscroll(Autoscroll::fit(), cx);
14745            SelectSyntaxNodeScrollBehavior::FitSelection
14746        } else if is_selection_reversed {
14747            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14748            SelectSyntaxNodeScrollBehavior::CursorTop
14749        } else {
14750            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14751            SelectSyntaxNodeScrollBehavior::CursorBottom
14752        };
14753
14754        self.select_syntax_node_history.push((
14755            old_selections,
14756            scroll_behavior,
14757            is_selection_reversed,
14758        ));
14759    }
14760
14761    pub fn select_smaller_syntax_node(
14762        &mut self,
14763        _: &SelectSmallerSyntaxNode,
14764        window: &mut Window,
14765        cx: &mut Context<Self>,
14766    ) {
14767        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14768
14769        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14770            self.select_syntax_node_history.pop()
14771        {
14772            if let Some(selection) = selections.last_mut() {
14773                selection.reversed = is_selection_reversed;
14774            }
14775
14776            self.select_syntax_node_history.disable_clearing = true;
14777            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14778                s.select(selections.to_vec());
14779            });
14780            self.select_syntax_node_history.disable_clearing = false;
14781
14782            match scroll_behavior {
14783                SelectSyntaxNodeScrollBehavior::CursorTop => {
14784                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14785                }
14786                SelectSyntaxNodeScrollBehavior::FitSelection => {
14787                    self.request_autoscroll(Autoscroll::fit(), cx);
14788                }
14789                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14790                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14791                }
14792            }
14793        }
14794    }
14795
14796    pub fn unwrap_syntax_node(
14797        &mut self,
14798        _: &UnwrapSyntaxNode,
14799        window: &mut Window,
14800        cx: &mut Context<Self>,
14801    ) {
14802        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14803
14804        let buffer = self.buffer.read(cx).snapshot(cx);
14805        let selections = self
14806            .selections
14807            .all::<usize>(cx)
14808            .into_iter()
14809            // subtracting the offset requires sorting
14810            .sorted_by_key(|i| i.start);
14811
14812        let full_edits = selections
14813            .into_iter()
14814            .filter_map(|selection| {
14815                // Only requires two branches once if-let-chains stabilize (#53667)
14816                let child = if !selection.is_empty() {
14817                    selection.range()
14818                } else if let Some((_, ancestor_range)) =
14819                    buffer.syntax_ancestor(selection.start..selection.end)
14820                {
14821                    match ancestor_range {
14822                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14823                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14824                    }
14825                } else {
14826                    selection.range()
14827                };
14828
14829                let mut parent = child.clone();
14830                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14831                    parent = match ancestor_range {
14832                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14833                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14834                    };
14835                    if parent.start < child.start || parent.end > child.end {
14836                        break;
14837                    }
14838                }
14839
14840                if parent == child {
14841                    return None;
14842                }
14843                let text = buffer.text_for_range(child.clone()).collect::<String>();
14844                Some((selection.id, parent, text))
14845            })
14846            .collect::<Vec<_>>();
14847
14848        self.transact(window, cx, |this, window, cx| {
14849            this.buffer.update(cx, |buffer, cx| {
14850                buffer.edit(
14851                    full_edits
14852                        .iter()
14853                        .map(|(_, p, t)| (p.clone(), t.clone()))
14854                        .collect::<Vec<_>>(),
14855                    None,
14856                    cx,
14857                );
14858            });
14859            this.change_selections(Default::default(), window, cx, |s| {
14860                let mut offset = 0;
14861                let mut selections = vec![];
14862                for (id, parent, text) in full_edits {
14863                    let start = parent.start - offset;
14864                    offset += parent.len() - text.len();
14865                    selections.push(Selection {
14866                        id,
14867                        start,
14868                        end: start + text.len(),
14869                        reversed: false,
14870                        goal: Default::default(),
14871                    });
14872                }
14873                s.select(selections);
14874            });
14875        });
14876    }
14877
14878    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14879        if !EditorSettings::get_global(cx).gutter.runnables {
14880            self.clear_tasks();
14881            return Task::ready(());
14882        }
14883        let project = self.project().map(Entity::downgrade);
14884        let task_sources = self.lsp_task_sources(cx);
14885        let multi_buffer = self.buffer.downgrade();
14886        cx.spawn_in(window, async move |editor, cx| {
14887            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14888            let Some(project) = project.and_then(|p| p.upgrade()) else {
14889                return;
14890            };
14891            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14892                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14893            }) else {
14894                return;
14895            };
14896
14897            let hide_runnables = project
14898                .update(cx, |project, cx| {
14899                    // Do not display any test indicators in non-dev server remote projects.
14900                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14901                })
14902                .unwrap_or(true);
14903            if hide_runnables {
14904                return;
14905            }
14906            let new_rows =
14907                cx.background_spawn({
14908                    let snapshot = display_snapshot.clone();
14909                    async move {
14910                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14911                    }
14912                })
14913                    .await;
14914            let Ok(lsp_tasks) =
14915                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14916            else {
14917                return;
14918            };
14919            let lsp_tasks = lsp_tasks.await;
14920
14921            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14922                lsp_tasks
14923                    .into_iter()
14924                    .flat_map(|(kind, tasks)| {
14925                        tasks.into_iter().filter_map(move |(location, task)| {
14926                            Some((kind.clone(), location?, task))
14927                        })
14928                    })
14929                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14930                        let buffer = location.target.buffer;
14931                        let buffer_snapshot = buffer.read(cx).snapshot();
14932                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14933                            |(excerpt_id, snapshot, _)| {
14934                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14935                                    display_snapshot
14936                                        .buffer_snapshot
14937                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14938                                } else {
14939                                    None
14940                                }
14941                            },
14942                        );
14943                        if let Some(offset) = offset {
14944                            let task_buffer_range =
14945                                location.target.range.to_point(&buffer_snapshot);
14946                            let context_buffer_range =
14947                                task_buffer_range.to_offset(&buffer_snapshot);
14948                            let context_range = BufferOffset(context_buffer_range.start)
14949                                ..BufferOffset(context_buffer_range.end);
14950
14951                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14952                                .or_insert_with(|| RunnableTasks {
14953                                    templates: Vec::new(),
14954                                    offset,
14955                                    column: task_buffer_range.start.column,
14956                                    extra_variables: HashMap::default(),
14957                                    context_range,
14958                                })
14959                                .templates
14960                                .push((kind, task.original_task().clone()));
14961                        }
14962
14963                        acc
14964                    })
14965            }) else {
14966                return;
14967            };
14968
14969            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14970                buffer.language_settings(cx).tasks.prefer_lsp
14971            }) else {
14972                return;
14973            };
14974
14975            let rows = Self::runnable_rows(
14976                project,
14977                display_snapshot,
14978                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14979                new_rows,
14980                cx.clone(),
14981            )
14982            .await;
14983            editor
14984                .update(cx, |editor, _| {
14985                    editor.clear_tasks();
14986                    for (key, mut value) in rows {
14987                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14988                            value.templates.extend(lsp_tasks.templates);
14989                        }
14990
14991                        editor.insert_tasks(key, value);
14992                    }
14993                    for (key, value) in lsp_tasks_by_rows {
14994                        editor.insert_tasks(key, value);
14995                    }
14996                })
14997                .ok();
14998        })
14999    }
15000    fn fetch_runnable_ranges(
15001        snapshot: &DisplaySnapshot,
15002        range: Range<Anchor>,
15003    ) -> Vec<language::RunnableRange> {
15004        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15005    }
15006
15007    fn runnable_rows(
15008        project: Entity<Project>,
15009        snapshot: DisplaySnapshot,
15010        prefer_lsp: bool,
15011        runnable_ranges: Vec<RunnableRange>,
15012        cx: AsyncWindowContext,
15013    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15014        cx.spawn(async move |cx| {
15015            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15016            for mut runnable in runnable_ranges {
15017                let Some(tasks) = cx
15018                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15019                    .ok()
15020                else {
15021                    continue;
15022                };
15023                let mut tasks = tasks.await;
15024
15025                if prefer_lsp {
15026                    tasks.retain(|(task_kind, _)| {
15027                        !matches!(task_kind, TaskSourceKind::Language { .. })
15028                    });
15029                }
15030                if tasks.is_empty() {
15031                    continue;
15032                }
15033
15034                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15035                let Some(row) = snapshot
15036                    .buffer_snapshot
15037                    .buffer_line_for_row(MultiBufferRow(point.row))
15038                    .map(|(_, range)| range.start.row)
15039                else {
15040                    continue;
15041                };
15042
15043                let context_range =
15044                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15045                runnable_rows.push((
15046                    (runnable.buffer_id, row),
15047                    RunnableTasks {
15048                        templates: tasks,
15049                        offset: snapshot
15050                            .buffer_snapshot
15051                            .anchor_before(runnable.run_range.start),
15052                        context_range,
15053                        column: point.column,
15054                        extra_variables: runnable.extra_captures,
15055                    },
15056                ));
15057            }
15058            runnable_rows
15059        })
15060    }
15061
15062    fn templates_with_tags(
15063        project: &Entity<Project>,
15064        runnable: &mut Runnable,
15065        cx: &mut App,
15066    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15067        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15068            let (worktree_id, file) = project
15069                .buffer_for_id(runnable.buffer, cx)
15070                .and_then(|buffer| buffer.read(cx).file())
15071                .map(|file| (file.worktree_id(cx), file.clone()))
15072                .unzip();
15073
15074            (
15075                project.task_store().read(cx).task_inventory().cloned(),
15076                worktree_id,
15077                file,
15078            )
15079        });
15080
15081        let tags = mem::take(&mut runnable.tags);
15082        let language = runnable.language.clone();
15083        cx.spawn(async move |cx| {
15084            let mut templates_with_tags = Vec::new();
15085            if let Some(inventory) = inventory {
15086                for RunnableTag(tag) in tags {
15087                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15088                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15089                    }) else {
15090                        return templates_with_tags;
15091                    };
15092                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15093                        move |(_, template)| {
15094                            template.tags.iter().any(|source_tag| source_tag == &tag)
15095                        },
15096                    ));
15097                }
15098            }
15099            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15100
15101            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15102                // Strongest source wins; if we have worktree tag binding, prefer that to
15103                // global and language bindings;
15104                // if we have a global binding, prefer that to language binding.
15105                let first_mismatch = templates_with_tags
15106                    .iter()
15107                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15108                if let Some(index) = first_mismatch {
15109                    templates_with_tags.truncate(index);
15110                }
15111            }
15112
15113            templates_with_tags
15114        })
15115    }
15116
15117    pub fn move_to_enclosing_bracket(
15118        &mut self,
15119        _: &MoveToEnclosingBracket,
15120        window: &mut Window,
15121        cx: &mut Context<Self>,
15122    ) {
15123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15124        self.change_selections(Default::default(), window, cx, |s| {
15125            s.move_offsets_with(|snapshot, selection| {
15126                let Some(enclosing_bracket_ranges) =
15127                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15128                else {
15129                    return;
15130                };
15131
15132                let mut best_length = usize::MAX;
15133                let mut best_inside = false;
15134                let mut best_in_bracket_range = false;
15135                let mut best_destination = None;
15136                for (open, close) in enclosing_bracket_ranges {
15137                    let close = close.to_inclusive();
15138                    let length = close.end() - open.start;
15139                    let inside = selection.start >= open.end && selection.end <= *close.start();
15140                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15141                        || close.contains(&selection.head());
15142
15143                    // If best is next to a bracket and current isn't, skip
15144                    if !in_bracket_range && best_in_bracket_range {
15145                        continue;
15146                    }
15147
15148                    // Prefer smaller lengths unless best is inside and current isn't
15149                    if length > best_length && (best_inside || !inside) {
15150                        continue;
15151                    }
15152
15153                    best_length = length;
15154                    best_inside = inside;
15155                    best_in_bracket_range = in_bracket_range;
15156                    best_destination = Some(
15157                        if close.contains(&selection.start) && close.contains(&selection.end) {
15158                            if inside { open.end } else { open.start }
15159                        } else if inside {
15160                            *close.start()
15161                        } else {
15162                            *close.end()
15163                        },
15164                    );
15165                }
15166
15167                if let Some(destination) = best_destination {
15168                    selection.collapse_to(destination, SelectionGoal::None);
15169                }
15170            })
15171        });
15172    }
15173
15174    pub fn undo_selection(
15175        &mut self,
15176        _: &UndoSelection,
15177        window: &mut Window,
15178        cx: &mut Context<Self>,
15179    ) {
15180        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15181        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15182            self.selection_history.mode = SelectionHistoryMode::Undoing;
15183            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15184                this.end_selection(window, cx);
15185                this.change_selections(
15186                    SelectionEffects::scroll(Autoscroll::newest()),
15187                    window,
15188                    cx,
15189                    |s| s.select_anchors(entry.selections.to_vec()),
15190                );
15191            });
15192            self.selection_history.mode = SelectionHistoryMode::Normal;
15193
15194            self.select_next_state = entry.select_next_state;
15195            self.select_prev_state = entry.select_prev_state;
15196            self.add_selections_state = entry.add_selections_state;
15197        }
15198    }
15199
15200    pub fn redo_selection(
15201        &mut self,
15202        _: &RedoSelection,
15203        window: &mut Window,
15204        cx: &mut Context<Self>,
15205    ) {
15206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15207        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15208            self.selection_history.mode = SelectionHistoryMode::Redoing;
15209            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15210                this.end_selection(window, cx);
15211                this.change_selections(
15212                    SelectionEffects::scroll(Autoscroll::newest()),
15213                    window,
15214                    cx,
15215                    |s| s.select_anchors(entry.selections.to_vec()),
15216                );
15217            });
15218            self.selection_history.mode = SelectionHistoryMode::Normal;
15219
15220            self.select_next_state = entry.select_next_state;
15221            self.select_prev_state = entry.select_prev_state;
15222            self.add_selections_state = entry.add_selections_state;
15223        }
15224    }
15225
15226    pub fn expand_excerpts(
15227        &mut self,
15228        action: &ExpandExcerpts,
15229        _: &mut Window,
15230        cx: &mut Context<Self>,
15231    ) {
15232        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15233    }
15234
15235    pub fn expand_excerpts_down(
15236        &mut self,
15237        action: &ExpandExcerptsDown,
15238        _: &mut Window,
15239        cx: &mut Context<Self>,
15240    ) {
15241        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15242    }
15243
15244    pub fn expand_excerpts_up(
15245        &mut self,
15246        action: &ExpandExcerptsUp,
15247        _: &mut Window,
15248        cx: &mut Context<Self>,
15249    ) {
15250        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15251    }
15252
15253    pub fn expand_excerpts_for_direction(
15254        &mut self,
15255        lines: u32,
15256        direction: ExpandExcerptDirection,
15257
15258        cx: &mut Context<Self>,
15259    ) {
15260        let selections = self.selections.disjoint_anchors();
15261
15262        let lines = if lines == 0 {
15263            EditorSettings::get_global(cx).expand_excerpt_lines
15264        } else {
15265            lines
15266        };
15267
15268        self.buffer.update(cx, |buffer, cx| {
15269            let snapshot = buffer.snapshot(cx);
15270            let mut excerpt_ids = selections
15271                .iter()
15272                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15273                .collect::<Vec<_>>();
15274            excerpt_ids.sort();
15275            excerpt_ids.dedup();
15276            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15277        })
15278    }
15279
15280    pub fn expand_excerpt(
15281        &mut self,
15282        excerpt: ExcerptId,
15283        direction: ExpandExcerptDirection,
15284        window: &mut Window,
15285        cx: &mut Context<Self>,
15286    ) {
15287        let current_scroll_position = self.scroll_position(cx);
15288        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15289        let mut should_scroll_up = false;
15290
15291        if direction == ExpandExcerptDirection::Down {
15292            let multi_buffer = self.buffer.read(cx);
15293            let snapshot = multi_buffer.snapshot(cx);
15294            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15295                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15296                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15297            {
15298                let buffer_snapshot = buffer.read(cx).snapshot();
15299                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15300                let last_row = buffer_snapshot.max_point().row;
15301                let lines_below = last_row.saturating_sub(excerpt_end_row);
15302                should_scroll_up = lines_below >= lines_to_expand;
15303            }
15304        }
15305
15306        self.buffer.update(cx, |buffer, cx| {
15307            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15308        });
15309
15310        if should_scroll_up {
15311            let new_scroll_position =
15312                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15313            self.set_scroll_position(new_scroll_position, window, cx);
15314        }
15315    }
15316
15317    pub fn go_to_singleton_buffer_point(
15318        &mut self,
15319        point: Point,
15320        window: &mut Window,
15321        cx: &mut Context<Self>,
15322    ) {
15323        self.go_to_singleton_buffer_range(point..point, window, cx);
15324    }
15325
15326    pub fn go_to_singleton_buffer_range(
15327        &mut self,
15328        range: Range<Point>,
15329        window: &mut Window,
15330        cx: &mut Context<Self>,
15331    ) {
15332        let multibuffer = self.buffer().read(cx);
15333        let Some(buffer) = multibuffer.as_singleton() else {
15334            return;
15335        };
15336        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15337            return;
15338        };
15339        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15340            return;
15341        };
15342        self.change_selections(
15343            SelectionEffects::default().nav_history(true),
15344            window,
15345            cx,
15346            |s| s.select_anchor_ranges([start..end]),
15347        );
15348    }
15349
15350    pub fn go_to_diagnostic(
15351        &mut self,
15352        action: &GoToDiagnostic,
15353        window: &mut Window,
15354        cx: &mut Context<Self>,
15355    ) {
15356        if !self.diagnostics_enabled() {
15357            return;
15358        }
15359        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15360        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15361    }
15362
15363    pub fn go_to_prev_diagnostic(
15364        &mut self,
15365        action: &GoToPreviousDiagnostic,
15366        window: &mut Window,
15367        cx: &mut Context<Self>,
15368    ) {
15369        if !self.diagnostics_enabled() {
15370            return;
15371        }
15372        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15373        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15374    }
15375
15376    pub fn go_to_diagnostic_impl(
15377        &mut self,
15378        direction: Direction,
15379        severity: GoToDiagnosticSeverityFilter,
15380        window: &mut Window,
15381        cx: &mut Context<Self>,
15382    ) {
15383        let buffer = self.buffer.read(cx).snapshot(cx);
15384        let selection = self.selections.newest::<usize>(cx);
15385
15386        let mut active_group_id = None;
15387        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15388            && active_group.active_range.start.to_offset(&buffer) == selection.start
15389        {
15390            active_group_id = Some(active_group.group_id);
15391        }
15392
15393        fn filtered(
15394            snapshot: EditorSnapshot,
15395            severity: GoToDiagnosticSeverityFilter,
15396            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15397        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15398            diagnostics
15399                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15400                .filter(|entry| entry.range.start != entry.range.end)
15401                .filter(|entry| !entry.diagnostic.is_unnecessary)
15402                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15403        }
15404
15405        let snapshot = self.snapshot(window, cx);
15406        let before = filtered(
15407            snapshot.clone(),
15408            severity,
15409            buffer
15410                .diagnostics_in_range(0..selection.start)
15411                .filter(|entry| entry.range.start <= selection.start),
15412        );
15413        let after = filtered(
15414            snapshot,
15415            severity,
15416            buffer
15417                .diagnostics_in_range(selection.start..buffer.len())
15418                .filter(|entry| entry.range.start >= selection.start),
15419        );
15420
15421        let mut found: Option<DiagnosticEntry<usize>> = None;
15422        if direction == Direction::Prev {
15423            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15424            {
15425                for diagnostic in prev_diagnostics.into_iter().rev() {
15426                    if diagnostic.range.start != selection.start
15427                        || active_group_id
15428                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15429                    {
15430                        found = Some(diagnostic);
15431                        break 'outer;
15432                    }
15433                }
15434            }
15435        } else {
15436            for diagnostic in after.chain(before) {
15437                if diagnostic.range.start != selection.start
15438                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15439                {
15440                    found = Some(diagnostic);
15441                    break;
15442                }
15443            }
15444        }
15445        let Some(next_diagnostic) = found else {
15446            return;
15447        };
15448
15449        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15450            return;
15451        };
15452        self.change_selections(Default::default(), window, cx, |s| {
15453            s.select_ranges(vec![
15454                next_diagnostic.range.start..next_diagnostic.range.start,
15455            ])
15456        });
15457        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15458        self.refresh_edit_prediction(false, true, window, cx);
15459    }
15460
15461    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15462        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15463        let snapshot = self.snapshot(window, cx);
15464        let selection = self.selections.newest::<Point>(cx);
15465        self.go_to_hunk_before_or_after_position(
15466            &snapshot,
15467            selection.head(),
15468            Direction::Next,
15469            window,
15470            cx,
15471        );
15472    }
15473
15474    pub fn go_to_hunk_before_or_after_position(
15475        &mut self,
15476        snapshot: &EditorSnapshot,
15477        position: Point,
15478        direction: Direction,
15479        window: &mut Window,
15480        cx: &mut Context<Editor>,
15481    ) {
15482        let row = if direction == Direction::Next {
15483            self.hunk_after_position(snapshot, position)
15484                .map(|hunk| hunk.row_range.start)
15485        } else {
15486            self.hunk_before_position(snapshot, position)
15487        };
15488
15489        if let Some(row) = row {
15490            let destination = Point::new(row.0, 0);
15491            let autoscroll = Autoscroll::center();
15492
15493            self.unfold_ranges(&[destination..destination], false, false, cx);
15494            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15495                s.select_ranges([destination..destination]);
15496            });
15497        }
15498    }
15499
15500    fn hunk_after_position(
15501        &mut self,
15502        snapshot: &EditorSnapshot,
15503        position: Point,
15504    ) -> Option<MultiBufferDiffHunk> {
15505        snapshot
15506            .buffer_snapshot
15507            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15508            .find(|hunk| hunk.row_range.start.0 > position.row)
15509            .or_else(|| {
15510                snapshot
15511                    .buffer_snapshot
15512                    .diff_hunks_in_range(Point::zero()..position)
15513                    .find(|hunk| hunk.row_range.end.0 < position.row)
15514            })
15515    }
15516
15517    fn go_to_prev_hunk(
15518        &mut self,
15519        _: &GoToPreviousHunk,
15520        window: &mut Window,
15521        cx: &mut Context<Self>,
15522    ) {
15523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15524        let snapshot = self.snapshot(window, cx);
15525        let selection = self.selections.newest::<Point>(cx);
15526        self.go_to_hunk_before_or_after_position(
15527            &snapshot,
15528            selection.head(),
15529            Direction::Prev,
15530            window,
15531            cx,
15532        );
15533    }
15534
15535    fn hunk_before_position(
15536        &mut self,
15537        snapshot: &EditorSnapshot,
15538        position: Point,
15539    ) -> Option<MultiBufferRow> {
15540        snapshot
15541            .buffer_snapshot
15542            .diff_hunk_before(position)
15543            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15544    }
15545
15546    fn go_to_next_change(
15547        &mut self,
15548        _: &GoToNextChange,
15549        window: &mut Window,
15550        cx: &mut Context<Self>,
15551    ) {
15552        if let Some(selections) = self
15553            .change_list
15554            .next_change(1, Direction::Next)
15555            .map(|s| s.to_vec())
15556        {
15557            self.change_selections(Default::default(), window, cx, |s| {
15558                let map = s.display_map();
15559                s.select_display_ranges(selections.iter().map(|a| {
15560                    let point = a.to_display_point(&map);
15561                    point..point
15562                }))
15563            })
15564        }
15565    }
15566
15567    fn go_to_previous_change(
15568        &mut self,
15569        _: &GoToPreviousChange,
15570        window: &mut Window,
15571        cx: &mut Context<Self>,
15572    ) {
15573        if let Some(selections) = self
15574            .change_list
15575            .next_change(1, Direction::Prev)
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_line<T: 'static>(
15589        &mut self,
15590        position: Anchor,
15591        highlight_color: Option<Hsla>,
15592        window: &mut Window,
15593        cx: &mut Context<Self>,
15594    ) {
15595        let snapshot = self.snapshot(window, cx).display_snapshot;
15596        let position = position.to_point(&snapshot.buffer_snapshot);
15597        let start = snapshot
15598            .buffer_snapshot
15599            .clip_point(Point::new(position.row, 0), Bias::Left);
15600        let end = start + Point::new(1, 0);
15601        let start = snapshot.buffer_snapshot.anchor_before(start);
15602        let end = snapshot.buffer_snapshot.anchor_before(end);
15603
15604        self.highlight_rows::<T>(
15605            start..end,
15606            highlight_color
15607                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15608            Default::default(),
15609            cx,
15610        );
15611
15612        if self.buffer.read(cx).is_singleton() {
15613            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15614        }
15615    }
15616
15617    pub fn go_to_definition(
15618        &mut self,
15619        _: &GoToDefinition,
15620        window: &mut Window,
15621        cx: &mut Context<Self>,
15622    ) -> Task<Result<Navigated>> {
15623        let definition =
15624            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15625        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15626        cx.spawn_in(window, async move |editor, cx| {
15627            if definition.await? == Navigated::Yes {
15628                return Ok(Navigated::Yes);
15629            }
15630            match fallback_strategy {
15631                GoToDefinitionFallback::None => Ok(Navigated::No),
15632                GoToDefinitionFallback::FindAllReferences => {
15633                    match editor.update_in(cx, |editor, window, cx| {
15634                        editor.find_all_references(&FindAllReferences, window, cx)
15635                    })? {
15636                        Some(references) => references.await,
15637                        None => Ok(Navigated::No),
15638                    }
15639                }
15640            }
15641        })
15642    }
15643
15644    pub fn go_to_declaration(
15645        &mut self,
15646        _: &GoToDeclaration,
15647        window: &mut Window,
15648        cx: &mut Context<Self>,
15649    ) -> Task<Result<Navigated>> {
15650        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15651    }
15652
15653    pub fn go_to_declaration_split(
15654        &mut self,
15655        _: &GoToDeclaration,
15656        window: &mut Window,
15657        cx: &mut Context<Self>,
15658    ) -> Task<Result<Navigated>> {
15659        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15660    }
15661
15662    pub fn go_to_implementation(
15663        &mut self,
15664        _: &GoToImplementation,
15665        window: &mut Window,
15666        cx: &mut Context<Self>,
15667    ) -> Task<Result<Navigated>> {
15668        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15669    }
15670
15671    pub fn go_to_implementation_split(
15672        &mut self,
15673        _: &GoToImplementationSplit,
15674        window: &mut Window,
15675        cx: &mut Context<Self>,
15676    ) -> Task<Result<Navigated>> {
15677        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15678    }
15679
15680    pub fn go_to_type_definition(
15681        &mut self,
15682        _: &GoToTypeDefinition,
15683        window: &mut Window,
15684        cx: &mut Context<Self>,
15685    ) -> Task<Result<Navigated>> {
15686        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15687    }
15688
15689    pub fn go_to_definition_split(
15690        &mut self,
15691        _: &GoToDefinitionSplit,
15692        window: &mut Window,
15693        cx: &mut Context<Self>,
15694    ) -> Task<Result<Navigated>> {
15695        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15696    }
15697
15698    pub fn go_to_type_definition_split(
15699        &mut self,
15700        _: &GoToTypeDefinitionSplit,
15701        window: &mut Window,
15702        cx: &mut Context<Self>,
15703    ) -> Task<Result<Navigated>> {
15704        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15705    }
15706
15707    fn go_to_definition_of_kind(
15708        &mut self,
15709        kind: GotoDefinitionKind,
15710        split: bool,
15711        window: &mut Window,
15712        cx: &mut Context<Self>,
15713    ) -> Task<Result<Navigated>> {
15714        let Some(provider) = self.semantics_provider.clone() else {
15715            return Task::ready(Ok(Navigated::No));
15716        };
15717        let head = self.selections.newest::<usize>(cx).head();
15718        let buffer = self.buffer.read(cx);
15719        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15720            return Task::ready(Ok(Navigated::No));
15721        };
15722        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15723            return Task::ready(Ok(Navigated::No));
15724        };
15725
15726        cx.spawn_in(window, async move |editor, cx| {
15727            let definitions = definitions.await?;
15728            let navigated = editor
15729                .update_in(cx, |editor, window, cx| {
15730                    editor.navigate_to_hover_links(
15731                        Some(kind),
15732                        definitions
15733                            .into_iter()
15734                            .filter(|location| {
15735                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15736                            })
15737                            .map(HoverLink::Text)
15738                            .collect::<Vec<_>>(),
15739                        split,
15740                        window,
15741                        cx,
15742                    )
15743                })?
15744                .await?;
15745            anyhow::Ok(navigated)
15746        })
15747    }
15748
15749    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15750        let selection = self.selections.newest_anchor();
15751        let head = selection.head();
15752        let tail = selection.tail();
15753
15754        let Some((buffer, start_position)) =
15755            self.buffer.read(cx).text_anchor_for_position(head, cx)
15756        else {
15757            return;
15758        };
15759
15760        let end_position = if head != tail {
15761            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15762                return;
15763            };
15764            Some(pos)
15765        } else {
15766            None
15767        };
15768
15769        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15770            let url = if let Some(end_pos) = end_position {
15771                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15772            } else {
15773                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15774            };
15775
15776            if let Some(url) = url {
15777                editor.update(cx, |_, cx| {
15778                    cx.open_url(&url);
15779                })
15780            } else {
15781                Ok(())
15782            }
15783        });
15784
15785        url_finder.detach();
15786    }
15787
15788    pub fn open_selected_filename(
15789        &mut self,
15790        _: &OpenSelectedFilename,
15791        window: &mut Window,
15792        cx: &mut Context<Self>,
15793    ) {
15794        let Some(workspace) = self.workspace() else {
15795            return;
15796        };
15797
15798        let position = self.selections.newest_anchor().head();
15799
15800        let Some((buffer, buffer_position)) =
15801            self.buffer.read(cx).text_anchor_for_position(position, cx)
15802        else {
15803            return;
15804        };
15805
15806        let project = self.project.clone();
15807
15808        cx.spawn_in(window, async move |_, cx| {
15809            let result = find_file(&buffer, project, buffer_position, cx).await;
15810
15811            if let Some((_, path)) = result {
15812                workspace
15813                    .update_in(cx, |workspace, window, cx| {
15814                        workspace.open_resolved_path(path, window, cx)
15815                    })?
15816                    .await?;
15817            }
15818            anyhow::Ok(())
15819        })
15820        .detach();
15821    }
15822
15823    pub(crate) fn navigate_to_hover_links(
15824        &mut self,
15825        kind: Option<GotoDefinitionKind>,
15826        definitions: Vec<HoverLink>,
15827        split: bool,
15828        window: &mut Window,
15829        cx: &mut Context<Editor>,
15830    ) -> Task<Result<Navigated>> {
15831        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15832        let mut first_url_or_file = None;
15833        let definitions: Vec<_> = definitions
15834            .into_iter()
15835            .filter_map(|def| match def {
15836                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15837                HoverLink::InlayHint(lsp_location, server_id) => {
15838                    let computation =
15839                        self.compute_target_location(lsp_location, server_id, window, cx);
15840                    Some(cx.background_spawn(computation))
15841                }
15842                HoverLink::Url(url) => {
15843                    first_url_or_file = Some(Either::Left(url));
15844                    None
15845                }
15846                HoverLink::File(path) => {
15847                    first_url_or_file = Some(Either::Right(path));
15848                    None
15849                }
15850            })
15851            .collect();
15852
15853        let workspace = self.workspace();
15854
15855        cx.spawn_in(window, async move |editor, acx| {
15856            let mut locations: Vec<Location> = future::join_all(definitions)
15857                .await
15858                .into_iter()
15859                .filter_map(|location| location.transpose())
15860                .collect::<Result<_>>()
15861                .context("location tasks")?;
15862
15863            if locations.len() > 1 {
15864                let Some(workspace) = workspace else {
15865                    return Ok(Navigated::No);
15866                };
15867
15868                let tab_kind = match kind {
15869                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15870                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15871                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15872                    Some(GotoDefinitionKind::Type) => "Types",
15873                };
15874                let title = editor
15875                    .update_in(acx, |_, _, cx| {
15876                        let target = locations
15877                            .iter()
15878                            .map(|location| {
15879                                location
15880                                    .buffer
15881                                    .read(cx)
15882                                    .text_for_range(location.range.clone())
15883                                    .collect::<String>()
15884                            })
15885                            .filter(|text| !text.contains('\n'))
15886                            .unique()
15887                            .take(3)
15888                            .join(", ");
15889                        if target.is_empty() {
15890                            tab_kind.to_owned()
15891                        } else {
15892                            format!("{tab_kind} for {target}")
15893                        }
15894                    })
15895                    .context("buffer title")?;
15896
15897                let opened = workspace
15898                    .update_in(acx, |workspace, window, cx| {
15899                        Self::open_locations_in_multibuffer(
15900                            workspace,
15901                            locations,
15902                            title,
15903                            split,
15904                            MultibufferSelectionMode::First,
15905                            window,
15906                            cx,
15907                        )
15908                    })
15909                    .is_ok();
15910
15911                anyhow::Ok(Navigated::from_bool(opened))
15912            } else if locations.is_empty() {
15913                // If there is one definition, just open it directly
15914                match first_url_or_file {
15915                    Some(Either::Left(url)) => {
15916                        acx.update(|_, cx| cx.open_url(&url))?;
15917                        Ok(Navigated::Yes)
15918                    }
15919                    Some(Either::Right(path)) => {
15920                        let Some(workspace) = workspace else {
15921                            return Ok(Navigated::No);
15922                        };
15923
15924                        workspace
15925                            .update_in(acx, |workspace, window, cx| {
15926                                workspace.open_resolved_path(path, window, cx)
15927                            })?
15928                            .await?;
15929                        Ok(Navigated::Yes)
15930                    }
15931                    None => Ok(Navigated::No),
15932                }
15933            } else {
15934                let Some(workspace) = workspace else {
15935                    return Ok(Navigated::No);
15936                };
15937
15938                let target = locations.pop().unwrap();
15939                editor.update_in(acx, |editor, window, cx| {
15940                    let pane = workspace.read(cx).active_pane().clone();
15941
15942                    let range = target.range.to_point(target.buffer.read(cx));
15943                    let range = editor.range_for_match(&range);
15944                    let range = collapse_multiline_range(range);
15945
15946                    if !split
15947                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15948                    {
15949                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15950                    } else {
15951                        window.defer(cx, move |window, cx| {
15952                            let target_editor: Entity<Self> =
15953                                workspace.update(cx, |workspace, cx| {
15954                                    let pane = if split {
15955                                        workspace.adjacent_pane(window, cx)
15956                                    } else {
15957                                        workspace.active_pane().clone()
15958                                    };
15959
15960                                    workspace.open_project_item(
15961                                        pane,
15962                                        target.buffer.clone(),
15963                                        true,
15964                                        true,
15965                                        window,
15966                                        cx,
15967                                    )
15968                                });
15969                            target_editor.update(cx, |target_editor, cx| {
15970                                // When selecting a definition in a different buffer, disable the nav history
15971                                // to avoid creating a history entry at the previous cursor location.
15972                                pane.update(cx, |pane, _| pane.disable_history());
15973                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15974                                pane.update(cx, |pane, _| pane.enable_history());
15975                            });
15976                        });
15977                    }
15978                    Navigated::Yes
15979                })
15980            }
15981        })
15982    }
15983
15984    fn compute_target_location(
15985        &self,
15986        lsp_location: lsp::Location,
15987        server_id: LanguageServerId,
15988        window: &mut Window,
15989        cx: &mut Context<Self>,
15990    ) -> Task<anyhow::Result<Option<Location>>> {
15991        let Some(project) = self.project.clone() else {
15992            return Task::ready(Ok(None));
15993        };
15994
15995        cx.spawn_in(window, async move |editor, cx| {
15996            let location_task = editor.update(cx, |_, cx| {
15997                project.update(cx, |project, cx| {
15998                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
15999                })
16000            })?;
16001            let location = Some({
16002                let target_buffer_handle = location_task.await.context("open local buffer")?;
16003                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16004                    let target_start = target_buffer
16005                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16006                    let target_end = target_buffer
16007                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16008                    target_buffer.anchor_after(target_start)
16009                        ..target_buffer.anchor_before(target_end)
16010                })?;
16011                Location {
16012                    buffer: target_buffer_handle,
16013                    range,
16014                }
16015            });
16016            Ok(location)
16017        })
16018    }
16019
16020    pub fn find_all_references(
16021        &mut self,
16022        _: &FindAllReferences,
16023        window: &mut Window,
16024        cx: &mut Context<Self>,
16025    ) -> Option<Task<Result<Navigated>>> {
16026        let selection = self.selections.newest::<usize>(cx);
16027        let multi_buffer = self.buffer.read(cx);
16028        let head = selection.head();
16029
16030        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16031        let head_anchor = multi_buffer_snapshot.anchor_at(
16032            head,
16033            if head < selection.tail() {
16034                Bias::Right
16035            } else {
16036                Bias::Left
16037            },
16038        );
16039
16040        match self
16041            .find_all_references_task_sources
16042            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16043        {
16044            Ok(_) => {
16045                log::info!(
16046                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16047                );
16048                return None;
16049            }
16050            Err(i) => {
16051                self.find_all_references_task_sources.insert(i, head_anchor);
16052            }
16053        }
16054
16055        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16056        let workspace = self.workspace()?;
16057        let project = workspace.read(cx).project().clone();
16058        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16059        Some(cx.spawn_in(window, async move |editor, cx| {
16060            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16061                if let Ok(i) = editor
16062                    .find_all_references_task_sources
16063                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16064                {
16065                    editor.find_all_references_task_sources.remove(i);
16066                }
16067            });
16068
16069            let locations = references.await?;
16070            if locations.is_empty() {
16071                return anyhow::Ok(Navigated::No);
16072            }
16073
16074            workspace.update_in(cx, |workspace, window, cx| {
16075                let target = locations
16076                    .iter()
16077                    .map(|location| {
16078                        location
16079                            .buffer
16080                            .read(cx)
16081                            .text_for_range(location.range.clone())
16082                            .collect::<String>()
16083                    })
16084                    .filter(|text| !text.contains('\n'))
16085                    .unique()
16086                    .take(3)
16087                    .join(", ");
16088                let title = if target.is_empty() {
16089                    "References".to_owned()
16090                } else {
16091                    format!("References to {target}")
16092                };
16093                Self::open_locations_in_multibuffer(
16094                    workspace,
16095                    locations,
16096                    title,
16097                    false,
16098                    MultibufferSelectionMode::First,
16099                    window,
16100                    cx,
16101                );
16102                Navigated::Yes
16103            })
16104        }))
16105    }
16106
16107    /// Opens a multibuffer with the given project locations in it
16108    pub fn open_locations_in_multibuffer(
16109        workspace: &mut Workspace,
16110        mut locations: Vec<Location>,
16111        title: String,
16112        split: bool,
16113        multibuffer_selection_mode: MultibufferSelectionMode,
16114        window: &mut Window,
16115        cx: &mut Context<Workspace>,
16116    ) {
16117        if locations.is_empty() {
16118            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16119            return;
16120        }
16121
16122        // If there are multiple definitions, open them in a multibuffer
16123        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16124        let mut locations = locations.into_iter().peekable();
16125        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16126        let capability = workspace.project().read(cx).capability();
16127
16128        let excerpt_buffer = cx.new(|cx| {
16129            let mut multibuffer = MultiBuffer::new(capability);
16130            while let Some(location) = locations.next() {
16131                let buffer = location.buffer.read(cx);
16132                let mut ranges_for_buffer = Vec::new();
16133                let range = location.range.to_point(buffer);
16134                ranges_for_buffer.push(range.clone());
16135
16136                while let Some(next_location) = locations.peek() {
16137                    if next_location.buffer == location.buffer {
16138                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16139                        locations.next();
16140                    } else {
16141                        break;
16142                    }
16143                }
16144
16145                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16146                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16147                    PathKey::for_buffer(&location.buffer, cx),
16148                    location.buffer.clone(),
16149                    ranges_for_buffer,
16150                    DEFAULT_MULTIBUFFER_CONTEXT,
16151                    cx,
16152                );
16153                ranges.extend(new_ranges)
16154            }
16155
16156            multibuffer.with_title(title)
16157        });
16158
16159        let editor = cx.new(|cx| {
16160            Editor::for_multibuffer(
16161                excerpt_buffer,
16162                Some(workspace.project().clone()),
16163                window,
16164                cx,
16165            )
16166        });
16167        editor.update(cx, |editor, cx| {
16168            match multibuffer_selection_mode {
16169                MultibufferSelectionMode::First => {
16170                    if let Some(first_range) = ranges.first() {
16171                        editor.change_selections(
16172                            SelectionEffects::no_scroll(),
16173                            window,
16174                            cx,
16175                            |selections| {
16176                                selections.clear_disjoint();
16177                                selections
16178                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16179                            },
16180                        );
16181                    }
16182                    editor.highlight_background::<Self>(
16183                        &ranges,
16184                        |theme| theme.colors().editor_highlighted_line_background,
16185                        cx,
16186                    );
16187                }
16188                MultibufferSelectionMode::All => {
16189                    editor.change_selections(
16190                        SelectionEffects::no_scroll(),
16191                        window,
16192                        cx,
16193                        |selections| {
16194                            selections.clear_disjoint();
16195                            selections.select_anchor_ranges(ranges);
16196                        },
16197                    );
16198                }
16199            }
16200            editor.register_buffers_with_language_servers(cx);
16201        });
16202
16203        let item = Box::new(editor);
16204        let item_id = item.item_id();
16205
16206        if split {
16207            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16208        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16209            let (preview_item_id, preview_item_idx) =
16210                workspace.active_pane().read_with(cx, |pane, _| {
16211                    (pane.preview_item_id(), pane.preview_item_idx())
16212                });
16213
16214            workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16215
16216            if let Some(preview_item_id) = preview_item_id {
16217                workspace.active_pane().update(cx, |pane, cx| {
16218                    pane.remove_item(preview_item_id, false, false, window, cx);
16219                });
16220            }
16221        } else {
16222            workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16223        }
16224        workspace.active_pane().update(cx, |pane, cx| {
16225            pane.set_preview_item_id(Some(item_id), cx);
16226        });
16227    }
16228
16229    pub fn rename(
16230        &mut self,
16231        _: &Rename,
16232        window: &mut Window,
16233        cx: &mut Context<Self>,
16234    ) -> Option<Task<Result<()>>> {
16235        use language::ToOffset as _;
16236
16237        let provider = self.semantics_provider.clone()?;
16238        let selection = self.selections.newest_anchor().clone();
16239        let (cursor_buffer, cursor_buffer_position) = self
16240            .buffer
16241            .read(cx)
16242            .text_anchor_for_position(selection.head(), cx)?;
16243        let (tail_buffer, cursor_buffer_position_end) = self
16244            .buffer
16245            .read(cx)
16246            .text_anchor_for_position(selection.tail(), cx)?;
16247        if tail_buffer != cursor_buffer {
16248            return None;
16249        }
16250
16251        let snapshot = cursor_buffer.read(cx).snapshot();
16252        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16253        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16254        let prepare_rename = provider
16255            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16256            .unwrap_or_else(|| Task::ready(Ok(None)));
16257        drop(snapshot);
16258
16259        Some(cx.spawn_in(window, async move |this, cx| {
16260            let rename_range = if let Some(range) = prepare_rename.await? {
16261                Some(range)
16262            } else {
16263                this.update(cx, |this, cx| {
16264                    let buffer = this.buffer.read(cx).snapshot(cx);
16265                    let mut buffer_highlights = this
16266                        .document_highlights_for_position(selection.head(), &buffer)
16267                        .filter(|highlight| {
16268                            highlight.start.excerpt_id == selection.head().excerpt_id
16269                                && highlight.end.excerpt_id == selection.head().excerpt_id
16270                        });
16271                    buffer_highlights
16272                        .next()
16273                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16274                })?
16275            };
16276            if let Some(rename_range) = rename_range {
16277                this.update_in(cx, |this, window, cx| {
16278                    let snapshot = cursor_buffer.read(cx).snapshot();
16279                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16280                    let cursor_offset_in_rename_range =
16281                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16282                    let cursor_offset_in_rename_range_end =
16283                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16284
16285                    this.take_rename(false, window, cx);
16286                    let buffer = this.buffer.read(cx).read(cx);
16287                    let cursor_offset = selection.head().to_offset(&buffer);
16288                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16289                    let rename_end = rename_start + rename_buffer_range.len();
16290                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16291                    let mut old_highlight_id = None;
16292                    let old_name: Arc<str> = buffer
16293                        .chunks(rename_start..rename_end, true)
16294                        .map(|chunk| {
16295                            if old_highlight_id.is_none() {
16296                                old_highlight_id = chunk.syntax_highlight_id;
16297                            }
16298                            chunk.text
16299                        })
16300                        .collect::<String>()
16301                        .into();
16302
16303                    drop(buffer);
16304
16305                    // Position the selection in the rename editor so that it matches the current selection.
16306                    this.show_local_selections = false;
16307                    let rename_editor = cx.new(|cx| {
16308                        let mut editor = Editor::single_line(window, cx);
16309                        editor.buffer.update(cx, |buffer, cx| {
16310                            buffer.edit([(0..0, old_name.clone())], None, cx)
16311                        });
16312                        let rename_selection_range = match cursor_offset_in_rename_range
16313                            .cmp(&cursor_offset_in_rename_range_end)
16314                        {
16315                            Ordering::Equal => {
16316                                editor.select_all(&SelectAll, window, cx);
16317                                return editor;
16318                            }
16319                            Ordering::Less => {
16320                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16321                            }
16322                            Ordering::Greater => {
16323                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16324                            }
16325                        };
16326                        if rename_selection_range.end > old_name.len() {
16327                            editor.select_all(&SelectAll, window, cx);
16328                        } else {
16329                            editor.change_selections(Default::default(), window, cx, |s| {
16330                                s.select_ranges([rename_selection_range]);
16331                            });
16332                        }
16333                        editor
16334                    });
16335                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16336                        if e == &EditorEvent::Focused {
16337                            cx.emit(EditorEvent::FocusedIn)
16338                        }
16339                    })
16340                    .detach();
16341
16342                    let write_highlights =
16343                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16344                    let read_highlights =
16345                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16346                    let ranges = write_highlights
16347                        .iter()
16348                        .flat_map(|(_, ranges)| ranges.iter())
16349                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16350                        .cloned()
16351                        .collect();
16352
16353                    this.highlight_text::<Rename>(
16354                        ranges,
16355                        HighlightStyle {
16356                            fade_out: Some(0.6),
16357                            ..Default::default()
16358                        },
16359                        cx,
16360                    );
16361                    let rename_focus_handle = rename_editor.focus_handle(cx);
16362                    window.focus(&rename_focus_handle);
16363                    let block_id = this.insert_blocks(
16364                        [BlockProperties {
16365                            style: BlockStyle::Flex,
16366                            placement: BlockPlacement::Below(range.start),
16367                            height: Some(1),
16368                            render: Arc::new({
16369                                let rename_editor = rename_editor.clone();
16370                                move |cx: &mut BlockContext| {
16371                                    let mut text_style = cx.editor_style.text.clone();
16372                                    if let Some(highlight_style) = old_highlight_id
16373                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16374                                    {
16375                                        text_style = text_style.highlight(highlight_style);
16376                                    }
16377                                    div()
16378                                        .block_mouse_except_scroll()
16379                                        .pl(cx.anchor_x)
16380                                        .child(EditorElement::new(
16381                                            &rename_editor,
16382                                            EditorStyle {
16383                                                background: cx.theme().system().transparent,
16384                                                local_player: cx.editor_style.local_player,
16385                                                text: text_style,
16386                                                scrollbar_width: cx.editor_style.scrollbar_width,
16387                                                syntax: cx.editor_style.syntax.clone(),
16388                                                status: cx.editor_style.status.clone(),
16389                                                inlay_hints_style: HighlightStyle {
16390                                                    font_weight: Some(FontWeight::BOLD),
16391                                                    ..make_inlay_hints_style(cx.app)
16392                                                },
16393                                                edit_prediction_styles: make_suggestion_styles(
16394                                                    cx.app,
16395                                                ),
16396                                                ..EditorStyle::default()
16397                                            },
16398                                        ))
16399                                        .into_any_element()
16400                                }
16401                            }),
16402                            priority: 0,
16403                        }],
16404                        Some(Autoscroll::fit()),
16405                        cx,
16406                    )[0];
16407                    this.pending_rename = Some(RenameState {
16408                        range,
16409                        old_name,
16410                        editor: rename_editor,
16411                        block_id,
16412                    });
16413                })?;
16414            }
16415
16416            Ok(())
16417        }))
16418    }
16419
16420    pub fn confirm_rename(
16421        &mut self,
16422        _: &ConfirmRename,
16423        window: &mut Window,
16424        cx: &mut Context<Self>,
16425    ) -> Option<Task<Result<()>>> {
16426        let rename = self.take_rename(false, window, cx)?;
16427        let workspace = self.workspace()?.downgrade();
16428        let (buffer, start) = self
16429            .buffer
16430            .read(cx)
16431            .text_anchor_for_position(rename.range.start, cx)?;
16432        let (end_buffer, _) = self
16433            .buffer
16434            .read(cx)
16435            .text_anchor_for_position(rename.range.end, cx)?;
16436        if buffer != end_buffer {
16437            return None;
16438        }
16439
16440        let old_name = rename.old_name;
16441        let new_name = rename.editor.read(cx).text(cx);
16442
16443        let rename = self.semantics_provider.as_ref()?.perform_rename(
16444            &buffer,
16445            start,
16446            new_name.clone(),
16447            cx,
16448        )?;
16449
16450        Some(cx.spawn_in(window, async move |editor, cx| {
16451            let project_transaction = rename.await?;
16452            Self::open_project_transaction(
16453                &editor,
16454                workspace,
16455                project_transaction,
16456                format!("Rename: {}{}", old_name, new_name),
16457                cx,
16458            )
16459            .await?;
16460
16461            editor.update(cx, |editor, cx| {
16462                editor.refresh_document_highlights(cx);
16463            })?;
16464            Ok(())
16465        }))
16466    }
16467
16468    fn take_rename(
16469        &mut self,
16470        moving_cursor: bool,
16471        window: &mut Window,
16472        cx: &mut Context<Self>,
16473    ) -> Option<RenameState> {
16474        let rename = self.pending_rename.take()?;
16475        if rename.editor.focus_handle(cx).is_focused(window) {
16476            window.focus(&self.focus_handle);
16477        }
16478
16479        self.remove_blocks(
16480            [rename.block_id].into_iter().collect(),
16481            Some(Autoscroll::fit()),
16482            cx,
16483        );
16484        self.clear_highlights::<Rename>(cx);
16485        self.show_local_selections = true;
16486
16487        if moving_cursor {
16488            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16489                editor.selections.newest::<usize>(cx).head()
16490            });
16491
16492            // Update the selection to match the position of the selection inside
16493            // the rename editor.
16494            let snapshot = self.buffer.read(cx).read(cx);
16495            let rename_range = rename.range.to_offset(&snapshot);
16496            let cursor_in_editor = snapshot
16497                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16498                .min(rename_range.end);
16499            drop(snapshot);
16500
16501            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16502                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16503            });
16504        } else {
16505            self.refresh_document_highlights(cx);
16506        }
16507
16508        Some(rename)
16509    }
16510
16511    pub fn pending_rename(&self) -> Option<&RenameState> {
16512        self.pending_rename.as_ref()
16513    }
16514
16515    fn format(
16516        &mut self,
16517        _: &Format,
16518        window: &mut Window,
16519        cx: &mut Context<Self>,
16520    ) -> Option<Task<Result<()>>> {
16521        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16522
16523        let project = match &self.project {
16524            Some(project) => project.clone(),
16525            None => return None,
16526        };
16527
16528        Some(self.perform_format(
16529            project,
16530            FormatTrigger::Manual,
16531            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16532            window,
16533            cx,
16534        ))
16535    }
16536
16537    fn format_selections(
16538        &mut self,
16539        _: &FormatSelections,
16540        window: &mut Window,
16541        cx: &mut Context<Self>,
16542    ) -> Option<Task<Result<()>>> {
16543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16544
16545        let project = match &self.project {
16546            Some(project) => project.clone(),
16547            None => return None,
16548        };
16549
16550        let ranges = self
16551            .selections
16552            .all_adjusted(cx)
16553            .into_iter()
16554            .map(|selection| selection.range())
16555            .collect_vec();
16556
16557        Some(self.perform_format(
16558            project,
16559            FormatTrigger::Manual,
16560            FormatTarget::Ranges(ranges),
16561            window,
16562            cx,
16563        ))
16564    }
16565
16566    fn perform_format(
16567        &mut self,
16568        project: Entity<Project>,
16569        trigger: FormatTrigger,
16570        target: FormatTarget,
16571        window: &mut Window,
16572        cx: &mut Context<Self>,
16573    ) -> Task<Result<()>> {
16574        let buffer = self.buffer.clone();
16575        let (buffers, target) = match target {
16576            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16577            FormatTarget::Ranges(selection_ranges) => {
16578                let multi_buffer = buffer.read(cx);
16579                let snapshot = multi_buffer.read(cx);
16580                let mut buffers = HashSet::default();
16581                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16582                    BTreeMap::new();
16583                for selection_range in selection_ranges {
16584                    for (buffer, buffer_range, _) in
16585                        snapshot.range_to_buffer_ranges(selection_range)
16586                    {
16587                        let buffer_id = buffer.remote_id();
16588                        let start = buffer.anchor_before(buffer_range.start);
16589                        let end = buffer.anchor_after(buffer_range.end);
16590                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16591                        buffer_id_to_ranges
16592                            .entry(buffer_id)
16593                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16594                            .or_insert_with(|| vec![start..end]);
16595                    }
16596                }
16597                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16598            }
16599        };
16600
16601        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16602        let selections_prev = transaction_id_prev
16603            .and_then(|transaction_id_prev| {
16604                // default to selections as they were after the last edit, if we have them,
16605                // instead of how they are now.
16606                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16607                // will take you back to where you made the last edit, instead of staying where you scrolled
16608                self.selection_history
16609                    .transaction(transaction_id_prev)
16610                    .map(|t| t.0.clone())
16611            })
16612            .unwrap_or_else(|| {
16613                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16614                self.selections.disjoint_anchors()
16615            });
16616
16617        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16618        let format = project.update(cx, |project, cx| {
16619            project.format(buffers, target, true, trigger, cx)
16620        });
16621
16622        cx.spawn_in(window, async move |editor, cx| {
16623            let transaction = futures::select_biased! {
16624                transaction = format.log_err().fuse() => transaction,
16625                () = timeout => {
16626                    log::warn!("timed out waiting for formatting");
16627                    None
16628                }
16629            };
16630
16631            buffer
16632                .update(cx, |buffer, cx| {
16633                    if let Some(transaction) = transaction
16634                        && !buffer.is_singleton()
16635                    {
16636                        buffer.push_transaction(&transaction.0, cx);
16637                    }
16638                    cx.notify();
16639                })
16640                .ok();
16641
16642            if let Some(transaction_id_now) =
16643                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16644            {
16645                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16646                if has_new_transaction {
16647                    _ = editor.update(cx, |editor, _| {
16648                        editor
16649                            .selection_history
16650                            .insert_transaction(transaction_id_now, selections_prev);
16651                    });
16652                }
16653            }
16654
16655            Ok(())
16656        })
16657    }
16658
16659    fn organize_imports(
16660        &mut self,
16661        _: &OrganizeImports,
16662        window: &mut Window,
16663        cx: &mut Context<Self>,
16664    ) -> Option<Task<Result<()>>> {
16665        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16666        let project = match &self.project {
16667            Some(project) => project.clone(),
16668            None => return None,
16669        };
16670        Some(self.perform_code_action_kind(
16671            project,
16672            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16673            window,
16674            cx,
16675        ))
16676    }
16677
16678    fn perform_code_action_kind(
16679        &mut self,
16680        project: Entity<Project>,
16681        kind: CodeActionKind,
16682        window: &mut Window,
16683        cx: &mut Context<Self>,
16684    ) -> Task<Result<()>> {
16685        let buffer = self.buffer.clone();
16686        let buffers = buffer.read(cx).all_buffers();
16687        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16688        let apply_action = project.update(cx, |project, cx| {
16689            project.apply_code_action_kind(buffers, kind, true, cx)
16690        });
16691        cx.spawn_in(window, async move |_, cx| {
16692            let transaction = futures::select_biased! {
16693                () = timeout => {
16694                    log::warn!("timed out waiting for executing code action");
16695                    None
16696                }
16697                transaction = apply_action.log_err().fuse() => transaction,
16698            };
16699            buffer
16700                .update(cx, |buffer, cx| {
16701                    // check if we need this
16702                    if let Some(transaction) = transaction
16703                        && !buffer.is_singleton()
16704                    {
16705                        buffer.push_transaction(&transaction.0, cx);
16706                    }
16707                    cx.notify();
16708                })
16709                .ok();
16710            Ok(())
16711        })
16712    }
16713
16714    pub fn restart_language_server(
16715        &mut self,
16716        _: &RestartLanguageServer,
16717        _: &mut Window,
16718        cx: &mut Context<Self>,
16719    ) {
16720        if let Some(project) = self.project.clone() {
16721            self.buffer.update(cx, |multi_buffer, cx| {
16722                project.update(cx, |project, cx| {
16723                    project.restart_language_servers_for_buffers(
16724                        multi_buffer.all_buffers().into_iter().collect(),
16725                        HashSet::default(),
16726                        cx,
16727                    );
16728                });
16729            })
16730        }
16731    }
16732
16733    pub fn stop_language_server(
16734        &mut self,
16735        _: &StopLanguageServer,
16736        _: &mut Window,
16737        cx: &mut Context<Self>,
16738    ) {
16739        if let Some(project) = self.project.clone() {
16740            self.buffer.update(cx, |multi_buffer, cx| {
16741                project.update(cx, |project, cx| {
16742                    project.stop_language_servers_for_buffers(
16743                        multi_buffer.all_buffers().into_iter().collect(),
16744                        HashSet::default(),
16745                        cx,
16746                    );
16747                    cx.emit(project::Event::RefreshInlayHints);
16748                });
16749            });
16750        }
16751    }
16752
16753    fn cancel_language_server_work(
16754        workspace: &mut Workspace,
16755        _: &actions::CancelLanguageServerWork,
16756        _: &mut Window,
16757        cx: &mut Context<Workspace>,
16758    ) {
16759        let project = workspace.project();
16760        let buffers = workspace
16761            .active_item(cx)
16762            .and_then(|item| item.act_as::<Editor>(cx))
16763            .map_or(HashSet::default(), |editor| {
16764                editor.read(cx).buffer.read(cx).all_buffers()
16765            });
16766        project.update(cx, |project, cx| {
16767            project.cancel_language_server_work_for_buffers(buffers, cx);
16768        });
16769    }
16770
16771    fn show_character_palette(
16772        &mut self,
16773        _: &ShowCharacterPalette,
16774        window: &mut Window,
16775        _: &mut Context<Self>,
16776    ) {
16777        window.show_character_palette();
16778    }
16779
16780    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16781        if !self.diagnostics_enabled() {
16782            return;
16783        }
16784
16785        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16786            let buffer = self.buffer.read(cx).snapshot(cx);
16787            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16788            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16789            let is_valid = buffer
16790                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16791                .any(|entry| {
16792                    entry.diagnostic.is_primary
16793                        && !entry.range.is_empty()
16794                        && entry.range.start == primary_range_start
16795                        && entry.diagnostic.message == active_diagnostics.active_message
16796                });
16797
16798            if !is_valid {
16799                self.dismiss_diagnostics(cx);
16800            }
16801        }
16802    }
16803
16804    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16805        match &self.active_diagnostics {
16806            ActiveDiagnostic::Group(group) => Some(group),
16807            _ => None,
16808        }
16809    }
16810
16811    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16812        if !self.diagnostics_enabled() {
16813            return;
16814        }
16815        self.dismiss_diagnostics(cx);
16816        self.active_diagnostics = ActiveDiagnostic::All;
16817    }
16818
16819    fn activate_diagnostics(
16820        &mut self,
16821        buffer_id: BufferId,
16822        diagnostic: DiagnosticEntry<usize>,
16823        window: &mut Window,
16824        cx: &mut Context<Self>,
16825    ) {
16826        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16827            return;
16828        }
16829        self.dismiss_diagnostics(cx);
16830        let snapshot = self.snapshot(window, cx);
16831        let buffer = self.buffer.read(cx).snapshot(cx);
16832        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16833            return;
16834        };
16835
16836        let diagnostic_group = buffer
16837            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16838            .collect::<Vec<_>>();
16839
16840        let blocks =
16841            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16842
16843        let blocks = self.display_map.update(cx, |display_map, cx| {
16844            display_map.insert_blocks(blocks, cx).into_iter().collect()
16845        });
16846        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16847            active_range: buffer.anchor_before(diagnostic.range.start)
16848                ..buffer.anchor_after(diagnostic.range.end),
16849            active_message: diagnostic.diagnostic.message.clone(),
16850            group_id: diagnostic.diagnostic.group_id,
16851            blocks,
16852        });
16853        cx.notify();
16854    }
16855
16856    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16857        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16858            return;
16859        };
16860
16861        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16862        if let ActiveDiagnostic::Group(group) = prev {
16863            self.display_map.update(cx, |display_map, cx| {
16864                display_map.remove_blocks(group.blocks, cx);
16865            });
16866            cx.notify();
16867        }
16868    }
16869
16870    /// Disable inline diagnostics rendering for this editor.
16871    pub fn disable_inline_diagnostics(&mut self) {
16872        self.inline_diagnostics_enabled = false;
16873        self.inline_diagnostics_update = Task::ready(());
16874        self.inline_diagnostics.clear();
16875    }
16876
16877    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16878        self.diagnostics_enabled = false;
16879        self.dismiss_diagnostics(cx);
16880        self.inline_diagnostics_update = Task::ready(());
16881        self.inline_diagnostics.clear();
16882    }
16883
16884    pub fn diagnostics_enabled(&self) -> bool {
16885        self.diagnostics_enabled && self.mode.is_full()
16886    }
16887
16888    pub fn inline_diagnostics_enabled(&self) -> bool {
16889        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16890    }
16891
16892    pub fn show_inline_diagnostics(&self) -> bool {
16893        self.show_inline_diagnostics
16894    }
16895
16896    pub fn toggle_inline_diagnostics(
16897        &mut self,
16898        _: &ToggleInlineDiagnostics,
16899        window: &mut Window,
16900        cx: &mut Context<Editor>,
16901    ) {
16902        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16903        self.refresh_inline_diagnostics(false, window, cx);
16904    }
16905
16906    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16907        self.diagnostics_max_severity = severity;
16908        self.display_map.update(cx, |display_map, _| {
16909            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16910        });
16911    }
16912
16913    pub fn toggle_diagnostics(
16914        &mut self,
16915        _: &ToggleDiagnostics,
16916        window: &mut Window,
16917        cx: &mut Context<Editor>,
16918    ) {
16919        if !self.diagnostics_enabled() {
16920            return;
16921        }
16922
16923        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16924            EditorSettings::get_global(cx)
16925                .diagnostics_max_severity
16926                .filter(|severity| severity != &DiagnosticSeverity::Off)
16927                .unwrap_or(DiagnosticSeverity::Hint)
16928        } else {
16929            DiagnosticSeverity::Off
16930        };
16931        self.set_max_diagnostics_severity(new_severity, cx);
16932        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16933            self.active_diagnostics = ActiveDiagnostic::None;
16934            self.inline_diagnostics_update = Task::ready(());
16935            self.inline_diagnostics.clear();
16936        } else {
16937            self.refresh_inline_diagnostics(false, window, cx);
16938        }
16939
16940        cx.notify();
16941    }
16942
16943    pub fn toggle_minimap(
16944        &mut self,
16945        _: &ToggleMinimap,
16946        window: &mut Window,
16947        cx: &mut Context<Editor>,
16948    ) {
16949        if self.supports_minimap(cx) {
16950            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16951        }
16952    }
16953
16954    fn refresh_inline_diagnostics(
16955        &mut self,
16956        debounce: bool,
16957        window: &mut Window,
16958        cx: &mut Context<Self>,
16959    ) {
16960        let max_severity = ProjectSettings::get_global(cx)
16961            .diagnostics
16962            .inline
16963            .max_severity
16964            .unwrap_or(self.diagnostics_max_severity);
16965
16966        if !self.inline_diagnostics_enabled()
16967            || !self.show_inline_diagnostics
16968            || max_severity == DiagnosticSeverity::Off
16969        {
16970            self.inline_diagnostics_update = Task::ready(());
16971            self.inline_diagnostics.clear();
16972            return;
16973        }
16974
16975        let debounce_ms = ProjectSettings::get_global(cx)
16976            .diagnostics
16977            .inline
16978            .update_debounce_ms;
16979        let debounce = if debounce && debounce_ms > 0 {
16980            Some(Duration::from_millis(debounce_ms))
16981        } else {
16982            None
16983        };
16984        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16985            if let Some(debounce) = debounce {
16986                cx.background_executor().timer(debounce).await;
16987            }
16988            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16989                editor
16990                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16991                    .ok()
16992            }) else {
16993                return;
16994            };
16995
16996            let new_inline_diagnostics = cx
16997                .background_spawn(async move {
16998                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16999                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17000                        let message = diagnostic_entry
17001                            .diagnostic
17002                            .message
17003                            .split_once('\n')
17004                            .map(|(line, _)| line)
17005                            .map(SharedString::new)
17006                            .unwrap_or_else(|| {
17007                                SharedString::from(diagnostic_entry.diagnostic.message)
17008                            });
17009                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17010                        let (Ok(i) | Err(i)) = inline_diagnostics
17011                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17012                        inline_diagnostics.insert(
17013                            i,
17014                            (
17015                                start_anchor,
17016                                InlineDiagnostic {
17017                                    message,
17018                                    group_id: diagnostic_entry.diagnostic.group_id,
17019                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17020                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17021                                    severity: diagnostic_entry.diagnostic.severity,
17022                                },
17023                            ),
17024                        );
17025                    }
17026                    inline_diagnostics
17027                })
17028                .await;
17029
17030            editor
17031                .update(cx, |editor, cx| {
17032                    editor.inline_diagnostics = new_inline_diagnostics;
17033                    cx.notify();
17034                })
17035                .ok();
17036        });
17037    }
17038
17039    fn pull_diagnostics(
17040        &mut self,
17041        buffer_id: Option<BufferId>,
17042        window: &Window,
17043        cx: &mut Context<Self>,
17044    ) -> Option<()> {
17045        if !self.mode().is_full() {
17046            return None;
17047        }
17048        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17049            .diagnostics
17050            .lsp_pull_diagnostics;
17051        if !pull_diagnostics_settings.enabled {
17052            return None;
17053        }
17054        let project = self.project()?.downgrade();
17055        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17056        let mut buffers = self.buffer.read(cx).all_buffers();
17057        if let Some(buffer_id) = buffer_id {
17058            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17059        }
17060
17061        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17062            cx.background_executor().timer(debounce).await;
17063
17064            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17065                buffers
17066                    .into_iter()
17067                    .filter_map(|buffer| {
17068                        project
17069                            .update(cx, |project, cx| {
17070                                project.lsp_store().update(cx, |lsp_store, cx| {
17071                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17072                                })
17073                            })
17074                            .ok()
17075                    })
17076                    .collect::<FuturesUnordered<_>>()
17077            }) else {
17078                return;
17079            };
17080
17081            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17082                match pull_task {
17083                    Ok(()) => {
17084                        if editor
17085                            .update_in(cx, |editor, window, cx| {
17086                                editor.update_diagnostics_state(window, cx);
17087                            })
17088                            .is_err()
17089                        {
17090                            return;
17091                        }
17092                    }
17093                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17094                }
17095            }
17096        });
17097
17098        Some(())
17099    }
17100
17101    pub fn set_selections_from_remote(
17102        &mut self,
17103        selections: Vec<Selection<Anchor>>,
17104        pending_selection: Option<Selection<Anchor>>,
17105        window: &mut Window,
17106        cx: &mut Context<Self>,
17107    ) {
17108        let old_cursor_position = self.selections.newest_anchor().head();
17109        self.selections.change_with(cx, |s| {
17110            s.select_anchors(selections);
17111            if let Some(pending_selection) = pending_selection {
17112                s.set_pending(pending_selection, SelectMode::Character);
17113            } else {
17114                s.clear_pending();
17115            }
17116        });
17117        self.selections_did_change(
17118            false,
17119            &old_cursor_position,
17120            SelectionEffects::default(),
17121            window,
17122            cx,
17123        );
17124    }
17125
17126    pub fn transact(
17127        &mut self,
17128        window: &mut Window,
17129        cx: &mut Context<Self>,
17130        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17131    ) -> Option<TransactionId> {
17132        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17133            this.start_transaction_at(Instant::now(), window, cx);
17134            update(this, window, cx);
17135            this.end_transaction_at(Instant::now(), cx)
17136        })
17137    }
17138
17139    pub fn start_transaction_at(
17140        &mut self,
17141        now: Instant,
17142        window: &mut Window,
17143        cx: &mut Context<Self>,
17144    ) -> Option<TransactionId> {
17145        self.end_selection(window, cx);
17146        if let Some(tx_id) = self
17147            .buffer
17148            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17149        {
17150            self.selection_history
17151                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17152            cx.emit(EditorEvent::TransactionBegun {
17153                transaction_id: tx_id,
17154            });
17155            Some(tx_id)
17156        } else {
17157            None
17158        }
17159    }
17160
17161    pub fn end_transaction_at(
17162        &mut self,
17163        now: Instant,
17164        cx: &mut Context<Self>,
17165    ) -> Option<TransactionId> {
17166        if let Some(transaction_id) = self
17167            .buffer
17168            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17169        {
17170            if let Some((_, end_selections)) =
17171                self.selection_history.transaction_mut(transaction_id)
17172            {
17173                *end_selections = Some(self.selections.disjoint_anchors());
17174            } else {
17175                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17176            }
17177
17178            cx.emit(EditorEvent::Edited { transaction_id });
17179            Some(transaction_id)
17180        } else {
17181            None
17182        }
17183    }
17184
17185    pub fn modify_transaction_selection_history(
17186        &mut self,
17187        transaction_id: TransactionId,
17188        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17189    ) -> bool {
17190        self.selection_history
17191            .transaction_mut(transaction_id)
17192            .map(modify)
17193            .is_some()
17194    }
17195
17196    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17197        if self.selection_mark_mode {
17198            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17199                s.move_with(|_, sel| {
17200                    sel.collapse_to(sel.head(), SelectionGoal::None);
17201                });
17202            })
17203        }
17204        self.selection_mark_mode = true;
17205        cx.notify();
17206    }
17207
17208    pub fn swap_selection_ends(
17209        &mut self,
17210        _: &actions::SwapSelectionEnds,
17211        window: &mut Window,
17212        cx: &mut Context<Self>,
17213    ) {
17214        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17215            s.move_with(|_, sel| {
17216                if sel.start != sel.end {
17217                    sel.reversed = !sel.reversed
17218                }
17219            });
17220        });
17221        self.request_autoscroll(Autoscroll::newest(), cx);
17222        cx.notify();
17223    }
17224
17225    pub fn toggle_focus(
17226        workspace: &mut Workspace,
17227        _: &actions::ToggleFocus,
17228        window: &mut Window,
17229        cx: &mut Context<Workspace>,
17230    ) {
17231        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17232            return;
17233        };
17234        workspace.activate_item(&item, true, true, window, cx);
17235    }
17236
17237    pub fn toggle_fold(
17238        &mut self,
17239        _: &actions::ToggleFold,
17240        window: &mut Window,
17241        cx: &mut Context<Self>,
17242    ) {
17243        if self.is_singleton(cx) {
17244            let selection = self.selections.newest::<Point>(cx);
17245
17246            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17247            let range = if selection.is_empty() {
17248                let point = selection.head().to_display_point(&display_map);
17249                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17250                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17251                    .to_point(&display_map);
17252                start..end
17253            } else {
17254                selection.range()
17255            };
17256            if display_map.folds_in_range(range).next().is_some() {
17257                self.unfold_lines(&Default::default(), window, cx)
17258            } else {
17259                self.fold(&Default::default(), window, cx)
17260            }
17261        } else {
17262            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17263            let buffer_ids: HashSet<_> = self
17264                .selections
17265                .disjoint_anchor_ranges()
17266                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17267                .collect();
17268
17269            let should_unfold = buffer_ids
17270                .iter()
17271                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17272
17273            for buffer_id in buffer_ids {
17274                if should_unfold {
17275                    self.unfold_buffer(buffer_id, cx);
17276                } else {
17277                    self.fold_buffer(buffer_id, cx);
17278                }
17279            }
17280        }
17281    }
17282
17283    pub fn toggle_fold_recursive(
17284        &mut self,
17285        _: &actions::ToggleFoldRecursive,
17286        window: &mut Window,
17287        cx: &mut Context<Self>,
17288    ) {
17289        let selection = self.selections.newest::<Point>(cx);
17290
17291        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17292        let range = if selection.is_empty() {
17293            let point = selection.head().to_display_point(&display_map);
17294            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17295            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17296                .to_point(&display_map);
17297            start..end
17298        } else {
17299            selection.range()
17300        };
17301        if display_map.folds_in_range(range).next().is_some() {
17302            self.unfold_recursive(&Default::default(), window, cx)
17303        } else {
17304            self.fold_recursive(&Default::default(), window, cx)
17305        }
17306    }
17307
17308    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17309        if self.is_singleton(cx) {
17310            let mut to_fold = Vec::new();
17311            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17312            let selections = self.selections.all_adjusted(cx);
17313
17314            for selection in selections {
17315                let range = selection.range().sorted();
17316                let buffer_start_row = range.start.row;
17317
17318                if range.start.row != range.end.row {
17319                    let mut found = false;
17320                    let mut row = range.start.row;
17321                    while row <= range.end.row {
17322                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17323                        {
17324                            found = true;
17325                            row = crease.range().end.row + 1;
17326                            to_fold.push(crease);
17327                        } else {
17328                            row += 1
17329                        }
17330                    }
17331                    if found {
17332                        continue;
17333                    }
17334                }
17335
17336                for row in (0..=range.start.row).rev() {
17337                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17338                        && crease.range().end.row >= buffer_start_row
17339                    {
17340                        to_fold.push(crease);
17341                        if row <= range.start.row {
17342                            break;
17343                        }
17344                    }
17345                }
17346            }
17347
17348            self.fold_creases(to_fold, true, window, cx);
17349        } else {
17350            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17351            let buffer_ids = self
17352                .selections
17353                .disjoint_anchor_ranges()
17354                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17355                .collect::<HashSet<_>>();
17356            for buffer_id in buffer_ids {
17357                self.fold_buffer(buffer_id, cx);
17358            }
17359        }
17360    }
17361
17362    pub fn toggle_fold_all(
17363        &mut self,
17364        _: &actions::ToggleFoldAll,
17365        window: &mut Window,
17366        cx: &mut Context<Self>,
17367    ) {
17368        if self.buffer.read(cx).is_singleton() {
17369            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17370            let has_folds = display_map
17371                .folds_in_range(0..display_map.buffer_snapshot.len())
17372                .next()
17373                .is_some();
17374
17375            if has_folds {
17376                self.unfold_all(&actions::UnfoldAll, window, cx);
17377            } else {
17378                self.fold_all(&actions::FoldAll, window, cx);
17379            }
17380        } else {
17381            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17382            let should_unfold = buffer_ids
17383                .iter()
17384                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17385
17386            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17387                editor
17388                    .update_in(cx, |editor, _, cx| {
17389                        for buffer_id in buffer_ids {
17390                            if should_unfold {
17391                                editor.unfold_buffer(buffer_id, cx);
17392                            } else {
17393                                editor.fold_buffer(buffer_id, cx);
17394                            }
17395                        }
17396                    })
17397                    .ok();
17398            });
17399        }
17400    }
17401
17402    fn fold_at_level(
17403        &mut self,
17404        fold_at: &FoldAtLevel,
17405        window: &mut Window,
17406        cx: &mut Context<Self>,
17407    ) {
17408        if !self.buffer.read(cx).is_singleton() {
17409            return;
17410        }
17411
17412        let fold_at_level = fold_at.0;
17413        let snapshot = self.buffer.read(cx).snapshot(cx);
17414        let mut to_fold = Vec::new();
17415        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17416
17417        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17418            while start_row < end_row {
17419                match self
17420                    .snapshot(window, cx)
17421                    .crease_for_buffer_row(MultiBufferRow(start_row))
17422                {
17423                    Some(crease) => {
17424                        let nested_start_row = crease.range().start.row + 1;
17425                        let nested_end_row = crease.range().end.row;
17426
17427                        if current_level < fold_at_level {
17428                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17429                        } else if current_level == fold_at_level {
17430                            to_fold.push(crease);
17431                        }
17432
17433                        start_row = nested_end_row + 1;
17434                    }
17435                    None => start_row += 1,
17436                }
17437            }
17438        }
17439
17440        self.fold_creases(to_fold, true, window, cx);
17441    }
17442
17443    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17444        if self.buffer.read(cx).is_singleton() {
17445            let mut fold_ranges = Vec::new();
17446            let snapshot = self.buffer.read(cx).snapshot(cx);
17447
17448            for row in 0..snapshot.max_row().0 {
17449                if let Some(foldable_range) = self
17450                    .snapshot(window, cx)
17451                    .crease_for_buffer_row(MultiBufferRow(row))
17452                {
17453                    fold_ranges.push(foldable_range);
17454                }
17455            }
17456
17457            self.fold_creases(fold_ranges, true, window, cx);
17458        } else {
17459            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17460                editor
17461                    .update_in(cx, |editor, _, cx| {
17462                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17463                            editor.fold_buffer(buffer_id, cx);
17464                        }
17465                    })
17466                    .ok();
17467            });
17468        }
17469    }
17470
17471    pub fn fold_function_bodies(
17472        &mut self,
17473        _: &actions::FoldFunctionBodies,
17474        window: &mut Window,
17475        cx: &mut Context<Self>,
17476    ) {
17477        let snapshot = self.buffer.read(cx).snapshot(cx);
17478
17479        let ranges = snapshot
17480            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17481            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17482            .collect::<Vec<_>>();
17483
17484        let creases = ranges
17485            .into_iter()
17486            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17487            .collect();
17488
17489        self.fold_creases(creases, true, window, cx);
17490    }
17491
17492    pub fn fold_recursive(
17493        &mut self,
17494        _: &actions::FoldRecursive,
17495        window: &mut Window,
17496        cx: &mut Context<Self>,
17497    ) {
17498        let mut to_fold = Vec::new();
17499        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17500        let selections = self.selections.all_adjusted(cx);
17501
17502        for selection in selections {
17503            let range = selection.range().sorted();
17504            let buffer_start_row = range.start.row;
17505
17506            if range.start.row != range.end.row {
17507                let mut found = false;
17508                for row in range.start.row..=range.end.row {
17509                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17510                        found = true;
17511                        to_fold.push(crease);
17512                    }
17513                }
17514                if found {
17515                    continue;
17516                }
17517            }
17518
17519            for row in (0..=range.start.row).rev() {
17520                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17521                    if crease.range().end.row >= buffer_start_row {
17522                        to_fold.push(crease);
17523                    } else {
17524                        break;
17525                    }
17526                }
17527            }
17528        }
17529
17530        self.fold_creases(to_fold, true, window, cx);
17531    }
17532
17533    pub fn fold_at(
17534        &mut self,
17535        buffer_row: MultiBufferRow,
17536        window: &mut Window,
17537        cx: &mut Context<Self>,
17538    ) {
17539        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17540
17541        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17542            let autoscroll = self
17543                .selections
17544                .all::<Point>(cx)
17545                .iter()
17546                .any(|selection| crease.range().overlaps(&selection.range()));
17547
17548            self.fold_creases(vec![crease], autoscroll, window, cx);
17549        }
17550    }
17551
17552    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17553        if self.is_singleton(cx) {
17554            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17555            let buffer = &display_map.buffer_snapshot;
17556            let selections = self.selections.all::<Point>(cx);
17557            let ranges = selections
17558                .iter()
17559                .map(|s| {
17560                    let range = s.display_range(&display_map).sorted();
17561                    let mut start = range.start.to_point(&display_map);
17562                    let mut end = range.end.to_point(&display_map);
17563                    start.column = 0;
17564                    end.column = buffer.line_len(MultiBufferRow(end.row));
17565                    start..end
17566                })
17567                .collect::<Vec<_>>();
17568
17569            self.unfold_ranges(&ranges, true, true, cx);
17570        } else {
17571            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17572            let buffer_ids = self
17573                .selections
17574                .disjoint_anchor_ranges()
17575                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17576                .collect::<HashSet<_>>();
17577            for buffer_id in buffer_ids {
17578                self.unfold_buffer(buffer_id, cx);
17579            }
17580        }
17581    }
17582
17583    pub fn unfold_recursive(
17584        &mut self,
17585        _: &UnfoldRecursive,
17586        _window: &mut Window,
17587        cx: &mut Context<Self>,
17588    ) {
17589        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17590        let selections = self.selections.all::<Point>(cx);
17591        let ranges = selections
17592            .iter()
17593            .map(|s| {
17594                let mut range = s.display_range(&display_map).sorted();
17595                *range.start.column_mut() = 0;
17596                *range.end.column_mut() = display_map.line_len(range.end.row());
17597                let start = range.start.to_point(&display_map);
17598                let end = range.end.to_point(&display_map);
17599                start..end
17600            })
17601            .collect::<Vec<_>>();
17602
17603        self.unfold_ranges(&ranges, true, true, cx);
17604    }
17605
17606    pub fn unfold_at(
17607        &mut self,
17608        buffer_row: MultiBufferRow,
17609        _window: &mut Window,
17610        cx: &mut Context<Self>,
17611    ) {
17612        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17613
17614        let intersection_range = Point::new(buffer_row.0, 0)
17615            ..Point::new(
17616                buffer_row.0,
17617                display_map.buffer_snapshot.line_len(buffer_row),
17618            );
17619
17620        let autoscroll = self
17621            .selections
17622            .all::<Point>(cx)
17623            .iter()
17624            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17625
17626        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17627    }
17628
17629    pub fn unfold_all(
17630        &mut self,
17631        _: &actions::UnfoldAll,
17632        _window: &mut Window,
17633        cx: &mut Context<Self>,
17634    ) {
17635        if self.buffer.read(cx).is_singleton() {
17636            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17637            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17638        } else {
17639            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17640                editor
17641                    .update(cx, |editor, cx| {
17642                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17643                            editor.unfold_buffer(buffer_id, cx);
17644                        }
17645                    })
17646                    .ok();
17647            });
17648        }
17649    }
17650
17651    pub fn fold_selected_ranges(
17652        &mut self,
17653        _: &FoldSelectedRanges,
17654        window: &mut Window,
17655        cx: &mut Context<Self>,
17656    ) {
17657        let selections = self.selections.all_adjusted(cx);
17658        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17659        let ranges = selections
17660            .into_iter()
17661            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17662            .collect::<Vec<_>>();
17663        self.fold_creases(ranges, true, window, cx);
17664    }
17665
17666    pub fn fold_ranges<T: ToOffset + Clone>(
17667        &mut self,
17668        ranges: Vec<Range<T>>,
17669        auto_scroll: bool,
17670        window: &mut Window,
17671        cx: &mut Context<Self>,
17672    ) {
17673        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17674        let ranges = ranges
17675            .into_iter()
17676            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17677            .collect::<Vec<_>>();
17678        self.fold_creases(ranges, auto_scroll, window, cx);
17679    }
17680
17681    pub fn fold_creases<T: ToOffset + Clone>(
17682        &mut self,
17683        creases: Vec<Crease<T>>,
17684        auto_scroll: bool,
17685        _window: &mut Window,
17686        cx: &mut Context<Self>,
17687    ) {
17688        if creases.is_empty() {
17689            return;
17690        }
17691
17692        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17693
17694        if auto_scroll {
17695            self.request_autoscroll(Autoscroll::fit(), cx);
17696        }
17697
17698        cx.notify();
17699
17700        self.scrollbar_marker_state.dirty = true;
17701        self.folds_did_change(cx);
17702    }
17703
17704    /// Removes any folds whose ranges intersect any of the given ranges.
17705    pub fn unfold_ranges<T: ToOffset + Clone>(
17706        &mut self,
17707        ranges: &[Range<T>],
17708        inclusive: bool,
17709        auto_scroll: bool,
17710        cx: &mut Context<Self>,
17711    ) {
17712        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17713            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17714        });
17715        self.folds_did_change(cx);
17716    }
17717
17718    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17719        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17720            return;
17721        }
17722        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17723        self.display_map.update(cx, |display_map, cx| {
17724            display_map.fold_buffers([buffer_id], cx)
17725        });
17726        cx.emit(EditorEvent::BufferFoldToggled {
17727            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17728            folded: true,
17729        });
17730        cx.notify();
17731    }
17732
17733    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17734        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17735            return;
17736        }
17737        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17738        self.display_map.update(cx, |display_map, cx| {
17739            display_map.unfold_buffers([buffer_id], cx);
17740        });
17741        cx.emit(EditorEvent::BufferFoldToggled {
17742            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17743            folded: false,
17744        });
17745        cx.notify();
17746    }
17747
17748    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17749        self.display_map.read(cx).is_buffer_folded(buffer)
17750    }
17751
17752    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17753        self.display_map.read(cx).folded_buffers()
17754    }
17755
17756    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17757        self.display_map.update(cx, |display_map, cx| {
17758            display_map.disable_header_for_buffer(buffer_id, cx);
17759        });
17760        cx.notify();
17761    }
17762
17763    /// Removes any folds with the given ranges.
17764    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17765        &mut self,
17766        ranges: &[Range<T>],
17767        type_id: TypeId,
17768        auto_scroll: bool,
17769        cx: &mut Context<Self>,
17770    ) {
17771        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17772            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17773        });
17774        self.folds_did_change(cx);
17775    }
17776
17777    fn remove_folds_with<T: ToOffset + Clone>(
17778        &mut self,
17779        ranges: &[Range<T>],
17780        auto_scroll: bool,
17781        cx: &mut Context<Self>,
17782        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17783    ) {
17784        if ranges.is_empty() {
17785            return;
17786        }
17787
17788        let mut buffers_affected = HashSet::default();
17789        let multi_buffer = self.buffer().read(cx);
17790        for range in ranges {
17791            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17792                buffers_affected.insert(buffer.read(cx).remote_id());
17793            };
17794        }
17795
17796        self.display_map.update(cx, update);
17797
17798        if auto_scroll {
17799            self.request_autoscroll(Autoscroll::fit(), cx);
17800        }
17801
17802        cx.notify();
17803        self.scrollbar_marker_state.dirty = true;
17804        self.active_indent_guides_state.dirty = true;
17805    }
17806
17807    pub fn update_renderer_widths(
17808        &mut self,
17809        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17810        cx: &mut Context<Self>,
17811    ) -> bool {
17812        self.display_map
17813            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17814    }
17815
17816    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17817        self.display_map.read(cx).fold_placeholder.clone()
17818    }
17819
17820    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17821        self.buffer.update(cx, |buffer, cx| {
17822            buffer.set_all_diff_hunks_expanded(cx);
17823        });
17824    }
17825
17826    pub fn expand_all_diff_hunks(
17827        &mut self,
17828        _: &ExpandAllDiffHunks,
17829        _window: &mut Window,
17830        cx: &mut Context<Self>,
17831    ) {
17832        self.buffer.update(cx, |buffer, cx| {
17833            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17834        });
17835    }
17836
17837    pub fn toggle_selected_diff_hunks(
17838        &mut self,
17839        _: &ToggleSelectedDiffHunks,
17840        _window: &mut Window,
17841        cx: &mut Context<Self>,
17842    ) {
17843        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17844        self.toggle_diff_hunks_in_ranges(ranges, cx);
17845    }
17846
17847    pub fn diff_hunks_in_ranges<'a>(
17848        &'a self,
17849        ranges: &'a [Range<Anchor>],
17850        buffer: &'a MultiBufferSnapshot,
17851    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17852        ranges.iter().flat_map(move |range| {
17853            let end_excerpt_id = range.end.excerpt_id;
17854            let range = range.to_point(buffer);
17855            let mut peek_end = range.end;
17856            if range.end.row < buffer.max_row().0 {
17857                peek_end = Point::new(range.end.row + 1, 0);
17858            }
17859            buffer
17860                .diff_hunks_in_range(range.start..peek_end)
17861                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17862        })
17863    }
17864
17865    pub fn has_stageable_diff_hunks_in_ranges(
17866        &self,
17867        ranges: &[Range<Anchor>],
17868        snapshot: &MultiBufferSnapshot,
17869    ) -> bool {
17870        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17871        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17872    }
17873
17874    pub fn toggle_staged_selected_diff_hunks(
17875        &mut self,
17876        _: &::git::ToggleStaged,
17877        _: &mut Window,
17878        cx: &mut Context<Self>,
17879    ) {
17880        let snapshot = self.buffer.read(cx).snapshot(cx);
17881        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17882        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17883        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17884    }
17885
17886    pub fn set_render_diff_hunk_controls(
17887        &mut self,
17888        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17889        cx: &mut Context<Self>,
17890    ) {
17891        self.render_diff_hunk_controls = render_diff_hunk_controls;
17892        cx.notify();
17893    }
17894
17895    pub fn stage_and_next(
17896        &mut self,
17897        _: &::git::StageAndNext,
17898        window: &mut Window,
17899        cx: &mut Context<Self>,
17900    ) {
17901        self.do_stage_or_unstage_and_next(true, window, cx);
17902    }
17903
17904    pub fn unstage_and_next(
17905        &mut self,
17906        _: &::git::UnstageAndNext,
17907        window: &mut Window,
17908        cx: &mut Context<Self>,
17909    ) {
17910        self.do_stage_or_unstage_and_next(false, window, cx);
17911    }
17912
17913    pub fn stage_or_unstage_diff_hunks(
17914        &mut self,
17915        stage: bool,
17916        ranges: Vec<Range<Anchor>>,
17917        cx: &mut Context<Self>,
17918    ) {
17919        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17920        cx.spawn(async move |this, cx| {
17921            task.await?;
17922            this.update(cx, |this, cx| {
17923                let snapshot = this.buffer.read(cx).snapshot(cx);
17924                let chunk_by = this
17925                    .diff_hunks_in_ranges(&ranges, &snapshot)
17926                    .chunk_by(|hunk| hunk.buffer_id);
17927                for (buffer_id, hunks) in &chunk_by {
17928                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17929                }
17930            })
17931        })
17932        .detach_and_log_err(cx);
17933    }
17934
17935    fn save_buffers_for_ranges_if_needed(
17936        &mut self,
17937        ranges: &[Range<Anchor>],
17938        cx: &mut Context<Editor>,
17939    ) -> Task<Result<()>> {
17940        let multibuffer = self.buffer.read(cx);
17941        let snapshot = multibuffer.read(cx);
17942        let buffer_ids: HashSet<_> = ranges
17943            .iter()
17944            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17945            .collect();
17946        drop(snapshot);
17947
17948        let mut buffers = HashSet::default();
17949        for buffer_id in buffer_ids {
17950            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17951                let buffer = buffer_entity.read(cx);
17952                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17953                {
17954                    buffers.insert(buffer_entity);
17955                }
17956            }
17957        }
17958
17959        if let Some(project) = &self.project {
17960            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17961        } else {
17962            Task::ready(Ok(()))
17963        }
17964    }
17965
17966    fn do_stage_or_unstage_and_next(
17967        &mut self,
17968        stage: bool,
17969        window: &mut Window,
17970        cx: &mut Context<Self>,
17971    ) {
17972        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17973
17974        if ranges.iter().any(|range| range.start != range.end) {
17975            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17976            return;
17977        }
17978
17979        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17980        let snapshot = self.snapshot(window, cx);
17981        let position = self.selections.newest::<Point>(cx).head();
17982        let mut row = snapshot
17983            .buffer_snapshot
17984            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17985            .find(|hunk| hunk.row_range.start.0 > position.row)
17986            .map(|hunk| hunk.row_range.start);
17987
17988        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17989        // Outside of the project diff editor, wrap around to the beginning.
17990        if !all_diff_hunks_expanded {
17991            row = row.or_else(|| {
17992                snapshot
17993                    .buffer_snapshot
17994                    .diff_hunks_in_range(Point::zero()..position)
17995                    .find(|hunk| hunk.row_range.end.0 < position.row)
17996                    .map(|hunk| hunk.row_range.start)
17997            });
17998        }
17999
18000        if let Some(row) = row {
18001            let destination = Point::new(row.0, 0);
18002            let autoscroll = Autoscroll::center();
18003
18004            self.unfold_ranges(&[destination..destination], false, false, cx);
18005            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18006                s.select_ranges([destination..destination]);
18007            });
18008        }
18009    }
18010
18011    fn do_stage_or_unstage(
18012        &self,
18013        stage: bool,
18014        buffer_id: BufferId,
18015        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18016        cx: &mut App,
18017    ) -> Option<()> {
18018        let project = self.project()?;
18019        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18020        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18021        let buffer_snapshot = buffer.read(cx).snapshot();
18022        let file_exists = buffer_snapshot
18023            .file()
18024            .is_some_and(|file| file.disk_state().exists());
18025        diff.update(cx, |diff, cx| {
18026            diff.stage_or_unstage_hunks(
18027                stage,
18028                &hunks
18029                    .map(|hunk| buffer_diff::DiffHunk {
18030                        buffer_range: hunk.buffer_range,
18031                        diff_base_byte_range: hunk.diff_base_byte_range,
18032                        secondary_status: hunk.secondary_status,
18033                        range: Point::zero()..Point::zero(), // unused
18034                    })
18035                    .collect::<Vec<_>>(),
18036                &buffer_snapshot,
18037                file_exists,
18038                cx,
18039            )
18040        });
18041        None
18042    }
18043
18044    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18045        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18046        self.buffer
18047            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18048    }
18049
18050    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18051        self.buffer.update(cx, |buffer, cx| {
18052            let ranges = vec![Anchor::min()..Anchor::max()];
18053            if !buffer.all_diff_hunks_expanded()
18054                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18055            {
18056                buffer.collapse_diff_hunks(ranges, cx);
18057                true
18058            } else {
18059                false
18060            }
18061        })
18062    }
18063
18064    fn toggle_diff_hunks_in_ranges(
18065        &mut self,
18066        ranges: Vec<Range<Anchor>>,
18067        cx: &mut Context<Editor>,
18068    ) {
18069        self.buffer.update(cx, |buffer, cx| {
18070            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18071            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18072        })
18073    }
18074
18075    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18076        self.buffer.update(cx, |buffer, cx| {
18077            let snapshot = buffer.snapshot(cx);
18078            let excerpt_id = range.end.excerpt_id;
18079            let point_range = range.to_point(&snapshot);
18080            let expand = !buffer.single_hunk_is_expanded(range, cx);
18081            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18082        })
18083    }
18084
18085    pub(crate) fn apply_all_diff_hunks(
18086        &mut self,
18087        _: &ApplyAllDiffHunks,
18088        window: &mut Window,
18089        cx: &mut Context<Self>,
18090    ) {
18091        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18092
18093        let buffers = self.buffer.read(cx).all_buffers();
18094        for branch_buffer in buffers {
18095            branch_buffer.update(cx, |branch_buffer, cx| {
18096                branch_buffer.merge_into_base(Vec::new(), cx);
18097            });
18098        }
18099
18100        if let Some(project) = self.project.clone() {
18101            self.save(
18102                SaveOptions {
18103                    format: true,
18104                    autosave: false,
18105                },
18106                project,
18107                window,
18108                cx,
18109            )
18110            .detach_and_log_err(cx);
18111        }
18112    }
18113
18114    pub(crate) fn apply_selected_diff_hunks(
18115        &mut self,
18116        _: &ApplyDiffHunk,
18117        window: &mut Window,
18118        cx: &mut Context<Self>,
18119    ) {
18120        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18121        let snapshot = self.snapshot(window, cx);
18122        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18123        let mut ranges_by_buffer = HashMap::default();
18124        self.transact(window, cx, |editor, _window, cx| {
18125            for hunk in hunks {
18126                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18127                    ranges_by_buffer
18128                        .entry(buffer.clone())
18129                        .or_insert_with(Vec::new)
18130                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18131                }
18132            }
18133
18134            for (buffer, ranges) in ranges_by_buffer {
18135                buffer.update(cx, |buffer, cx| {
18136                    buffer.merge_into_base(ranges, cx);
18137                });
18138            }
18139        });
18140
18141        if let Some(project) = self.project.clone() {
18142            self.save(
18143                SaveOptions {
18144                    format: true,
18145                    autosave: false,
18146                },
18147                project,
18148                window,
18149                cx,
18150            )
18151            .detach_and_log_err(cx);
18152        }
18153    }
18154
18155    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18156        if hovered != self.gutter_hovered {
18157            self.gutter_hovered = hovered;
18158            cx.notify();
18159        }
18160    }
18161
18162    pub fn insert_blocks(
18163        &mut self,
18164        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18165        autoscroll: Option<Autoscroll>,
18166        cx: &mut Context<Self>,
18167    ) -> Vec<CustomBlockId> {
18168        let blocks = self
18169            .display_map
18170            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18171        if let Some(autoscroll) = autoscroll {
18172            self.request_autoscroll(autoscroll, cx);
18173        }
18174        cx.notify();
18175        blocks
18176    }
18177
18178    pub fn resize_blocks(
18179        &mut self,
18180        heights: HashMap<CustomBlockId, u32>,
18181        autoscroll: Option<Autoscroll>,
18182        cx: &mut Context<Self>,
18183    ) {
18184        self.display_map
18185            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18186        if let Some(autoscroll) = autoscroll {
18187            self.request_autoscroll(autoscroll, cx);
18188        }
18189        cx.notify();
18190    }
18191
18192    pub fn replace_blocks(
18193        &mut self,
18194        renderers: HashMap<CustomBlockId, RenderBlock>,
18195        autoscroll: Option<Autoscroll>,
18196        cx: &mut Context<Self>,
18197    ) {
18198        self.display_map
18199            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18200        if let Some(autoscroll) = autoscroll {
18201            self.request_autoscroll(autoscroll, cx);
18202        }
18203        cx.notify();
18204    }
18205
18206    pub fn remove_blocks(
18207        &mut self,
18208        block_ids: HashSet<CustomBlockId>,
18209        autoscroll: Option<Autoscroll>,
18210        cx: &mut Context<Self>,
18211    ) {
18212        self.display_map.update(cx, |display_map, cx| {
18213            display_map.remove_blocks(block_ids, cx)
18214        });
18215        if let Some(autoscroll) = autoscroll {
18216            self.request_autoscroll(autoscroll, cx);
18217        }
18218        cx.notify();
18219    }
18220
18221    pub fn row_for_block(
18222        &self,
18223        block_id: CustomBlockId,
18224        cx: &mut Context<Self>,
18225    ) -> Option<DisplayRow> {
18226        self.display_map
18227            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18228    }
18229
18230    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18231        self.focused_block = Some(focused_block);
18232    }
18233
18234    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18235        self.focused_block.take()
18236    }
18237
18238    pub fn insert_creases(
18239        &mut self,
18240        creases: impl IntoIterator<Item = Crease<Anchor>>,
18241        cx: &mut Context<Self>,
18242    ) -> Vec<CreaseId> {
18243        self.display_map
18244            .update(cx, |map, cx| map.insert_creases(creases, cx))
18245    }
18246
18247    pub fn remove_creases(
18248        &mut self,
18249        ids: impl IntoIterator<Item = CreaseId>,
18250        cx: &mut Context<Self>,
18251    ) -> Vec<(CreaseId, Range<Anchor>)> {
18252        self.display_map
18253            .update(cx, |map, cx| map.remove_creases(ids, cx))
18254    }
18255
18256    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18257        self.display_map
18258            .update(cx, |map, cx| map.snapshot(cx))
18259            .longest_row()
18260    }
18261
18262    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18263        self.display_map
18264            .update(cx, |map, cx| map.snapshot(cx))
18265            .max_point()
18266    }
18267
18268    pub fn text(&self, cx: &App) -> String {
18269        self.buffer.read(cx).read(cx).text()
18270    }
18271
18272    pub fn is_empty(&self, cx: &App) -> bool {
18273        self.buffer.read(cx).read(cx).is_empty()
18274    }
18275
18276    pub fn text_option(&self, cx: &App) -> Option<String> {
18277        let text = self.text(cx);
18278        let text = text.trim();
18279
18280        if text.is_empty() {
18281            return None;
18282        }
18283
18284        Some(text.to_string())
18285    }
18286
18287    pub fn set_text(
18288        &mut self,
18289        text: impl Into<Arc<str>>,
18290        window: &mut Window,
18291        cx: &mut Context<Self>,
18292    ) {
18293        self.transact(window, cx, |this, _, cx| {
18294            this.buffer
18295                .read(cx)
18296                .as_singleton()
18297                .expect("you can only call set_text on editors for singleton buffers")
18298                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18299        });
18300    }
18301
18302    pub fn display_text(&self, cx: &mut App) -> String {
18303        self.display_map
18304            .update(cx, |map, cx| map.snapshot(cx))
18305            .text()
18306    }
18307
18308    fn create_minimap(
18309        &self,
18310        minimap_settings: MinimapSettings,
18311        window: &mut Window,
18312        cx: &mut Context<Self>,
18313    ) -> Option<Entity<Self>> {
18314        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18315            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18316    }
18317
18318    fn initialize_new_minimap(
18319        &self,
18320        minimap_settings: MinimapSettings,
18321        window: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) -> Entity<Self> {
18324        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18325
18326        let mut minimap = Editor::new_internal(
18327            EditorMode::Minimap {
18328                parent: cx.weak_entity(),
18329            },
18330            self.buffer.clone(),
18331            None,
18332            Some(self.display_map.clone()),
18333            window,
18334            cx,
18335        );
18336        minimap.scroll_manager.clone_state(&self.scroll_manager);
18337        minimap.set_text_style_refinement(TextStyleRefinement {
18338            font_size: Some(MINIMAP_FONT_SIZE),
18339            font_weight: Some(MINIMAP_FONT_WEIGHT),
18340            ..Default::default()
18341        });
18342        minimap.update_minimap_configuration(minimap_settings, cx);
18343        cx.new(|_| minimap)
18344    }
18345
18346    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18347        let current_line_highlight = minimap_settings
18348            .current_line_highlight
18349            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18350        self.set_current_line_highlight(Some(current_line_highlight));
18351    }
18352
18353    pub fn minimap(&self) -> Option<&Entity<Self>> {
18354        self.minimap
18355            .as_ref()
18356            .filter(|_| self.minimap_visibility.visible())
18357    }
18358
18359    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18360        let mut wrap_guides = smallvec![];
18361
18362        if self.show_wrap_guides == Some(false) {
18363            return wrap_guides;
18364        }
18365
18366        let settings = self.buffer.read(cx).language_settings(cx);
18367        if settings.show_wrap_guides {
18368            match self.soft_wrap_mode(cx) {
18369                SoftWrap::Column(soft_wrap) => {
18370                    wrap_guides.push((soft_wrap as usize, true));
18371                }
18372                SoftWrap::Bounded(soft_wrap) => {
18373                    wrap_guides.push((soft_wrap as usize, true));
18374                }
18375                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18376            }
18377            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18378        }
18379
18380        wrap_guides
18381    }
18382
18383    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18384        let settings = self.buffer.read(cx).language_settings(cx);
18385        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18386        match mode {
18387            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18388                SoftWrap::None
18389            }
18390            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18391            language_settings::SoftWrap::PreferredLineLength => {
18392                SoftWrap::Column(settings.preferred_line_length)
18393            }
18394            language_settings::SoftWrap::Bounded => {
18395                SoftWrap::Bounded(settings.preferred_line_length)
18396            }
18397        }
18398    }
18399
18400    pub fn set_soft_wrap_mode(
18401        &mut self,
18402        mode: language_settings::SoftWrap,
18403
18404        cx: &mut Context<Self>,
18405    ) {
18406        self.soft_wrap_mode_override = Some(mode);
18407        cx.notify();
18408    }
18409
18410    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18411        self.hard_wrap = hard_wrap;
18412        cx.notify();
18413    }
18414
18415    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18416        self.text_style_refinement = Some(style);
18417    }
18418
18419    /// called by the Element so we know what style we were most recently rendered with.
18420    pub(crate) fn set_style(
18421        &mut self,
18422        style: EditorStyle,
18423        window: &mut Window,
18424        cx: &mut Context<Self>,
18425    ) {
18426        // We intentionally do not inform the display map about the minimap style
18427        // so that wrapping is not recalculated and stays consistent for the editor
18428        // and its linked minimap.
18429        if !self.mode.is_minimap() {
18430            let rem_size = window.rem_size();
18431            self.display_map.update(cx, |map, cx| {
18432                map.set_font(
18433                    style.text.font(),
18434                    style.text.font_size.to_pixels(rem_size),
18435                    cx,
18436                )
18437            });
18438        }
18439        self.style = Some(style);
18440    }
18441
18442    pub fn style(&self) -> Option<&EditorStyle> {
18443        self.style.as_ref()
18444    }
18445
18446    // Called by the element. This method is not designed to be called outside of the editor
18447    // element's layout code because it does not notify when rewrapping is computed synchronously.
18448    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18449        self.display_map
18450            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18451    }
18452
18453    pub fn set_soft_wrap(&mut self) {
18454        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18455    }
18456
18457    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18458        if self.soft_wrap_mode_override.is_some() {
18459            self.soft_wrap_mode_override.take();
18460        } else {
18461            let soft_wrap = match self.soft_wrap_mode(cx) {
18462                SoftWrap::GitDiff => return,
18463                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18464                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18465                    language_settings::SoftWrap::None
18466                }
18467            };
18468            self.soft_wrap_mode_override = Some(soft_wrap);
18469        }
18470        cx.notify();
18471    }
18472
18473    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18474        let Some(workspace) = self.workspace() else {
18475            return;
18476        };
18477        let fs = workspace.read(cx).app_state().fs.clone();
18478        let current_show = TabBarSettings::get_global(cx).show;
18479        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18480            setting.show = Some(!current_show);
18481        });
18482    }
18483
18484    pub fn toggle_indent_guides(
18485        &mut self,
18486        _: &ToggleIndentGuides,
18487        _: &mut Window,
18488        cx: &mut Context<Self>,
18489    ) {
18490        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18491            self.buffer
18492                .read(cx)
18493                .language_settings(cx)
18494                .indent_guides
18495                .enabled
18496        });
18497        self.show_indent_guides = Some(!currently_enabled);
18498        cx.notify();
18499    }
18500
18501    fn should_show_indent_guides(&self) -> Option<bool> {
18502        self.show_indent_guides
18503    }
18504
18505    pub fn toggle_line_numbers(
18506        &mut self,
18507        _: &ToggleLineNumbers,
18508        _: &mut Window,
18509        cx: &mut Context<Self>,
18510    ) {
18511        let mut editor_settings = EditorSettings::get_global(cx).clone();
18512        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18513        EditorSettings::override_global(editor_settings, cx);
18514    }
18515
18516    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18517        if let Some(show_line_numbers) = self.show_line_numbers {
18518            return show_line_numbers;
18519        }
18520        EditorSettings::get_global(cx).gutter.line_numbers
18521    }
18522
18523    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18524        self.use_relative_line_numbers
18525            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18526    }
18527
18528    pub fn toggle_relative_line_numbers(
18529        &mut self,
18530        _: &ToggleRelativeLineNumbers,
18531        _: &mut Window,
18532        cx: &mut Context<Self>,
18533    ) {
18534        let is_relative = self.should_use_relative_line_numbers(cx);
18535        self.set_relative_line_number(Some(!is_relative), cx)
18536    }
18537
18538    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18539        self.use_relative_line_numbers = is_relative;
18540        cx.notify();
18541    }
18542
18543    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18544        self.show_gutter = show_gutter;
18545        cx.notify();
18546    }
18547
18548    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18549        self.show_scrollbars = ScrollbarAxes {
18550            horizontal: show,
18551            vertical: show,
18552        };
18553        cx.notify();
18554    }
18555
18556    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18557        self.show_scrollbars.vertical = show;
18558        cx.notify();
18559    }
18560
18561    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18562        self.show_scrollbars.horizontal = show;
18563        cx.notify();
18564    }
18565
18566    pub fn set_minimap_visibility(
18567        &mut self,
18568        minimap_visibility: MinimapVisibility,
18569        window: &mut Window,
18570        cx: &mut Context<Self>,
18571    ) {
18572        if self.minimap_visibility != minimap_visibility {
18573            if minimap_visibility.visible() && self.minimap.is_none() {
18574                let minimap_settings = EditorSettings::get_global(cx).minimap;
18575                self.minimap =
18576                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18577            }
18578            self.minimap_visibility = minimap_visibility;
18579            cx.notify();
18580        }
18581    }
18582
18583    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18584        self.set_show_scrollbars(false, cx);
18585        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18586    }
18587
18588    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18589        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18590    }
18591
18592    /// Normally the text in full mode and auto height editors is padded on the
18593    /// left side by roughly half a character width for improved hit testing.
18594    ///
18595    /// Use this method to disable this for cases where this is not wanted (e.g.
18596    /// if you want to align the editor text with some other text above or below)
18597    /// or if you want to add this padding to single-line editors.
18598    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18599        self.offset_content = offset_content;
18600        cx.notify();
18601    }
18602
18603    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18604        self.show_line_numbers = Some(show_line_numbers);
18605        cx.notify();
18606    }
18607
18608    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18609        self.disable_expand_excerpt_buttons = true;
18610        cx.notify();
18611    }
18612
18613    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18614        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18615        cx.notify();
18616    }
18617
18618    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18619        self.show_code_actions = Some(show_code_actions);
18620        cx.notify();
18621    }
18622
18623    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18624        self.show_runnables = Some(show_runnables);
18625        cx.notify();
18626    }
18627
18628    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18629        self.show_breakpoints = Some(show_breakpoints);
18630        cx.notify();
18631    }
18632
18633    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18634        if self.display_map.read(cx).masked != masked {
18635            self.display_map.update(cx, |map, _| map.masked = masked);
18636        }
18637        cx.notify()
18638    }
18639
18640    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18641        self.show_wrap_guides = Some(show_wrap_guides);
18642        cx.notify();
18643    }
18644
18645    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18646        self.show_indent_guides = Some(show_indent_guides);
18647        cx.notify();
18648    }
18649
18650    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18651        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18652            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18653                && let Some(dir) = file.abs_path(cx).parent()
18654            {
18655                return Some(dir.to_owned());
18656            }
18657
18658            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18659                return Some(project_path.path.to_path_buf());
18660            }
18661        }
18662
18663        None
18664    }
18665
18666    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18667        self.active_excerpt(cx)?
18668            .1
18669            .read(cx)
18670            .file()
18671            .and_then(|f| f.as_local())
18672    }
18673
18674    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18675        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18676            let buffer = buffer.read(cx);
18677            if let Some(project_path) = buffer.project_path(cx) {
18678                let project = self.project()?.read(cx);
18679                project.absolute_path(&project_path, cx)
18680            } else {
18681                buffer
18682                    .file()
18683                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18684            }
18685        })
18686    }
18687
18688    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18689        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18690            let project_path = buffer.read(cx).project_path(cx)?;
18691            let project = self.project()?.read(cx);
18692            let entry = project.entry_for_path(&project_path, cx)?;
18693            let path = entry.path.to_path_buf();
18694            Some(path)
18695        })
18696    }
18697
18698    pub fn reveal_in_finder(
18699        &mut self,
18700        _: &RevealInFileManager,
18701        _window: &mut Window,
18702        cx: &mut Context<Self>,
18703    ) {
18704        if let Some(target) = self.target_file(cx) {
18705            cx.reveal_path(&target.abs_path(cx));
18706        }
18707    }
18708
18709    pub fn copy_path(
18710        &mut self,
18711        _: &zed_actions::workspace::CopyPath,
18712        _window: &mut Window,
18713        cx: &mut Context<Self>,
18714    ) {
18715        if let Some(path) = self.target_file_abs_path(cx)
18716            && let Some(path) = path.to_str()
18717        {
18718            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18719        }
18720    }
18721
18722    pub fn copy_relative_path(
18723        &mut self,
18724        _: &zed_actions::workspace::CopyRelativePath,
18725        _window: &mut Window,
18726        cx: &mut Context<Self>,
18727    ) {
18728        if let Some(path) = self.target_file_path(cx)
18729            && let Some(path) = path.to_str()
18730        {
18731            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18732        }
18733    }
18734
18735    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18736        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18737            buffer.read(cx).project_path(cx)
18738        } else {
18739            None
18740        }
18741    }
18742
18743    // Returns true if the editor handled a go-to-line request
18744    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18745        maybe!({
18746            let breakpoint_store = self.breakpoint_store.as_ref()?;
18747
18748            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18749            else {
18750                self.clear_row_highlights::<ActiveDebugLine>();
18751                return None;
18752            };
18753
18754            let position = active_stack_frame.position;
18755            let buffer_id = position.buffer_id?;
18756            let snapshot = self
18757                .project
18758                .as_ref()?
18759                .read(cx)
18760                .buffer_for_id(buffer_id, cx)?
18761                .read(cx)
18762                .snapshot();
18763
18764            let mut handled = false;
18765            for (id, ExcerptRange { context, .. }) in
18766                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18767            {
18768                if context.start.cmp(&position, &snapshot).is_ge()
18769                    || context.end.cmp(&position, &snapshot).is_lt()
18770                {
18771                    continue;
18772                }
18773                let snapshot = self.buffer.read(cx).snapshot(cx);
18774                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18775
18776                handled = true;
18777                self.clear_row_highlights::<ActiveDebugLine>();
18778
18779                self.go_to_line::<ActiveDebugLine>(
18780                    multibuffer_anchor,
18781                    Some(cx.theme().colors().editor_debugger_active_line_background),
18782                    window,
18783                    cx,
18784                );
18785
18786                cx.notify();
18787            }
18788
18789            handled.then_some(())
18790        })
18791        .is_some()
18792    }
18793
18794    pub fn copy_file_name_without_extension(
18795        &mut self,
18796        _: &CopyFileNameWithoutExtension,
18797        _: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) {
18800        if let Some(file) = self.target_file(cx)
18801            && let Some(file_stem) = file.path().file_stem()
18802            && let Some(name) = file_stem.to_str()
18803        {
18804            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18805        }
18806    }
18807
18808    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18809        if let Some(file) = self.target_file(cx)
18810            && let Some(file_name) = file.path().file_name()
18811            && let Some(name) = file_name.to_str()
18812        {
18813            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18814        }
18815    }
18816
18817    pub fn toggle_git_blame(
18818        &mut self,
18819        _: &::git::Blame,
18820        window: &mut Window,
18821        cx: &mut Context<Self>,
18822    ) {
18823        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18824
18825        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18826            self.start_git_blame(true, window, cx);
18827        }
18828
18829        cx.notify();
18830    }
18831
18832    pub fn toggle_git_blame_inline(
18833        &mut self,
18834        _: &ToggleGitBlameInline,
18835        window: &mut Window,
18836        cx: &mut Context<Self>,
18837    ) {
18838        self.toggle_git_blame_inline_internal(true, window, cx);
18839        cx.notify();
18840    }
18841
18842    pub fn open_git_blame_commit(
18843        &mut self,
18844        _: &OpenGitBlameCommit,
18845        window: &mut Window,
18846        cx: &mut Context<Self>,
18847    ) {
18848        self.open_git_blame_commit_internal(window, cx);
18849    }
18850
18851    fn open_git_blame_commit_internal(
18852        &mut self,
18853        window: &mut Window,
18854        cx: &mut Context<Self>,
18855    ) -> Option<()> {
18856        let blame = self.blame.as_ref()?;
18857        let snapshot = self.snapshot(window, cx);
18858        let cursor = self.selections.newest::<Point>(cx).head();
18859        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18860        let blame_entry = blame
18861            .update(cx, |blame, cx| {
18862                blame
18863                    .blame_for_rows(
18864                        &[RowInfo {
18865                            buffer_id: Some(buffer.remote_id()),
18866                            buffer_row: Some(point.row),
18867                            ..Default::default()
18868                        }],
18869                        cx,
18870                    )
18871                    .next()
18872            })
18873            .flatten()?;
18874        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18875        let repo = blame.read(cx).repository(cx)?;
18876        let workspace = self.workspace()?.downgrade();
18877        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18878        None
18879    }
18880
18881    pub fn git_blame_inline_enabled(&self) -> bool {
18882        self.git_blame_inline_enabled
18883    }
18884
18885    pub fn toggle_selection_menu(
18886        &mut self,
18887        _: &ToggleSelectionMenu,
18888        _: &mut Window,
18889        cx: &mut Context<Self>,
18890    ) {
18891        self.show_selection_menu = self
18892            .show_selection_menu
18893            .map(|show_selections_menu| !show_selections_menu)
18894            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18895
18896        cx.notify();
18897    }
18898
18899    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18900        self.show_selection_menu
18901            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18902    }
18903
18904    fn start_git_blame(
18905        &mut self,
18906        user_triggered: bool,
18907        window: &mut Window,
18908        cx: &mut Context<Self>,
18909    ) {
18910        if let Some(project) = self.project() {
18911            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18912                return;
18913            };
18914
18915            if buffer.read(cx).file().is_none() {
18916                return;
18917            }
18918
18919            let focused = self.focus_handle(cx).contains_focused(window, cx);
18920
18921            let project = project.clone();
18922            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18923            self.blame_subscription =
18924                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18925            self.blame = Some(blame);
18926        }
18927    }
18928
18929    fn toggle_git_blame_inline_internal(
18930        &mut self,
18931        user_triggered: bool,
18932        window: &mut Window,
18933        cx: &mut Context<Self>,
18934    ) {
18935        if self.git_blame_inline_enabled {
18936            self.git_blame_inline_enabled = false;
18937            self.show_git_blame_inline = false;
18938            self.show_git_blame_inline_delay_task.take();
18939        } else {
18940            self.git_blame_inline_enabled = true;
18941            self.start_git_blame_inline(user_triggered, window, cx);
18942        }
18943
18944        cx.notify();
18945    }
18946
18947    fn start_git_blame_inline(
18948        &mut self,
18949        user_triggered: bool,
18950        window: &mut Window,
18951        cx: &mut Context<Self>,
18952    ) {
18953        self.start_git_blame(user_triggered, window, cx);
18954
18955        if ProjectSettings::get_global(cx)
18956            .git
18957            .inline_blame_delay()
18958            .is_some()
18959        {
18960            self.start_inline_blame_timer(window, cx);
18961        } else {
18962            self.show_git_blame_inline = true
18963        }
18964    }
18965
18966    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18967        self.blame.as_ref()
18968    }
18969
18970    pub fn show_git_blame_gutter(&self) -> bool {
18971        self.show_git_blame_gutter
18972    }
18973
18974    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18975        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18976    }
18977
18978    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18979        self.show_git_blame_inline
18980            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18981            && !self.newest_selection_head_on_empty_line(cx)
18982            && self.has_blame_entries(cx)
18983    }
18984
18985    fn has_blame_entries(&self, cx: &App) -> bool {
18986        self.blame()
18987            .is_some_and(|blame| blame.read(cx).has_generated_entries())
18988    }
18989
18990    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18991        let cursor_anchor = self.selections.newest_anchor().head();
18992
18993        let snapshot = self.buffer.read(cx).snapshot(cx);
18994        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18995
18996        snapshot.line_len(buffer_row) == 0
18997    }
18998
18999    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19000        let buffer_and_selection = maybe!({
19001            let selection = self.selections.newest::<Point>(cx);
19002            let selection_range = selection.range();
19003
19004            let multi_buffer = self.buffer().read(cx);
19005            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19006            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19007
19008            let (buffer, range, _) = if selection.reversed {
19009                buffer_ranges.first()
19010            } else {
19011                buffer_ranges.last()
19012            }?;
19013
19014            let selection = text::ToPoint::to_point(&range.start, buffer).row
19015                ..text::ToPoint::to_point(&range.end, buffer).row;
19016            Some((
19017                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
19018                selection,
19019            ))
19020        });
19021
19022        let Some((buffer, selection)) = buffer_and_selection else {
19023            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19024        };
19025
19026        let Some(project) = self.project() else {
19027            return Task::ready(Err(anyhow!("editor does not have project")));
19028        };
19029
19030        project.update(cx, |project, cx| {
19031            project.get_permalink_to_line(&buffer, selection, cx)
19032        })
19033    }
19034
19035    pub fn copy_permalink_to_line(
19036        &mut self,
19037        _: &CopyPermalinkToLine,
19038        window: &mut Window,
19039        cx: &mut Context<Self>,
19040    ) {
19041        let permalink_task = self.get_permalink_to_line(cx);
19042        let workspace = self.workspace();
19043
19044        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19045            Ok(permalink) => {
19046                cx.update(|_, cx| {
19047                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19048                })
19049                .ok();
19050            }
19051            Err(err) => {
19052                let message = format!("Failed to copy permalink: {err}");
19053
19054                anyhow::Result::<()>::Err(err).log_err();
19055
19056                if let Some(workspace) = workspace {
19057                    workspace
19058                        .update_in(cx, |workspace, _, cx| {
19059                            struct CopyPermalinkToLine;
19060
19061                            workspace.show_toast(
19062                                Toast::new(
19063                                    NotificationId::unique::<CopyPermalinkToLine>(),
19064                                    message,
19065                                ),
19066                                cx,
19067                            )
19068                        })
19069                        .ok();
19070                }
19071            }
19072        })
19073        .detach();
19074    }
19075
19076    pub fn copy_file_location(
19077        &mut self,
19078        _: &CopyFileLocation,
19079        _: &mut Window,
19080        cx: &mut Context<Self>,
19081    ) {
19082        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19083        if let Some(file) = self.target_file(cx)
19084            && let Some(path) = file.path().to_str()
19085        {
19086            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19087        }
19088    }
19089
19090    pub fn open_permalink_to_line(
19091        &mut self,
19092        _: &OpenPermalinkToLine,
19093        window: &mut Window,
19094        cx: &mut Context<Self>,
19095    ) {
19096        let permalink_task = self.get_permalink_to_line(cx);
19097        let workspace = self.workspace();
19098
19099        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19100            Ok(permalink) => {
19101                cx.update(|_, cx| {
19102                    cx.open_url(permalink.as_ref());
19103                })
19104                .ok();
19105            }
19106            Err(err) => {
19107                let message = format!("Failed to open permalink: {err}");
19108
19109                anyhow::Result::<()>::Err(err).log_err();
19110
19111                if let Some(workspace) = workspace {
19112                    workspace
19113                        .update(cx, |workspace, cx| {
19114                            struct OpenPermalinkToLine;
19115
19116                            workspace.show_toast(
19117                                Toast::new(
19118                                    NotificationId::unique::<OpenPermalinkToLine>(),
19119                                    message,
19120                                ),
19121                                cx,
19122                            )
19123                        })
19124                        .ok();
19125                }
19126            }
19127        })
19128        .detach();
19129    }
19130
19131    pub fn insert_uuid_v4(
19132        &mut self,
19133        _: &InsertUuidV4,
19134        window: &mut Window,
19135        cx: &mut Context<Self>,
19136    ) {
19137        self.insert_uuid(UuidVersion::V4, window, cx);
19138    }
19139
19140    pub fn insert_uuid_v7(
19141        &mut self,
19142        _: &InsertUuidV7,
19143        window: &mut Window,
19144        cx: &mut Context<Self>,
19145    ) {
19146        self.insert_uuid(UuidVersion::V7, window, cx);
19147    }
19148
19149    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19150        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19151        self.transact(window, cx, |this, window, cx| {
19152            let edits = this
19153                .selections
19154                .all::<Point>(cx)
19155                .into_iter()
19156                .map(|selection| {
19157                    let uuid = match version {
19158                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19159                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19160                    };
19161
19162                    (selection.range(), uuid.to_string())
19163                });
19164            this.edit(edits, cx);
19165            this.refresh_edit_prediction(true, false, window, cx);
19166        });
19167    }
19168
19169    pub fn open_selections_in_multibuffer(
19170        &mut self,
19171        _: &OpenSelectionsInMultibuffer,
19172        window: &mut Window,
19173        cx: &mut Context<Self>,
19174    ) {
19175        let multibuffer = self.buffer.read(cx);
19176
19177        let Some(buffer) = multibuffer.as_singleton() else {
19178            return;
19179        };
19180
19181        let Some(workspace) = self.workspace() else {
19182            return;
19183        };
19184
19185        let title = multibuffer.title(cx).to_string();
19186
19187        let locations = self
19188            .selections
19189            .all_anchors(cx)
19190            .iter()
19191            .map(|selection| Location {
19192                buffer: buffer.clone(),
19193                range: selection.start.text_anchor..selection.end.text_anchor,
19194            })
19195            .collect::<Vec<_>>();
19196
19197        cx.spawn_in(window, async move |_, cx| {
19198            workspace.update_in(cx, |workspace, window, cx| {
19199                Self::open_locations_in_multibuffer(
19200                    workspace,
19201                    locations,
19202                    format!("Selections for '{title}'"),
19203                    false,
19204                    MultibufferSelectionMode::All,
19205                    window,
19206                    cx,
19207                );
19208            })
19209        })
19210        .detach();
19211    }
19212
19213    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19214    /// last highlight added will be used.
19215    ///
19216    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19217    pub fn highlight_rows<T: 'static>(
19218        &mut self,
19219        range: Range<Anchor>,
19220        color: Hsla,
19221        options: RowHighlightOptions,
19222        cx: &mut Context<Self>,
19223    ) {
19224        let snapshot = self.buffer().read(cx).snapshot(cx);
19225        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19226        let ix = row_highlights.binary_search_by(|highlight| {
19227            Ordering::Equal
19228                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19229                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19230        });
19231
19232        if let Err(mut ix) = ix {
19233            let index = post_inc(&mut self.highlight_order);
19234
19235            // If this range intersects with the preceding highlight, then merge it with
19236            // the preceding highlight. Otherwise insert a new highlight.
19237            let mut merged = false;
19238            if ix > 0 {
19239                let prev_highlight = &mut row_highlights[ix - 1];
19240                if prev_highlight
19241                    .range
19242                    .end
19243                    .cmp(&range.start, &snapshot)
19244                    .is_ge()
19245                {
19246                    ix -= 1;
19247                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19248                        prev_highlight.range.end = range.end;
19249                    }
19250                    merged = true;
19251                    prev_highlight.index = index;
19252                    prev_highlight.color = color;
19253                    prev_highlight.options = options;
19254                }
19255            }
19256
19257            if !merged {
19258                row_highlights.insert(
19259                    ix,
19260                    RowHighlight {
19261                        range: range.clone(),
19262                        index,
19263                        color,
19264                        options,
19265                        type_id: TypeId::of::<T>(),
19266                    },
19267                );
19268            }
19269
19270            // If any of the following highlights intersect with this one, merge them.
19271            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19272                let highlight = &row_highlights[ix];
19273                if next_highlight
19274                    .range
19275                    .start
19276                    .cmp(&highlight.range.end, &snapshot)
19277                    .is_le()
19278                {
19279                    if next_highlight
19280                        .range
19281                        .end
19282                        .cmp(&highlight.range.end, &snapshot)
19283                        .is_gt()
19284                    {
19285                        row_highlights[ix].range.end = next_highlight.range.end;
19286                    }
19287                    row_highlights.remove(ix + 1);
19288                } else {
19289                    break;
19290                }
19291            }
19292        }
19293    }
19294
19295    /// Remove any highlighted row ranges of the given type that intersect the
19296    /// given ranges.
19297    pub fn remove_highlighted_rows<T: 'static>(
19298        &mut self,
19299        ranges_to_remove: Vec<Range<Anchor>>,
19300        cx: &mut Context<Self>,
19301    ) {
19302        let snapshot = self.buffer().read(cx).snapshot(cx);
19303        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19304        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19305        row_highlights.retain(|highlight| {
19306            while let Some(range_to_remove) = ranges_to_remove.peek() {
19307                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19308                    Ordering::Less | Ordering::Equal => {
19309                        ranges_to_remove.next();
19310                    }
19311                    Ordering::Greater => {
19312                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19313                            Ordering::Less | Ordering::Equal => {
19314                                return false;
19315                            }
19316                            Ordering::Greater => break,
19317                        }
19318                    }
19319                }
19320            }
19321
19322            true
19323        })
19324    }
19325
19326    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19327    pub fn clear_row_highlights<T: 'static>(&mut self) {
19328        self.highlighted_rows.remove(&TypeId::of::<T>());
19329    }
19330
19331    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19332    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19333        self.highlighted_rows
19334            .get(&TypeId::of::<T>())
19335            .map_or(&[] as &[_], |vec| vec.as_slice())
19336            .iter()
19337            .map(|highlight| (highlight.range.clone(), highlight.color))
19338    }
19339
19340    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19341    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19342    /// Allows to ignore certain kinds of highlights.
19343    pub fn highlighted_display_rows(
19344        &self,
19345        window: &mut Window,
19346        cx: &mut App,
19347    ) -> BTreeMap<DisplayRow, LineHighlight> {
19348        let snapshot = self.snapshot(window, cx);
19349        let mut used_highlight_orders = HashMap::default();
19350        self.highlighted_rows
19351            .iter()
19352            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19353            .fold(
19354                BTreeMap::<DisplayRow, LineHighlight>::new(),
19355                |mut unique_rows, highlight| {
19356                    let start = highlight.range.start.to_display_point(&snapshot);
19357                    let end = highlight.range.end.to_display_point(&snapshot);
19358                    let start_row = start.row().0;
19359                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19360                        && end.column() == 0
19361                    {
19362                        end.row().0.saturating_sub(1)
19363                    } else {
19364                        end.row().0
19365                    };
19366                    for row in start_row..=end_row {
19367                        let used_index =
19368                            used_highlight_orders.entry(row).or_insert(highlight.index);
19369                        if highlight.index >= *used_index {
19370                            *used_index = highlight.index;
19371                            unique_rows.insert(
19372                                DisplayRow(row),
19373                                LineHighlight {
19374                                    include_gutter: highlight.options.include_gutter,
19375                                    border: None,
19376                                    background: highlight.color.into(),
19377                                    type_id: Some(highlight.type_id),
19378                                },
19379                            );
19380                        }
19381                    }
19382                    unique_rows
19383                },
19384            )
19385    }
19386
19387    pub fn highlighted_display_row_for_autoscroll(
19388        &self,
19389        snapshot: &DisplaySnapshot,
19390    ) -> Option<DisplayRow> {
19391        self.highlighted_rows
19392            .values()
19393            .flat_map(|highlighted_rows| highlighted_rows.iter())
19394            .filter_map(|highlight| {
19395                if highlight.options.autoscroll {
19396                    Some(highlight.range.start.to_display_point(snapshot).row())
19397                } else {
19398                    None
19399                }
19400            })
19401            .min()
19402    }
19403
19404    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19405        self.highlight_background::<SearchWithinRange>(
19406            ranges,
19407            |colors| colors.colors().editor_document_highlight_read_background,
19408            cx,
19409        )
19410    }
19411
19412    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19413        self.breadcrumb_header = Some(new_header);
19414    }
19415
19416    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19417        self.clear_background_highlights::<SearchWithinRange>(cx);
19418    }
19419
19420    pub fn highlight_background<T: 'static>(
19421        &mut self,
19422        ranges: &[Range<Anchor>],
19423        color_fetcher: fn(&Theme) -> Hsla,
19424        cx: &mut Context<Self>,
19425    ) {
19426        self.background_highlights.insert(
19427            HighlightKey::Type(TypeId::of::<T>()),
19428            (color_fetcher, Arc::from(ranges)),
19429        );
19430        self.scrollbar_marker_state.dirty = true;
19431        cx.notify();
19432    }
19433
19434    pub fn highlight_background_key<T: 'static>(
19435        &mut self,
19436        key: usize,
19437        ranges: &[Range<Anchor>],
19438        color_fetcher: fn(&Theme) -> Hsla,
19439        cx: &mut Context<Self>,
19440    ) {
19441        self.background_highlights.insert(
19442            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19443            (color_fetcher, Arc::from(ranges)),
19444        );
19445        self.scrollbar_marker_state.dirty = true;
19446        cx.notify();
19447    }
19448
19449    pub fn clear_background_highlights<T: 'static>(
19450        &mut self,
19451        cx: &mut Context<Self>,
19452    ) -> Option<BackgroundHighlight> {
19453        let text_highlights = self
19454            .background_highlights
19455            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19456        if !text_highlights.1.is_empty() {
19457            self.scrollbar_marker_state.dirty = true;
19458            cx.notify();
19459        }
19460        Some(text_highlights)
19461    }
19462
19463    pub fn highlight_gutter<T: 'static>(
19464        &mut self,
19465        ranges: impl Into<Vec<Range<Anchor>>>,
19466        color_fetcher: fn(&App) -> Hsla,
19467        cx: &mut Context<Self>,
19468    ) {
19469        self.gutter_highlights
19470            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19471        cx.notify();
19472    }
19473
19474    pub fn clear_gutter_highlights<T: 'static>(
19475        &mut self,
19476        cx: &mut Context<Self>,
19477    ) -> Option<GutterHighlight> {
19478        cx.notify();
19479        self.gutter_highlights.remove(&TypeId::of::<T>())
19480    }
19481
19482    pub fn insert_gutter_highlight<T: 'static>(
19483        &mut self,
19484        range: Range<Anchor>,
19485        color_fetcher: fn(&App) -> Hsla,
19486        cx: &mut Context<Self>,
19487    ) {
19488        let snapshot = self.buffer().read(cx).snapshot(cx);
19489        let mut highlights = self
19490            .gutter_highlights
19491            .remove(&TypeId::of::<T>())
19492            .map(|(_, highlights)| highlights)
19493            .unwrap_or_default();
19494        let ix = highlights.binary_search_by(|highlight| {
19495            Ordering::Equal
19496                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19497                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19498        });
19499        if let Err(ix) = ix {
19500            highlights.insert(ix, range);
19501        }
19502        self.gutter_highlights
19503            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19504    }
19505
19506    pub fn remove_gutter_highlights<T: 'static>(
19507        &mut self,
19508        ranges_to_remove: Vec<Range<Anchor>>,
19509        cx: &mut Context<Self>,
19510    ) {
19511        let snapshot = self.buffer().read(cx).snapshot(cx);
19512        let Some((color_fetcher, mut gutter_highlights)) =
19513            self.gutter_highlights.remove(&TypeId::of::<T>())
19514        else {
19515            return;
19516        };
19517        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19518        gutter_highlights.retain(|highlight| {
19519            while let Some(range_to_remove) = ranges_to_remove.peek() {
19520                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19521                    Ordering::Less | Ordering::Equal => {
19522                        ranges_to_remove.next();
19523                    }
19524                    Ordering::Greater => {
19525                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19526                            Ordering::Less | Ordering::Equal => {
19527                                return false;
19528                            }
19529                            Ordering::Greater => break,
19530                        }
19531                    }
19532                }
19533            }
19534
19535            true
19536        });
19537        self.gutter_highlights
19538            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19539    }
19540
19541    #[cfg(feature = "test-support")]
19542    pub fn all_text_highlights(
19543        &self,
19544        window: &mut Window,
19545        cx: &mut Context<Self>,
19546    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19547        let snapshot = self.snapshot(window, cx);
19548        self.display_map.update(cx, |display_map, _| {
19549            display_map
19550                .all_text_highlights()
19551                .map(|highlight| {
19552                    let (style, ranges) = highlight.as_ref();
19553                    (
19554                        *style,
19555                        ranges
19556                            .iter()
19557                            .map(|range| range.clone().to_display_points(&snapshot))
19558                            .collect(),
19559                    )
19560                })
19561                .collect()
19562        })
19563    }
19564
19565    #[cfg(feature = "test-support")]
19566    pub fn all_text_background_highlights(
19567        &self,
19568        window: &mut Window,
19569        cx: &mut Context<Self>,
19570    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19571        let snapshot = self.snapshot(window, cx);
19572        let buffer = &snapshot.buffer_snapshot;
19573        let start = buffer.anchor_before(0);
19574        let end = buffer.anchor_after(buffer.len());
19575        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19576    }
19577
19578    #[cfg(feature = "test-support")]
19579    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19580        let snapshot = self.buffer().read(cx).snapshot(cx);
19581
19582        let highlights = self
19583            .background_highlights
19584            .get(&HighlightKey::Type(TypeId::of::<
19585                items::BufferSearchHighlights,
19586            >()));
19587
19588        if let Some((_color, ranges)) = highlights {
19589            ranges
19590                .iter()
19591                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19592                .collect_vec()
19593        } else {
19594            vec![]
19595        }
19596    }
19597
19598    fn document_highlights_for_position<'a>(
19599        &'a self,
19600        position: Anchor,
19601        buffer: &'a MultiBufferSnapshot,
19602    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19603        let read_highlights = self
19604            .background_highlights
19605            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19606            .map(|h| &h.1);
19607        let write_highlights = self
19608            .background_highlights
19609            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19610            .map(|h| &h.1);
19611        let left_position = position.bias_left(buffer);
19612        let right_position = position.bias_right(buffer);
19613        read_highlights
19614            .into_iter()
19615            .chain(write_highlights)
19616            .flat_map(move |ranges| {
19617                let start_ix = match ranges.binary_search_by(|probe| {
19618                    let cmp = probe.end.cmp(&left_position, buffer);
19619                    if cmp.is_ge() {
19620                        Ordering::Greater
19621                    } else {
19622                        Ordering::Less
19623                    }
19624                }) {
19625                    Ok(i) | Err(i) => i,
19626                };
19627
19628                ranges[start_ix..]
19629                    .iter()
19630                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19631            })
19632    }
19633
19634    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19635        self.background_highlights
19636            .get(&HighlightKey::Type(TypeId::of::<T>()))
19637            .is_some_and(|(_, highlights)| !highlights.is_empty())
19638    }
19639
19640    pub fn background_highlights_in_range(
19641        &self,
19642        search_range: Range<Anchor>,
19643        display_snapshot: &DisplaySnapshot,
19644        theme: &Theme,
19645    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19646        let mut results = Vec::new();
19647        for (color_fetcher, ranges) in self.background_highlights.values() {
19648            let color = color_fetcher(theme);
19649            let start_ix = match ranges.binary_search_by(|probe| {
19650                let cmp = probe
19651                    .end
19652                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19653                if cmp.is_gt() {
19654                    Ordering::Greater
19655                } else {
19656                    Ordering::Less
19657                }
19658            }) {
19659                Ok(i) | Err(i) => i,
19660            };
19661            for range in &ranges[start_ix..] {
19662                if range
19663                    .start
19664                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19665                    .is_ge()
19666                {
19667                    break;
19668                }
19669
19670                let start = range.start.to_display_point(display_snapshot);
19671                let end = range.end.to_display_point(display_snapshot);
19672                results.push((start..end, color))
19673            }
19674        }
19675        results
19676    }
19677
19678    pub fn background_highlight_row_ranges<T: 'static>(
19679        &self,
19680        search_range: Range<Anchor>,
19681        display_snapshot: &DisplaySnapshot,
19682        count: usize,
19683    ) -> Vec<RangeInclusive<DisplayPoint>> {
19684        let mut results = Vec::new();
19685        let Some((_, ranges)) = self
19686            .background_highlights
19687            .get(&HighlightKey::Type(TypeId::of::<T>()))
19688        else {
19689            return vec![];
19690        };
19691
19692        let start_ix = match ranges.binary_search_by(|probe| {
19693            let cmp = probe
19694                .end
19695                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19696            if cmp.is_gt() {
19697                Ordering::Greater
19698            } else {
19699                Ordering::Less
19700            }
19701        }) {
19702            Ok(i) | Err(i) => i,
19703        };
19704        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19705            if let (Some(start_display), Some(end_display)) = (start, end) {
19706                results.push(
19707                    start_display.to_display_point(display_snapshot)
19708                        ..=end_display.to_display_point(display_snapshot),
19709                );
19710            }
19711        };
19712        let mut start_row: Option<Point> = None;
19713        let mut end_row: Option<Point> = None;
19714        if ranges.len() > count {
19715            return Vec::new();
19716        }
19717        for range in &ranges[start_ix..] {
19718            if range
19719                .start
19720                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19721                .is_ge()
19722            {
19723                break;
19724            }
19725            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19726            if let Some(current_row) = &end_row
19727                && end.row == current_row.row
19728            {
19729                continue;
19730            }
19731            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19732            if start_row.is_none() {
19733                assert_eq!(end_row, None);
19734                start_row = Some(start);
19735                end_row = Some(end);
19736                continue;
19737            }
19738            if let Some(current_end) = end_row.as_mut() {
19739                if start.row > current_end.row + 1 {
19740                    push_region(start_row, end_row);
19741                    start_row = Some(start);
19742                    end_row = Some(end);
19743                } else {
19744                    // Merge two hunks.
19745                    *current_end = end;
19746                }
19747            } else {
19748                unreachable!();
19749            }
19750        }
19751        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19752        push_region(start_row, end_row);
19753        results
19754    }
19755
19756    pub fn gutter_highlights_in_range(
19757        &self,
19758        search_range: Range<Anchor>,
19759        display_snapshot: &DisplaySnapshot,
19760        cx: &App,
19761    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19762        let mut results = Vec::new();
19763        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19764            let color = color_fetcher(cx);
19765            let start_ix = match ranges.binary_search_by(|probe| {
19766                let cmp = probe
19767                    .end
19768                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19769                if cmp.is_gt() {
19770                    Ordering::Greater
19771                } else {
19772                    Ordering::Less
19773                }
19774            }) {
19775                Ok(i) | Err(i) => i,
19776            };
19777            for range in &ranges[start_ix..] {
19778                if range
19779                    .start
19780                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19781                    .is_ge()
19782                {
19783                    break;
19784                }
19785
19786                let start = range.start.to_display_point(display_snapshot);
19787                let end = range.end.to_display_point(display_snapshot);
19788                results.push((start..end, color))
19789            }
19790        }
19791        results
19792    }
19793
19794    /// Get the text ranges corresponding to the redaction query
19795    pub fn redacted_ranges(
19796        &self,
19797        search_range: Range<Anchor>,
19798        display_snapshot: &DisplaySnapshot,
19799        cx: &App,
19800    ) -> Vec<Range<DisplayPoint>> {
19801        display_snapshot
19802            .buffer_snapshot
19803            .redacted_ranges(search_range, |file| {
19804                if let Some(file) = file {
19805                    file.is_private()
19806                        && EditorSettings::get(
19807                            Some(SettingsLocation {
19808                                worktree_id: file.worktree_id(cx),
19809                                path: file.path().as_ref(),
19810                            }),
19811                            cx,
19812                        )
19813                        .redact_private_values
19814                } else {
19815                    false
19816                }
19817            })
19818            .map(|range| {
19819                range.start.to_display_point(display_snapshot)
19820                    ..range.end.to_display_point(display_snapshot)
19821            })
19822            .collect()
19823    }
19824
19825    pub fn highlight_text_key<T: 'static>(
19826        &mut self,
19827        key: usize,
19828        ranges: Vec<Range<Anchor>>,
19829        style: HighlightStyle,
19830        cx: &mut Context<Self>,
19831    ) {
19832        self.display_map.update(cx, |map, _| {
19833            map.highlight_text(
19834                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19835                ranges,
19836                style,
19837            );
19838        });
19839        cx.notify();
19840    }
19841
19842    pub fn highlight_text<T: 'static>(
19843        &mut self,
19844        ranges: Vec<Range<Anchor>>,
19845        style: HighlightStyle,
19846        cx: &mut Context<Self>,
19847    ) {
19848        self.display_map.update(cx, |map, _| {
19849            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19850        });
19851        cx.notify();
19852    }
19853
19854    pub(crate) fn highlight_inlays<T: 'static>(
19855        &mut self,
19856        highlights: Vec<InlayHighlight>,
19857        style: HighlightStyle,
19858        cx: &mut Context<Self>,
19859    ) {
19860        self.display_map.update(cx, |map, _| {
19861            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19862        });
19863        cx.notify();
19864    }
19865
19866    pub fn text_highlights<'a, T: 'static>(
19867        &'a self,
19868        cx: &'a App,
19869    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19870        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19871    }
19872
19873    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19874        let cleared = self
19875            .display_map
19876            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19877        if cleared {
19878            cx.notify();
19879        }
19880    }
19881
19882    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19883        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19884            && self.focus_handle.is_focused(window)
19885    }
19886
19887    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19888        self.show_cursor_when_unfocused = is_enabled;
19889        cx.notify();
19890    }
19891
19892    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19893        cx.notify();
19894    }
19895
19896    fn on_debug_session_event(
19897        &mut self,
19898        _session: Entity<Session>,
19899        event: &SessionEvent,
19900        cx: &mut Context<Self>,
19901    ) {
19902        if let SessionEvent::InvalidateInlineValue = event {
19903            self.refresh_inline_values(cx);
19904        }
19905    }
19906
19907    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19908        let Some(project) = self.project.clone() else {
19909            return;
19910        };
19911
19912        if !self.inline_value_cache.enabled {
19913            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19914            self.splice_inlays(&inlays, Vec::new(), cx);
19915            return;
19916        }
19917
19918        let current_execution_position = self
19919            .highlighted_rows
19920            .get(&TypeId::of::<ActiveDebugLine>())
19921            .and_then(|lines| lines.last().map(|line| line.range.end));
19922
19923        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19924            let inline_values = editor
19925                .update(cx, |editor, cx| {
19926                    let Some(current_execution_position) = current_execution_position else {
19927                        return Some(Task::ready(Ok(Vec::new())));
19928                    };
19929
19930                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19931                        let snapshot = buffer.snapshot(cx);
19932
19933                        let excerpt = snapshot.excerpt_containing(
19934                            current_execution_position..current_execution_position,
19935                        )?;
19936
19937                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19938                    })?;
19939
19940                    let range =
19941                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19942
19943                    project.inline_values(buffer, range, cx)
19944                })
19945                .ok()
19946                .flatten()?
19947                .await
19948                .context("refreshing debugger inlays")
19949                .log_err()?;
19950
19951            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19952
19953            for (buffer_id, inline_value) in inline_values
19954                .into_iter()
19955                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19956            {
19957                buffer_inline_values
19958                    .entry(buffer_id)
19959                    .or_default()
19960                    .push(inline_value);
19961            }
19962
19963            editor
19964                .update(cx, |editor, cx| {
19965                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19966                    let mut new_inlays = Vec::default();
19967
19968                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19969                        let buffer_id = buffer_snapshot.remote_id();
19970                        buffer_inline_values
19971                            .get(&buffer_id)
19972                            .into_iter()
19973                            .flatten()
19974                            .for_each(|hint| {
19975                                let inlay = Inlay::debugger(
19976                                    post_inc(&mut editor.next_inlay_id),
19977                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19978                                    hint.text(),
19979                                );
19980                                if !inlay.text.chars().contains(&'\n') {
19981                                    new_inlays.push(inlay);
19982                                }
19983                            });
19984                    }
19985
19986                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19987                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19988
19989                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19990                })
19991                .ok()?;
19992            Some(())
19993        });
19994    }
19995
19996    fn on_buffer_event(
19997        &mut self,
19998        multibuffer: &Entity<MultiBuffer>,
19999        event: &multi_buffer::Event,
20000        window: &mut Window,
20001        cx: &mut Context<Self>,
20002    ) {
20003        match event {
20004            multi_buffer::Event::Edited {
20005                singleton_buffer_edited,
20006                edited_buffer,
20007            } => {
20008                self.scrollbar_marker_state.dirty = true;
20009                self.active_indent_guides_state.dirty = true;
20010                self.refresh_active_diagnostics(cx);
20011                self.refresh_code_actions(window, cx);
20012                self.refresh_selected_text_highlights(true, window, cx);
20013                self.refresh_single_line_folds(window, cx);
20014                refresh_matching_bracket_highlights(self, window, cx);
20015                if self.has_active_edit_prediction() {
20016                    self.update_visible_edit_prediction(window, cx);
20017                }
20018                if let Some(project) = self.project.as_ref()
20019                    && let Some(edited_buffer) = edited_buffer
20020                {
20021                    project.update(cx, |project, cx| {
20022                        self.registered_buffers
20023                            .entry(edited_buffer.read(cx).remote_id())
20024                            .or_insert_with(|| {
20025                                project.register_buffer_with_language_servers(edited_buffer, cx)
20026                            });
20027                    });
20028                }
20029                cx.emit(EditorEvent::BufferEdited);
20030                cx.emit(SearchEvent::MatchesInvalidated);
20031
20032                if let Some(buffer) = edited_buffer {
20033                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20034                }
20035
20036                if *singleton_buffer_edited {
20037                    if let Some(buffer) = edited_buffer
20038                        && buffer.read(cx).file().is_none()
20039                    {
20040                        cx.emit(EditorEvent::TitleChanged);
20041                    }
20042                    if let Some(project) = &self.project {
20043                        #[allow(clippy::mutable_key_type)]
20044                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20045                            multibuffer
20046                                .all_buffers()
20047                                .into_iter()
20048                                .filter_map(|buffer| {
20049                                    buffer.update(cx, |buffer, cx| {
20050                                        let language = buffer.language()?;
20051                                        let should_discard = project.update(cx, |project, cx| {
20052                                            project.is_local()
20053                                                && !project.has_language_servers_for(buffer, cx)
20054                                        });
20055                                        should_discard.not().then_some(language.clone())
20056                                    })
20057                                })
20058                                .collect::<HashSet<_>>()
20059                        });
20060                        if !languages_affected.is_empty() {
20061                            self.refresh_inlay_hints(
20062                                InlayHintRefreshReason::BufferEdited(languages_affected),
20063                                cx,
20064                            );
20065                        }
20066                    }
20067                }
20068
20069                let Some(project) = &self.project else { return };
20070                let (telemetry, is_via_ssh) = {
20071                    let project = project.read(cx);
20072                    let telemetry = project.client().telemetry().clone();
20073                    let is_via_ssh = project.is_via_ssh();
20074                    (telemetry, is_via_ssh)
20075                };
20076                refresh_linked_ranges(self, window, cx);
20077                telemetry.log_edit_event("editor", is_via_ssh);
20078            }
20079            multi_buffer::Event::ExcerptsAdded {
20080                buffer,
20081                predecessor,
20082                excerpts,
20083            } => {
20084                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20085                let buffer_id = buffer.read(cx).remote_id();
20086                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20087                    && let Some(project) = &self.project
20088                {
20089                    update_uncommitted_diff_for_buffer(
20090                        cx.entity(),
20091                        project,
20092                        [buffer.clone()],
20093                        self.buffer.clone(),
20094                        cx,
20095                    )
20096                    .detach();
20097                }
20098                self.update_lsp_data(false, Some(buffer_id), window, cx);
20099                cx.emit(EditorEvent::ExcerptsAdded {
20100                    buffer: buffer.clone(),
20101                    predecessor: *predecessor,
20102                    excerpts: excerpts.clone(),
20103                });
20104                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20105            }
20106            multi_buffer::Event::ExcerptsRemoved {
20107                ids,
20108                removed_buffer_ids,
20109            } => {
20110                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20111                let buffer = self.buffer.read(cx);
20112                self.registered_buffers
20113                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20114                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20115                cx.emit(EditorEvent::ExcerptsRemoved {
20116                    ids: ids.clone(),
20117                    removed_buffer_ids: removed_buffer_ids.clone(),
20118                });
20119            }
20120            multi_buffer::Event::ExcerptsEdited {
20121                excerpt_ids,
20122                buffer_ids,
20123            } => {
20124                self.display_map.update(cx, |map, cx| {
20125                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20126                });
20127                cx.emit(EditorEvent::ExcerptsEdited {
20128                    ids: excerpt_ids.clone(),
20129                });
20130            }
20131            multi_buffer::Event::ExcerptsExpanded { ids } => {
20132                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20133                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20134            }
20135            multi_buffer::Event::Reparsed(buffer_id) => {
20136                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20137                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20138
20139                cx.emit(EditorEvent::Reparsed(*buffer_id));
20140            }
20141            multi_buffer::Event::DiffHunksToggled => {
20142                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20143            }
20144            multi_buffer::Event::LanguageChanged(buffer_id) => {
20145                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20146                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20147                cx.emit(EditorEvent::Reparsed(*buffer_id));
20148                cx.notify();
20149            }
20150            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20151            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20152            multi_buffer::Event::FileHandleChanged
20153            | multi_buffer::Event::Reloaded
20154            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20155            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20156            multi_buffer::Event::DiagnosticsUpdated => {
20157                self.update_diagnostics_state(window, cx);
20158            }
20159            _ => {}
20160        };
20161    }
20162
20163    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20164        if !self.diagnostics_enabled() {
20165            return;
20166        }
20167        self.refresh_active_diagnostics(cx);
20168        self.refresh_inline_diagnostics(true, window, cx);
20169        self.scrollbar_marker_state.dirty = true;
20170        cx.notify();
20171    }
20172
20173    pub fn start_temporary_diff_override(&mut self) {
20174        self.load_diff_task.take();
20175        self.temporary_diff_override = true;
20176    }
20177
20178    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20179        self.temporary_diff_override = false;
20180        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20181        self.buffer.update(cx, |buffer, cx| {
20182            buffer.set_all_diff_hunks_collapsed(cx);
20183        });
20184
20185        if let Some(project) = self.project.clone() {
20186            self.load_diff_task = Some(
20187                update_uncommitted_diff_for_buffer(
20188                    cx.entity(),
20189                    &project,
20190                    self.buffer.read(cx).all_buffers(),
20191                    self.buffer.clone(),
20192                    cx,
20193                )
20194                .shared(),
20195            );
20196        }
20197    }
20198
20199    fn on_display_map_changed(
20200        &mut self,
20201        _: Entity<DisplayMap>,
20202        _: &mut Window,
20203        cx: &mut Context<Self>,
20204    ) {
20205        cx.notify();
20206    }
20207
20208    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20209        if self.diagnostics_enabled() {
20210            let new_severity = EditorSettings::get_global(cx)
20211                .diagnostics_max_severity
20212                .unwrap_or(DiagnosticSeverity::Hint);
20213            self.set_max_diagnostics_severity(new_severity, cx);
20214        }
20215        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20216        self.update_edit_prediction_settings(cx);
20217        self.refresh_edit_prediction(true, false, window, cx);
20218        self.refresh_inline_values(cx);
20219        self.refresh_inlay_hints(
20220            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20221                self.selections.newest_anchor().head(),
20222                &self.buffer.read(cx).snapshot(cx),
20223                cx,
20224            )),
20225            cx,
20226        );
20227
20228        let old_cursor_shape = self.cursor_shape;
20229        let old_show_breadcrumbs = self.show_breadcrumbs;
20230
20231        {
20232            let editor_settings = EditorSettings::get_global(cx);
20233            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20234            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20235            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20236            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20237        }
20238
20239        if old_cursor_shape != self.cursor_shape {
20240            cx.emit(EditorEvent::CursorShapeChanged);
20241        }
20242
20243        if old_show_breadcrumbs != self.show_breadcrumbs {
20244            cx.emit(EditorEvent::BreadcrumbsChanged);
20245        }
20246
20247        let project_settings = ProjectSettings::get_global(cx);
20248        self.serialize_dirty_buffers =
20249            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20250
20251        if self.mode.is_full() {
20252            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20253            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20254            if self.show_inline_diagnostics != show_inline_diagnostics {
20255                self.show_inline_diagnostics = show_inline_diagnostics;
20256                self.refresh_inline_diagnostics(false, window, cx);
20257            }
20258
20259            if self.git_blame_inline_enabled != inline_blame_enabled {
20260                self.toggle_git_blame_inline_internal(false, window, cx);
20261            }
20262
20263            let minimap_settings = EditorSettings::get_global(cx).minimap;
20264            if self.minimap_visibility != MinimapVisibility::Disabled {
20265                if self.minimap_visibility.settings_visibility()
20266                    != minimap_settings.minimap_enabled()
20267                {
20268                    self.set_minimap_visibility(
20269                        MinimapVisibility::for_mode(self.mode(), cx),
20270                        window,
20271                        cx,
20272                    );
20273                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20274                    minimap_entity.update(cx, |minimap_editor, cx| {
20275                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20276                    })
20277                }
20278            }
20279        }
20280
20281        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20282            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20283        }) {
20284            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20285                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20286            }
20287            self.refresh_colors(false, None, window, cx);
20288        }
20289
20290        cx.notify();
20291    }
20292
20293    pub fn set_searchable(&mut self, searchable: bool) {
20294        self.searchable = searchable;
20295    }
20296
20297    pub fn searchable(&self) -> bool {
20298        self.searchable
20299    }
20300
20301    fn open_proposed_changes_editor(
20302        &mut self,
20303        _: &OpenProposedChangesEditor,
20304        window: &mut Window,
20305        cx: &mut Context<Self>,
20306    ) {
20307        let Some(workspace) = self.workspace() else {
20308            cx.propagate();
20309            return;
20310        };
20311
20312        let selections = self.selections.all::<usize>(cx);
20313        let multi_buffer = self.buffer.read(cx);
20314        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20315        let mut new_selections_by_buffer = HashMap::default();
20316        for selection in selections {
20317            for (buffer, range, _) in
20318                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20319            {
20320                let mut range = range.to_point(buffer);
20321                range.start.column = 0;
20322                range.end.column = buffer.line_len(range.end.row);
20323                new_selections_by_buffer
20324                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20325                    .or_insert(Vec::new())
20326                    .push(range)
20327            }
20328        }
20329
20330        let proposed_changes_buffers = new_selections_by_buffer
20331            .into_iter()
20332            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20333            .collect::<Vec<_>>();
20334        let proposed_changes_editor = cx.new(|cx| {
20335            ProposedChangesEditor::new(
20336                "Proposed changes",
20337                proposed_changes_buffers,
20338                self.project.clone(),
20339                window,
20340                cx,
20341            )
20342        });
20343
20344        window.defer(cx, move |window, cx| {
20345            workspace.update(cx, |workspace, cx| {
20346                workspace.active_pane().update(cx, |pane, cx| {
20347                    pane.add_item(
20348                        Box::new(proposed_changes_editor),
20349                        true,
20350                        true,
20351                        None,
20352                        window,
20353                        cx,
20354                    );
20355                });
20356            });
20357        });
20358    }
20359
20360    pub fn open_excerpts_in_split(
20361        &mut self,
20362        _: &OpenExcerptsSplit,
20363        window: &mut Window,
20364        cx: &mut Context<Self>,
20365    ) {
20366        self.open_excerpts_common(None, true, window, cx)
20367    }
20368
20369    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20370        self.open_excerpts_common(None, false, window, cx)
20371    }
20372
20373    fn open_excerpts_common(
20374        &mut self,
20375        jump_data: Option<JumpData>,
20376        split: bool,
20377        window: &mut Window,
20378        cx: &mut Context<Self>,
20379    ) {
20380        let Some(workspace) = self.workspace() else {
20381            cx.propagate();
20382            return;
20383        };
20384
20385        if self.buffer.read(cx).is_singleton() {
20386            cx.propagate();
20387            return;
20388        }
20389
20390        let mut new_selections_by_buffer = HashMap::default();
20391        match &jump_data {
20392            Some(JumpData::MultiBufferPoint {
20393                excerpt_id,
20394                position,
20395                anchor,
20396                line_offset_from_top,
20397            }) => {
20398                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20399                if let Some(buffer) = multi_buffer_snapshot
20400                    .buffer_id_for_excerpt(*excerpt_id)
20401                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20402                {
20403                    let buffer_snapshot = buffer.read(cx).snapshot();
20404                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20405                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20406                    } else {
20407                        buffer_snapshot.clip_point(*position, Bias::Left)
20408                    };
20409                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20410                    new_selections_by_buffer.insert(
20411                        buffer,
20412                        (
20413                            vec![jump_to_offset..jump_to_offset],
20414                            Some(*line_offset_from_top),
20415                        ),
20416                    );
20417                }
20418            }
20419            Some(JumpData::MultiBufferRow {
20420                row,
20421                line_offset_from_top,
20422            }) => {
20423                let point = MultiBufferPoint::new(row.0, 0);
20424                if let Some((buffer, buffer_point, _)) =
20425                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20426                {
20427                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20428                    new_selections_by_buffer
20429                        .entry(buffer)
20430                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20431                        .0
20432                        .push(buffer_offset..buffer_offset)
20433                }
20434            }
20435            None => {
20436                let selections = self.selections.all::<usize>(cx);
20437                let multi_buffer = self.buffer.read(cx);
20438                for selection in selections {
20439                    for (snapshot, range, _, anchor) in multi_buffer
20440                        .snapshot(cx)
20441                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20442                    {
20443                        if let Some(anchor) = anchor {
20444                            // selection is in a deleted hunk
20445                            let Some(buffer_id) = anchor.buffer_id else {
20446                                continue;
20447                            };
20448                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20449                                continue;
20450                            };
20451                            let offset = text::ToOffset::to_offset(
20452                                &anchor.text_anchor,
20453                                &buffer_handle.read(cx).snapshot(),
20454                            );
20455                            let range = offset..offset;
20456                            new_selections_by_buffer
20457                                .entry(buffer_handle)
20458                                .or_insert((Vec::new(), None))
20459                                .0
20460                                .push(range)
20461                        } else {
20462                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20463                            else {
20464                                continue;
20465                            };
20466                            new_selections_by_buffer
20467                                .entry(buffer_handle)
20468                                .or_insert((Vec::new(), None))
20469                                .0
20470                                .push(range)
20471                        }
20472                    }
20473                }
20474            }
20475        }
20476
20477        new_selections_by_buffer
20478            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20479
20480        if new_selections_by_buffer.is_empty() {
20481            return;
20482        }
20483
20484        // We defer the pane interaction because we ourselves are a workspace item
20485        // and activating a new item causes the pane to call a method on us reentrantly,
20486        // which panics if we're on the stack.
20487        window.defer(cx, move |window, cx| {
20488            workspace.update(cx, |workspace, cx| {
20489                let pane = if split {
20490                    workspace.adjacent_pane(window, cx)
20491                } else {
20492                    workspace.active_pane().clone()
20493                };
20494
20495                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20496                    let editor = buffer
20497                        .read(cx)
20498                        .file()
20499                        .is_none()
20500                        .then(|| {
20501                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20502                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20503                            // Instead, we try to activate the existing editor in the pane first.
20504                            let (editor, pane_item_index) =
20505                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20506                                    let editor = item.downcast::<Editor>()?;
20507                                    let singleton_buffer =
20508                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20509                                    if singleton_buffer == buffer {
20510                                        Some((editor, i))
20511                                    } else {
20512                                        None
20513                                    }
20514                                })?;
20515                            pane.update(cx, |pane, cx| {
20516                                pane.activate_item(pane_item_index, true, true, window, cx)
20517                            });
20518                            Some(editor)
20519                        })
20520                        .flatten()
20521                        .unwrap_or_else(|| {
20522                            workspace.open_project_item::<Self>(
20523                                pane.clone(),
20524                                buffer,
20525                                true,
20526                                true,
20527                                window,
20528                                cx,
20529                            )
20530                        });
20531
20532                    editor.update(cx, |editor, cx| {
20533                        let autoscroll = match scroll_offset {
20534                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20535                            None => Autoscroll::newest(),
20536                        };
20537                        let nav_history = editor.nav_history.take();
20538                        editor.change_selections(
20539                            SelectionEffects::scroll(autoscroll),
20540                            window,
20541                            cx,
20542                            |s| {
20543                                s.select_ranges(ranges);
20544                            },
20545                        );
20546                        editor.nav_history = nav_history;
20547                    });
20548                }
20549            })
20550        });
20551    }
20552
20553    // For now, don't allow opening excerpts in buffers that aren't backed by
20554    // regular project files.
20555    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20556        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20557    }
20558
20559    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20560        let snapshot = self.buffer.read(cx).read(cx);
20561        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20562        Some(
20563            ranges
20564                .iter()
20565                .map(move |range| {
20566                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20567                })
20568                .collect(),
20569        )
20570    }
20571
20572    fn selection_replacement_ranges(
20573        &self,
20574        range: Range<OffsetUtf16>,
20575        cx: &mut App,
20576    ) -> Vec<Range<OffsetUtf16>> {
20577        let selections = self.selections.all::<OffsetUtf16>(cx);
20578        let newest_selection = selections
20579            .iter()
20580            .max_by_key(|selection| selection.id)
20581            .unwrap();
20582        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20583        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20584        let snapshot = self.buffer.read(cx).read(cx);
20585        selections
20586            .into_iter()
20587            .map(|mut selection| {
20588                selection.start.0 =
20589                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20590                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20591                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20592                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20593            })
20594            .collect()
20595    }
20596
20597    fn report_editor_event(
20598        &self,
20599        reported_event: ReportEditorEvent,
20600        file_extension: Option<String>,
20601        cx: &App,
20602    ) {
20603        if cfg!(any(test, feature = "test-support")) {
20604            return;
20605        }
20606
20607        let Some(project) = &self.project else { return };
20608
20609        // If None, we are in a file without an extension
20610        let file = self
20611            .buffer
20612            .read(cx)
20613            .as_singleton()
20614            .and_then(|b| b.read(cx).file());
20615        let file_extension = file_extension.or(file
20616            .as_ref()
20617            .and_then(|file| Path::new(file.file_name(cx)).extension())
20618            .and_then(|e| e.to_str())
20619            .map(|a| a.to_string()));
20620
20621        let vim_mode = vim_enabled(cx);
20622
20623        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20624        let copilot_enabled = edit_predictions_provider
20625            == language::language_settings::EditPredictionProvider::Copilot;
20626        let copilot_enabled_for_language = self
20627            .buffer
20628            .read(cx)
20629            .language_settings(cx)
20630            .show_edit_predictions;
20631
20632        let project = project.read(cx);
20633        let event_type = reported_event.event_type();
20634
20635        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20636            telemetry::event!(
20637                event_type,
20638                type = if auto_saved {"autosave"} else {"manual"},
20639                file_extension,
20640                vim_mode,
20641                copilot_enabled,
20642                copilot_enabled_for_language,
20643                edit_predictions_provider,
20644                is_via_ssh = project.is_via_ssh(),
20645            );
20646        } else {
20647            telemetry::event!(
20648                event_type,
20649                file_extension,
20650                vim_mode,
20651                copilot_enabled,
20652                copilot_enabled_for_language,
20653                edit_predictions_provider,
20654                is_via_ssh = project.is_via_ssh(),
20655            );
20656        };
20657    }
20658
20659    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20660    /// with each line being an array of {text, highlight} objects.
20661    fn copy_highlight_json(
20662        &mut self,
20663        _: &CopyHighlightJson,
20664        window: &mut Window,
20665        cx: &mut Context<Self>,
20666    ) {
20667        #[derive(Serialize)]
20668        struct Chunk<'a> {
20669            text: String,
20670            highlight: Option<&'a str>,
20671        }
20672
20673        let snapshot = self.buffer.read(cx).snapshot(cx);
20674        let range = self
20675            .selected_text_range(false, window, cx)
20676            .and_then(|selection| {
20677                if selection.range.is_empty() {
20678                    None
20679                } else {
20680                    Some(selection.range)
20681                }
20682            })
20683            .unwrap_or_else(|| 0..snapshot.len());
20684
20685        let chunks = snapshot.chunks(range, true);
20686        let mut lines = Vec::new();
20687        let mut line: VecDeque<Chunk> = VecDeque::new();
20688
20689        let Some(style) = self.style.as_ref() else {
20690            return;
20691        };
20692
20693        for chunk in chunks {
20694            let highlight = chunk
20695                .syntax_highlight_id
20696                .and_then(|id| id.name(&style.syntax));
20697            let mut chunk_lines = chunk.text.split('\n').peekable();
20698            while let Some(text) = chunk_lines.next() {
20699                let mut merged_with_last_token = false;
20700                if let Some(last_token) = line.back_mut()
20701                    && last_token.highlight == highlight
20702                {
20703                    last_token.text.push_str(text);
20704                    merged_with_last_token = true;
20705                }
20706
20707                if !merged_with_last_token {
20708                    line.push_back(Chunk {
20709                        text: text.into(),
20710                        highlight,
20711                    });
20712                }
20713
20714                if chunk_lines.peek().is_some() {
20715                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20716                        line.pop_front();
20717                    }
20718                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20719                        line.pop_back();
20720                    }
20721
20722                    lines.push(mem::take(&mut line));
20723                }
20724            }
20725        }
20726
20727        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20728            return;
20729        };
20730        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20731    }
20732
20733    pub fn open_context_menu(
20734        &mut self,
20735        _: &OpenContextMenu,
20736        window: &mut Window,
20737        cx: &mut Context<Self>,
20738    ) {
20739        self.request_autoscroll(Autoscroll::newest(), cx);
20740        let position = self.selections.newest_display(cx).start;
20741        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20742    }
20743
20744    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20745        &self.inlay_hint_cache
20746    }
20747
20748    pub fn replay_insert_event(
20749        &mut self,
20750        text: &str,
20751        relative_utf16_range: Option<Range<isize>>,
20752        window: &mut Window,
20753        cx: &mut Context<Self>,
20754    ) {
20755        if !self.input_enabled {
20756            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20757            return;
20758        }
20759        if let Some(relative_utf16_range) = relative_utf16_range {
20760            let selections = self.selections.all::<OffsetUtf16>(cx);
20761            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20762                let new_ranges = selections.into_iter().map(|range| {
20763                    let start = OffsetUtf16(
20764                        range
20765                            .head()
20766                            .0
20767                            .saturating_add_signed(relative_utf16_range.start),
20768                    );
20769                    let end = OffsetUtf16(
20770                        range
20771                            .head()
20772                            .0
20773                            .saturating_add_signed(relative_utf16_range.end),
20774                    );
20775                    start..end
20776                });
20777                s.select_ranges(new_ranges);
20778            });
20779        }
20780
20781        self.handle_input(text, window, cx);
20782    }
20783
20784    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20785        let Some(provider) = self.semantics_provider.as_ref() else {
20786            return false;
20787        };
20788
20789        let mut supports = false;
20790        self.buffer().update(cx, |this, cx| {
20791            this.for_each_buffer(|buffer| {
20792                supports |= provider.supports_inlay_hints(buffer, cx);
20793            });
20794        });
20795
20796        supports
20797    }
20798
20799    pub fn is_focused(&self, window: &Window) -> bool {
20800        self.focus_handle.is_focused(window)
20801    }
20802
20803    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20804        cx.emit(EditorEvent::Focused);
20805
20806        if let Some(descendant) = self
20807            .last_focused_descendant
20808            .take()
20809            .and_then(|descendant| descendant.upgrade())
20810        {
20811            window.focus(&descendant);
20812        } else {
20813            if let Some(blame) = self.blame.as_ref() {
20814                blame.update(cx, GitBlame::focus)
20815            }
20816
20817            self.blink_manager.update(cx, BlinkManager::enable);
20818            self.show_cursor_names(window, cx);
20819            self.buffer.update(cx, |buffer, cx| {
20820                buffer.finalize_last_transaction(cx);
20821                if self.leader_id.is_none() {
20822                    buffer.set_active_selections(
20823                        &self.selections.disjoint_anchors(),
20824                        self.selections.line_mode,
20825                        self.cursor_shape,
20826                        cx,
20827                    );
20828                }
20829            });
20830        }
20831    }
20832
20833    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20834        cx.emit(EditorEvent::FocusedIn)
20835    }
20836
20837    fn handle_focus_out(
20838        &mut self,
20839        event: FocusOutEvent,
20840        _window: &mut Window,
20841        cx: &mut Context<Self>,
20842    ) {
20843        if event.blurred != self.focus_handle {
20844            self.last_focused_descendant = Some(event.blurred);
20845        }
20846        self.selection_drag_state = SelectionDragState::None;
20847        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20848    }
20849
20850    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20851        self.blink_manager.update(cx, BlinkManager::disable);
20852        self.buffer
20853            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20854
20855        if let Some(blame) = self.blame.as_ref() {
20856            blame.update(cx, GitBlame::blur)
20857        }
20858        if !self.hover_state.focused(window, cx) {
20859            hide_hover(self, cx);
20860        }
20861        if !self
20862            .context_menu
20863            .borrow()
20864            .as_ref()
20865            .is_some_and(|context_menu| context_menu.focused(window, cx))
20866        {
20867            self.hide_context_menu(window, cx);
20868        }
20869        self.discard_edit_prediction(false, cx);
20870        cx.emit(EditorEvent::Blurred);
20871        cx.notify();
20872    }
20873
20874    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20875        let mut pending: String = window
20876            .pending_input_keystrokes()
20877            .into_iter()
20878            .flatten()
20879            .filter_map(|keystroke| {
20880                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20881                    keystroke.key_char.clone()
20882                } else {
20883                    None
20884                }
20885            })
20886            .collect();
20887
20888        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20889            pending = "".to_string();
20890        }
20891
20892        let existing_pending = self
20893            .text_highlights::<PendingInput>(cx)
20894            .map(|(_, ranges)| ranges.to_vec());
20895        if existing_pending.is_none() && pending.is_empty() {
20896            return;
20897        }
20898        let transaction =
20899            self.transact(window, cx, |this, window, cx| {
20900                let selections = this.selections.all::<usize>(cx);
20901                let edits = selections
20902                    .iter()
20903                    .map(|selection| (selection.end..selection.end, pending.clone()));
20904                this.edit(edits, cx);
20905                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20906                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20907                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20908                    }));
20909                });
20910                if let Some(existing_ranges) = existing_pending {
20911                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20912                    this.edit(edits, cx);
20913                }
20914            });
20915
20916        let snapshot = self.snapshot(window, cx);
20917        let ranges = self
20918            .selections
20919            .all::<usize>(cx)
20920            .into_iter()
20921            .map(|selection| {
20922                snapshot.buffer_snapshot.anchor_after(selection.end)
20923                    ..snapshot
20924                        .buffer_snapshot
20925                        .anchor_before(selection.end + pending.len())
20926            })
20927            .collect();
20928
20929        if pending.is_empty() {
20930            self.clear_highlights::<PendingInput>(cx);
20931        } else {
20932            self.highlight_text::<PendingInput>(
20933                ranges,
20934                HighlightStyle {
20935                    underline: Some(UnderlineStyle {
20936                        thickness: px(1.),
20937                        color: None,
20938                        wavy: false,
20939                    }),
20940                    ..Default::default()
20941                },
20942                cx,
20943            );
20944        }
20945
20946        self.ime_transaction = self.ime_transaction.or(transaction);
20947        if let Some(transaction) = self.ime_transaction {
20948            self.buffer.update(cx, |buffer, cx| {
20949                buffer.group_until_transaction(transaction, cx);
20950            });
20951        }
20952
20953        if self.text_highlights::<PendingInput>(cx).is_none() {
20954            self.ime_transaction.take();
20955        }
20956    }
20957
20958    pub fn register_action_renderer(
20959        &mut self,
20960        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20961    ) -> Subscription {
20962        let id = self.next_editor_action_id.post_inc();
20963        self.editor_actions
20964            .borrow_mut()
20965            .insert(id, Box::new(listener));
20966
20967        let editor_actions = self.editor_actions.clone();
20968        Subscription::new(move || {
20969            editor_actions.borrow_mut().remove(&id);
20970        })
20971    }
20972
20973    pub fn register_action<A: Action>(
20974        &mut self,
20975        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20976    ) -> Subscription {
20977        let id = self.next_editor_action_id.post_inc();
20978        let listener = Arc::new(listener);
20979        self.editor_actions.borrow_mut().insert(
20980            id,
20981            Box::new(move |_, window, _| {
20982                let listener = listener.clone();
20983                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20984                    let action = action.downcast_ref().unwrap();
20985                    if phase == DispatchPhase::Bubble {
20986                        listener(action, window, cx)
20987                    }
20988                })
20989            }),
20990        );
20991
20992        let editor_actions = self.editor_actions.clone();
20993        Subscription::new(move || {
20994            editor_actions.borrow_mut().remove(&id);
20995        })
20996    }
20997
20998    pub fn file_header_size(&self) -> u32 {
20999        FILE_HEADER_HEIGHT
21000    }
21001
21002    pub fn restore(
21003        &mut self,
21004        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21005        window: &mut Window,
21006        cx: &mut Context<Self>,
21007    ) {
21008        let workspace = self.workspace();
21009        let project = self.project();
21010        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21011            let mut tasks = Vec::new();
21012            for (buffer_id, changes) in revert_changes {
21013                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21014                    buffer.update(cx, |buffer, cx| {
21015                        buffer.edit(
21016                            changes
21017                                .into_iter()
21018                                .map(|(range, text)| (range, text.to_string())),
21019                            None,
21020                            cx,
21021                        );
21022                    });
21023
21024                    if let Some(project) =
21025                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21026                    {
21027                        project.update(cx, |project, cx| {
21028                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21029                        })
21030                    }
21031                }
21032            }
21033            tasks
21034        });
21035        cx.spawn_in(window, async move |_, cx| {
21036            for (buffer, task) in save_tasks {
21037                let result = task.await;
21038                if result.is_err() {
21039                    let Some(path) = buffer
21040                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21041                        .ok()
21042                    else {
21043                        continue;
21044                    };
21045                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21046                        let Some(task) = cx
21047                            .update_window_entity(workspace, |workspace, window, cx| {
21048                                workspace
21049                                    .open_path_preview(path, None, false, false, false, window, cx)
21050                            })
21051                            .ok()
21052                        else {
21053                            continue;
21054                        };
21055                        task.await.log_err();
21056                    }
21057                }
21058            }
21059        })
21060        .detach();
21061        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21062            selections.refresh()
21063        });
21064    }
21065
21066    pub fn to_pixel_point(
21067        &self,
21068        source: multi_buffer::Anchor,
21069        editor_snapshot: &EditorSnapshot,
21070        window: &mut Window,
21071    ) -> Option<gpui::Point<Pixels>> {
21072        let source_point = source.to_display_point(editor_snapshot);
21073        self.display_to_pixel_point(source_point, editor_snapshot, window)
21074    }
21075
21076    pub fn display_to_pixel_point(
21077        &self,
21078        source: DisplayPoint,
21079        editor_snapshot: &EditorSnapshot,
21080        window: &mut Window,
21081    ) -> Option<gpui::Point<Pixels>> {
21082        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21083        let text_layout_details = self.text_layout_details(window);
21084        let scroll_top = text_layout_details
21085            .scroll_anchor
21086            .scroll_position(editor_snapshot)
21087            .y;
21088
21089        if source.row().as_f32() < scroll_top.floor() {
21090            return None;
21091        }
21092        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21093        let source_y = line_height * (source.row().as_f32() - scroll_top);
21094        Some(gpui::Point::new(source_x, source_y))
21095    }
21096
21097    pub fn has_visible_completions_menu(&self) -> bool {
21098        !self.edit_prediction_preview_is_active()
21099            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21100                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21101            })
21102    }
21103
21104    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21105        if self.mode.is_minimap() {
21106            return;
21107        }
21108        self.addons
21109            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21110    }
21111
21112    pub fn unregister_addon<T: Addon>(&mut self) {
21113        self.addons.remove(&std::any::TypeId::of::<T>());
21114    }
21115
21116    pub fn addon<T: Addon>(&self) -> Option<&T> {
21117        let type_id = std::any::TypeId::of::<T>();
21118        self.addons
21119            .get(&type_id)
21120            .and_then(|item| item.to_any().downcast_ref::<T>())
21121    }
21122
21123    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21124        let type_id = std::any::TypeId::of::<T>();
21125        self.addons
21126            .get_mut(&type_id)
21127            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21128    }
21129
21130    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21131        let text_layout_details = self.text_layout_details(window);
21132        let style = &text_layout_details.editor_style;
21133        let font_id = window.text_system().resolve_font(&style.text.font());
21134        let font_size = style.text.font_size.to_pixels(window.rem_size());
21135        let line_height = style.text.line_height_in_pixels(window.rem_size());
21136        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21137        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21138
21139        CharacterDimensions {
21140            em_width,
21141            em_advance,
21142            line_height,
21143        }
21144    }
21145
21146    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21147        self.load_diff_task.clone()
21148    }
21149
21150    fn read_metadata_from_db(
21151        &mut self,
21152        item_id: u64,
21153        workspace_id: WorkspaceId,
21154        window: &mut Window,
21155        cx: &mut Context<Editor>,
21156    ) {
21157        if self.is_singleton(cx)
21158            && !self.mode.is_minimap()
21159            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21160        {
21161            let buffer_snapshot = OnceCell::new();
21162
21163            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21164                && !folds.is_empty()
21165            {
21166                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21167                self.fold_ranges(
21168                    folds
21169                        .into_iter()
21170                        .map(|(start, end)| {
21171                            snapshot.clip_offset(start, Bias::Left)
21172                                ..snapshot.clip_offset(end, Bias::Right)
21173                        })
21174                        .collect(),
21175                    false,
21176                    window,
21177                    cx,
21178                );
21179            }
21180
21181            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21182                && !selections.is_empty()
21183            {
21184                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21185                // skip adding the initial selection to selection history
21186                self.selection_history.mode = SelectionHistoryMode::Skipping;
21187                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21188                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21189                        snapshot.clip_offset(start, Bias::Left)
21190                            ..snapshot.clip_offset(end, Bias::Right)
21191                    }));
21192                });
21193                self.selection_history.mode = SelectionHistoryMode::Normal;
21194            };
21195        }
21196
21197        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21198    }
21199
21200    fn update_lsp_data(
21201        &mut self,
21202        ignore_cache: bool,
21203        for_buffer: Option<BufferId>,
21204        window: &mut Window,
21205        cx: &mut Context<'_, Self>,
21206    ) {
21207        self.pull_diagnostics(for_buffer, window, cx);
21208        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21209    }
21210}
21211
21212fn vim_enabled(cx: &App) -> bool {
21213    cx.global::<SettingsStore>()
21214        .raw_user_settings()
21215        .get("vim_mode")
21216        == Some(&serde_json::Value::Bool(true))
21217}
21218
21219fn process_completion_for_edit(
21220    completion: &Completion,
21221    intent: CompletionIntent,
21222    buffer: &Entity<Buffer>,
21223    cursor_position: &text::Anchor,
21224    cx: &mut Context<Editor>,
21225) -> CompletionEdit {
21226    let buffer = buffer.read(cx);
21227    let buffer_snapshot = buffer.snapshot();
21228    let (snippet, new_text) = if completion.is_snippet() {
21229        // Workaround for typescript language server issues so that methods don't expand within
21230        // strings and functions with type expressions. The previous point is used because the query
21231        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21232        let mut snippet_source = completion.new_text.clone();
21233        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21234        previous_point.column = previous_point.column.saturating_sub(1);
21235        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21236            && scope.prefers_label_for_snippet_in_completion()
21237            && let Some(label) = completion.label()
21238            && matches!(
21239                completion.kind(),
21240                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21241            )
21242        {
21243            snippet_source = label;
21244        }
21245        match Snippet::parse(&snippet_source).log_err() {
21246            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21247            None => (None, completion.new_text.clone()),
21248        }
21249    } else {
21250        (None, completion.new_text.clone())
21251    };
21252
21253    let mut range_to_replace = {
21254        let replace_range = &completion.replace_range;
21255        if let CompletionSource::Lsp {
21256            insert_range: Some(insert_range),
21257            ..
21258        } = &completion.source
21259        {
21260            debug_assert_eq!(
21261                insert_range.start, replace_range.start,
21262                "insert_range and replace_range should start at the same position"
21263            );
21264            debug_assert!(
21265                insert_range
21266                    .start
21267                    .cmp(cursor_position, &buffer_snapshot)
21268                    .is_le(),
21269                "insert_range should start before or at cursor position"
21270            );
21271            debug_assert!(
21272                replace_range
21273                    .start
21274                    .cmp(cursor_position, &buffer_snapshot)
21275                    .is_le(),
21276                "replace_range should start before or at cursor position"
21277            );
21278
21279            let should_replace = match intent {
21280                CompletionIntent::CompleteWithInsert => false,
21281                CompletionIntent::CompleteWithReplace => true,
21282                CompletionIntent::Complete | CompletionIntent::Compose => {
21283                    let insert_mode =
21284                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21285                            .completions
21286                            .lsp_insert_mode;
21287                    match insert_mode {
21288                        LspInsertMode::Insert => false,
21289                        LspInsertMode::Replace => true,
21290                        LspInsertMode::ReplaceSubsequence => {
21291                            let mut text_to_replace = buffer.chars_for_range(
21292                                buffer.anchor_before(replace_range.start)
21293                                    ..buffer.anchor_after(replace_range.end),
21294                            );
21295                            let mut current_needle = text_to_replace.next();
21296                            for haystack_ch in completion.label.text.chars() {
21297                                if let Some(needle_ch) = current_needle
21298                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21299                                {
21300                                    current_needle = text_to_replace.next();
21301                                }
21302                            }
21303                            current_needle.is_none()
21304                        }
21305                        LspInsertMode::ReplaceSuffix => {
21306                            if replace_range
21307                                .end
21308                                .cmp(cursor_position, &buffer_snapshot)
21309                                .is_gt()
21310                            {
21311                                let range_after_cursor = *cursor_position..replace_range.end;
21312                                let text_after_cursor = buffer
21313                                    .text_for_range(
21314                                        buffer.anchor_before(range_after_cursor.start)
21315                                            ..buffer.anchor_after(range_after_cursor.end),
21316                                    )
21317                                    .collect::<String>()
21318                                    .to_ascii_lowercase();
21319                                completion
21320                                    .label
21321                                    .text
21322                                    .to_ascii_lowercase()
21323                                    .ends_with(&text_after_cursor)
21324                            } else {
21325                                true
21326                            }
21327                        }
21328                    }
21329                }
21330            };
21331
21332            if should_replace {
21333                replace_range.clone()
21334            } else {
21335                insert_range.clone()
21336            }
21337        } else {
21338            replace_range.clone()
21339        }
21340    };
21341
21342    if range_to_replace
21343        .end
21344        .cmp(cursor_position, &buffer_snapshot)
21345        .is_lt()
21346    {
21347        range_to_replace.end = *cursor_position;
21348    }
21349
21350    CompletionEdit {
21351        new_text,
21352        replace_range: range_to_replace.to_offset(buffer),
21353        snippet,
21354    }
21355}
21356
21357struct CompletionEdit {
21358    new_text: String,
21359    replace_range: Range<usize>,
21360    snippet: Option<Snippet>,
21361}
21362
21363fn insert_extra_newline_brackets(
21364    buffer: &MultiBufferSnapshot,
21365    range: Range<usize>,
21366    language: &language::LanguageScope,
21367) -> bool {
21368    let leading_whitespace_len = buffer
21369        .reversed_chars_at(range.start)
21370        .take_while(|c| c.is_whitespace() && *c != '\n')
21371        .map(|c| c.len_utf8())
21372        .sum::<usize>();
21373    let trailing_whitespace_len = buffer
21374        .chars_at(range.end)
21375        .take_while(|c| c.is_whitespace() && *c != '\n')
21376        .map(|c| c.len_utf8())
21377        .sum::<usize>();
21378    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21379
21380    language.brackets().any(|(pair, enabled)| {
21381        let pair_start = pair.start.trim_end();
21382        let pair_end = pair.end.trim_start();
21383
21384        enabled
21385            && pair.newline
21386            && buffer.contains_str_at(range.end, pair_end)
21387            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21388    })
21389}
21390
21391fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21392    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21393        [(buffer, range, _)] => (*buffer, range.clone()),
21394        _ => return false,
21395    };
21396    let pair = {
21397        let mut result: Option<BracketMatch> = None;
21398
21399        for pair in buffer
21400            .all_bracket_ranges(range.clone())
21401            .filter(move |pair| {
21402                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21403            })
21404        {
21405            let len = pair.close_range.end - pair.open_range.start;
21406
21407            if let Some(existing) = &result {
21408                let existing_len = existing.close_range.end - existing.open_range.start;
21409                if len > existing_len {
21410                    continue;
21411                }
21412            }
21413
21414            result = Some(pair);
21415        }
21416
21417        result
21418    };
21419    let Some(pair) = pair else {
21420        return false;
21421    };
21422    pair.newline_only
21423        && buffer
21424            .chars_for_range(pair.open_range.end..range.start)
21425            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21426            .all(|c| c.is_whitespace() && c != '\n')
21427}
21428
21429fn update_uncommitted_diff_for_buffer(
21430    editor: Entity<Editor>,
21431    project: &Entity<Project>,
21432    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21433    buffer: Entity<MultiBuffer>,
21434    cx: &mut App,
21435) -> Task<()> {
21436    let mut tasks = Vec::new();
21437    project.update(cx, |project, cx| {
21438        for buffer in buffers {
21439            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21440                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21441            }
21442        }
21443    });
21444    cx.spawn(async move |cx| {
21445        let diffs = future::join_all(tasks).await;
21446        if editor
21447            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21448            .unwrap_or(false)
21449        {
21450            return;
21451        }
21452
21453        buffer
21454            .update(cx, |buffer, cx| {
21455                for diff in diffs.into_iter().flatten() {
21456                    buffer.add_diff(diff, cx);
21457                }
21458            })
21459            .ok();
21460    })
21461}
21462
21463fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21464    let tab_size = tab_size.get() as usize;
21465    let mut width = offset;
21466
21467    for ch in text.chars() {
21468        width += if ch == '\t' {
21469            tab_size - (width % tab_size)
21470        } else {
21471            1
21472        };
21473    }
21474
21475    width - offset
21476}
21477
21478#[cfg(test)]
21479mod tests {
21480    use super::*;
21481
21482    #[test]
21483    fn test_string_size_with_expanded_tabs() {
21484        let nz = |val| NonZeroU32::new(val).unwrap();
21485        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21486        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21487        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21488        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21489        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21490        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21491        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21492        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21493    }
21494}
21495
21496/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21497struct WordBreakingTokenizer<'a> {
21498    input: &'a str,
21499}
21500
21501impl<'a> WordBreakingTokenizer<'a> {
21502    fn new(input: &'a str) -> Self {
21503        Self { input }
21504    }
21505}
21506
21507fn is_char_ideographic(ch: char) -> bool {
21508    use unicode_script::Script::*;
21509    use unicode_script::UnicodeScript;
21510    matches!(ch.script(), Han | Tangut | Yi)
21511}
21512
21513fn is_grapheme_ideographic(text: &str) -> bool {
21514    text.chars().any(is_char_ideographic)
21515}
21516
21517fn is_grapheme_whitespace(text: &str) -> bool {
21518    text.chars().any(|x| x.is_whitespace())
21519}
21520
21521fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21522    text.chars()
21523        .next()
21524        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21525}
21526
21527#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21528enum WordBreakToken<'a> {
21529    Word { token: &'a str, grapheme_len: usize },
21530    InlineWhitespace { token: &'a str, grapheme_len: usize },
21531    Newline,
21532}
21533
21534impl<'a> Iterator for WordBreakingTokenizer<'a> {
21535    /// Yields a span, the count of graphemes in the token, and whether it was
21536    /// whitespace. Note that it also breaks at word boundaries.
21537    type Item = WordBreakToken<'a>;
21538
21539    fn next(&mut self) -> Option<Self::Item> {
21540        use unicode_segmentation::UnicodeSegmentation;
21541        if self.input.is_empty() {
21542            return None;
21543        }
21544
21545        let mut iter = self.input.graphemes(true).peekable();
21546        let mut offset = 0;
21547        let mut grapheme_len = 0;
21548        if let Some(first_grapheme) = iter.next() {
21549            let is_newline = first_grapheme == "\n";
21550            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21551            offset += first_grapheme.len();
21552            grapheme_len += 1;
21553            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21554                if let Some(grapheme) = iter.peek().copied()
21555                    && should_stay_with_preceding_ideograph(grapheme)
21556                {
21557                    offset += grapheme.len();
21558                    grapheme_len += 1;
21559                }
21560            } else {
21561                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21562                let mut next_word_bound = words.peek().copied();
21563                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21564                    next_word_bound = words.next();
21565                }
21566                while let Some(grapheme) = iter.peek().copied() {
21567                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21568                        break;
21569                    };
21570                    if is_grapheme_whitespace(grapheme) != is_whitespace
21571                        || (grapheme == "\n") != is_newline
21572                    {
21573                        break;
21574                    };
21575                    offset += grapheme.len();
21576                    grapheme_len += 1;
21577                    iter.next();
21578                }
21579            }
21580            let token = &self.input[..offset];
21581            self.input = &self.input[offset..];
21582            if token == "\n" {
21583                Some(WordBreakToken::Newline)
21584            } else if is_whitespace {
21585                Some(WordBreakToken::InlineWhitespace {
21586                    token,
21587                    grapheme_len,
21588                })
21589            } else {
21590                Some(WordBreakToken::Word {
21591                    token,
21592                    grapheme_len,
21593                })
21594            }
21595        } else {
21596            None
21597        }
21598    }
21599}
21600
21601#[test]
21602fn test_word_breaking_tokenizer() {
21603    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21604        ("", &[]),
21605        ("  ", &[whitespace("  ", 2)]),
21606        ("Ʒ", &[word("Ʒ", 1)]),
21607        ("Ǽ", &[word("Ǽ", 1)]),
21608        ("", &[word("", 1)]),
21609        ("⋑⋑", &[word("⋑⋑", 2)]),
21610        (
21611            "原理,进而",
21612            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21613        ),
21614        (
21615            "hello world",
21616            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21617        ),
21618        (
21619            "hello, world",
21620            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21621        ),
21622        (
21623            "  hello world",
21624            &[
21625                whitespace("  ", 2),
21626                word("hello", 5),
21627                whitespace(" ", 1),
21628                word("world", 5),
21629            ],
21630        ),
21631        (
21632            "这是什么 \n 钢笔",
21633            &[
21634                word("", 1),
21635                word("", 1),
21636                word("", 1),
21637                word("", 1),
21638                whitespace(" ", 1),
21639                newline(),
21640                whitespace(" ", 1),
21641                word("", 1),
21642                word("", 1),
21643            ],
21644        ),
21645        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21646    ];
21647
21648    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21649        WordBreakToken::Word {
21650            token,
21651            grapheme_len,
21652        }
21653    }
21654
21655    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21656        WordBreakToken::InlineWhitespace {
21657            token,
21658            grapheme_len,
21659        }
21660    }
21661
21662    fn newline() -> WordBreakToken<'static> {
21663        WordBreakToken::Newline
21664    }
21665
21666    for (input, result) in tests {
21667        assert_eq!(
21668            WordBreakingTokenizer::new(input)
21669                .collect::<Vec<_>>()
21670                .as_slice(),
21671            *result,
21672        );
21673    }
21674}
21675
21676fn wrap_with_prefix(
21677    first_line_prefix: String,
21678    subsequent_lines_prefix: String,
21679    unwrapped_text: String,
21680    wrap_column: usize,
21681    tab_size: NonZeroU32,
21682    preserve_existing_whitespace: bool,
21683) -> String {
21684    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21685    let subsequent_lines_prefix_len =
21686        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21687    let mut wrapped_text = String::new();
21688    let mut current_line = first_line_prefix.clone();
21689    let mut is_first_line = true;
21690
21691    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21692    let mut current_line_len = first_line_prefix_len;
21693    let mut in_whitespace = false;
21694    for token in tokenizer {
21695        let have_preceding_whitespace = in_whitespace;
21696        match token {
21697            WordBreakToken::Word {
21698                token,
21699                grapheme_len,
21700            } => {
21701                in_whitespace = false;
21702                let current_prefix_len = if is_first_line {
21703                    first_line_prefix_len
21704                } else {
21705                    subsequent_lines_prefix_len
21706                };
21707                if current_line_len + grapheme_len > wrap_column
21708                    && current_line_len != current_prefix_len
21709                {
21710                    wrapped_text.push_str(current_line.trim_end());
21711                    wrapped_text.push('\n');
21712                    is_first_line = false;
21713                    current_line = subsequent_lines_prefix.clone();
21714                    current_line_len = subsequent_lines_prefix_len;
21715                }
21716                current_line.push_str(token);
21717                current_line_len += grapheme_len;
21718            }
21719            WordBreakToken::InlineWhitespace {
21720                mut token,
21721                mut grapheme_len,
21722            } => {
21723                in_whitespace = true;
21724                if have_preceding_whitespace && !preserve_existing_whitespace {
21725                    continue;
21726                }
21727                if !preserve_existing_whitespace {
21728                    token = " ";
21729                    grapheme_len = 1;
21730                }
21731                let current_prefix_len = if is_first_line {
21732                    first_line_prefix_len
21733                } else {
21734                    subsequent_lines_prefix_len
21735                };
21736                if current_line_len + grapheme_len > wrap_column {
21737                    wrapped_text.push_str(current_line.trim_end());
21738                    wrapped_text.push('\n');
21739                    is_first_line = false;
21740                    current_line = subsequent_lines_prefix.clone();
21741                    current_line_len = subsequent_lines_prefix_len;
21742                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21743                    current_line.push_str(token);
21744                    current_line_len += grapheme_len;
21745                }
21746            }
21747            WordBreakToken::Newline => {
21748                in_whitespace = true;
21749                let current_prefix_len = if is_first_line {
21750                    first_line_prefix_len
21751                } else {
21752                    subsequent_lines_prefix_len
21753                };
21754                if preserve_existing_whitespace {
21755                    wrapped_text.push_str(current_line.trim_end());
21756                    wrapped_text.push('\n');
21757                    is_first_line = false;
21758                    current_line = subsequent_lines_prefix.clone();
21759                    current_line_len = subsequent_lines_prefix_len;
21760                } else if have_preceding_whitespace {
21761                    continue;
21762                } else if current_line_len + 1 > wrap_column
21763                    && current_line_len != current_prefix_len
21764                {
21765                    wrapped_text.push_str(current_line.trim_end());
21766                    wrapped_text.push('\n');
21767                    is_first_line = false;
21768                    current_line = subsequent_lines_prefix.clone();
21769                    current_line_len = subsequent_lines_prefix_len;
21770                } else if current_line_len != current_prefix_len {
21771                    current_line.push(' ');
21772                    current_line_len += 1;
21773                }
21774            }
21775        }
21776    }
21777
21778    if !current_line.is_empty() {
21779        wrapped_text.push_str(&current_line);
21780    }
21781    wrapped_text
21782}
21783
21784#[test]
21785fn test_wrap_with_prefix() {
21786    assert_eq!(
21787        wrap_with_prefix(
21788            "# ".to_string(),
21789            "# ".to_string(),
21790            "abcdefg".to_string(),
21791            4,
21792            NonZeroU32::new(4).unwrap(),
21793            false,
21794        ),
21795        "# abcdefg"
21796    );
21797    assert_eq!(
21798        wrap_with_prefix(
21799            "".to_string(),
21800            "".to_string(),
21801            "\thello world".to_string(),
21802            8,
21803            NonZeroU32::new(4).unwrap(),
21804            false,
21805        ),
21806        "hello\nworld"
21807    );
21808    assert_eq!(
21809        wrap_with_prefix(
21810            "// ".to_string(),
21811            "// ".to_string(),
21812            "xx \nyy zz aa bb cc".to_string(),
21813            12,
21814            NonZeroU32::new(4).unwrap(),
21815            false,
21816        ),
21817        "// xx yy zz\n// aa bb cc"
21818    );
21819    assert_eq!(
21820        wrap_with_prefix(
21821            String::new(),
21822            String::new(),
21823            "这是什么 \n 钢笔".to_string(),
21824            3,
21825            NonZeroU32::new(4).unwrap(),
21826            false,
21827        ),
21828        "这是什\n么 钢\n"
21829    );
21830}
21831
21832pub trait CollaborationHub {
21833    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21834    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21835    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21836}
21837
21838impl CollaborationHub for Entity<Project> {
21839    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21840        self.read(cx).collaborators()
21841    }
21842
21843    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21844        self.read(cx).user_store().read(cx).participant_indices()
21845    }
21846
21847    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21848        let this = self.read(cx);
21849        let user_ids = this.collaborators().values().map(|c| c.user_id);
21850        this.user_store().read(cx).participant_names(user_ids, cx)
21851    }
21852}
21853
21854pub trait SemanticsProvider {
21855    fn hover(
21856        &self,
21857        buffer: &Entity<Buffer>,
21858        position: text::Anchor,
21859        cx: &mut App,
21860    ) -> Option<Task<Vec<project::Hover>>>;
21861
21862    fn inline_values(
21863        &self,
21864        buffer_handle: Entity<Buffer>,
21865        range: Range<text::Anchor>,
21866        cx: &mut App,
21867    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21868
21869    fn inlay_hints(
21870        &self,
21871        buffer_handle: Entity<Buffer>,
21872        range: Range<text::Anchor>,
21873        cx: &mut App,
21874    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21875
21876    fn resolve_inlay_hint(
21877        &self,
21878        hint: InlayHint,
21879        buffer_handle: Entity<Buffer>,
21880        server_id: LanguageServerId,
21881        cx: &mut App,
21882    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21883
21884    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21885
21886    fn document_highlights(
21887        &self,
21888        buffer: &Entity<Buffer>,
21889        position: text::Anchor,
21890        cx: &mut App,
21891    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21892
21893    fn definitions(
21894        &self,
21895        buffer: &Entity<Buffer>,
21896        position: text::Anchor,
21897        kind: GotoDefinitionKind,
21898        cx: &mut App,
21899    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21900
21901    fn range_for_rename(
21902        &self,
21903        buffer: &Entity<Buffer>,
21904        position: text::Anchor,
21905        cx: &mut App,
21906    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21907
21908    fn perform_rename(
21909        &self,
21910        buffer: &Entity<Buffer>,
21911        position: text::Anchor,
21912        new_name: String,
21913        cx: &mut App,
21914    ) -> Option<Task<Result<ProjectTransaction>>>;
21915}
21916
21917pub trait CompletionProvider {
21918    fn completions(
21919        &self,
21920        excerpt_id: ExcerptId,
21921        buffer: &Entity<Buffer>,
21922        buffer_position: text::Anchor,
21923        trigger: CompletionContext,
21924        window: &mut Window,
21925        cx: &mut Context<Editor>,
21926    ) -> Task<Result<Vec<CompletionResponse>>>;
21927
21928    fn resolve_completions(
21929        &self,
21930        _buffer: Entity<Buffer>,
21931        _completion_indices: Vec<usize>,
21932        _completions: Rc<RefCell<Box<[Completion]>>>,
21933        _cx: &mut Context<Editor>,
21934    ) -> Task<Result<bool>> {
21935        Task::ready(Ok(false))
21936    }
21937
21938    fn apply_additional_edits_for_completion(
21939        &self,
21940        _buffer: Entity<Buffer>,
21941        _completions: Rc<RefCell<Box<[Completion]>>>,
21942        _completion_index: usize,
21943        _push_to_history: bool,
21944        _cx: &mut Context<Editor>,
21945    ) -> Task<Result<Option<language::Transaction>>> {
21946        Task::ready(Ok(None))
21947    }
21948
21949    fn is_completion_trigger(
21950        &self,
21951        buffer: &Entity<Buffer>,
21952        position: language::Anchor,
21953        text: &str,
21954        trigger_in_words: bool,
21955        menu_is_open: bool,
21956        cx: &mut Context<Editor>,
21957    ) -> bool;
21958
21959    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21960
21961    fn sort_completions(&self) -> bool {
21962        true
21963    }
21964
21965    fn filter_completions(&self) -> bool {
21966        true
21967    }
21968}
21969
21970pub trait CodeActionProvider {
21971    fn id(&self) -> Arc<str>;
21972
21973    fn code_actions(
21974        &self,
21975        buffer: &Entity<Buffer>,
21976        range: Range<text::Anchor>,
21977        window: &mut Window,
21978        cx: &mut App,
21979    ) -> Task<Result<Vec<CodeAction>>>;
21980
21981    fn apply_code_action(
21982        &self,
21983        buffer_handle: Entity<Buffer>,
21984        action: CodeAction,
21985        excerpt_id: ExcerptId,
21986        push_to_history: bool,
21987        window: &mut Window,
21988        cx: &mut App,
21989    ) -> Task<Result<ProjectTransaction>>;
21990}
21991
21992impl CodeActionProvider for Entity<Project> {
21993    fn id(&self) -> Arc<str> {
21994        "project".into()
21995    }
21996
21997    fn code_actions(
21998        &self,
21999        buffer: &Entity<Buffer>,
22000        range: Range<text::Anchor>,
22001        _window: &mut Window,
22002        cx: &mut App,
22003    ) -> Task<Result<Vec<CodeAction>>> {
22004        self.update(cx, |project, cx| {
22005            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22006            let code_actions = project.code_actions(buffer, range, None, cx);
22007            cx.background_spawn(async move {
22008                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22009                Ok(code_lens_actions
22010                    .context("code lens fetch")?
22011                    .into_iter()
22012                    .chain(code_actions.context("code action fetch")?)
22013                    .collect())
22014            })
22015        })
22016    }
22017
22018    fn apply_code_action(
22019        &self,
22020        buffer_handle: Entity<Buffer>,
22021        action: CodeAction,
22022        _excerpt_id: ExcerptId,
22023        push_to_history: bool,
22024        _window: &mut Window,
22025        cx: &mut App,
22026    ) -> Task<Result<ProjectTransaction>> {
22027        self.update(cx, |project, cx| {
22028            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22029        })
22030    }
22031}
22032
22033fn snippet_completions(
22034    project: &Project,
22035    buffer: &Entity<Buffer>,
22036    buffer_position: text::Anchor,
22037    cx: &mut App,
22038) -> Task<Result<CompletionResponse>> {
22039    let languages = buffer.read(cx).languages_at(buffer_position);
22040    let snippet_store = project.snippets().read(cx);
22041
22042    let scopes: Vec<_> = languages
22043        .iter()
22044        .filter_map(|language| {
22045            let language_name = language.lsp_id();
22046            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22047
22048            if snippets.is_empty() {
22049                None
22050            } else {
22051                Some((language.default_scope(), snippets))
22052            }
22053        })
22054        .collect();
22055
22056    if scopes.is_empty() {
22057        return Task::ready(Ok(CompletionResponse {
22058            completions: vec![],
22059            is_incomplete: false,
22060        }));
22061    }
22062
22063    let snapshot = buffer.read(cx).text_snapshot();
22064    let chars: String = snapshot
22065        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22066        .collect();
22067    let executor = cx.background_executor().clone();
22068
22069    cx.background_spawn(async move {
22070        let mut is_incomplete = false;
22071        let mut completions: Vec<Completion> = Vec::new();
22072        for (scope, snippets) in scopes.into_iter() {
22073            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22074            let mut last_word = chars
22075                .chars()
22076                .take_while(|c| classifier.is_word(*c))
22077                .collect::<String>();
22078            last_word = last_word.chars().rev().collect();
22079
22080            if last_word.is_empty() {
22081                return Ok(CompletionResponse {
22082                    completions: vec![],
22083                    is_incomplete: true,
22084                });
22085            }
22086
22087            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22088            let to_lsp = |point: &text::Anchor| {
22089                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22090                point_to_lsp(end)
22091            };
22092            let lsp_end = to_lsp(&buffer_position);
22093
22094            let candidates = snippets
22095                .iter()
22096                .enumerate()
22097                .flat_map(|(ix, snippet)| {
22098                    snippet
22099                        .prefix
22100                        .iter()
22101                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22102                })
22103                .collect::<Vec<StringMatchCandidate>>();
22104
22105            const MAX_RESULTS: usize = 100;
22106            let mut matches = fuzzy::match_strings(
22107                &candidates,
22108                &last_word,
22109                last_word.chars().any(|c| c.is_uppercase()),
22110                true,
22111                MAX_RESULTS,
22112                &Default::default(),
22113                executor.clone(),
22114            )
22115            .await;
22116
22117            if matches.len() >= MAX_RESULTS {
22118                is_incomplete = true;
22119            }
22120
22121            // Remove all candidates where the query's start does not match the start of any word in the candidate
22122            if let Some(query_start) = last_word.chars().next() {
22123                matches.retain(|string_match| {
22124                    split_words(&string_match.string).any(|word| {
22125                        // Check that the first codepoint of the word as lowercase matches the first
22126                        // codepoint of the query as lowercase
22127                        word.chars()
22128                            .flat_map(|codepoint| codepoint.to_lowercase())
22129                            .zip(query_start.to_lowercase())
22130                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22131                    })
22132                });
22133            }
22134
22135            let matched_strings = matches
22136                .into_iter()
22137                .map(|m| m.string)
22138                .collect::<HashSet<_>>();
22139
22140            completions.extend(snippets.iter().filter_map(|snippet| {
22141                let matching_prefix = snippet
22142                    .prefix
22143                    .iter()
22144                    .find(|prefix| matched_strings.contains(*prefix))?;
22145                let start = as_offset - last_word.len();
22146                let start = snapshot.anchor_before(start);
22147                let range = start..buffer_position;
22148                let lsp_start = to_lsp(&start);
22149                let lsp_range = lsp::Range {
22150                    start: lsp_start,
22151                    end: lsp_end,
22152                };
22153                Some(Completion {
22154                    replace_range: range,
22155                    new_text: snippet.body.clone(),
22156                    source: CompletionSource::Lsp {
22157                        insert_range: None,
22158                        server_id: LanguageServerId(usize::MAX),
22159                        resolved: true,
22160                        lsp_completion: Box::new(lsp::CompletionItem {
22161                            label: snippet.prefix.first().unwrap().clone(),
22162                            kind: Some(CompletionItemKind::SNIPPET),
22163                            label_details: snippet.description.as_ref().map(|description| {
22164                                lsp::CompletionItemLabelDetails {
22165                                    detail: Some(description.clone()),
22166                                    description: None,
22167                                }
22168                            }),
22169                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22170                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22171                                lsp::InsertReplaceEdit {
22172                                    new_text: snippet.body.clone(),
22173                                    insert: lsp_range,
22174                                    replace: lsp_range,
22175                                },
22176                            )),
22177                            filter_text: Some(snippet.body.clone()),
22178                            sort_text: Some(char::MAX.to_string()),
22179                            ..lsp::CompletionItem::default()
22180                        }),
22181                        lsp_defaults: None,
22182                    },
22183                    label: CodeLabel {
22184                        text: matching_prefix.clone(),
22185                        runs: Vec::new(),
22186                        filter_range: 0..matching_prefix.len(),
22187                    },
22188                    icon_path: None,
22189                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22190                        single_line: snippet.name.clone().into(),
22191                        plain_text: snippet
22192                            .description
22193                            .clone()
22194                            .map(|description| description.into()),
22195                    }),
22196                    insert_text_mode: None,
22197                    confirm: None,
22198                })
22199            }))
22200        }
22201
22202        Ok(CompletionResponse {
22203            completions,
22204            is_incomplete,
22205        })
22206    })
22207}
22208
22209impl CompletionProvider for Entity<Project> {
22210    fn completions(
22211        &self,
22212        _excerpt_id: ExcerptId,
22213        buffer: &Entity<Buffer>,
22214        buffer_position: text::Anchor,
22215        options: CompletionContext,
22216        _window: &mut Window,
22217        cx: &mut Context<Editor>,
22218    ) -> Task<Result<Vec<CompletionResponse>>> {
22219        self.update(cx, |project, cx| {
22220            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22221            let project_completions = project.completions(buffer, buffer_position, options, cx);
22222            cx.background_spawn(async move {
22223                let mut responses = project_completions.await?;
22224                let snippets = snippets.await?;
22225                if !snippets.completions.is_empty() {
22226                    responses.push(snippets);
22227                }
22228                Ok(responses)
22229            })
22230        })
22231    }
22232
22233    fn resolve_completions(
22234        &self,
22235        buffer: Entity<Buffer>,
22236        completion_indices: Vec<usize>,
22237        completions: Rc<RefCell<Box<[Completion]>>>,
22238        cx: &mut Context<Editor>,
22239    ) -> Task<Result<bool>> {
22240        self.update(cx, |project, cx| {
22241            project.lsp_store().update(cx, |lsp_store, cx| {
22242                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22243            })
22244        })
22245    }
22246
22247    fn apply_additional_edits_for_completion(
22248        &self,
22249        buffer: Entity<Buffer>,
22250        completions: Rc<RefCell<Box<[Completion]>>>,
22251        completion_index: usize,
22252        push_to_history: bool,
22253        cx: &mut Context<Editor>,
22254    ) -> Task<Result<Option<language::Transaction>>> {
22255        self.update(cx, |project, cx| {
22256            project.lsp_store().update(cx, |lsp_store, cx| {
22257                lsp_store.apply_additional_edits_for_completion(
22258                    buffer,
22259                    completions,
22260                    completion_index,
22261                    push_to_history,
22262                    cx,
22263                )
22264            })
22265        })
22266    }
22267
22268    fn is_completion_trigger(
22269        &self,
22270        buffer: &Entity<Buffer>,
22271        position: language::Anchor,
22272        text: &str,
22273        trigger_in_words: bool,
22274        menu_is_open: bool,
22275        cx: &mut Context<Editor>,
22276    ) -> bool {
22277        let mut chars = text.chars();
22278        let char = if let Some(char) = chars.next() {
22279            char
22280        } else {
22281            return false;
22282        };
22283        if chars.next().is_some() {
22284            return false;
22285        }
22286
22287        let buffer = buffer.read(cx);
22288        let snapshot = buffer.snapshot();
22289        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22290            return false;
22291        }
22292        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22293        if trigger_in_words && classifier.is_word(char) {
22294            return true;
22295        }
22296
22297        buffer.completion_triggers().contains(text)
22298    }
22299}
22300
22301impl SemanticsProvider for Entity<Project> {
22302    fn hover(
22303        &self,
22304        buffer: &Entity<Buffer>,
22305        position: text::Anchor,
22306        cx: &mut App,
22307    ) -> Option<Task<Vec<project::Hover>>> {
22308        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22309    }
22310
22311    fn document_highlights(
22312        &self,
22313        buffer: &Entity<Buffer>,
22314        position: text::Anchor,
22315        cx: &mut App,
22316    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22317        Some(self.update(cx, |project, cx| {
22318            project.document_highlights(buffer, position, cx)
22319        }))
22320    }
22321
22322    fn definitions(
22323        &self,
22324        buffer: &Entity<Buffer>,
22325        position: text::Anchor,
22326        kind: GotoDefinitionKind,
22327        cx: &mut App,
22328    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22329        Some(self.update(cx, |project, cx| match kind {
22330            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22331            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22332            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22333            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22334        }))
22335    }
22336
22337    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22338        self.update(cx, |project, cx| {
22339            if project
22340                .active_debug_session(cx)
22341                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22342            {
22343                return true;
22344            }
22345
22346            buffer.update(cx, |buffer, cx| {
22347                project.any_language_server_supports_inlay_hints(buffer, cx)
22348            })
22349        })
22350    }
22351
22352    fn inline_values(
22353        &self,
22354        buffer_handle: Entity<Buffer>,
22355        range: Range<text::Anchor>,
22356        cx: &mut App,
22357    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22358        self.update(cx, |project, cx| {
22359            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22360
22361            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22362        })
22363    }
22364
22365    fn inlay_hints(
22366        &self,
22367        buffer_handle: Entity<Buffer>,
22368        range: Range<text::Anchor>,
22369        cx: &mut App,
22370    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22371        Some(self.update(cx, |project, cx| {
22372            project.inlay_hints(buffer_handle, range, cx)
22373        }))
22374    }
22375
22376    fn resolve_inlay_hint(
22377        &self,
22378        hint: InlayHint,
22379        buffer_handle: Entity<Buffer>,
22380        server_id: LanguageServerId,
22381        cx: &mut App,
22382    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22383        Some(self.update(cx, |project, cx| {
22384            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22385        }))
22386    }
22387
22388    fn range_for_rename(
22389        &self,
22390        buffer: &Entity<Buffer>,
22391        position: text::Anchor,
22392        cx: &mut App,
22393    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22394        Some(self.update(cx, |project, cx| {
22395            let buffer = buffer.clone();
22396            let task = project.prepare_rename(buffer.clone(), position, cx);
22397            cx.spawn(async move |_, cx| {
22398                Ok(match task.await? {
22399                    PrepareRenameResponse::Success(range) => Some(range),
22400                    PrepareRenameResponse::InvalidPosition => None,
22401                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22402                        // Fallback on using TreeSitter info to determine identifier range
22403                        buffer.read_with(cx, |buffer, _| {
22404                            let snapshot = buffer.snapshot();
22405                            let (range, kind) = snapshot.surrounding_word(position, false);
22406                            if kind != Some(CharKind::Word) {
22407                                return None;
22408                            }
22409                            Some(
22410                                snapshot.anchor_before(range.start)
22411                                    ..snapshot.anchor_after(range.end),
22412                            )
22413                        })?
22414                    }
22415                })
22416            })
22417        }))
22418    }
22419
22420    fn perform_rename(
22421        &self,
22422        buffer: &Entity<Buffer>,
22423        position: text::Anchor,
22424        new_name: String,
22425        cx: &mut App,
22426    ) -> Option<Task<Result<ProjectTransaction>>> {
22427        Some(self.update(cx, |project, cx| {
22428            project.perform_rename(buffer.clone(), position, new_name, cx)
22429        }))
22430    }
22431}
22432
22433fn inlay_hint_settings(
22434    location: Anchor,
22435    snapshot: &MultiBufferSnapshot,
22436    cx: &mut Context<Editor>,
22437) -> InlayHintSettings {
22438    let file = snapshot.file_at(location);
22439    let language = snapshot.language_at(location).map(|l| l.name());
22440    language_settings(language, file, cx).inlay_hints
22441}
22442
22443fn consume_contiguous_rows(
22444    contiguous_row_selections: &mut Vec<Selection<Point>>,
22445    selection: &Selection<Point>,
22446    display_map: &DisplaySnapshot,
22447    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22448) -> (MultiBufferRow, MultiBufferRow) {
22449    contiguous_row_selections.push(selection.clone());
22450    let start_row = starting_row(selection, display_map);
22451    let mut end_row = ending_row(selection, display_map);
22452
22453    while let Some(next_selection) = selections.peek() {
22454        if next_selection.start.row <= end_row.0 {
22455            end_row = ending_row(next_selection, display_map);
22456            contiguous_row_selections.push(selections.next().unwrap().clone());
22457        } else {
22458            break;
22459        }
22460    }
22461    (start_row, end_row)
22462}
22463
22464fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22465    if selection.start.column > 0 {
22466        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22467    } else {
22468        MultiBufferRow(selection.start.row)
22469    }
22470}
22471
22472fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22473    if next_selection.end.column > 0 || next_selection.is_empty() {
22474        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22475    } else {
22476        MultiBufferRow(next_selection.end.row)
22477    }
22478}
22479
22480impl EditorSnapshot {
22481    pub fn remote_selections_in_range<'a>(
22482        &'a self,
22483        range: &'a Range<Anchor>,
22484        collaboration_hub: &dyn CollaborationHub,
22485        cx: &'a App,
22486    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22487        let participant_names = collaboration_hub.user_names(cx);
22488        let participant_indices = collaboration_hub.user_participant_indices(cx);
22489        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22490        let collaborators_by_replica_id = collaborators_by_peer_id
22491            .values()
22492            .map(|collaborator| (collaborator.replica_id, collaborator))
22493            .collect::<HashMap<_, _>>();
22494        self.buffer_snapshot
22495            .selections_in_range(range, false)
22496            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22497                if replica_id == AGENT_REPLICA_ID {
22498                    Some(RemoteSelection {
22499                        replica_id,
22500                        selection,
22501                        cursor_shape,
22502                        line_mode,
22503                        collaborator_id: CollaboratorId::Agent,
22504                        user_name: Some("Agent".into()),
22505                        color: cx.theme().players().agent(),
22506                    })
22507                } else {
22508                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22509                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22510                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22511                    Some(RemoteSelection {
22512                        replica_id,
22513                        selection,
22514                        cursor_shape,
22515                        line_mode,
22516                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22517                        user_name,
22518                        color: if let Some(index) = participant_index {
22519                            cx.theme().players().color_for_participant(index.0)
22520                        } else {
22521                            cx.theme().players().absent()
22522                        },
22523                    })
22524                }
22525            })
22526    }
22527
22528    pub fn hunks_for_ranges(
22529        &self,
22530        ranges: impl IntoIterator<Item = Range<Point>>,
22531    ) -> Vec<MultiBufferDiffHunk> {
22532        let mut hunks = Vec::new();
22533        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22534            HashMap::default();
22535        for query_range in ranges {
22536            let query_rows =
22537                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22538            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22539                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22540            ) {
22541                // Include deleted hunks that are adjacent to the query range, because
22542                // otherwise they would be missed.
22543                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22544                if hunk.status().is_deleted() {
22545                    intersects_range |= hunk.row_range.start == query_rows.end;
22546                    intersects_range |= hunk.row_range.end == query_rows.start;
22547                }
22548                if intersects_range {
22549                    if !processed_buffer_rows
22550                        .entry(hunk.buffer_id)
22551                        .or_default()
22552                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22553                    {
22554                        continue;
22555                    }
22556                    hunks.push(hunk);
22557                }
22558            }
22559        }
22560
22561        hunks
22562    }
22563
22564    fn display_diff_hunks_for_rows<'a>(
22565        &'a self,
22566        display_rows: Range<DisplayRow>,
22567        folded_buffers: &'a HashSet<BufferId>,
22568    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22569        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22570        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22571
22572        self.buffer_snapshot
22573            .diff_hunks_in_range(buffer_start..buffer_end)
22574            .filter_map(|hunk| {
22575                if folded_buffers.contains(&hunk.buffer_id) {
22576                    return None;
22577                }
22578
22579                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22580                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22581
22582                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22583                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22584
22585                let display_hunk = if hunk_display_start.column() != 0 {
22586                    DisplayDiffHunk::Folded {
22587                        display_row: hunk_display_start.row(),
22588                    }
22589                } else {
22590                    let mut end_row = hunk_display_end.row();
22591                    if hunk_display_end.column() > 0 {
22592                        end_row.0 += 1;
22593                    }
22594                    let is_created_file = hunk.is_created_file();
22595                    DisplayDiffHunk::Unfolded {
22596                        status: hunk.status(),
22597                        diff_base_byte_range: hunk.diff_base_byte_range,
22598                        display_row_range: hunk_display_start.row()..end_row,
22599                        multi_buffer_range: Anchor::range_in_buffer(
22600                            hunk.excerpt_id,
22601                            hunk.buffer_id,
22602                            hunk.buffer_range,
22603                        ),
22604                        is_created_file,
22605                    }
22606                };
22607
22608                Some(display_hunk)
22609            })
22610    }
22611
22612    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22613        self.display_snapshot.buffer_snapshot.language_at(position)
22614    }
22615
22616    pub fn is_focused(&self) -> bool {
22617        self.is_focused
22618    }
22619
22620    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22621        self.placeholder_text.as_ref()
22622    }
22623
22624    pub fn scroll_position(&self) -> gpui::Point<f32> {
22625        self.scroll_anchor.scroll_position(&self.display_snapshot)
22626    }
22627
22628    fn gutter_dimensions(
22629        &self,
22630        font_id: FontId,
22631        font_size: Pixels,
22632        max_line_number_width: Pixels,
22633        cx: &App,
22634    ) -> Option<GutterDimensions> {
22635        if !self.show_gutter {
22636            return None;
22637        }
22638
22639        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22640        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22641
22642        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22643            matches!(
22644                ProjectSettings::get_global(cx).git.git_gutter,
22645                Some(GitGutterSetting::TrackedFiles)
22646            )
22647        });
22648        let gutter_settings = EditorSettings::get_global(cx).gutter;
22649        let show_line_numbers = self
22650            .show_line_numbers
22651            .unwrap_or(gutter_settings.line_numbers);
22652        let line_gutter_width = if show_line_numbers {
22653            // Avoid flicker-like gutter resizes when the line number gains another digit by
22654            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22655            let min_width_for_number_on_gutter =
22656                ch_advance * gutter_settings.min_line_number_digits as f32;
22657            max_line_number_width.max(min_width_for_number_on_gutter)
22658        } else {
22659            0.0.into()
22660        };
22661
22662        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22663        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22664
22665        let git_blame_entries_width =
22666            self.git_blame_gutter_max_author_length
22667                .map(|max_author_length| {
22668                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22669                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22670
22671                    /// The number of characters to dedicate to gaps and margins.
22672                    const SPACING_WIDTH: usize = 4;
22673
22674                    let max_char_count = max_author_length.min(renderer.max_author_length())
22675                        + ::git::SHORT_SHA_LENGTH
22676                        + MAX_RELATIVE_TIMESTAMP.len()
22677                        + SPACING_WIDTH;
22678
22679                    ch_advance * max_char_count
22680                });
22681
22682        let is_singleton = self.buffer_snapshot.is_singleton();
22683
22684        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22685        left_padding += if !is_singleton {
22686            ch_width * 4.0
22687        } else if show_runnables || show_breakpoints {
22688            ch_width * 3.0
22689        } else if show_git_gutter && show_line_numbers {
22690            ch_width * 2.0
22691        } else if show_git_gutter || show_line_numbers {
22692            ch_width
22693        } else {
22694            px(0.)
22695        };
22696
22697        let shows_folds = is_singleton && gutter_settings.folds;
22698
22699        let right_padding = if shows_folds && show_line_numbers {
22700            ch_width * 4.0
22701        } else if shows_folds || (!is_singleton && show_line_numbers) {
22702            ch_width * 3.0
22703        } else if show_line_numbers {
22704            ch_width
22705        } else {
22706            px(0.)
22707        };
22708
22709        Some(GutterDimensions {
22710            left_padding,
22711            right_padding,
22712            width: line_gutter_width + left_padding + right_padding,
22713            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22714            git_blame_entries_width,
22715        })
22716    }
22717
22718    pub fn render_crease_toggle(
22719        &self,
22720        buffer_row: MultiBufferRow,
22721        row_contains_cursor: bool,
22722        editor: Entity<Editor>,
22723        window: &mut Window,
22724        cx: &mut App,
22725    ) -> Option<AnyElement> {
22726        let folded = self.is_line_folded(buffer_row);
22727        let mut is_foldable = false;
22728
22729        if let Some(crease) = self
22730            .crease_snapshot
22731            .query_row(buffer_row, &self.buffer_snapshot)
22732        {
22733            is_foldable = true;
22734            match crease {
22735                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22736                    if let Some(render_toggle) = render_toggle {
22737                        let toggle_callback =
22738                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22739                                if folded {
22740                                    editor.update(cx, |editor, cx| {
22741                                        editor.fold_at(buffer_row, window, cx)
22742                                    });
22743                                } else {
22744                                    editor.update(cx, |editor, cx| {
22745                                        editor.unfold_at(buffer_row, window, cx)
22746                                    });
22747                                }
22748                            });
22749                        return Some((render_toggle)(
22750                            buffer_row,
22751                            folded,
22752                            toggle_callback,
22753                            window,
22754                            cx,
22755                        ));
22756                    }
22757                }
22758            }
22759        }
22760
22761        is_foldable |= self.starts_indent(buffer_row);
22762
22763        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22764            Some(
22765                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22766                    .toggle_state(folded)
22767                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22768                        if folded {
22769                            this.unfold_at(buffer_row, window, cx);
22770                        } else {
22771                            this.fold_at(buffer_row, window, cx);
22772                        }
22773                    }))
22774                    .into_any_element(),
22775            )
22776        } else {
22777            None
22778        }
22779    }
22780
22781    pub fn render_crease_trailer(
22782        &self,
22783        buffer_row: MultiBufferRow,
22784        window: &mut Window,
22785        cx: &mut App,
22786    ) -> Option<AnyElement> {
22787        let folded = self.is_line_folded(buffer_row);
22788        if let Crease::Inline { render_trailer, .. } = self
22789            .crease_snapshot
22790            .query_row(buffer_row, &self.buffer_snapshot)?
22791        {
22792            let render_trailer = render_trailer.as_ref()?;
22793            Some(render_trailer(buffer_row, folded, window, cx))
22794        } else {
22795            None
22796        }
22797    }
22798}
22799
22800impl Deref for EditorSnapshot {
22801    type Target = DisplaySnapshot;
22802
22803    fn deref(&self) -> &Self::Target {
22804        &self.display_snapshot
22805    }
22806}
22807
22808#[derive(Clone, Debug, PartialEq, Eq)]
22809pub enum EditorEvent {
22810    InputIgnored {
22811        text: Arc<str>,
22812    },
22813    InputHandled {
22814        utf16_range_to_replace: Option<Range<isize>>,
22815        text: Arc<str>,
22816    },
22817    ExcerptsAdded {
22818        buffer: Entity<Buffer>,
22819        predecessor: ExcerptId,
22820        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22821    },
22822    ExcerptsRemoved {
22823        ids: Vec<ExcerptId>,
22824        removed_buffer_ids: Vec<BufferId>,
22825    },
22826    BufferFoldToggled {
22827        ids: Vec<ExcerptId>,
22828        folded: bool,
22829    },
22830    ExcerptsEdited {
22831        ids: Vec<ExcerptId>,
22832    },
22833    ExcerptsExpanded {
22834        ids: Vec<ExcerptId>,
22835    },
22836    BufferEdited,
22837    Edited {
22838        transaction_id: clock::Lamport,
22839    },
22840    Reparsed(BufferId),
22841    Focused,
22842    FocusedIn,
22843    Blurred,
22844    DirtyChanged,
22845    Saved,
22846    TitleChanged,
22847    DiffBaseChanged,
22848    SelectionsChanged {
22849        local: bool,
22850    },
22851    ScrollPositionChanged {
22852        local: bool,
22853        autoscroll: bool,
22854    },
22855    Closed,
22856    TransactionUndone {
22857        transaction_id: clock::Lamport,
22858    },
22859    TransactionBegun {
22860        transaction_id: clock::Lamport,
22861    },
22862    Reloaded,
22863    CursorShapeChanged,
22864    BreadcrumbsChanged,
22865    PushedToNavHistory {
22866        anchor: Anchor,
22867        is_deactivate: bool,
22868    },
22869}
22870
22871impl EventEmitter<EditorEvent> for Editor {}
22872
22873impl Focusable for Editor {
22874    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22875        self.focus_handle.clone()
22876    }
22877}
22878
22879impl Render for Editor {
22880    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22881        let settings = ThemeSettings::get_global(cx);
22882
22883        let mut text_style = match self.mode {
22884            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22885                color: cx.theme().colors().editor_foreground,
22886                font_family: settings.ui_font.family.clone(),
22887                font_features: settings.ui_font.features.clone(),
22888                font_fallbacks: settings.ui_font.fallbacks.clone(),
22889                font_size: rems(0.875).into(),
22890                font_weight: settings.ui_font.weight,
22891                line_height: relative(settings.buffer_line_height.value()),
22892                ..Default::default()
22893            },
22894            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22895                color: cx.theme().colors().editor_foreground,
22896                font_family: settings.buffer_font.family.clone(),
22897                font_features: settings.buffer_font.features.clone(),
22898                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22899                font_size: settings.buffer_font_size(cx).into(),
22900                font_weight: settings.buffer_font.weight,
22901                line_height: relative(settings.buffer_line_height.value()),
22902                ..Default::default()
22903            },
22904        };
22905        if let Some(text_style_refinement) = &self.text_style_refinement {
22906            text_style.refine(text_style_refinement)
22907        }
22908
22909        let background = match self.mode {
22910            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22911            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22912            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22913            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22914        };
22915
22916        EditorElement::new(
22917            &cx.entity(),
22918            EditorStyle {
22919                background,
22920                border: cx.theme().colors().border,
22921                local_player: cx.theme().players().local(),
22922                text: text_style,
22923                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22924                syntax: cx.theme().syntax().clone(),
22925                status: cx.theme().status().clone(),
22926                inlay_hints_style: make_inlay_hints_style(cx),
22927                edit_prediction_styles: make_suggestion_styles(cx),
22928                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22929                show_underlines: self.diagnostics_enabled(),
22930            },
22931        )
22932    }
22933}
22934
22935impl EntityInputHandler for Editor {
22936    fn text_for_range(
22937        &mut self,
22938        range_utf16: Range<usize>,
22939        adjusted_range: &mut Option<Range<usize>>,
22940        _: &mut Window,
22941        cx: &mut Context<Self>,
22942    ) -> Option<String> {
22943        let snapshot = self.buffer.read(cx).read(cx);
22944        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22945        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22946        if (start.0..end.0) != range_utf16 {
22947            adjusted_range.replace(start.0..end.0);
22948        }
22949        Some(snapshot.text_for_range(start..end).collect())
22950    }
22951
22952    fn selected_text_range(
22953        &mut self,
22954        ignore_disabled_input: bool,
22955        _: &mut Window,
22956        cx: &mut Context<Self>,
22957    ) -> Option<UTF16Selection> {
22958        // Prevent the IME menu from appearing when holding down an alphabetic key
22959        // while input is disabled.
22960        if !ignore_disabled_input && !self.input_enabled {
22961            return None;
22962        }
22963
22964        let selection = self.selections.newest::<OffsetUtf16>(cx);
22965        let range = selection.range();
22966
22967        Some(UTF16Selection {
22968            range: range.start.0..range.end.0,
22969            reversed: selection.reversed,
22970        })
22971    }
22972
22973    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22974        let snapshot = self.buffer.read(cx).read(cx);
22975        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22976        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22977    }
22978
22979    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22980        self.clear_highlights::<InputComposition>(cx);
22981        self.ime_transaction.take();
22982    }
22983
22984    fn replace_text_in_range(
22985        &mut self,
22986        range_utf16: Option<Range<usize>>,
22987        text: &str,
22988        window: &mut Window,
22989        cx: &mut Context<Self>,
22990    ) {
22991        if !self.input_enabled {
22992            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22993            return;
22994        }
22995
22996        self.transact(window, cx, |this, window, cx| {
22997            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22998                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22999                Some(this.selection_replacement_ranges(range_utf16, cx))
23000            } else {
23001                this.marked_text_ranges(cx)
23002            };
23003
23004            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23005                let newest_selection_id = this.selections.newest_anchor().id;
23006                this.selections
23007                    .all::<OffsetUtf16>(cx)
23008                    .iter()
23009                    .zip(ranges_to_replace.iter())
23010                    .find_map(|(selection, range)| {
23011                        if selection.id == newest_selection_id {
23012                            Some(
23013                                (range.start.0 as isize - selection.head().0 as isize)
23014                                    ..(range.end.0 as isize - selection.head().0 as isize),
23015                            )
23016                        } else {
23017                            None
23018                        }
23019                    })
23020            });
23021
23022            cx.emit(EditorEvent::InputHandled {
23023                utf16_range_to_replace: range_to_replace,
23024                text: text.into(),
23025            });
23026
23027            if let Some(new_selected_ranges) = new_selected_ranges {
23028                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23029                    selections.select_ranges(new_selected_ranges)
23030                });
23031                this.backspace(&Default::default(), window, cx);
23032            }
23033
23034            this.handle_input(text, window, cx);
23035        });
23036
23037        if let Some(transaction) = self.ime_transaction {
23038            self.buffer.update(cx, |buffer, cx| {
23039                buffer.group_until_transaction(transaction, cx);
23040            });
23041        }
23042
23043        self.unmark_text(window, cx);
23044    }
23045
23046    fn replace_and_mark_text_in_range(
23047        &mut self,
23048        range_utf16: Option<Range<usize>>,
23049        text: &str,
23050        new_selected_range_utf16: Option<Range<usize>>,
23051        window: &mut Window,
23052        cx: &mut Context<Self>,
23053    ) {
23054        if !self.input_enabled {
23055            return;
23056        }
23057
23058        let transaction = self.transact(window, cx, |this, window, cx| {
23059            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23060                let snapshot = this.buffer.read(cx).read(cx);
23061                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23062                    for marked_range in &mut marked_ranges {
23063                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23064                        marked_range.start.0 += relative_range_utf16.start;
23065                        marked_range.start =
23066                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23067                        marked_range.end =
23068                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23069                    }
23070                }
23071                Some(marked_ranges)
23072            } else if let Some(range_utf16) = range_utf16 {
23073                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23074                Some(this.selection_replacement_ranges(range_utf16, cx))
23075            } else {
23076                None
23077            };
23078
23079            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23080                let newest_selection_id = this.selections.newest_anchor().id;
23081                this.selections
23082                    .all::<OffsetUtf16>(cx)
23083                    .iter()
23084                    .zip(ranges_to_replace.iter())
23085                    .find_map(|(selection, range)| {
23086                        if selection.id == newest_selection_id {
23087                            Some(
23088                                (range.start.0 as isize - selection.head().0 as isize)
23089                                    ..(range.end.0 as isize - selection.head().0 as isize),
23090                            )
23091                        } else {
23092                            None
23093                        }
23094                    })
23095            });
23096
23097            cx.emit(EditorEvent::InputHandled {
23098                utf16_range_to_replace: range_to_replace,
23099                text: text.into(),
23100            });
23101
23102            if let Some(ranges) = ranges_to_replace {
23103                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23104                    s.select_ranges(ranges)
23105                });
23106            }
23107
23108            let marked_ranges = {
23109                let snapshot = this.buffer.read(cx).read(cx);
23110                this.selections
23111                    .disjoint_anchors()
23112                    .iter()
23113                    .map(|selection| {
23114                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23115                    })
23116                    .collect::<Vec<_>>()
23117            };
23118
23119            if text.is_empty() {
23120                this.unmark_text(window, cx);
23121            } else {
23122                this.highlight_text::<InputComposition>(
23123                    marked_ranges.clone(),
23124                    HighlightStyle {
23125                        underline: Some(UnderlineStyle {
23126                            thickness: px(1.),
23127                            color: None,
23128                            wavy: false,
23129                        }),
23130                        ..Default::default()
23131                    },
23132                    cx,
23133                );
23134            }
23135
23136            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23137            let use_autoclose = this.use_autoclose;
23138            let use_auto_surround = this.use_auto_surround;
23139            this.set_use_autoclose(false);
23140            this.set_use_auto_surround(false);
23141            this.handle_input(text, window, cx);
23142            this.set_use_autoclose(use_autoclose);
23143            this.set_use_auto_surround(use_auto_surround);
23144
23145            if let Some(new_selected_range) = new_selected_range_utf16 {
23146                let snapshot = this.buffer.read(cx).read(cx);
23147                let new_selected_ranges = marked_ranges
23148                    .into_iter()
23149                    .map(|marked_range| {
23150                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23151                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23152                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23153                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23154                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23155                    })
23156                    .collect::<Vec<_>>();
23157
23158                drop(snapshot);
23159                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23160                    selections.select_ranges(new_selected_ranges)
23161                });
23162            }
23163        });
23164
23165        self.ime_transaction = self.ime_transaction.or(transaction);
23166        if let Some(transaction) = self.ime_transaction {
23167            self.buffer.update(cx, |buffer, cx| {
23168                buffer.group_until_transaction(transaction, cx);
23169            });
23170        }
23171
23172        if self.text_highlights::<InputComposition>(cx).is_none() {
23173            self.ime_transaction.take();
23174        }
23175    }
23176
23177    fn bounds_for_range(
23178        &mut self,
23179        range_utf16: Range<usize>,
23180        element_bounds: gpui::Bounds<Pixels>,
23181        window: &mut Window,
23182        cx: &mut Context<Self>,
23183    ) -> Option<gpui::Bounds<Pixels>> {
23184        let text_layout_details = self.text_layout_details(window);
23185        let CharacterDimensions {
23186            em_width,
23187            em_advance,
23188            line_height,
23189        } = self.character_dimensions(window);
23190
23191        let snapshot = self.snapshot(window, cx);
23192        let scroll_position = snapshot.scroll_position();
23193        let scroll_left = scroll_position.x * em_advance;
23194
23195        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23196        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23197            + self.gutter_dimensions.full_width();
23198        let y = line_height * (start.row().as_f32() - scroll_position.y);
23199
23200        Some(Bounds {
23201            origin: element_bounds.origin + point(x, y),
23202            size: size(em_width, line_height),
23203        })
23204    }
23205
23206    fn character_index_for_point(
23207        &mut self,
23208        point: gpui::Point<Pixels>,
23209        _window: &mut Window,
23210        _cx: &mut Context<Self>,
23211    ) -> Option<usize> {
23212        let position_map = self.last_position_map.as_ref()?;
23213        if !position_map.text_hitbox.contains(&point) {
23214            return None;
23215        }
23216        let display_point = position_map.point_for_position(point).previous_valid;
23217        let anchor = position_map
23218            .snapshot
23219            .display_point_to_anchor(display_point, Bias::Left);
23220        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23221        Some(utf16_offset.0)
23222    }
23223}
23224
23225trait SelectionExt {
23226    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23227    fn spanned_rows(
23228        &self,
23229        include_end_if_at_line_start: bool,
23230        map: &DisplaySnapshot,
23231    ) -> Range<MultiBufferRow>;
23232}
23233
23234impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23235    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23236        let start = self
23237            .start
23238            .to_point(&map.buffer_snapshot)
23239            .to_display_point(map);
23240        let end = self
23241            .end
23242            .to_point(&map.buffer_snapshot)
23243            .to_display_point(map);
23244        if self.reversed {
23245            end..start
23246        } else {
23247            start..end
23248        }
23249    }
23250
23251    fn spanned_rows(
23252        &self,
23253        include_end_if_at_line_start: bool,
23254        map: &DisplaySnapshot,
23255    ) -> Range<MultiBufferRow> {
23256        let start = self.start.to_point(&map.buffer_snapshot);
23257        let mut end = self.end.to_point(&map.buffer_snapshot);
23258        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23259            end.row -= 1;
23260        }
23261
23262        let buffer_start = map.prev_line_boundary(start).0;
23263        let buffer_end = map.next_line_boundary(end).0;
23264        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23265    }
23266}
23267
23268impl<T: InvalidationRegion> InvalidationStack<T> {
23269    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23270    where
23271        S: Clone + ToOffset,
23272    {
23273        while let Some(region) = self.last() {
23274            let all_selections_inside_invalidation_ranges =
23275                if selections.len() == region.ranges().len() {
23276                    selections
23277                        .iter()
23278                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23279                        .all(|(selection, invalidation_range)| {
23280                            let head = selection.head().to_offset(buffer);
23281                            invalidation_range.start <= head && invalidation_range.end >= head
23282                        })
23283                } else {
23284                    false
23285                };
23286
23287            if all_selections_inside_invalidation_ranges {
23288                break;
23289            } else {
23290                self.pop();
23291            }
23292        }
23293    }
23294}
23295
23296impl<T> Default for InvalidationStack<T> {
23297    fn default() -> Self {
23298        Self(Default::default())
23299    }
23300}
23301
23302impl<T> Deref for InvalidationStack<T> {
23303    type Target = Vec<T>;
23304
23305    fn deref(&self) -> &Self::Target {
23306        &self.0
23307    }
23308}
23309
23310impl<T> DerefMut for InvalidationStack<T> {
23311    fn deref_mut(&mut self) -> &mut Self::Target {
23312        &mut self.0
23313    }
23314}
23315
23316impl InvalidationRegion for SnippetState {
23317    fn ranges(&self) -> &[Range<Anchor>] {
23318        &self.ranges[self.active_index]
23319    }
23320}
23321
23322fn edit_prediction_edit_text(
23323    current_snapshot: &BufferSnapshot,
23324    edits: &[(Range<Anchor>, String)],
23325    edit_preview: &EditPreview,
23326    include_deletions: bool,
23327    cx: &App,
23328) -> HighlightedText {
23329    let edits = edits
23330        .iter()
23331        .map(|(anchor, text)| {
23332            (
23333                anchor.start.text_anchor..anchor.end.text_anchor,
23334                text.clone(),
23335            )
23336        })
23337        .collect::<Vec<_>>();
23338
23339    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23340}
23341
23342fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23343    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23344    // Just show the raw edit text with basic styling
23345    let mut text = String::new();
23346    let mut highlights = Vec::new();
23347
23348    let insertion_highlight_style = HighlightStyle {
23349        color: Some(cx.theme().colors().text),
23350        ..Default::default()
23351    };
23352
23353    for (_, edit_text) in edits {
23354        let start_offset = text.len();
23355        text.push_str(edit_text);
23356        let end_offset = text.len();
23357
23358        if start_offset < end_offset {
23359            highlights.push((start_offset..end_offset, insertion_highlight_style));
23360        }
23361    }
23362
23363    HighlightedText {
23364        text: text.into(),
23365        highlights,
23366    }
23367}
23368
23369pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23370    match severity {
23371        lsp::DiagnosticSeverity::ERROR => colors.error,
23372        lsp::DiagnosticSeverity::WARNING => colors.warning,
23373        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23374        lsp::DiagnosticSeverity::HINT => colors.info,
23375        _ => colors.ignored,
23376    }
23377}
23378
23379pub fn styled_runs_for_code_label<'a>(
23380    label: &'a CodeLabel,
23381    syntax_theme: &'a theme::SyntaxTheme,
23382) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23383    let fade_out = HighlightStyle {
23384        fade_out: Some(0.35),
23385        ..Default::default()
23386    };
23387
23388    let mut prev_end = label.filter_range.end;
23389    label
23390        .runs
23391        .iter()
23392        .enumerate()
23393        .flat_map(move |(ix, (range, highlight_id))| {
23394            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23395                style
23396            } else {
23397                return Default::default();
23398            };
23399            let mut muted_style = style;
23400            muted_style.highlight(fade_out);
23401
23402            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23403            if range.start >= label.filter_range.end {
23404                if range.start > prev_end {
23405                    runs.push((prev_end..range.start, fade_out));
23406                }
23407                runs.push((range.clone(), muted_style));
23408            } else if range.end <= label.filter_range.end {
23409                runs.push((range.clone(), style));
23410            } else {
23411                runs.push((range.start..label.filter_range.end, style));
23412                runs.push((label.filter_range.end..range.end, muted_style));
23413            }
23414            prev_end = cmp::max(prev_end, range.end);
23415
23416            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23417                runs.push((prev_end..label.text.len(), fade_out));
23418            }
23419
23420            runs
23421        })
23422}
23423
23424pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23425    let mut prev_index = 0;
23426    let mut prev_codepoint: Option<char> = None;
23427    text.char_indices()
23428        .chain([(text.len(), '\0')])
23429        .filter_map(move |(index, codepoint)| {
23430            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23431            let is_boundary = index == text.len()
23432                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23433                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23434            if is_boundary {
23435                let chunk = &text[prev_index..index];
23436                prev_index = index;
23437                Some(chunk)
23438            } else {
23439                None
23440            }
23441        })
23442}
23443
23444pub trait RangeToAnchorExt: Sized {
23445    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23446
23447    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23448        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23449        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23450    }
23451}
23452
23453impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23454    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23455        let start_offset = self.start.to_offset(snapshot);
23456        let end_offset = self.end.to_offset(snapshot);
23457        if start_offset == end_offset {
23458            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23459        } else {
23460            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23461        }
23462    }
23463}
23464
23465pub trait RowExt {
23466    fn as_f32(&self) -> f32;
23467
23468    fn next_row(&self) -> Self;
23469
23470    fn previous_row(&self) -> Self;
23471
23472    fn minus(&self, other: Self) -> u32;
23473}
23474
23475impl RowExt for DisplayRow {
23476    fn as_f32(&self) -> f32 {
23477        self.0 as f32
23478    }
23479
23480    fn next_row(&self) -> Self {
23481        Self(self.0 + 1)
23482    }
23483
23484    fn previous_row(&self) -> Self {
23485        Self(self.0.saturating_sub(1))
23486    }
23487
23488    fn minus(&self, other: Self) -> u32 {
23489        self.0 - other.0
23490    }
23491}
23492
23493impl RowExt for MultiBufferRow {
23494    fn as_f32(&self) -> f32 {
23495        self.0 as f32
23496    }
23497
23498    fn next_row(&self) -> Self {
23499        Self(self.0 + 1)
23500    }
23501
23502    fn previous_row(&self) -> Self {
23503        Self(self.0.saturating_sub(1))
23504    }
23505
23506    fn minus(&self, other: Self) -> u32 {
23507        self.0 - other.0
23508    }
23509}
23510
23511trait RowRangeExt {
23512    type Row;
23513
23514    fn len(&self) -> usize;
23515
23516    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23517}
23518
23519impl RowRangeExt for Range<MultiBufferRow> {
23520    type Row = MultiBufferRow;
23521
23522    fn len(&self) -> usize {
23523        (self.end.0 - self.start.0) as usize
23524    }
23525
23526    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23527        (self.start.0..self.end.0).map(MultiBufferRow)
23528    }
23529}
23530
23531impl RowRangeExt for Range<DisplayRow> {
23532    type Row = DisplayRow;
23533
23534    fn len(&self) -> usize {
23535        (self.end.0 - self.start.0) as usize
23536    }
23537
23538    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23539        (self.start.0..self.end.0).map(DisplayRow)
23540    }
23541}
23542
23543/// If select range has more than one line, we
23544/// just point the cursor to range.start.
23545fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23546    if range.start.row == range.end.row {
23547        range
23548    } else {
23549        range.start..range.start
23550    }
23551}
23552pub struct KillRing(ClipboardItem);
23553impl Global for KillRing {}
23554
23555const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23556
23557enum BreakpointPromptEditAction {
23558    Log,
23559    Condition,
23560    HitCondition,
23561}
23562
23563struct BreakpointPromptEditor {
23564    pub(crate) prompt: Entity<Editor>,
23565    editor: WeakEntity<Editor>,
23566    breakpoint_anchor: Anchor,
23567    breakpoint: Breakpoint,
23568    edit_action: BreakpointPromptEditAction,
23569    block_ids: HashSet<CustomBlockId>,
23570    editor_margins: Arc<Mutex<EditorMargins>>,
23571    _subscriptions: Vec<Subscription>,
23572}
23573
23574impl BreakpointPromptEditor {
23575    const MAX_LINES: u8 = 4;
23576
23577    fn new(
23578        editor: WeakEntity<Editor>,
23579        breakpoint_anchor: Anchor,
23580        breakpoint: Breakpoint,
23581        edit_action: BreakpointPromptEditAction,
23582        window: &mut Window,
23583        cx: &mut Context<Self>,
23584    ) -> Self {
23585        let base_text = match edit_action {
23586            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23587            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23588            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23589        }
23590        .map(|msg| msg.to_string())
23591        .unwrap_or_default();
23592
23593        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23594        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23595
23596        let prompt = cx.new(|cx| {
23597            let mut prompt = Editor::new(
23598                EditorMode::AutoHeight {
23599                    min_lines: 1,
23600                    max_lines: Some(Self::MAX_LINES as usize),
23601                },
23602                buffer,
23603                None,
23604                window,
23605                cx,
23606            );
23607            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23608            prompt.set_show_cursor_when_unfocused(false, cx);
23609            prompt.set_placeholder_text(
23610                match edit_action {
23611                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23612                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23613                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23614                },
23615                cx,
23616            );
23617
23618            prompt
23619        });
23620
23621        Self {
23622            prompt,
23623            editor,
23624            breakpoint_anchor,
23625            breakpoint,
23626            edit_action,
23627            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23628            block_ids: Default::default(),
23629            _subscriptions: vec![],
23630        }
23631    }
23632
23633    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23634        self.block_ids.extend(block_ids)
23635    }
23636
23637    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23638        if let Some(editor) = self.editor.upgrade() {
23639            let message = self
23640                .prompt
23641                .read(cx)
23642                .buffer
23643                .read(cx)
23644                .as_singleton()
23645                .expect("A multi buffer in breakpoint prompt isn't possible")
23646                .read(cx)
23647                .as_rope()
23648                .to_string();
23649
23650            editor.update(cx, |editor, cx| {
23651                editor.edit_breakpoint_at_anchor(
23652                    self.breakpoint_anchor,
23653                    self.breakpoint.clone(),
23654                    match self.edit_action {
23655                        BreakpointPromptEditAction::Log => {
23656                            BreakpointEditAction::EditLogMessage(message.into())
23657                        }
23658                        BreakpointPromptEditAction::Condition => {
23659                            BreakpointEditAction::EditCondition(message.into())
23660                        }
23661                        BreakpointPromptEditAction::HitCondition => {
23662                            BreakpointEditAction::EditHitCondition(message.into())
23663                        }
23664                    },
23665                    cx,
23666                );
23667
23668                editor.remove_blocks(self.block_ids.clone(), None, cx);
23669                cx.focus_self(window);
23670            });
23671        }
23672    }
23673
23674    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23675        self.editor
23676            .update(cx, |editor, cx| {
23677                editor.remove_blocks(self.block_ids.clone(), None, cx);
23678                window.focus(&editor.focus_handle);
23679            })
23680            .log_err();
23681    }
23682
23683    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23684        let settings = ThemeSettings::get_global(cx);
23685        let text_style = TextStyle {
23686            color: if self.prompt.read(cx).read_only(cx) {
23687                cx.theme().colors().text_disabled
23688            } else {
23689                cx.theme().colors().text
23690            },
23691            font_family: settings.buffer_font.family.clone(),
23692            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23693            font_size: settings.buffer_font_size(cx).into(),
23694            font_weight: settings.buffer_font.weight,
23695            line_height: relative(settings.buffer_line_height.value()),
23696            ..Default::default()
23697        };
23698        EditorElement::new(
23699            &self.prompt,
23700            EditorStyle {
23701                background: cx.theme().colors().editor_background,
23702                local_player: cx.theme().players().local(),
23703                text: text_style,
23704                ..Default::default()
23705            },
23706        )
23707    }
23708}
23709
23710impl Render for BreakpointPromptEditor {
23711    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23712        let editor_margins = *self.editor_margins.lock();
23713        let gutter_dimensions = editor_margins.gutter;
23714        h_flex()
23715            .key_context("Editor")
23716            .bg(cx.theme().colors().editor_background)
23717            .border_y_1()
23718            .border_color(cx.theme().status().info_border)
23719            .size_full()
23720            .py(window.line_height() / 2.5)
23721            .on_action(cx.listener(Self::confirm))
23722            .on_action(cx.listener(Self::cancel))
23723            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23724            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23725    }
23726}
23727
23728impl Focusable for BreakpointPromptEditor {
23729    fn focus_handle(&self, cx: &App) -> FocusHandle {
23730        self.prompt.focus_handle(cx)
23731    }
23732}
23733
23734fn all_edits_insertions_or_deletions(
23735    edits: &Vec<(Range<Anchor>, String)>,
23736    snapshot: &MultiBufferSnapshot,
23737) -> bool {
23738    let mut all_insertions = true;
23739    let mut all_deletions = true;
23740
23741    for (range, new_text) in edits.iter() {
23742        let range_is_empty = range.to_offset(snapshot).is_empty();
23743        let text_is_empty = new_text.is_empty();
23744
23745        if range_is_empty != text_is_empty {
23746            if range_is_empty {
23747                all_deletions = false;
23748            } else {
23749                all_insertions = false;
23750            }
23751        } else {
23752            return false;
23753        }
23754
23755        if !all_insertions && !all_deletions {
23756            return false;
23757        }
23758    }
23759    all_insertions || all_deletions
23760}
23761
23762struct MissingEditPredictionKeybindingTooltip;
23763
23764impl Render for MissingEditPredictionKeybindingTooltip {
23765    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23766        ui::tooltip_container(window, cx, |container, _, cx| {
23767            container
23768                .flex_shrink_0()
23769                .max_w_80()
23770                .min_h(rems_from_px(124.))
23771                .justify_between()
23772                .child(
23773                    v_flex()
23774                        .flex_1()
23775                        .text_ui_sm(cx)
23776                        .child(Label::new("Conflict with Accept Keybinding"))
23777                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23778                )
23779                .child(
23780                    h_flex()
23781                        .pb_1()
23782                        .gap_1()
23783                        .items_end()
23784                        .w_full()
23785                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23786                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23787                        }))
23788                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23789                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23790                        })),
23791                )
23792        })
23793    }
23794}
23795
23796#[derive(Debug, Clone, Copy, PartialEq)]
23797pub struct LineHighlight {
23798    pub background: Background,
23799    pub border: Option<gpui::Hsla>,
23800    pub include_gutter: bool,
23801    pub type_id: Option<TypeId>,
23802}
23803
23804struct LineManipulationResult {
23805    pub new_text: String,
23806    pub line_count_before: usize,
23807    pub line_count_after: usize,
23808}
23809
23810fn render_diff_hunk_controls(
23811    row: u32,
23812    status: &DiffHunkStatus,
23813    hunk_range: Range<Anchor>,
23814    is_created_file: bool,
23815    line_height: Pixels,
23816    editor: &Entity<Editor>,
23817    _window: &mut Window,
23818    cx: &mut App,
23819) -> AnyElement {
23820    h_flex()
23821        .h(line_height)
23822        .mr_1()
23823        .gap_1()
23824        .px_0p5()
23825        .pb_1()
23826        .border_x_1()
23827        .border_b_1()
23828        .border_color(cx.theme().colors().border_variant)
23829        .rounded_b_lg()
23830        .bg(cx.theme().colors().editor_background)
23831        .gap_1()
23832        .block_mouse_except_scroll()
23833        .shadow_md()
23834        .child(if status.has_secondary_hunk() {
23835            Button::new(("stage", row as u64), "Stage")
23836                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23837                .tooltip({
23838                    let focus_handle = editor.focus_handle(cx);
23839                    move |window, cx| {
23840                        Tooltip::for_action_in(
23841                            "Stage Hunk",
23842                            &::git::ToggleStaged,
23843                            &focus_handle,
23844                            window,
23845                            cx,
23846                        )
23847                    }
23848                })
23849                .on_click({
23850                    let editor = editor.clone();
23851                    move |_event, _window, cx| {
23852                        editor.update(cx, |editor, cx| {
23853                            editor.stage_or_unstage_diff_hunks(
23854                                true,
23855                                vec![hunk_range.start..hunk_range.start],
23856                                cx,
23857                            );
23858                        });
23859                    }
23860                })
23861        } else {
23862            Button::new(("unstage", row as u64), "Unstage")
23863                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23864                .tooltip({
23865                    let focus_handle = editor.focus_handle(cx);
23866                    move |window, cx| {
23867                        Tooltip::for_action_in(
23868                            "Unstage Hunk",
23869                            &::git::ToggleStaged,
23870                            &focus_handle,
23871                            window,
23872                            cx,
23873                        )
23874                    }
23875                })
23876                .on_click({
23877                    let editor = editor.clone();
23878                    move |_event, _window, cx| {
23879                        editor.update(cx, |editor, cx| {
23880                            editor.stage_or_unstage_diff_hunks(
23881                                false,
23882                                vec![hunk_range.start..hunk_range.start],
23883                                cx,
23884                            );
23885                        });
23886                    }
23887                })
23888        })
23889        .child(
23890            Button::new(("restore", row as u64), "Restore")
23891                .tooltip({
23892                    let focus_handle = editor.focus_handle(cx);
23893                    move |window, cx| {
23894                        Tooltip::for_action_in(
23895                            "Restore Hunk",
23896                            &::git::Restore,
23897                            &focus_handle,
23898                            window,
23899                            cx,
23900                        )
23901                    }
23902                })
23903                .on_click({
23904                    let editor = editor.clone();
23905                    move |_event, window, cx| {
23906                        editor.update(cx, |editor, cx| {
23907                            let snapshot = editor.snapshot(window, cx);
23908                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23909                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23910                        });
23911                    }
23912                })
23913                .disabled(is_created_file),
23914        )
23915        .when(
23916            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23917            |el| {
23918                el.child(
23919                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23920                        .shape(IconButtonShape::Square)
23921                        .icon_size(IconSize::Small)
23922                        // .disabled(!has_multiple_hunks)
23923                        .tooltip({
23924                            let focus_handle = editor.focus_handle(cx);
23925                            move |window, cx| {
23926                                Tooltip::for_action_in(
23927                                    "Next Hunk",
23928                                    &GoToHunk,
23929                                    &focus_handle,
23930                                    window,
23931                                    cx,
23932                                )
23933                            }
23934                        })
23935                        .on_click({
23936                            let editor = editor.clone();
23937                            move |_event, window, cx| {
23938                                editor.update(cx, |editor, cx| {
23939                                    let snapshot = editor.snapshot(window, cx);
23940                                    let position =
23941                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23942                                    editor.go_to_hunk_before_or_after_position(
23943                                        &snapshot,
23944                                        position,
23945                                        Direction::Next,
23946                                        window,
23947                                        cx,
23948                                    );
23949                                    editor.expand_selected_diff_hunks(cx);
23950                                });
23951                            }
23952                        }),
23953                )
23954                .child(
23955                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23956                        .shape(IconButtonShape::Square)
23957                        .icon_size(IconSize::Small)
23958                        // .disabled(!has_multiple_hunks)
23959                        .tooltip({
23960                            let focus_handle = editor.focus_handle(cx);
23961                            move |window, cx| {
23962                                Tooltip::for_action_in(
23963                                    "Previous Hunk",
23964                                    &GoToPreviousHunk,
23965                                    &focus_handle,
23966                                    window,
23967                                    cx,
23968                                )
23969                            }
23970                        })
23971                        .on_click({
23972                            let editor = editor.clone();
23973                            move |_event, window, cx| {
23974                                editor.update(cx, |editor, cx| {
23975                                    let snapshot = editor.snapshot(window, cx);
23976                                    let point =
23977                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23978                                    editor.go_to_hunk_before_or_after_position(
23979                                        &snapshot,
23980                                        point,
23981                                        Direction::Prev,
23982                                        window,
23983                                        cx,
23984                                    );
23985                                    editor.expand_selected_diff_hunks(cx);
23986                                });
23987                            }
23988                        }),
23989                )
23990            },
23991        )
23992        .into_any_element()
23993}