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, _| project.is_via_collab())
14899                .unwrap_or(true);
14900            if hide_runnables {
14901                return;
14902            }
14903            let new_rows =
14904                cx.background_spawn({
14905                    let snapshot = display_snapshot.clone();
14906                    async move {
14907                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14908                    }
14909                })
14910                    .await;
14911            let Ok(lsp_tasks) =
14912                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14913            else {
14914                return;
14915            };
14916            let lsp_tasks = lsp_tasks.await;
14917
14918            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14919                lsp_tasks
14920                    .into_iter()
14921                    .flat_map(|(kind, tasks)| {
14922                        tasks.into_iter().filter_map(move |(location, task)| {
14923                            Some((kind.clone(), location?, task))
14924                        })
14925                    })
14926                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14927                        let buffer = location.target.buffer;
14928                        let buffer_snapshot = buffer.read(cx).snapshot();
14929                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14930                            |(excerpt_id, snapshot, _)| {
14931                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14932                                    display_snapshot
14933                                        .buffer_snapshot
14934                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14935                                } else {
14936                                    None
14937                                }
14938                            },
14939                        );
14940                        if let Some(offset) = offset {
14941                            let task_buffer_range =
14942                                location.target.range.to_point(&buffer_snapshot);
14943                            let context_buffer_range =
14944                                task_buffer_range.to_offset(&buffer_snapshot);
14945                            let context_range = BufferOffset(context_buffer_range.start)
14946                                ..BufferOffset(context_buffer_range.end);
14947
14948                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14949                                .or_insert_with(|| RunnableTasks {
14950                                    templates: Vec::new(),
14951                                    offset,
14952                                    column: task_buffer_range.start.column,
14953                                    extra_variables: HashMap::default(),
14954                                    context_range,
14955                                })
14956                                .templates
14957                                .push((kind, task.original_task().clone()));
14958                        }
14959
14960                        acc
14961                    })
14962            }) else {
14963                return;
14964            };
14965
14966            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14967                buffer.language_settings(cx).tasks.prefer_lsp
14968            }) else {
14969                return;
14970            };
14971
14972            let rows = Self::runnable_rows(
14973                project,
14974                display_snapshot,
14975                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14976                new_rows,
14977                cx.clone(),
14978            )
14979            .await;
14980            editor
14981                .update(cx, |editor, _| {
14982                    editor.clear_tasks();
14983                    for (key, mut value) in rows {
14984                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14985                            value.templates.extend(lsp_tasks.templates);
14986                        }
14987
14988                        editor.insert_tasks(key, value);
14989                    }
14990                    for (key, value) in lsp_tasks_by_rows {
14991                        editor.insert_tasks(key, value);
14992                    }
14993                })
14994                .ok();
14995        })
14996    }
14997    fn fetch_runnable_ranges(
14998        snapshot: &DisplaySnapshot,
14999        range: Range<Anchor>,
15000    ) -> Vec<language::RunnableRange> {
15001        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15002    }
15003
15004    fn runnable_rows(
15005        project: Entity<Project>,
15006        snapshot: DisplaySnapshot,
15007        prefer_lsp: bool,
15008        runnable_ranges: Vec<RunnableRange>,
15009        cx: AsyncWindowContext,
15010    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15011        cx.spawn(async move |cx| {
15012            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15013            for mut runnable in runnable_ranges {
15014                let Some(tasks) = cx
15015                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15016                    .ok()
15017                else {
15018                    continue;
15019                };
15020                let mut tasks = tasks.await;
15021
15022                if prefer_lsp {
15023                    tasks.retain(|(task_kind, _)| {
15024                        !matches!(task_kind, TaskSourceKind::Language { .. })
15025                    });
15026                }
15027                if tasks.is_empty() {
15028                    continue;
15029                }
15030
15031                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15032                let Some(row) = snapshot
15033                    .buffer_snapshot
15034                    .buffer_line_for_row(MultiBufferRow(point.row))
15035                    .map(|(_, range)| range.start.row)
15036                else {
15037                    continue;
15038                };
15039
15040                let context_range =
15041                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15042                runnable_rows.push((
15043                    (runnable.buffer_id, row),
15044                    RunnableTasks {
15045                        templates: tasks,
15046                        offset: snapshot
15047                            .buffer_snapshot
15048                            .anchor_before(runnable.run_range.start),
15049                        context_range,
15050                        column: point.column,
15051                        extra_variables: runnable.extra_captures,
15052                    },
15053                ));
15054            }
15055            runnable_rows
15056        })
15057    }
15058
15059    fn templates_with_tags(
15060        project: &Entity<Project>,
15061        runnable: &mut Runnable,
15062        cx: &mut App,
15063    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15064        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15065            let (worktree_id, file) = project
15066                .buffer_for_id(runnable.buffer, cx)
15067                .and_then(|buffer| buffer.read(cx).file())
15068                .map(|file| (file.worktree_id(cx), file.clone()))
15069                .unzip();
15070
15071            (
15072                project.task_store().read(cx).task_inventory().cloned(),
15073                worktree_id,
15074                file,
15075            )
15076        });
15077
15078        let tags = mem::take(&mut runnable.tags);
15079        let language = runnable.language.clone();
15080        cx.spawn(async move |cx| {
15081            let mut templates_with_tags = Vec::new();
15082            if let Some(inventory) = inventory {
15083                for RunnableTag(tag) in tags {
15084                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15085                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15086                    }) else {
15087                        return templates_with_tags;
15088                    };
15089                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15090                        move |(_, template)| {
15091                            template.tags.iter().any(|source_tag| source_tag == &tag)
15092                        },
15093                    ));
15094                }
15095            }
15096            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15097
15098            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15099                // Strongest source wins; if we have worktree tag binding, prefer that to
15100                // global and language bindings;
15101                // if we have a global binding, prefer that to language binding.
15102                let first_mismatch = templates_with_tags
15103                    .iter()
15104                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15105                if let Some(index) = first_mismatch {
15106                    templates_with_tags.truncate(index);
15107                }
15108            }
15109
15110            templates_with_tags
15111        })
15112    }
15113
15114    pub fn move_to_enclosing_bracket(
15115        &mut self,
15116        _: &MoveToEnclosingBracket,
15117        window: &mut Window,
15118        cx: &mut Context<Self>,
15119    ) {
15120        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15121        self.change_selections(Default::default(), window, cx, |s| {
15122            s.move_offsets_with(|snapshot, selection| {
15123                let Some(enclosing_bracket_ranges) =
15124                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15125                else {
15126                    return;
15127                };
15128
15129                let mut best_length = usize::MAX;
15130                let mut best_inside = false;
15131                let mut best_in_bracket_range = false;
15132                let mut best_destination = None;
15133                for (open, close) in enclosing_bracket_ranges {
15134                    let close = close.to_inclusive();
15135                    let length = close.end() - open.start;
15136                    let inside = selection.start >= open.end && selection.end <= *close.start();
15137                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15138                        || close.contains(&selection.head());
15139
15140                    // If best is next to a bracket and current isn't, skip
15141                    if !in_bracket_range && best_in_bracket_range {
15142                        continue;
15143                    }
15144
15145                    // Prefer smaller lengths unless best is inside and current isn't
15146                    if length > best_length && (best_inside || !inside) {
15147                        continue;
15148                    }
15149
15150                    best_length = length;
15151                    best_inside = inside;
15152                    best_in_bracket_range = in_bracket_range;
15153                    best_destination = Some(
15154                        if close.contains(&selection.start) && close.contains(&selection.end) {
15155                            if inside { open.end } else { open.start }
15156                        } else if inside {
15157                            *close.start()
15158                        } else {
15159                            *close.end()
15160                        },
15161                    );
15162                }
15163
15164                if let Some(destination) = best_destination {
15165                    selection.collapse_to(destination, SelectionGoal::None);
15166                }
15167            })
15168        });
15169    }
15170
15171    pub fn undo_selection(
15172        &mut self,
15173        _: &UndoSelection,
15174        window: &mut Window,
15175        cx: &mut Context<Self>,
15176    ) {
15177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15178        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15179            self.selection_history.mode = SelectionHistoryMode::Undoing;
15180            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15181                this.end_selection(window, cx);
15182                this.change_selections(
15183                    SelectionEffects::scroll(Autoscroll::newest()),
15184                    window,
15185                    cx,
15186                    |s| s.select_anchors(entry.selections.to_vec()),
15187                );
15188            });
15189            self.selection_history.mode = SelectionHistoryMode::Normal;
15190
15191            self.select_next_state = entry.select_next_state;
15192            self.select_prev_state = entry.select_prev_state;
15193            self.add_selections_state = entry.add_selections_state;
15194        }
15195    }
15196
15197    pub fn redo_selection(
15198        &mut self,
15199        _: &RedoSelection,
15200        window: &mut Window,
15201        cx: &mut Context<Self>,
15202    ) {
15203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15204        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15205            self.selection_history.mode = SelectionHistoryMode::Redoing;
15206            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15207                this.end_selection(window, cx);
15208                this.change_selections(
15209                    SelectionEffects::scroll(Autoscroll::newest()),
15210                    window,
15211                    cx,
15212                    |s| s.select_anchors(entry.selections.to_vec()),
15213                );
15214            });
15215            self.selection_history.mode = SelectionHistoryMode::Normal;
15216
15217            self.select_next_state = entry.select_next_state;
15218            self.select_prev_state = entry.select_prev_state;
15219            self.add_selections_state = entry.add_selections_state;
15220        }
15221    }
15222
15223    pub fn expand_excerpts(
15224        &mut self,
15225        action: &ExpandExcerpts,
15226        _: &mut Window,
15227        cx: &mut Context<Self>,
15228    ) {
15229        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15230    }
15231
15232    pub fn expand_excerpts_down(
15233        &mut self,
15234        action: &ExpandExcerptsDown,
15235        _: &mut Window,
15236        cx: &mut Context<Self>,
15237    ) {
15238        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15239    }
15240
15241    pub fn expand_excerpts_up(
15242        &mut self,
15243        action: &ExpandExcerptsUp,
15244        _: &mut Window,
15245        cx: &mut Context<Self>,
15246    ) {
15247        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15248    }
15249
15250    pub fn expand_excerpts_for_direction(
15251        &mut self,
15252        lines: u32,
15253        direction: ExpandExcerptDirection,
15254
15255        cx: &mut Context<Self>,
15256    ) {
15257        let selections = self.selections.disjoint_anchors();
15258
15259        let lines = if lines == 0 {
15260            EditorSettings::get_global(cx).expand_excerpt_lines
15261        } else {
15262            lines
15263        };
15264
15265        self.buffer.update(cx, |buffer, cx| {
15266            let snapshot = buffer.snapshot(cx);
15267            let mut excerpt_ids = selections
15268                .iter()
15269                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15270                .collect::<Vec<_>>();
15271            excerpt_ids.sort();
15272            excerpt_ids.dedup();
15273            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15274        })
15275    }
15276
15277    pub fn expand_excerpt(
15278        &mut self,
15279        excerpt: ExcerptId,
15280        direction: ExpandExcerptDirection,
15281        window: &mut Window,
15282        cx: &mut Context<Self>,
15283    ) {
15284        let current_scroll_position = self.scroll_position(cx);
15285        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15286        let mut should_scroll_up = false;
15287
15288        if direction == ExpandExcerptDirection::Down {
15289            let multi_buffer = self.buffer.read(cx);
15290            let snapshot = multi_buffer.snapshot(cx);
15291            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15292                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15293                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15294            {
15295                let buffer_snapshot = buffer.read(cx).snapshot();
15296                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15297                let last_row = buffer_snapshot.max_point().row;
15298                let lines_below = last_row.saturating_sub(excerpt_end_row);
15299                should_scroll_up = lines_below >= lines_to_expand;
15300            }
15301        }
15302
15303        self.buffer.update(cx, |buffer, cx| {
15304            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15305        });
15306
15307        if should_scroll_up {
15308            let new_scroll_position =
15309                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15310            self.set_scroll_position(new_scroll_position, window, cx);
15311        }
15312    }
15313
15314    pub fn go_to_singleton_buffer_point(
15315        &mut self,
15316        point: Point,
15317        window: &mut Window,
15318        cx: &mut Context<Self>,
15319    ) {
15320        self.go_to_singleton_buffer_range(point..point, window, cx);
15321    }
15322
15323    pub fn go_to_singleton_buffer_range(
15324        &mut self,
15325        range: Range<Point>,
15326        window: &mut Window,
15327        cx: &mut Context<Self>,
15328    ) {
15329        let multibuffer = self.buffer().read(cx);
15330        let Some(buffer) = multibuffer.as_singleton() else {
15331            return;
15332        };
15333        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15334            return;
15335        };
15336        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15337            return;
15338        };
15339        self.change_selections(
15340            SelectionEffects::default().nav_history(true),
15341            window,
15342            cx,
15343            |s| s.select_anchor_ranges([start..end]),
15344        );
15345    }
15346
15347    pub fn go_to_diagnostic(
15348        &mut self,
15349        action: &GoToDiagnostic,
15350        window: &mut Window,
15351        cx: &mut Context<Self>,
15352    ) {
15353        if !self.diagnostics_enabled() {
15354            return;
15355        }
15356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15357        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15358    }
15359
15360    pub fn go_to_prev_diagnostic(
15361        &mut self,
15362        action: &GoToPreviousDiagnostic,
15363        window: &mut Window,
15364        cx: &mut Context<Self>,
15365    ) {
15366        if !self.diagnostics_enabled() {
15367            return;
15368        }
15369        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15370        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15371    }
15372
15373    pub fn go_to_diagnostic_impl(
15374        &mut self,
15375        direction: Direction,
15376        severity: GoToDiagnosticSeverityFilter,
15377        window: &mut Window,
15378        cx: &mut Context<Self>,
15379    ) {
15380        let buffer = self.buffer.read(cx).snapshot(cx);
15381        let selection = self.selections.newest::<usize>(cx);
15382
15383        let mut active_group_id = None;
15384        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15385            && active_group.active_range.start.to_offset(&buffer) == selection.start
15386        {
15387            active_group_id = Some(active_group.group_id);
15388        }
15389
15390        fn filtered(
15391            snapshot: EditorSnapshot,
15392            severity: GoToDiagnosticSeverityFilter,
15393            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15394        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15395            diagnostics
15396                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15397                .filter(|entry| entry.range.start != entry.range.end)
15398                .filter(|entry| !entry.diagnostic.is_unnecessary)
15399                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15400        }
15401
15402        let snapshot = self.snapshot(window, cx);
15403        let before = filtered(
15404            snapshot.clone(),
15405            severity,
15406            buffer
15407                .diagnostics_in_range(0..selection.start)
15408                .filter(|entry| entry.range.start <= selection.start),
15409        );
15410        let after = filtered(
15411            snapshot,
15412            severity,
15413            buffer
15414                .diagnostics_in_range(selection.start..buffer.len())
15415                .filter(|entry| entry.range.start >= selection.start),
15416        );
15417
15418        let mut found: Option<DiagnosticEntry<usize>> = None;
15419        if direction == Direction::Prev {
15420            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15421            {
15422                for diagnostic in prev_diagnostics.into_iter().rev() {
15423                    if diagnostic.range.start != selection.start
15424                        || active_group_id
15425                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15426                    {
15427                        found = Some(diagnostic);
15428                        break 'outer;
15429                    }
15430                }
15431            }
15432        } else {
15433            for diagnostic in after.chain(before) {
15434                if diagnostic.range.start != selection.start
15435                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15436                {
15437                    found = Some(diagnostic);
15438                    break;
15439                }
15440            }
15441        }
15442        let Some(next_diagnostic) = found else {
15443            return;
15444        };
15445
15446        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15447            return;
15448        };
15449        self.change_selections(Default::default(), window, cx, |s| {
15450            s.select_ranges(vec![
15451                next_diagnostic.range.start..next_diagnostic.range.start,
15452            ])
15453        });
15454        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15455        self.refresh_edit_prediction(false, true, window, cx);
15456    }
15457
15458    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15460        let snapshot = self.snapshot(window, cx);
15461        let selection = self.selections.newest::<Point>(cx);
15462        self.go_to_hunk_before_or_after_position(
15463            &snapshot,
15464            selection.head(),
15465            Direction::Next,
15466            window,
15467            cx,
15468        );
15469    }
15470
15471    pub fn go_to_hunk_before_or_after_position(
15472        &mut self,
15473        snapshot: &EditorSnapshot,
15474        position: Point,
15475        direction: Direction,
15476        window: &mut Window,
15477        cx: &mut Context<Editor>,
15478    ) {
15479        let row = if direction == Direction::Next {
15480            self.hunk_after_position(snapshot, position)
15481                .map(|hunk| hunk.row_range.start)
15482        } else {
15483            self.hunk_before_position(snapshot, position)
15484        };
15485
15486        if let Some(row) = row {
15487            let destination = Point::new(row.0, 0);
15488            let autoscroll = Autoscroll::center();
15489
15490            self.unfold_ranges(&[destination..destination], false, false, cx);
15491            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15492                s.select_ranges([destination..destination]);
15493            });
15494        }
15495    }
15496
15497    fn hunk_after_position(
15498        &mut self,
15499        snapshot: &EditorSnapshot,
15500        position: Point,
15501    ) -> Option<MultiBufferDiffHunk> {
15502        snapshot
15503            .buffer_snapshot
15504            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15505            .find(|hunk| hunk.row_range.start.0 > position.row)
15506            .or_else(|| {
15507                snapshot
15508                    .buffer_snapshot
15509                    .diff_hunks_in_range(Point::zero()..position)
15510                    .find(|hunk| hunk.row_range.end.0 < position.row)
15511            })
15512    }
15513
15514    fn go_to_prev_hunk(
15515        &mut self,
15516        _: &GoToPreviousHunk,
15517        window: &mut Window,
15518        cx: &mut Context<Self>,
15519    ) {
15520        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15521        let snapshot = self.snapshot(window, cx);
15522        let selection = self.selections.newest::<Point>(cx);
15523        self.go_to_hunk_before_or_after_position(
15524            &snapshot,
15525            selection.head(),
15526            Direction::Prev,
15527            window,
15528            cx,
15529        );
15530    }
15531
15532    fn hunk_before_position(
15533        &mut self,
15534        snapshot: &EditorSnapshot,
15535        position: Point,
15536    ) -> Option<MultiBufferRow> {
15537        snapshot
15538            .buffer_snapshot
15539            .diff_hunk_before(position)
15540            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15541    }
15542
15543    fn go_to_next_change(
15544        &mut self,
15545        _: &GoToNextChange,
15546        window: &mut Window,
15547        cx: &mut Context<Self>,
15548    ) {
15549        if let Some(selections) = self
15550            .change_list
15551            .next_change(1, Direction::Next)
15552            .map(|s| s.to_vec())
15553        {
15554            self.change_selections(Default::default(), window, cx, |s| {
15555                let map = s.display_map();
15556                s.select_display_ranges(selections.iter().map(|a| {
15557                    let point = a.to_display_point(&map);
15558                    point..point
15559                }))
15560            })
15561        }
15562    }
15563
15564    fn go_to_previous_change(
15565        &mut self,
15566        _: &GoToPreviousChange,
15567        window: &mut Window,
15568        cx: &mut Context<Self>,
15569    ) {
15570        if let Some(selections) = self
15571            .change_list
15572            .next_change(1, Direction::Prev)
15573            .map(|s| s.to_vec())
15574        {
15575            self.change_selections(Default::default(), window, cx, |s| {
15576                let map = s.display_map();
15577                s.select_display_ranges(selections.iter().map(|a| {
15578                    let point = a.to_display_point(&map);
15579                    point..point
15580                }))
15581            })
15582        }
15583    }
15584
15585    fn go_to_line<T: 'static>(
15586        &mut self,
15587        position: Anchor,
15588        highlight_color: Option<Hsla>,
15589        window: &mut Window,
15590        cx: &mut Context<Self>,
15591    ) {
15592        let snapshot = self.snapshot(window, cx).display_snapshot;
15593        let position = position.to_point(&snapshot.buffer_snapshot);
15594        let start = snapshot
15595            .buffer_snapshot
15596            .clip_point(Point::new(position.row, 0), Bias::Left);
15597        let end = start + Point::new(1, 0);
15598        let start = snapshot.buffer_snapshot.anchor_before(start);
15599        let end = snapshot.buffer_snapshot.anchor_before(end);
15600
15601        self.highlight_rows::<T>(
15602            start..end,
15603            highlight_color
15604                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15605            Default::default(),
15606            cx,
15607        );
15608
15609        if self.buffer.read(cx).is_singleton() {
15610            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15611        }
15612    }
15613
15614    pub fn go_to_definition(
15615        &mut self,
15616        _: &GoToDefinition,
15617        window: &mut Window,
15618        cx: &mut Context<Self>,
15619    ) -> Task<Result<Navigated>> {
15620        let definition =
15621            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15622        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15623        cx.spawn_in(window, async move |editor, cx| {
15624            if definition.await? == Navigated::Yes {
15625                return Ok(Navigated::Yes);
15626            }
15627            match fallback_strategy {
15628                GoToDefinitionFallback::None => Ok(Navigated::No),
15629                GoToDefinitionFallback::FindAllReferences => {
15630                    match editor.update_in(cx, |editor, window, cx| {
15631                        editor.find_all_references(&FindAllReferences, window, cx)
15632                    })? {
15633                        Some(references) => references.await,
15634                        None => Ok(Navigated::No),
15635                    }
15636                }
15637            }
15638        })
15639    }
15640
15641    pub fn go_to_declaration(
15642        &mut self,
15643        _: &GoToDeclaration,
15644        window: &mut Window,
15645        cx: &mut Context<Self>,
15646    ) -> Task<Result<Navigated>> {
15647        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15648    }
15649
15650    pub fn go_to_declaration_split(
15651        &mut self,
15652        _: &GoToDeclaration,
15653        window: &mut Window,
15654        cx: &mut Context<Self>,
15655    ) -> Task<Result<Navigated>> {
15656        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15657    }
15658
15659    pub fn go_to_implementation(
15660        &mut self,
15661        _: &GoToImplementation,
15662        window: &mut Window,
15663        cx: &mut Context<Self>,
15664    ) -> Task<Result<Navigated>> {
15665        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15666    }
15667
15668    pub fn go_to_implementation_split(
15669        &mut self,
15670        _: &GoToImplementationSplit,
15671        window: &mut Window,
15672        cx: &mut Context<Self>,
15673    ) -> Task<Result<Navigated>> {
15674        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15675    }
15676
15677    pub fn go_to_type_definition(
15678        &mut self,
15679        _: &GoToTypeDefinition,
15680        window: &mut Window,
15681        cx: &mut Context<Self>,
15682    ) -> Task<Result<Navigated>> {
15683        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15684    }
15685
15686    pub fn go_to_definition_split(
15687        &mut self,
15688        _: &GoToDefinitionSplit,
15689        window: &mut Window,
15690        cx: &mut Context<Self>,
15691    ) -> Task<Result<Navigated>> {
15692        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15693    }
15694
15695    pub fn go_to_type_definition_split(
15696        &mut self,
15697        _: &GoToTypeDefinitionSplit,
15698        window: &mut Window,
15699        cx: &mut Context<Self>,
15700    ) -> Task<Result<Navigated>> {
15701        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15702    }
15703
15704    fn go_to_definition_of_kind(
15705        &mut self,
15706        kind: GotoDefinitionKind,
15707        split: bool,
15708        window: &mut Window,
15709        cx: &mut Context<Self>,
15710    ) -> Task<Result<Navigated>> {
15711        let Some(provider) = self.semantics_provider.clone() else {
15712            return Task::ready(Ok(Navigated::No));
15713        };
15714        let head = self.selections.newest::<usize>(cx).head();
15715        let buffer = self.buffer.read(cx);
15716        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15717            return Task::ready(Ok(Navigated::No));
15718        };
15719        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15720            return Task::ready(Ok(Navigated::No));
15721        };
15722
15723        cx.spawn_in(window, async move |editor, cx| {
15724            let definitions = definitions.await?;
15725            let navigated = editor
15726                .update_in(cx, |editor, window, cx| {
15727                    editor.navigate_to_hover_links(
15728                        Some(kind),
15729                        definitions
15730                            .into_iter()
15731                            .filter(|location| {
15732                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15733                            })
15734                            .map(HoverLink::Text)
15735                            .collect::<Vec<_>>(),
15736                        split,
15737                        window,
15738                        cx,
15739                    )
15740                })?
15741                .await?;
15742            anyhow::Ok(navigated)
15743        })
15744    }
15745
15746    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15747        let selection = self.selections.newest_anchor();
15748        let head = selection.head();
15749        let tail = selection.tail();
15750
15751        let Some((buffer, start_position)) =
15752            self.buffer.read(cx).text_anchor_for_position(head, cx)
15753        else {
15754            return;
15755        };
15756
15757        let end_position = if head != tail {
15758            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15759                return;
15760            };
15761            Some(pos)
15762        } else {
15763            None
15764        };
15765
15766        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15767            let url = if let Some(end_pos) = end_position {
15768                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15769            } else {
15770                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15771            };
15772
15773            if let Some(url) = url {
15774                editor.update(cx, |_, cx| {
15775                    cx.open_url(&url);
15776                })
15777            } else {
15778                Ok(())
15779            }
15780        });
15781
15782        url_finder.detach();
15783    }
15784
15785    pub fn open_selected_filename(
15786        &mut self,
15787        _: &OpenSelectedFilename,
15788        window: &mut Window,
15789        cx: &mut Context<Self>,
15790    ) {
15791        let Some(workspace) = self.workspace() else {
15792            return;
15793        };
15794
15795        let position = self.selections.newest_anchor().head();
15796
15797        let Some((buffer, buffer_position)) =
15798            self.buffer.read(cx).text_anchor_for_position(position, cx)
15799        else {
15800            return;
15801        };
15802
15803        let project = self.project.clone();
15804
15805        cx.spawn_in(window, async move |_, cx| {
15806            let result = find_file(&buffer, project, buffer_position, cx).await;
15807
15808            if let Some((_, path)) = result {
15809                workspace
15810                    .update_in(cx, |workspace, window, cx| {
15811                        workspace.open_resolved_path(path, window, cx)
15812                    })?
15813                    .await?;
15814            }
15815            anyhow::Ok(())
15816        })
15817        .detach();
15818    }
15819
15820    pub(crate) fn navigate_to_hover_links(
15821        &mut self,
15822        kind: Option<GotoDefinitionKind>,
15823        definitions: Vec<HoverLink>,
15824        split: bool,
15825        window: &mut Window,
15826        cx: &mut Context<Editor>,
15827    ) -> Task<Result<Navigated>> {
15828        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15829        let mut first_url_or_file = None;
15830        let definitions: Vec<_> = definitions
15831            .into_iter()
15832            .filter_map(|def| match def {
15833                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15834                HoverLink::InlayHint(lsp_location, server_id) => {
15835                    let computation =
15836                        self.compute_target_location(lsp_location, server_id, window, cx);
15837                    Some(cx.background_spawn(computation))
15838                }
15839                HoverLink::Url(url) => {
15840                    first_url_or_file = Some(Either::Left(url));
15841                    None
15842                }
15843                HoverLink::File(path) => {
15844                    first_url_or_file = Some(Either::Right(path));
15845                    None
15846                }
15847            })
15848            .collect();
15849
15850        let workspace = self.workspace();
15851
15852        cx.spawn_in(window, async move |editor, acx| {
15853            let mut locations: Vec<Location> = future::join_all(definitions)
15854                .await
15855                .into_iter()
15856                .filter_map(|location| location.transpose())
15857                .collect::<Result<_>>()
15858                .context("location tasks")?;
15859
15860            if locations.len() > 1 {
15861                let Some(workspace) = workspace else {
15862                    return Ok(Navigated::No);
15863                };
15864
15865                let tab_kind = match kind {
15866                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15867                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15868                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15869                    Some(GotoDefinitionKind::Type) => "Types",
15870                };
15871                let title = editor
15872                    .update_in(acx, |_, _, cx| {
15873                        let target = locations
15874                            .iter()
15875                            .map(|location| {
15876                                location
15877                                    .buffer
15878                                    .read(cx)
15879                                    .text_for_range(location.range.clone())
15880                                    .collect::<String>()
15881                            })
15882                            .filter(|text| !text.contains('\n'))
15883                            .unique()
15884                            .take(3)
15885                            .join(", ");
15886                        if target.is_empty() {
15887                            tab_kind.to_owned()
15888                        } else {
15889                            format!("{tab_kind} for {target}")
15890                        }
15891                    })
15892                    .context("buffer title")?;
15893
15894                let opened = workspace
15895                    .update_in(acx, |workspace, window, cx| {
15896                        Self::open_locations_in_multibuffer(
15897                            workspace,
15898                            locations,
15899                            title,
15900                            split,
15901                            MultibufferSelectionMode::First,
15902                            window,
15903                            cx,
15904                        )
15905                    })
15906                    .is_ok();
15907
15908                anyhow::Ok(Navigated::from_bool(opened))
15909            } else if locations.is_empty() {
15910                // If there is one definition, just open it directly
15911                match first_url_or_file {
15912                    Some(Either::Left(url)) => {
15913                        acx.update(|_, cx| cx.open_url(&url))?;
15914                        Ok(Navigated::Yes)
15915                    }
15916                    Some(Either::Right(path)) => {
15917                        let Some(workspace) = workspace else {
15918                            return Ok(Navigated::No);
15919                        };
15920
15921                        workspace
15922                            .update_in(acx, |workspace, window, cx| {
15923                                workspace.open_resolved_path(path, window, cx)
15924                            })?
15925                            .await?;
15926                        Ok(Navigated::Yes)
15927                    }
15928                    None => Ok(Navigated::No),
15929                }
15930            } else {
15931                let Some(workspace) = workspace else {
15932                    return Ok(Navigated::No);
15933                };
15934
15935                let target = locations.pop().unwrap();
15936                editor.update_in(acx, |editor, window, cx| {
15937                    let pane = workspace.read(cx).active_pane().clone();
15938
15939                    let range = target.range.to_point(target.buffer.read(cx));
15940                    let range = editor.range_for_match(&range);
15941                    let range = collapse_multiline_range(range);
15942
15943                    if !split
15944                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15945                    {
15946                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15947                    } else {
15948                        window.defer(cx, move |window, cx| {
15949                            let target_editor: Entity<Self> =
15950                                workspace.update(cx, |workspace, cx| {
15951                                    let pane = if split {
15952                                        workspace.adjacent_pane(window, cx)
15953                                    } else {
15954                                        workspace.active_pane().clone()
15955                                    };
15956
15957                                    workspace.open_project_item(
15958                                        pane,
15959                                        target.buffer.clone(),
15960                                        true,
15961                                        true,
15962                                        window,
15963                                        cx,
15964                                    )
15965                                });
15966                            target_editor.update(cx, |target_editor, cx| {
15967                                // When selecting a definition in a different buffer, disable the nav history
15968                                // to avoid creating a history entry at the previous cursor location.
15969                                pane.update(cx, |pane, _| pane.disable_history());
15970                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15971                                pane.update(cx, |pane, _| pane.enable_history());
15972                            });
15973                        });
15974                    }
15975                    Navigated::Yes
15976                })
15977            }
15978        })
15979    }
15980
15981    fn compute_target_location(
15982        &self,
15983        lsp_location: lsp::Location,
15984        server_id: LanguageServerId,
15985        window: &mut Window,
15986        cx: &mut Context<Self>,
15987    ) -> Task<anyhow::Result<Option<Location>>> {
15988        let Some(project) = self.project.clone() else {
15989            return Task::ready(Ok(None));
15990        };
15991
15992        cx.spawn_in(window, async move |editor, cx| {
15993            let location_task = editor.update(cx, |_, cx| {
15994                project.update(cx, |project, cx| {
15995                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
15996                })
15997            })?;
15998            let location = Some({
15999                let target_buffer_handle = location_task.await.context("open local buffer")?;
16000                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16001                    let target_start = target_buffer
16002                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16003                    let target_end = target_buffer
16004                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16005                    target_buffer.anchor_after(target_start)
16006                        ..target_buffer.anchor_before(target_end)
16007                })?;
16008                Location {
16009                    buffer: target_buffer_handle,
16010                    range,
16011                }
16012            });
16013            Ok(location)
16014        })
16015    }
16016
16017    pub fn find_all_references(
16018        &mut self,
16019        _: &FindAllReferences,
16020        window: &mut Window,
16021        cx: &mut Context<Self>,
16022    ) -> Option<Task<Result<Navigated>>> {
16023        let selection = self.selections.newest::<usize>(cx);
16024        let multi_buffer = self.buffer.read(cx);
16025        let head = selection.head();
16026
16027        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16028        let head_anchor = multi_buffer_snapshot.anchor_at(
16029            head,
16030            if head < selection.tail() {
16031                Bias::Right
16032            } else {
16033                Bias::Left
16034            },
16035        );
16036
16037        match self
16038            .find_all_references_task_sources
16039            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16040        {
16041            Ok(_) => {
16042                log::info!(
16043                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16044                );
16045                return None;
16046            }
16047            Err(i) => {
16048                self.find_all_references_task_sources.insert(i, head_anchor);
16049            }
16050        }
16051
16052        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16053        let workspace = self.workspace()?;
16054        let project = workspace.read(cx).project().clone();
16055        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16056        Some(cx.spawn_in(window, async move |editor, cx| {
16057            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16058                if let Ok(i) = editor
16059                    .find_all_references_task_sources
16060                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16061                {
16062                    editor.find_all_references_task_sources.remove(i);
16063                }
16064            });
16065
16066            let locations = references.await?;
16067            if locations.is_empty() {
16068                return anyhow::Ok(Navigated::No);
16069            }
16070
16071            workspace.update_in(cx, |workspace, window, cx| {
16072                let target = locations
16073                    .iter()
16074                    .map(|location| {
16075                        location
16076                            .buffer
16077                            .read(cx)
16078                            .text_for_range(location.range.clone())
16079                            .collect::<String>()
16080                    })
16081                    .filter(|text| !text.contains('\n'))
16082                    .unique()
16083                    .take(3)
16084                    .join(", ");
16085                let title = if target.is_empty() {
16086                    "References".to_owned()
16087                } else {
16088                    format!("References to {target}")
16089                };
16090                Self::open_locations_in_multibuffer(
16091                    workspace,
16092                    locations,
16093                    title,
16094                    false,
16095                    MultibufferSelectionMode::First,
16096                    window,
16097                    cx,
16098                );
16099                Navigated::Yes
16100            })
16101        }))
16102    }
16103
16104    /// Opens a multibuffer with the given project locations in it
16105    pub fn open_locations_in_multibuffer(
16106        workspace: &mut Workspace,
16107        mut locations: Vec<Location>,
16108        title: String,
16109        split: bool,
16110        multibuffer_selection_mode: MultibufferSelectionMode,
16111        window: &mut Window,
16112        cx: &mut Context<Workspace>,
16113    ) {
16114        if locations.is_empty() {
16115            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16116            return;
16117        }
16118
16119        // If there are multiple definitions, open them in a multibuffer
16120        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16121        let mut locations = locations.into_iter().peekable();
16122        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16123        let capability = workspace.project().read(cx).capability();
16124
16125        let excerpt_buffer = cx.new(|cx| {
16126            let mut multibuffer = MultiBuffer::new(capability);
16127            while let Some(location) = locations.next() {
16128                let buffer = location.buffer.read(cx);
16129                let mut ranges_for_buffer = Vec::new();
16130                let range = location.range.to_point(buffer);
16131                ranges_for_buffer.push(range.clone());
16132
16133                while let Some(next_location) = locations.peek() {
16134                    if next_location.buffer == location.buffer {
16135                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16136                        locations.next();
16137                    } else {
16138                        break;
16139                    }
16140                }
16141
16142                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16143                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16144                    PathKey::for_buffer(&location.buffer, cx),
16145                    location.buffer.clone(),
16146                    ranges_for_buffer,
16147                    DEFAULT_MULTIBUFFER_CONTEXT,
16148                    cx,
16149                );
16150                ranges.extend(new_ranges)
16151            }
16152
16153            multibuffer.with_title(title)
16154        });
16155
16156        let editor = cx.new(|cx| {
16157            Editor::for_multibuffer(
16158                excerpt_buffer,
16159                Some(workspace.project().clone()),
16160                window,
16161                cx,
16162            )
16163        });
16164        editor.update(cx, |editor, cx| {
16165            match multibuffer_selection_mode {
16166                MultibufferSelectionMode::First => {
16167                    if let Some(first_range) = ranges.first() {
16168                        editor.change_selections(
16169                            SelectionEffects::no_scroll(),
16170                            window,
16171                            cx,
16172                            |selections| {
16173                                selections.clear_disjoint();
16174                                selections
16175                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16176                            },
16177                        );
16178                    }
16179                    editor.highlight_background::<Self>(
16180                        &ranges,
16181                        |theme| theme.colors().editor_highlighted_line_background,
16182                        cx,
16183                    );
16184                }
16185                MultibufferSelectionMode::All => {
16186                    editor.change_selections(
16187                        SelectionEffects::no_scroll(),
16188                        window,
16189                        cx,
16190                        |selections| {
16191                            selections.clear_disjoint();
16192                            selections.select_anchor_ranges(ranges);
16193                        },
16194                    );
16195                }
16196            }
16197            editor.register_buffers_with_language_servers(cx);
16198        });
16199
16200        let item = Box::new(editor);
16201        let item_id = item.item_id();
16202
16203        if split {
16204            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16205        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16206            let (preview_item_id, preview_item_idx) =
16207                workspace.active_pane().read_with(cx, |pane, _| {
16208                    (pane.preview_item_id(), pane.preview_item_idx())
16209                });
16210
16211            workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16212
16213            if let Some(preview_item_id) = preview_item_id {
16214                workspace.active_pane().update(cx, |pane, cx| {
16215                    pane.remove_item(preview_item_id, false, false, window, cx);
16216                });
16217            }
16218        } else {
16219            workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16220        }
16221        workspace.active_pane().update(cx, |pane, cx| {
16222            pane.set_preview_item_id(Some(item_id), cx);
16223        });
16224    }
16225
16226    pub fn rename(
16227        &mut self,
16228        _: &Rename,
16229        window: &mut Window,
16230        cx: &mut Context<Self>,
16231    ) -> Option<Task<Result<()>>> {
16232        use language::ToOffset as _;
16233
16234        let provider = self.semantics_provider.clone()?;
16235        let selection = self.selections.newest_anchor().clone();
16236        let (cursor_buffer, cursor_buffer_position) = self
16237            .buffer
16238            .read(cx)
16239            .text_anchor_for_position(selection.head(), cx)?;
16240        let (tail_buffer, cursor_buffer_position_end) = self
16241            .buffer
16242            .read(cx)
16243            .text_anchor_for_position(selection.tail(), cx)?;
16244        if tail_buffer != cursor_buffer {
16245            return None;
16246        }
16247
16248        let snapshot = cursor_buffer.read(cx).snapshot();
16249        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16250        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16251        let prepare_rename = provider
16252            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16253            .unwrap_or_else(|| Task::ready(Ok(None)));
16254        drop(snapshot);
16255
16256        Some(cx.spawn_in(window, async move |this, cx| {
16257            let rename_range = if let Some(range) = prepare_rename.await? {
16258                Some(range)
16259            } else {
16260                this.update(cx, |this, cx| {
16261                    let buffer = this.buffer.read(cx).snapshot(cx);
16262                    let mut buffer_highlights = this
16263                        .document_highlights_for_position(selection.head(), &buffer)
16264                        .filter(|highlight| {
16265                            highlight.start.excerpt_id == selection.head().excerpt_id
16266                                && highlight.end.excerpt_id == selection.head().excerpt_id
16267                        });
16268                    buffer_highlights
16269                        .next()
16270                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16271                })?
16272            };
16273            if let Some(rename_range) = rename_range {
16274                this.update_in(cx, |this, window, cx| {
16275                    let snapshot = cursor_buffer.read(cx).snapshot();
16276                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16277                    let cursor_offset_in_rename_range =
16278                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16279                    let cursor_offset_in_rename_range_end =
16280                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16281
16282                    this.take_rename(false, window, cx);
16283                    let buffer = this.buffer.read(cx).read(cx);
16284                    let cursor_offset = selection.head().to_offset(&buffer);
16285                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16286                    let rename_end = rename_start + rename_buffer_range.len();
16287                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16288                    let mut old_highlight_id = None;
16289                    let old_name: Arc<str> = buffer
16290                        .chunks(rename_start..rename_end, true)
16291                        .map(|chunk| {
16292                            if old_highlight_id.is_none() {
16293                                old_highlight_id = chunk.syntax_highlight_id;
16294                            }
16295                            chunk.text
16296                        })
16297                        .collect::<String>()
16298                        .into();
16299
16300                    drop(buffer);
16301
16302                    // Position the selection in the rename editor so that it matches the current selection.
16303                    this.show_local_selections = false;
16304                    let rename_editor = cx.new(|cx| {
16305                        let mut editor = Editor::single_line(window, cx);
16306                        editor.buffer.update(cx, |buffer, cx| {
16307                            buffer.edit([(0..0, old_name.clone())], None, cx)
16308                        });
16309                        let rename_selection_range = match cursor_offset_in_rename_range
16310                            .cmp(&cursor_offset_in_rename_range_end)
16311                        {
16312                            Ordering::Equal => {
16313                                editor.select_all(&SelectAll, window, cx);
16314                                return editor;
16315                            }
16316                            Ordering::Less => {
16317                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16318                            }
16319                            Ordering::Greater => {
16320                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16321                            }
16322                        };
16323                        if rename_selection_range.end > old_name.len() {
16324                            editor.select_all(&SelectAll, window, cx);
16325                        } else {
16326                            editor.change_selections(Default::default(), window, cx, |s| {
16327                                s.select_ranges([rename_selection_range]);
16328                            });
16329                        }
16330                        editor
16331                    });
16332                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16333                        if e == &EditorEvent::Focused {
16334                            cx.emit(EditorEvent::FocusedIn)
16335                        }
16336                    })
16337                    .detach();
16338
16339                    let write_highlights =
16340                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16341                    let read_highlights =
16342                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16343                    let ranges = write_highlights
16344                        .iter()
16345                        .flat_map(|(_, ranges)| ranges.iter())
16346                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16347                        .cloned()
16348                        .collect();
16349
16350                    this.highlight_text::<Rename>(
16351                        ranges,
16352                        HighlightStyle {
16353                            fade_out: Some(0.6),
16354                            ..Default::default()
16355                        },
16356                        cx,
16357                    );
16358                    let rename_focus_handle = rename_editor.focus_handle(cx);
16359                    window.focus(&rename_focus_handle);
16360                    let block_id = this.insert_blocks(
16361                        [BlockProperties {
16362                            style: BlockStyle::Flex,
16363                            placement: BlockPlacement::Below(range.start),
16364                            height: Some(1),
16365                            render: Arc::new({
16366                                let rename_editor = rename_editor.clone();
16367                                move |cx: &mut BlockContext| {
16368                                    let mut text_style = cx.editor_style.text.clone();
16369                                    if let Some(highlight_style) = old_highlight_id
16370                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16371                                    {
16372                                        text_style = text_style.highlight(highlight_style);
16373                                    }
16374                                    div()
16375                                        .block_mouse_except_scroll()
16376                                        .pl(cx.anchor_x)
16377                                        .child(EditorElement::new(
16378                                            &rename_editor,
16379                                            EditorStyle {
16380                                                background: cx.theme().system().transparent,
16381                                                local_player: cx.editor_style.local_player,
16382                                                text: text_style,
16383                                                scrollbar_width: cx.editor_style.scrollbar_width,
16384                                                syntax: cx.editor_style.syntax.clone(),
16385                                                status: cx.editor_style.status.clone(),
16386                                                inlay_hints_style: HighlightStyle {
16387                                                    font_weight: Some(FontWeight::BOLD),
16388                                                    ..make_inlay_hints_style(cx.app)
16389                                                },
16390                                                edit_prediction_styles: make_suggestion_styles(
16391                                                    cx.app,
16392                                                ),
16393                                                ..EditorStyle::default()
16394                                            },
16395                                        ))
16396                                        .into_any_element()
16397                                }
16398                            }),
16399                            priority: 0,
16400                        }],
16401                        Some(Autoscroll::fit()),
16402                        cx,
16403                    )[0];
16404                    this.pending_rename = Some(RenameState {
16405                        range,
16406                        old_name,
16407                        editor: rename_editor,
16408                        block_id,
16409                    });
16410                })?;
16411            }
16412
16413            Ok(())
16414        }))
16415    }
16416
16417    pub fn confirm_rename(
16418        &mut self,
16419        _: &ConfirmRename,
16420        window: &mut Window,
16421        cx: &mut Context<Self>,
16422    ) -> Option<Task<Result<()>>> {
16423        let rename = self.take_rename(false, window, cx)?;
16424        let workspace = self.workspace()?.downgrade();
16425        let (buffer, start) = self
16426            .buffer
16427            .read(cx)
16428            .text_anchor_for_position(rename.range.start, cx)?;
16429        let (end_buffer, _) = self
16430            .buffer
16431            .read(cx)
16432            .text_anchor_for_position(rename.range.end, cx)?;
16433        if buffer != end_buffer {
16434            return None;
16435        }
16436
16437        let old_name = rename.old_name;
16438        let new_name = rename.editor.read(cx).text(cx);
16439
16440        let rename = self.semantics_provider.as_ref()?.perform_rename(
16441            &buffer,
16442            start,
16443            new_name.clone(),
16444            cx,
16445        )?;
16446
16447        Some(cx.spawn_in(window, async move |editor, cx| {
16448            let project_transaction = rename.await?;
16449            Self::open_project_transaction(
16450                &editor,
16451                workspace,
16452                project_transaction,
16453                format!("Rename: {}{}", old_name, new_name),
16454                cx,
16455            )
16456            .await?;
16457
16458            editor.update(cx, |editor, cx| {
16459                editor.refresh_document_highlights(cx);
16460            })?;
16461            Ok(())
16462        }))
16463    }
16464
16465    fn take_rename(
16466        &mut self,
16467        moving_cursor: bool,
16468        window: &mut Window,
16469        cx: &mut Context<Self>,
16470    ) -> Option<RenameState> {
16471        let rename = self.pending_rename.take()?;
16472        if rename.editor.focus_handle(cx).is_focused(window) {
16473            window.focus(&self.focus_handle);
16474        }
16475
16476        self.remove_blocks(
16477            [rename.block_id].into_iter().collect(),
16478            Some(Autoscroll::fit()),
16479            cx,
16480        );
16481        self.clear_highlights::<Rename>(cx);
16482        self.show_local_selections = true;
16483
16484        if moving_cursor {
16485            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16486                editor.selections.newest::<usize>(cx).head()
16487            });
16488
16489            // Update the selection to match the position of the selection inside
16490            // the rename editor.
16491            let snapshot = self.buffer.read(cx).read(cx);
16492            let rename_range = rename.range.to_offset(&snapshot);
16493            let cursor_in_editor = snapshot
16494                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16495                .min(rename_range.end);
16496            drop(snapshot);
16497
16498            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16499                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16500            });
16501        } else {
16502            self.refresh_document_highlights(cx);
16503        }
16504
16505        Some(rename)
16506    }
16507
16508    pub fn pending_rename(&self) -> Option<&RenameState> {
16509        self.pending_rename.as_ref()
16510    }
16511
16512    fn format(
16513        &mut self,
16514        _: &Format,
16515        window: &mut Window,
16516        cx: &mut Context<Self>,
16517    ) -> Option<Task<Result<()>>> {
16518        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16519
16520        let project = match &self.project {
16521            Some(project) => project.clone(),
16522            None => return None,
16523        };
16524
16525        Some(self.perform_format(
16526            project,
16527            FormatTrigger::Manual,
16528            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16529            window,
16530            cx,
16531        ))
16532    }
16533
16534    fn format_selections(
16535        &mut self,
16536        _: &FormatSelections,
16537        window: &mut Window,
16538        cx: &mut Context<Self>,
16539    ) -> Option<Task<Result<()>>> {
16540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16541
16542        let project = match &self.project {
16543            Some(project) => project.clone(),
16544            None => return None,
16545        };
16546
16547        let ranges = self
16548            .selections
16549            .all_adjusted(cx)
16550            .into_iter()
16551            .map(|selection| selection.range())
16552            .collect_vec();
16553
16554        Some(self.perform_format(
16555            project,
16556            FormatTrigger::Manual,
16557            FormatTarget::Ranges(ranges),
16558            window,
16559            cx,
16560        ))
16561    }
16562
16563    fn perform_format(
16564        &mut self,
16565        project: Entity<Project>,
16566        trigger: FormatTrigger,
16567        target: FormatTarget,
16568        window: &mut Window,
16569        cx: &mut Context<Self>,
16570    ) -> Task<Result<()>> {
16571        let buffer = self.buffer.clone();
16572        let (buffers, target) = match target {
16573            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16574            FormatTarget::Ranges(selection_ranges) => {
16575                let multi_buffer = buffer.read(cx);
16576                let snapshot = multi_buffer.read(cx);
16577                let mut buffers = HashSet::default();
16578                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16579                    BTreeMap::new();
16580                for selection_range in selection_ranges {
16581                    for (buffer, buffer_range, _) in
16582                        snapshot.range_to_buffer_ranges(selection_range)
16583                    {
16584                        let buffer_id = buffer.remote_id();
16585                        let start = buffer.anchor_before(buffer_range.start);
16586                        let end = buffer.anchor_after(buffer_range.end);
16587                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16588                        buffer_id_to_ranges
16589                            .entry(buffer_id)
16590                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16591                            .or_insert_with(|| vec![start..end]);
16592                    }
16593                }
16594                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16595            }
16596        };
16597
16598        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16599        let selections_prev = transaction_id_prev
16600            .and_then(|transaction_id_prev| {
16601                // default to selections as they were after the last edit, if we have them,
16602                // instead of how they are now.
16603                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16604                // will take you back to where you made the last edit, instead of staying where you scrolled
16605                self.selection_history
16606                    .transaction(transaction_id_prev)
16607                    .map(|t| t.0.clone())
16608            })
16609            .unwrap_or_else(|| self.selections.disjoint_anchors());
16610
16611        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16612        let format = project.update(cx, |project, cx| {
16613            project.format(buffers, target, true, trigger, cx)
16614        });
16615
16616        cx.spawn_in(window, async move |editor, cx| {
16617            let transaction = futures::select_biased! {
16618                transaction = format.log_err().fuse() => transaction,
16619                () = timeout => {
16620                    log::warn!("timed out waiting for formatting");
16621                    None
16622                }
16623            };
16624
16625            buffer
16626                .update(cx, |buffer, cx| {
16627                    if let Some(transaction) = transaction
16628                        && !buffer.is_singleton()
16629                    {
16630                        buffer.push_transaction(&transaction.0, cx);
16631                    }
16632                    cx.notify();
16633                })
16634                .ok();
16635
16636            if let Some(transaction_id_now) =
16637                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16638            {
16639                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16640                if has_new_transaction {
16641                    _ = editor.update(cx, |editor, _| {
16642                        editor
16643                            .selection_history
16644                            .insert_transaction(transaction_id_now, selections_prev);
16645                    });
16646                }
16647            }
16648
16649            Ok(())
16650        })
16651    }
16652
16653    fn organize_imports(
16654        &mut self,
16655        _: &OrganizeImports,
16656        window: &mut Window,
16657        cx: &mut Context<Self>,
16658    ) -> Option<Task<Result<()>>> {
16659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16660        let project = match &self.project {
16661            Some(project) => project.clone(),
16662            None => return None,
16663        };
16664        Some(self.perform_code_action_kind(
16665            project,
16666            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16667            window,
16668            cx,
16669        ))
16670    }
16671
16672    fn perform_code_action_kind(
16673        &mut self,
16674        project: Entity<Project>,
16675        kind: CodeActionKind,
16676        window: &mut Window,
16677        cx: &mut Context<Self>,
16678    ) -> Task<Result<()>> {
16679        let buffer = self.buffer.clone();
16680        let buffers = buffer.read(cx).all_buffers();
16681        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16682        let apply_action = project.update(cx, |project, cx| {
16683            project.apply_code_action_kind(buffers, kind, true, cx)
16684        });
16685        cx.spawn_in(window, async move |_, cx| {
16686            let transaction = futures::select_biased! {
16687                () = timeout => {
16688                    log::warn!("timed out waiting for executing code action");
16689                    None
16690                }
16691                transaction = apply_action.log_err().fuse() => transaction,
16692            };
16693            buffer
16694                .update(cx, |buffer, cx| {
16695                    // check if we need this
16696                    if let Some(transaction) = transaction
16697                        && !buffer.is_singleton()
16698                    {
16699                        buffer.push_transaction(&transaction.0, cx);
16700                    }
16701                    cx.notify();
16702                })
16703                .ok();
16704            Ok(())
16705        })
16706    }
16707
16708    pub fn restart_language_server(
16709        &mut self,
16710        _: &RestartLanguageServer,
16711        _: &mut Window,
16712        cx: &mut Context<Self>,
16713    ) {
16714        if let Some(project) = self.project.clone() {
16715            self.buffer.update(cx, |multi_buffer, cx| {
16716                project.update(cx, |project, cx| {
16717                    project.restart_language_servers_for_buffers(
16718                        multi_buffer.all_buffers().into_iter().collect(),
16719                        HashSet::default(),
16720                        cx,
16721                    );
16722                });
16723            })
16724        }
16725    }
16726
16727    pub fn stop_language_server(
16728        &mut self,
16729        _: &StopLanguageServer,
16730        _: &mut Window,
16731        cx: &mut Context<Self>,
16732    ) {
16733        if let Some(project) = self.project.clone() {
16734            self.buffer.update(cx, |multi_buffer, cx| {
16735                project.update(cx, |project, cx| {
16736                    project.stop_language_servers_for_buffers(
16737                        multi_buffer.all_buffers().into_iter().collect(),
16738                        HashSet::default(),
16739                        cx,
16740                    );
16741                    cx.emit(project::Event::RefreshInlayHints);
16742                });
16743            });
16744        }
16745    }
16746
16747    fn cancel_language_server_work(
16748        workspace: &mut Workspace,
16749        _: &actions::CancelLanguageServerWork,
16750        _: &mut Window,
16751        cx: &mut Context<Workspace>,
16752    ) {
16753        let project = workspace.project();
16754        let buffers = workspace
16755            .active_item(cx)
16756            .and_then(|item| item.act_as::<Editor>(cx))
16757            .map_or(HashSet::default(), |editor| {
16758                editor.read(cx).buffer.read(cx).all_buffers()
16759            });
16760        project.update(cx, |project, cx| {
16761            project.cancel_language_server_work_for_buffers(buffers, cx);
16762        });
16763    }
16764
16765    fn show_character_palette(
16766        &mut self,
16767        _: &ShowCharacterPalette,
16768        window: &mut Window,
16769        _: &mut Context<Self>,
16770    ) {
16771        window.show_character_palette();
16772    }
16773
16774    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16775        if !self.diagnostics_enabled() {
16776            return;
16777        }
16778
16779        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16780            let buffer = self.buffer.read(cx).snapshot(cx);
16781            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16782            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16783            let is_valid = buffer
16784                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16785                .any(|entry| {
16786                    entry.diagnostic.is_primary
16787                        && !entry.range.is_empty()
16788                        && entry.range.start == primary_range_start
16789                        && entry.diagnostic.message == active_diagnostics.active_message
16790                });
16791
16792            if !is_valid {
16793                self.dismiss_diagnostics(cx);
16794            }
16795        }
16796    }
16797
16798    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16799        match &self.active_diagnostics {
16800            ActiveDiagnostic::Group(group) => Some(group),
16801            _ => None,
16802        }
16803    }
16804
16805    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16806        if !self.diagnostics_enabled() {
16807            return;
16808        }
16809        self.dismiss_diagnostics(cx);
16810        self.active_diagnostics = ActiveDiagnostic::All;
16811    }
16812
16813    fn activate_diagnostics(
16814        &mut self,
16815        buffer_id: BufferId,
16816        diagnostic: DiagnosticEntry<usize>,
16817        window: &mut Window,
16818        cx: &mut Context<Self>,
16819    ) {
16820        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16821            return;
16822        }
16823        self.dismiss_diagnostics(cx);
16824        let snapshot = self.snapshot(window, cx);
16825        let buffer = self.buffer.read(cx).snapshot(cx);
16826        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16827            return;
16828        };
16829
16830        let diagnostic_group = buffer
16831            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16832            .collect::<Vec<_>>();
16833
16834        let blocks =
16835            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16836
16837        let blocks = self.display_map.update(cx, |display_map, cx| {
16838            display_map.insert_blocks(blocks, cx).into_iter().collect()
16839        });
16840        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16841            active_range: buffer.anchor_before(diagnostic.range.start)
16842                ..buffer.anchor_after(diagnostic.range.end),
16843            active_message: diagnostic.diagnostic.message.clone(),
16844            group_id: diagnostic.diagnostic.group_id,
16845            blocks,
16846        });
16847        cx.notify();
16848    }
16849
16850    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16851        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16852            return;
16853        };
16854
16855        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16856        if let ActiveDiagnostic::Group(group) = prev {
16857            self.display_map.update(cx, |display_map, cx| {
16858                display_map.remove_blocks(group.blocks, cx);
16859            });
16860            cx.notify();
16861        }
16862    }
16863
16864    /// Disable inline diagnostics rendering for this editor.
16865    pub fn disable_inline_diagnostics(&mut self) {
16866        self.inline_diagnostics_enabled = false;
16867        self.inline_diagnostics_update = Task::ready(());
16868        self.inline_diagnostics.clear();
16869    }
16870
16871    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16872        self.diagnostics_enabled = false;
16873        self.dismiss_diagnostics(cx);
16874        self.inline_diagnostics_update = Task::ready(());
16875        self.inline_diagnostics.clear();
16876    }
16877
16878    pub fn diagnostics_enabled(&self) -> bool {
16879        self.diagnostics_enabled && self.mode.is_full()
16880    }
16881
16882    pub fn inline_diagnostics_enabled(&self) -> bool {
16883        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16884    }
16885
16886    pub fn show_inline_diagnostics(&self) -> bool {
16887        self.show_inline_diagnostics
16888    }
16889
16890    pub fn toggle_inline_diagnostics(
16891        &mut self,
16892        _: &ToggleInlineDiagnostics,
16893        window: &mut Window,
16894        cx: &mut Context<Editor>,
16895    ) {
16896        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16897        self.refresh_inline_diagnostics(false, window, cx);
16898    }
16899
16900    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16901        self.diagnostics_max_severity = severity;
16902        self.display_map.update(cx, |display_map, _| {
16903            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16904        });
16905    }
16906
16907    pub fn toggle_diagnostics(
16908        &mut self,
16909        _: &ToggleDiagnostics,
16910        window: &mut Window,
16911        cx: &mut Context<Editor>,
16912    ) {
16913        if !self.diagnostics_enabled() {
16914            return;
16915        }
16916
16917        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16918            EditorSettings::get_global(cx)
16919                .diagnostics_max_severity
16920                .filter(|severity| severity != &DiagnosticSeverity::Off)
16921                .unwrap_or(DiagnosticSeverity::Hint)
16922        } else {
16923            DiagnosticSeverity::Off
16924        };
16925        self.set_max_diagnostics_severity(new_severity, cx);
16926        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16927            self.active_diagnostics = ActiveDiagnostic::None;
16928            self.inline_diagnostics_update = Task::ready(());
16929            self.inline_diagnostics.clear();
16930        } else {
16931            self.refresh_inline_diagnostics(false, window, cx);
16932        }
16933
16934        cx.notify();
16935    }
16936
16937    pub fn toggle_minimap(
16938        &mut self,
16939        _: &ToggleMinimap,
16940        window: &mut Window,
16941        cx: &mut Context<Editor>,
16942    ) {
16943        if self.supports_minimap(cx) {
16944            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16945        }
16946    }
16947
16948    fn refresh_inline_diagnostics(
16949        &mut self,
16950        debounce: bool,
16951        window: &mut Window,
16952        cx: &mut Context<Self>,
16953    ) {
16954        let max_severity = ProjectSettings::get_global(cx)
16955            .diagnostics
16956            .inline
16957            .max_severity
16958            .unwrap_or(self.diagnostics_max_severity);
16959
16960        if !self.inline_diagnostics_enabled()
16961            || !self.show_inline_diagnostics
16962            || max_severity == DiagnosticSeverity::Off
16963        {
16964            self.inline_diagnostics_update = Task::ready(());
16965            self.inline_diagnostics.clear();
16966            return;
16967        }
16968
16969        let debounce_ms = ProjectSettings::get_global(cx)
16970            .diagnostics
16971            .inline
16972            .update_debounce_ms;
16973        let debounce = if debounce && debounce_ms > 0 {
16974            Some(Duration::from_millis(debounce_ms))
16975        } else {
16976            None
16977        };
16978        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16979            if let Some(debounce) = debounce {
16980                cx.background_executor().timer(debounce).await;
16981            }
16982            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16983                editor
16984                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16985                    .ok()
16986            }) else {
16987                return;
16988            };
16989
16990            let new_inline_diagnostics = cx
16991                .background_spawn(async move {
16992                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16993                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16994                        let message = diagnostic_entry
16995                            .diagnostic
16996                            .message
16997                            .split_once('\n')
16998                            .map(|(line, _)| line)
16999                            .map(SharedString::new)
17000                            .unwrap_or_else(|| {
17001                                SharedString::from(diagnostic_entry.diagnostic.message)
17002                            });
17003                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17004                        let (Ok(i) | Err(i)) = inline_diagnostics
17005                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17006                        inline_diagnostics.insert(
17007                            i,
17008                            (
17009                                start_anchor,
17010                                InlineDiagnostic {
17011                                    message,
17012                                    group_id: diagnostic_entry.diagnostic.group_id,
17013                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17014                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17015                                    severity: diagnostic_entry.diagnostic.severity,
17016                                },
17017                            ),
17018                        );
17019                    }
17020                    inline_diagnostics
17021                })
17022                .await;
17023
17024            editor
17025                .update(cx, |editor, cx| {
17026                    editor.inline_diagnostics = new_inline_diagnostics;
17027                    cx.notify();
17028                })
17029                .ok();
17030        });
17031    }
17032
17033    fn pull_diagnostics(
17034        &mut self,
17035        buffer_id: Option<BufferId>,
17036        window: &Window,
17037        cx: &mut Context<Self>,
17038    ) -> Option<()> {
17039        if !self.mode().is_full() {
17040            return None;
17041        }
17042        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17043            .diagnostics
17044            .lsp_pull_diagnostics;
17045        if !pull_diagnostics_settings.enabled {
17046            return None;
17047        }
17048        let project = self.project()?.downgrade();
17049        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17050        let mut buffers = self.buffer.read(cx).all_buffers();
17051        if let Some(buffer_id) = buffer_id {
17052            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17053        }
17054
17055        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17056            cx.background_executor().timer(debounce).await;
17057
17058            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17059                buffers
17060                    .into_iter()
17061                    .filter_map(|buffer| {
17062                        project
17063                            .update(cx, |project, cx| {
17064                                project.lsp_store().update(cx, |lsp_store, cx| {
17065                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17066                                })
17067                            })
17068                            .ok()
17069                    })
17070                    .collect::<FuturesUnordered<_>>()
17071            }) else {
17072                return;
17073            };
17074
17075            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17076                match pull_task {
17077                    Ok(()) => {
17078                        if editor
17079                            .update_in(cx, |editor, window, cx| {
17080                                editor.update_diagnostics_state(window, cx);
17081                            })
17082                            .is_err()
17083                        {
17084                            return;
17085                        }
17086                    }
17087                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17088                }
17089            }
17090        });
17091
17092        Some(())
17093    }
17094
17095    pub fn set_selections_from_remote(
17096        &mut self,
17097        selections: Vec<Selection<Anchor>>,
17098        pending_selection: Option<Selection<Anchor>>,
17099        window: &mut Window,
17100        cx: &mut Context<Self>,
17101    ) {
17102        let old_cursor_position = self.selections.newest_anchor().head();
17103        self.selections.change_with(cx, |s| {
17104            s.select_anchors(selections);
17105            if let Some(pending_selection) = pending_selection {
17106                s.set_pending(pending_selection, SelectMode::Character);
17107            } else {
17108                s.clear_pending();
17109            }
17110        });
17111        self.selections_did_change(
17112            false,
17113            &old_cursor_position,
17114            SelectionEffects::default(),
17115            window,
17116            cx,
17117        );
17118    }
17119
17120    pub fn transact(
17121        &mut self,
17122        window: &mut Window,
17123        cx: &mut Context<Self>,
17124        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17125    ) -> Option<TransactionId> {
17126        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17127            this.start_transaction_at(Instant::now(), window, cx);
17128            update(this, window, cx);
17129            this.end_transaction_at(Instant::now(), cx)
17130        })
17131    }
17132
17133    pub fn start_transaction_at(
17134        &mut self,
17135        now: Instant,
17136        window: &mut Window,
17137        cx: &mut Context<Self>,
17138    ) -> Option<TransactionId> {
17139        self.end_selection(window, cx);
17140        if let Some(tx_id) = self
17141            .buffer
17142            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17143        {
17144            self.selection_history
17145                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17146            cx.emit(EditorEvent::TransactionBegun {
17147                transaction_id: tx_id,
17148            });
17149            Some(tx_id)
17150        } else {
17151            None
17152        }
17153    }
17154
17155    pub fn end_transaction_at(
17156        &mut self,
17157        now: Instant,
17158        cx: &mut Context<Self>,
17159    ) -> Option<TransactionId> {
17160        if let Some(transaction_id) = self
17161            .buffer
17162            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17163        {
17164            if let Some((_, end_selections)) =
17165                self.selection_history.transaction_mut(transaction_id)
17166            {
17167                *end_selections = Some(self.selections.disjoint_anchors());
17168            } else {
17169                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17170            }
17171
17172            cx.emit(EditorEvent::Edited { transaction_id });
17173            Some(transaction_id)
17174        } else {
17175            None
17176        }
17177    }
17178
17179    pub fn modify_transaction_selection_history(
17180        &mut self,
17181        transaction_id: TransactionId,
17182        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17183    ) -> bool {
17184        self.selection_history
17185            .transaction_mut(transaction_id)
17186            .map(modify)
17187            .is_some()
17188    }
17189
17190    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17191        if self.selection_mark_mode {
17192            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17193                s.move_with(|_, sel| {
17194                    sel.collapse_to(sel.head(), SelectionGoal::None);
17195                });
17196            })
17197        }
17198        self.selection_mark_mode = true;
17199        cx.notify();
17200    }
17201
17202    pub fn swap_selection_ends(
17203        &mut self,
17204        _: &actions::SwapSelectionEnds,
17205        window: &mut Window,
17206        cx: &mut Context<Self>,
17207    ) {
17208        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17209            s.move_with(|_, sel| {
17210                if sel.start != sel.end {
17211                    sel.reversed = !sel.reversed
17212                }
17213            });
17214        });
17215        self.request_autoscroll(Autoscroll::newest(), cx);
17216        cx.notify();
17217    }
17218
17219    pub fn toggle_focus(
17220        workspace: &mut Workspace,
17221        _: &actions::ToggleFocus,
17222        window: &mut Window,
17223        cx: &mut Context<Workspace>,
17224    ) {
17225        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17226            return;
17227        };
17228        workspace.activate_item(&item, true, true, window, cx);
17229    }
17230
17231    pub fn toggle_fold(
17232        &mut self,
17233        _: &actions::ToggleFold,
17234        window: &mut Window,
17235        cx: &mut Context<Self>,
17236    ) {
17237        if self.is_singleton(cx) {
17238            let selection = self.selections.newest::<Point>(cx);
17239
17240            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17241            let range = if selection.is_empty() {
17242                let point = selection.head().to_display_point(&display_map);
17243                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17244                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17245                    .to_point(&display_map);
17246                start..end
17247            } else {
17248                selection.range()
17249            };
17250            if display_map.folds_in_range(range).next().is_some() {
17251                self.unfold_lines(&Default::default(), window, cx)
17252            } else {
17253                self.fold(&Default::default(), window, cx)
17254            }
17255        } else {
17256            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17257            let buffer_ids: HashSet<_> = self
17258                .selections
17259                .disjoint_anchor_ranges()
17260                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17261                .collect();
17262
17263            let should_unfold = buffer_ids
17264                .iter()
17265                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17266
17267            for buffer_id in buffer_ids {
17268                if should_unfold {
17269                    self.unfold_buffer(buffer_id, cx);
17270                } else {
17271                    self.fold_buffer(buffer_id, cx);
17272                }
17273            }
17274        }
17275    }
17276
17277    pub fn toggle_fold_recursive(
17278        &mut self,
17279        _: &actions::ToggleFoldRecursive,
17280        window: &mut Window,
17281        cx: &mut Context<Self>,
17282    ) {
17283        let selection = self.selections.newest::<Point>(cx);
17284
17285        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17286        let range = if selection.is_empty() {
17287            let point = selection.head().to_display_point(&display_map);
17288            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17289            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17290                .to_point(&display_map);
17291            start..end
17292        } else {
17293            selection.range()
17294        };
17295        if display_map.folds_in_range(range).next().is_some() {
17296            self.unfold_recursive(&Default::default(), window, cx)
17297        } else {
17298            self.fold_recursive(&Default::default(), window, cx)
17299        }
17300    }
17301
17302    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17303        if self.is_singleton(cx) {
17304            let mut to_fold = Vec::new();
17305            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17306            let selections = self.selections.all_adjusted(cx);
17307
17308            for selection in selections {
17309                let range = selection.range().sorted();
17310                let buffer_start_row = range.start.row;
17311
17312                if range.start.row != range.end.row {
17313                    let mut found = false;
17314                    let mut row = range.start.row;
17315                    while row <= range.end.row {
17316                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17317                        {
17318                            found = true;
17319                            row = crease.range().end.row + 1;
17320                            to_fold.push(crease);
17321                        } else {
17322                            row += 1
17323                        }
17324                    }
17325                    if found {
17326                        continue;
17327                    }
17328                }
17329
17330                for row in (0..=range.start.row).rev() {
17331                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17332                        && crease.range().end.row >= buffer_start_row
17333                    {
17334                        to_fold.push(crease);
17335                        if row <= range.start.row {
17336                            break;
17337                        }
17338                    }
17339                }
17340            }
17341
17342            self.fold_creases(to_fold, true, window, cx);
17343        } else {
17344            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17345            let buffer_ids = self
17346                .selections
17347                .disjoint_anchor_ranges()
17348                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17349                .collect::<HashSet<_>>();
17350            for buffer_id in buffer_ids {
17351                self.fold_buffer(buffer_id, cx);
17352            }
17353        }
17354    }
17355
17356    pub fn toggle_fold_all(
17357        &mut self,
17358        _: &actions::ToggleFoldAll,
17359        window: &mut Window,
17360        cx: &mut Context<Self>,
17361    ) {
17362        if self.buffer.read(cx).is_singleton() {
17363            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17364            let has_folds = display_map
17365                .folds_in_range(0..display_map.buffer_snapshot.len())
17366                .next()
17367                .is_some();
17368
17369            if has_folds {
17370                self.unfold_all(&actions::UnfoldAll, window, cx);
17371            } else {
17372                self.fold_all(&actions::FoldAll, window, cx);
17373            }
17374        } else {
17375            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17376            let should_unfold = buffer_ids
17377                .iter()
17378                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17379
17380            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17381                editor
17382                    .update_in(cx, |editor, _, cx| {
17383                        for buffer_id in buffer_ids {
17384                            if should_unfold {
17385                                editor.unfold_buffer(buffer_id, cx);
17386                            } else {
17387                                editor.fold_buffer(buffer_id, cx);
17388                            }
17389                        }
17390                    })
17391                    .ok();
17392            });
17393        }
17394    }
17395
17396    fn fold_at_level(
17397        &mut self,
17398        fold_at: &FoldAtLevel,
17399        window: &mut Window,
17400        cx: &mut Context<Self>,
17401    ) {
17402        if !self.buffer.read(cx).is_singleton() {
17403            return;
17404        }
17405
17406        let fold_at_level = fold_at.0;
17407        let snapshot = self.buffer.read(cx).snapshot(cx);
17408        let mut to_fold = Vec::new();
17409        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17410
17411        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17412            while start_row < end_row {
17413                match self
17414                    .snapshot(window, cx)
17415                    .crease_for_buffer_row(MultiBufferRow(start_row))
17416                {
17417                    Some(crease) => {
17418                        let nested_start_row = crease.range().start.row + 1;
17419                        let nested_end_row = crease.range().end.row;
17420
17421                        if current_level < fold_at_level {
17422                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17423                        } else if current_level == fold_at_level {
17424                            to_fold.push(crease);
17425                        }
17426
17427                        start_row = nested_end_row + 1;
17428                    }
17429                    None => start_row += 1,
17430                }
17431            }
17432        }
17433
17434        self.fold_creases(to_fold, true, window, cx);
17435    }
17436
17437    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17438        if self.buffer.read(cx).is_singleton() {
17439            let mut fold_ranges = Vec::new();
17440            let snapshot = self.buffer.read(cx).snapshot(cx);
17441
17442            for row in 0..snapshot.max_row().0 {
17443                if let Some(foldable_range) = self
17444                    .snapshot(window, cx)
17445                    .crease_for_buffer_row(MultiBufferRow(row))
17446                {
17447                    fold_ranges.push(foldable_range);
17448                }
17449            }
17450
17451            self.fold_creases(fold_ranges, true, window, cx);
17452        } else {
17453            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17454                editor
17455                    .update_in(cx, |editor, _, cx| {
17456                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17457                            editor.fold_buffer(buffer_id, cx);
17458                        }
17459                    })
17460                    .ok();
17461            });
17462        }
17463    }
17464
17465    pub fn fold_function_bodies(
17466        &mut self,
17467        _: &actions::FoldFunctionBodies,
17468        window: &mut Window,
17469        cx: &mut Context<Self>,
17470    ) {
17471        let snapshot = self.buffer.read(cx).snapshot(cx);
17472
17473        let ranges = snapshot
17474            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17475            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17476            .collect::<Vec<_>>();
17477
17478        let creases = ranges
17479            .into_iter()
17480            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17481            .collect();
17482
17483        self.fold_creases(creases, true, window, cx);
17484    }
17485
17486    pub fn fold_recursive(
17487        &mut self,
17488        _: &actions::FoldRecursive,
17489        window: &mut Window,
17490        cx: &mut Context<Self>,
17491    ) {
17492        let mut to_fold = Vec::new();
17493        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17494        let selections = self.selections.all_adjusted(cx);
17495
17496        for selection in selections {
17497            let range = selection.range().sorted();
17498            let buffer_start_row = range.start.row;
17499
17500            if range.start.row != range.end.row {
17501                let mut found = false;
17502                for row in range.start.row..=range.end.row {
17503                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17504                        found = true;
17505                        to_fold.push(crease);
17506                    }
17507                }
17508                if found {
17509                    continue;
17510                }
17511            }
17512
17513            for row in (0..=range.start.row).rev() {
17514                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17515                    if crease.range().end.row >= buffer_start_row {
17516                        to_fold.push(crease);
17517                    } else {
17518                        break;
17519                    }
17520                }
17521            }
17522        }
17523
17524        self.fold_creases(to_fold, true, window, cx);
17525    }
17526
17527    pub fn fold_at(
17528        &mut self,
17529        buffer_row: MultiBufferRow,
17530        window: &mut Window,
17531        cx: &mut Context<Self>,
17532    ) {
17533        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17534
17535        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17536            let autoscroll = self
17537                .selections
17538                .all::<Point>(cx)
17539                .iter()
17540                .any(|selection| crease.range().overlaps(&selection.range()));
17541
17542            self.fold_creases(vec![crease], autoscroll, window, cx);
17543        }
17544    }
17545
17546    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17547        if self.is_singleton(cx) {
17548            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17549            let buffer = &display_map.buffer_snapshot;
17550            let selections = self.selections.all::<Point>(cx);
17551            let ranges = selections
17552                .iter()
17553                .map(|s| {
17554                    let range = s.display_range(&display_map).sorted();
17555                    let mut start = range.start.to_point(&display_map);
17556                    let mut end = range.end.to_point(&display_map);
17557                    start.column = 0;
17558                    end.column = buffer.line_len(MultiBufferRow(end.row));
17559                    start..end
17560                })
17561                .collect::<Vec<_>>();
17562
17563            self.unfold_ranges(&ranges, true, true, cx);
17564        } else {
17565            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17566            let buffer_ids = self
17567                .selections
17568                .disjoint_anchor_ranges()
17569                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17570                .collect::<HashSet<_>>();
17571            for buffer_id in buffer_ids {
17572                self.unfold_buffer(buffer_id, cx);
17573            }
17574        }
17575    }
17576
17577    pub fn unfold_recursive(
17578        &mut self,
17579        _: &UnfoldRecursive,
17580        _window: &mut Window,
17581        cx: &mut Context<Self>,
17582    ) {
17583        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17584        let selections = self.selections.all::<Point>(cx);
17585        let ranges = selections
17586            .iter()
17587            .map(|s| {
17588                let mut range = s.display_range(&display_map).sorted();
17589                *range.start.column_mut() = 0;
17590                *range.end.column_mut() = display_map.line_len(range.end.row());
17591                let start = range.start.to_point(&display_map);
17592                let end = range.end.to_point(&display_map);
17593                start..end
17594            })
17595            .collect::<Vec<_>>();
17596
17597        self.unfold_ranges(&ranges, true, true, cx);
17598    }
17599
17600    pub fn unfold_at(
17601        &mut self,
17602        buffer_row: MultiBufferRow,
17603        _window: &mut Window,
17604        cx: &mut Context<Self>,
17605    ) {
17606        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17607
17608        let intersection_range = Point::new(buffer_row.0, 0)
17609            ..Point::new(
17610                buffer_row.0,
17611                display_map.buffer_snapshot.line_len(buffer_row),
17612            );
17613
17614        let autoscroll = self
17615            .selections
17616            .all::<Point>(cx)
17617            .iter()
17618            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17619
17620        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17621    }
17622
17623    pub fn unfold_all(
17624        &mut self,
17625        _: &actions::UnfoldAll,
17626        _window: &mut Window,
17627        cx: &mut Context<Self>,
17628    ) {
17629        if self.buffer.read(cx).is_singleton() {
17630            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17631            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17632        } else {
17633            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17634                editor
17635                    .update(cx, |editor, cx| {
17636                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17637                            editor.unfold_buffer(buffer_id, cx);
17638                        }
17639                    })
17640                    .ok();
17641            });
17642        }
17643    }
17644
17645    pub fn fold_selected_ranges(
17646        &mut self,
17647        _: &FoldSelectedRanges,
17648        window: &mut Window,
17649        cx: &mut Context<Self>,
17650    ) {
17651        let selections = self.selections.all_adjusted(cx);
17652        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17653        let ranges = selections
17654            .into_iter()
17655            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17656            .collect::<Vec<_>>();
17657        self.fold_creases(ranges, true, window, cx);
17658    }
17659
17660    pub fn fold_ranges<T: ToOffset + Clone>(
17661        &mut self,
17662        ranges: Vec<Range<T>>,
17663        auto_scroll: bool,
17664        window: &mut Window,
17665        cx: &mut Context<Self>,
17666    ) {
17667        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17668        let ranges = ranges
17669            .into_iter()
17670            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17671            .collect::<Vec<_>>();
17672        self.fold_creases(ranges, auto_scroll, window, cx);
17673    }
17674
17675    pub fn fold_creases<T: ToOffset + Clone>(
17676        &mut self,
17677        creases: Vec<Crease<T>>,
17678        auto_scroll: bool,
17679        _window: &mut Window,
17680        cx: &mut Context<Self>,
17681    ) {
17682        if creases.is_empty() {
17683            return;
17684        }
17685
17686        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17687
17688        if auto_scroll {
17689            self.request_autoscroll(Autoscroll::fit(), cx);
17690        }
17691
17692        cx.notify();
17693
17694        self.scrollbar_marker_state.dirty = true;
17695        self.folds_did_change(cx);
17696    }
17697
17698    /// Removes any folds whose ranges intersect any of the given ranges.
17699    pub fn unfold_ranges<T: ToOffset + Clone>(
17700        &mut self,
17701        ranges: &[Range<T>],
17702        inclusive: bool,
17703        auto_scroll: bool,
17704        cx: &mut Context<Self>,
17705    ) {
17706        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17707            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17708        });
17709        self.folds_did_change(cx);
17710    }
17711
17712    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17713        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17714            return;
17715        }
17716        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17717        self.display_map.update(cx, |display_map, cx| {
17718            display_map.fold_buffers([buffer_id], cx)
17719        });
17720        cx.emit(EditorEvent::BufferFoldToggled {
17721            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17722            folded: true,
17723        });
17724        cx.notify();
17725    }
17726
17727    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17728        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17729            return;
17730        }
17731        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17732        self.display_map.update(cx, |display_map, cx| {
17733            display_map.unfold_buffers([buffer_id], cx);
17734        });
17735        cx.emit(EditorEvent::BufferFoldToggled {
17736            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17737            folded: false,
17738        });
17739        cx.notify();
17740    }
17741
17742    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17743        self.display_map.read(cx).is_buffer_folded(buffer)
17744    }
17745
17746    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17747        self.display_map.read(cx).folded_buffers()
17748    }
17749
17750    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17751        self.display_map.update(cx, |display_map, cx| {
17752            display_map.disable_header_for_buffer(buffer_id, cx);
17753        });
17754        cx.notify();
17755    }
17756
17757    /// Removes any folds with the given ranges.
17758    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17759        &mut self,
17760        ranges: &[Range<T>],
17761        type_id: TypeId,
17762        auto_scroll: bool,
17763        cx: &mut Context<Self>,
17764    ) {
17765        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17766            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17767        });
17768        self.folds_did_change(cx);
17769    }
17770
17771    fn remove_folds_with<T: ToOffset + Clone>(
17772        &mut self,
17773        ranges: &[Range<T>],
17774        auto_scroll: bool,
17775        cx: &mut Context<Self>,
17776        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17777    ) {
17778        if ranges.is_empty() {
17779            return;
17780        }
17781
17782        let mut buffers_affected = HashSet::default();
17783        let multi_buffer = self.buffer().read(cx);
17784        for range in ranges {
17785            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17786                buffers_affected.insert(buffer.read(cx).remote_id());
17787            };
17788        }
17789
17790        self.display_map.update(cx, update);
17791
17792        if auto_scroll {
17793            self.request_autoscroll(Autoscroll::fit(), cx);
17794        }
17795
17796        cx.notify();
17797        self.scrollbar_marker_state.dirty = true;
17798        self.active_indent_guides_state.dirty = true;
17799    }
17800
17801    pub fn update_renderer_widths(
17802        &mut self,
17803        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17804        cx: &mut Context<Self>,
17805    ) -> bool {
17806        self.display_map
17807            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17808    }
17809
17810    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17811        self.display_map.read(cx).fold_placeholder.clone()
17812    }
17813
17814    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17815        self.buffer.update(cx, |buffer, cx| {
17816            buffer.set_all_diff_hunks_expanded(cx);
17817        });
17818    }
17819
17820    pub fn expand_all_diff_hunks(
17821        &mut self,
17822        _: &ExpandAllDiffHunks,
17823        _window: &mut Window,
17824        cx: &mut Context<Self>,
17825    ) {
17826        self.buffer.update(cx, |buffer, cx| {
17827            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17828        });
17829    }
17830
17831    pub fn toggle_selected_diff_hunks(
17832        &mut self,
17833        _: &ToggleSelectedDiffHunks,
17834        _window: &mut Window,
17835        cx: &mut Context<Self>,
17836    ) {
17837        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17838        self.toggle_diff_hunks_in_ranges(ranges, cx);
17839    }
17840
17841    pub fn diff_hunks_in_ranges<'a>(
17842        &'a self,
17843        ranges: &'a [Range<Anchor>],
17844        buffer: &'a MultiBufferSnapshot,
17845    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17846        ranges.iter().flat_map(move |range| {
17847            let end_excerpt_id = range.end.excerpt_id;
17848            let range = range.to_point(buffer);
17849            let mut peek_end = range.end;
17850            if range.end.row < buffer.max_row().0 {
17851                peek_end = Point::new(range.end.row + 1, 0);
17852            }
17853            buffer
17854                .diff_hunks_in_range(range.start..peek_end)
17855                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17856        })
17857    }
17858
17859    pub fn has_stageable_diff_hunks_in_ranges(
17860        &self,
17861        ranges: &[Range<Anchor>],
17862        snapshot: &MultiBufferSnapshot,
17863    ) -> bool {
17864        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17865        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17866    }
17867
17868    pub fn toggle_staged_selected_diff_hunks(
17869        &mut self,
17870        _: &::git::ToggleStaged,
17871        _: &mut Window,
17872        cx: &mut Context<Self>,
17873    ) {
17874        let snapshot = self.buffer.read(cx).snapshot(cx);
17875        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17876        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17877        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17878    }
17879
17880    pub fn set_render_diff_hunk_controls(
17881        &mut self,
17882        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17883        cx: &mut Context<Self>,
17884    ) {
17885        self.render_diff_hunk_controls = render_diff_hunk_controls;
17886        cx.notify();
17887    }
17888
17889    pub fn stage_and_next(
17890        &mut self,
17891        _: &::git::StageAndNext,
17892        window: &mut Window,
17893        cx: &mut Context<Self>,
17894    ) {
17895        self.do_stage_or_unstage_and_next(true, window, cx);
17896    }
17897
17898    pub fn unstage_and_next(
17899        &mut self,
17900        _: &::git::UnstageAndNext,
17901        window: &mut Window,
17902        cx: &mut Context<Self>,
17903    ) {
17904        self.do_stage_or_unstage_and_next(false, window, cx);
17905    }
17906
17907    pub fn stage_or_unstage_diff_hunks(
17908        &mut self,
17909        stage: bool,
17910        ranges: Vec<Range<Anchor>>,
17911        cx: &mut Context<Self>,
17912    ) {
17913        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17914        cx.spawn(async move |this, cx| {
17915            task.await?;
17916            this.update(cx, |this, cx| {
17917                let snapshot = this.buffer.read(cx).snapshot(cx);
17918                let chunk_by = this
17919                    .diff_hunks_in_ranges(&ranges, &snapshot)
17920                    .chunk_by(|hunk| hunk.buffer_id);
17921                for (buffer_id, hunks) in &chunk_by {
17922                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17923                }
17924            })
17925        })
17926        .detach_and_log_err(cx);
17927    }
17928
17929    fn save_buffers_for_ranges_if_needed(
17930        &mut self,
17931        ranges: &[Range<Anchor>],
17932        cx: &mut Context<Editor>,
17933    ) -> Task<Result<()>> {
17934        let multibuffer = self.buffer.read(cx);
17935        let snapshot = multibuffer.read(cx);
17936        let buffer_ids: HashSet<_> = ranges
17937            .iter()
17938            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17939            .collect();
17940        drop(snapshot);
17941
17942        let mut buffers = HashSet::default();
17943        for buffer_id in buffer_ids {
17944            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17945                let buffer = buffer_entity.read(cx);
17946                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17947                {
17948                    buffers.insert(buffer_entity);
17949                }
17950            }
17951        }
17952
17953        if let Some(project) = &self.project {
17954            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17955        } else {
17956            Task::ready(Ok(()))
17957        }
17958    }
17959
17960    fn do_stage_or_unstage_and_next(
17961        &mut self,
17962        stage: bool,
17963        window: &mut Window,
17964        cx: &mut Context<Self>,
17965    ) {
17966        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17967
17968        if ranges.iter().any(|range| range.start != range.end) {
17969            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17970            return;
17971        }
17972
17973        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17974        let snapshot = self.snapshot(window, cx);
17975        let position = self.selections.newest::<Point>(cx).head();
17976        let mut row = snapshot
17977            .buffer_snapshot
17978            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17979            .find(|hunk| hunk.row_range.start.0 > position.row)
17980            .map(|hunk| hunk.row_range.start);
17981
17982        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17983        // Outside of the project diff editor, wrap around to the beginning.
17984        if !all_diff_hunks_expanded {
17985            row = row.or_else(|| {
17986                snapshot
17987                    .buffer_snapshot
17988                    .diff_hunks_in_range(Point::zero()..position)
17989                    .find(|hunk| hunk.row_range.end.0 < position.row)
17990                    .map(|hunk| hunk.row_range.start)
17991            });
17992        }
17993
17994        if let Some(row) = row {
17995            let destination = Point::new(row.0, 0);
17996            let autoscroll = Autoscroll::center();
17997
17998            self.unfold_ranges(&[destination..destination], false, false, cx);
17999            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18000                s.select_ranges([destination..destination]);
18001            });
18002        }
18003    }
18004
18005    fn do_stage_or_unstage(
18006        &self,
18007        stage: bool,
18008        buffer_id: BufferId,
18009        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18010        cx: &mut App,
18011    ) -> Option<()> {
18012        let project = self.project()?;
18013        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18014        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18015        let buffer_snapshot = buffer.read(cx).snapshot();
18016        let file_exists = buffer_snapshot
18017            .file()
18018            .is_some_and(|file| file.disk_state().exists());
18019        diff.update(cx, |diff, cx| {
18020            diff.stage_or_unstage_hunks(
18021                stage,
18022                &hunks
18023                    .map(|hunk| buffer_diff::DiffHunk {
18024                        buffer_range: hunk.buffer_range,
18025                        diff_base_byte_range: hunk.diff_base_byte_range,
18026                        secondary_status: hunk.secondary_status,
18027                        range: Point::zero()..Point::zero(), // unused
18028                    })
18029                    .collect::<Vec<_>>(),
18030                &buffer_snapshot,
18031                file_exists,
18032                cx,
18033            )
18034        });
18035        None
18036    }
18037
18038    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18039        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18040        self.buffer
18041            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18042    }
18043
18044    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18045        self.buffer.update(cx, |buffer, cx| {
18046            let ranges = vec![Anchor::min()..Anchor::max()];
18047            if !buffer.all_diff_hunks_expanded()
18048                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18049            {
18050                buffer.collapse_diff_hunks(ranges, cx);
18051                true
18052            } else {
18053                false
18054            }
18055        })
18056    }
18057
18058    fn toggle_diff_hunks_in_ranges(
18059        &mut self,
18060        ranges: Vec<Range<Anchor>>,
18061        cx: &mut Context<Editor>,
18062    ) {
18063        self.buffer.update(cx, |buffer, cx| {
18064            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18065            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18066        })
18067    }
18068
18069    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18070        self.buffer.update(cx, |buffer, cx| {
18071            let snapshot = buffer.snapshot(cx);
18072            let excerpt_id = range.end.excerpt_id;
18073            let point_range = range.to_point(&snapshot);
18074            let expand = !buffer.single_hunk_is_expanded(range, cx);
18075            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18076        })
18077    }
18078
18079    pub(crate) fn apply_all_diff_hunks(
18080        &mut self,
18081        _: &ApplyAllDiffHunks,
18082        window: &mut Window,
18083        cx: &mut Context<Self>,
18084    ) {
18085        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18086
18087        let buffers = self.buffer.read(cx).all_buffers();
18088        for branch_buffer in buffers {
18089            branch_buffer.update(cx, |branch_buffer, cx| {
18090                branch_buffer.merge_into_base(Vec::new(), cx);
18091            });
18092        }
18093
18094        if let Some(project) = self.project.clone() {
18095            self.save(
18096                SaveOptions {
18097                    format: true,
18098                    autosave: false,
18099                },
18100                project,
18101                window,
18102                cx,
18103            )
18104            .detach_and_log_err(cx);
18105        }
18106    }
18107
18108    pub(crate) fn apply_selected_diff_hunks(
18109        &mut self,
18110        _: &ApplyDiffHunk,
18111        window: &mut Window,
18112        cx: &mut Context<Self>,
18113    ) {
18114        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18115        let snapshot = self.snapshot(window, cx);
18116        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18117        let mut ranges_by_buffer = HashMap::default();
18118        self.transact(window, cx, |editor, _window, cx| {
18119            for hunk in hunks {
18120                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18121                    ranges_by_buffer
18122                        .entry(buffer.clone())
18123                        .or_insert_with(Vec::new)
18124                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18125                }
18126            }
18127
18128            for (buffer, ranges) in ranges_by_buffer {
18129                buffer.update(cx, |buffer, cx| {
18130                    buffer.merge_into_base(ranges, cx);
18131                });
18132            }
18133        });
18134
18135        if let Some(project) = self.project.clone() {
18136            self.save(
18137                SaveOptions {
18138                    format: true,
18139                    autosave: false,
18140                },
18141                project,
18142                window,
18143                cx,
18144            )
18145            .detach_and_log_err(cx);
18146        }
18147    }
18148
18149    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18150        if hovered != self.gutter_hovered {
18151            self.gutter_hovered = hovered;
18152            cx.notify();
18153        }
18154    }
18155
18156    pub fn insert_blocks(
18157        &mut self,
18158        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18159        autoscroll: Option<Autoscroll>,
18160        cx: &mut Context<Self>,
18161    ) -> Vec<CustomBlockId> {
18162        let blocks = self
18163            .display_map
18164            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18165        if let Some(autoscroll) = autoscroll {
18166            self.request_autoscroll(autoscroll, cx);
18167        }
18168        cx.notify();
18169        blocks
18170    }
18171
18172    pub fn resize_blocks(
18173        &mut self,
18174        heights: HashMap<CustomBlockId, u32>,
18175        autoscroll: Option<Autoscroll>,
18176        cx: &mut Context<Self>,
18177    ) {
18178        self.display_map
18179            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18180        if let Some(autoscroll) = autoscroll {
18181            self.request_autoscroll(autoscroll, cx);
18182        }
18183        cx.notify();
18184    }
18185
18186    pub fn replace_blocks(
18187        &mut self,
18188        renderers: HashMap<CustomBlockId, RenderBlock>,
18189        autoscroll: Option<Autoscroll>,
18190        cx: &mut Context<Self>,
18191    ) {
18192        self.display_map
18193            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18194        if let Some(autoscroll) = autoscroll {
18195            self.request_autoscroll(autoscroll, cx);
18196        }
18197        cx.notify();
18198    }
18199
18200    pub fn remove_blocks(
18201        &mut self,
18202        block_ids: HashSet<CustomBlockId>,
18203        autoscroll: Option<Autoscroll>,
18204        cx: &mut Context<Self>,
18205    ) {
18206        self.display_map.update(cx, |display_map, cx| {
18207            display_map.remove_blocks(block_ids, cx)
18208        });
18209        if let Some(autoscroll) = autoscroll {
18210            self.request_autoscroll(autoscroll, cx);
18211        }
18212        cx.notify();
18213    }
18214
18215    pub fn row_for_block(
18216        &self,
18217        block_id: CustomBlockId,
18218        cx: &mut Context<Self>,
18219    ) -> Option<DisplayRow> {
18220        self.display_map
18221            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18222    }
18223
18224    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18225        self.focused_block = Some(focused_block);
18226    }
18227
18228    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18229        self.focused_block.take()
18230    }
18231
18232    pub fn insert_creases(
18233        &mut self,
18234        creases: impl IntoIterator<Item = Crease<Anchor>>,
18235        cx: &mut Context<Self>,
18236    ) -> Vec<CreaseId> {
18237        self.display_map
18238            .update(cx, |map, cx| map.insert_creases(creases, cx))
18239    }
18240
18241    pub fn remove_creases(
18242        &mut self,
18243        ids: impl IntoIterator<Item = CreaseId>,
18244        cx: &mut Context<Self>,
18245    ) -> Vec<(CreaseId, Range<Anchor>)> {
18246        self.display_map
18247            .update(cx, |map, cx| map.remove_creases(ids, cx))
18248    }
18249
18250    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18251        self.display_map
18252            .update(cx, |map, cx| map.snapshot(cx))
18253            .longest_row()
18254    }
18255
18256    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18257        self.display_map
18258            .update(cx, |map, cx| map.snapshot(cx))
18259            .max_point()
18260    }
18261
18262    pub fn text(&self, cx: &App) -> String {
18263        self.buffer.read(cx).read(cx).text()
18264    }
18265
18266    pub fn is_empty(&self, cx: &App) -> bool {
18267        self.buffer.read(cx).read(cx).is_empty()
18268    }
18269
18270    pub fn text_option(&self, cx: &App) -> Option<String> {
18271        let text = self.text(cx);
18272        let text = text.trim();
18273
18274        if text.is_empty() {
18275            return None;
18276        }
18277
18278        Some(text.to_string())
18279    }
18280
18281    pub fn set_text(
18282        &mut self,
18283        text: impl Into<Arc<str>>,
18284        window: &mut Window,
18285        cx: &mut Context<Self>,
18286    ) {
18287        self.transact(window, cx, |this, _, cx| {
18288            this.buffer
18289                .read(cx)
18290                .as_singleton()
18291                .expect("you can only call set_text on editors for singleton buffers")
18292                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18293        });
18294    }
18295
18296    pub fn display_text(&self, cx: &mut App) -> String {
18297        self.display_map
18298            .update(cx, |map, cx| map.snapshot(cx))
18299            .text()
18300    }
18301
18302    fn create_minimap(
18303        &self,
18304        minimap_settings: MinimapSettings,
18305        window: &mut Window,
18306        cx: &mut Context<Self>,
18307    ) -> Option<Entity<Self>> {
18308        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18309            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18310    }
18311
18312    fn initialize_new_minimap(
18313        &self,
18314        minimap_settings: MinimapSettings,
18315        window: &mut Window,
18316        cx: &mut Context<Self>,
18317    ) -> Entity<Self> {
18318        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18319
18320        let mut minimap = Editor::new_internal(
18321            EditorMode::Minimap {
18322                parent: cx.weak_entity(),
18323            },
18324            self.buffer.clone(),
18325            None,
18326            Some(self.display_map.clone()),
18327            window,
18328            cx,
18329        );
18330        minimap.scroll_manager.clone_state(&self.scroll_manager);
18331        minimap.set_text_style_refinement(TextStyleRefinement {
18332            font_size: Some(MINIMAP_FONT_SIZE),
18333            font_weight: Some(MINIMAP_FONT_WEIGHT),
18334            ..Default::default()
18335        });
18336        minimap.update_minimap_configuration(minimap_settings, cx);
18337        cx.new(|_| minimap)
18338    }
18339
18340    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18341        let current_line_highlight = minimap_settings
18342            .current_line_highlight
18343            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18344        self.set_current_line_highlight(Some(current_line_highlight));
18345    }
18346
18347    pub fn minimap(&self) -> Option<&Entity<Self>> {
18348        self.minimap
18349            .as_ref()
18350            .filter(|_| self.minimap_visibility.visible())
18351    }
18352
18353    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18354        let mut wrap_guides = smallvec![];
18355
18356        if self.show_wrap_guides == Some(false) {
18357            return wrap_guides;
18358        }
18359
18360        let settings = self.buffer.read(cx).language_settings(cx);
18361        if settings.show_wrap_guides {
18362            match self.soft_wrap_mode(cx) {
18363                SoftWrap::Column(soft_wrap) => {
18364                    wrap_guides.push((soft_wrap as usize, true));
18365                }
18366                SoftWrap::Bounded(soft_wrap) => {
18367                    wrap_guides.push((soft_wrap as usize, true));
18368                }
18369                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18370            }
18371            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18372        }
18373
18374        wrap_guides
18375    }
18376
18377    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18378        let settings = self.buffer.read(cx).language_settings(cx);
18379        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18380        match mode {
18381            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18382                SoftWrap::None
18383            }
18384            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18385            language_settings::SoftWrap::PreferredLineLength => {
18386                SoftWrap::Column(settings.preferred_line_length)
18387            }
18388            language_settings::SoftWrap::Bounded => {
18389                SoftWrap::Bounded(settings.preferred_line_length)
18390            }
18391        }
18392    }
18393
18394    pub fn set_soft_wrap_mode(
18395        &mut self,
18396        mode: language_settings::SoftWrap,
18397
18398        cx: &mut Context<Self>,
18399    ) {
18400        self.soft_wrap_mode_override = Some(mode);
18401        cx.notify();
18402    }
18403
18404    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18405        self.hard_wrap = hard_wrap;
18406        cx.notify();
18407    }
18408
18409    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18410        self.text_style_refinement = Some(style);
18411    }
18412
18413    /// called by the Element so we know what style we were most recently rendered with.
18414    pub(crate) fn set_style(
18415        &mut self,
18416        style: EditorStyle,
18417        window: &mut Window,
18418        cx: &mut Context<Self>,
18419    ) {
18420        // We intentionally do not inform the display map about the minimap style
18421        // so that wrapping is not recalculated and stays consistent for the editor
18422        // and its linked minimap.
18423        if !self.mode.is_minimap() {
18424            let rem_size = window.rem_size();
18425            self.display_map.update(cx, |map, cx| {
18426                map.set_font(
18427                    style.text.font(),
18428                    style.text.font_size.to_pixels(rem_size),
18429                    cx,
18430                )
18431            });
18432        }
18433        self.style = Some(style);
18434    }
18435
18436    pub fn style(&self) -> Option<&EditorStyle> {
18437        self.style.as_ref()
18438    }
18439
18440    // Called by the element. This method is not designed to be called outside of the editor
18441    // element's layout code because it does not notify when rewrapping is computed synchronously.
18442    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18443        self.display_map
18444            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18445    }
18446
18447    pub fn set_soft_wrap(&mut self) {
18448        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18449    }
18450
18451    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18452        if self.soft_wrap_mode_override.is_some() {
18453            self.soft_wrap_mode_override.take();
18454        } else {
18455            let soft_wrap = match self.soft_wrap_mode(cx) {
18456                SoftWrap::GitDiff => return,
18457                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18458                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18459                    language_settings::SoftWrap::None
18460                }
18461            };
18462            self.soft_wrap_mode_override = Some(soft_wrap);
18463        }
18464        cx.notify();
18465    }
18466
18467    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18468        let Some(workspace) = self.workspace() else {
18469            return;
18470        };
18471        let fs = workspace.read(cx).app_state().fs.clone();
18472        let current_show = TabBarSettings::get_global(cx).show;
18473        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18474            setting.show = Some(!current_show);
18475        });
18476    }
18477
18478    pub fn toggle_indent_guides(
18479        &mut self,
18480        _: &ToggleIndentGuides,
18481        _: &mut Window,
18482        cx: &mut Context<Self>,
18483    ) {
18484        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18485            self.buffer
18486                .read(cx)
18487                .language_settings(cx)
18488                .indent_guides
18489                .enabled
18490        });
18491        self.show_indent_guides = Some(!currently_enabled);
18492        cx.notify();
18493    }
18494
18495    fn should_show_indent_guides(&self) -> Option<bool> {
18496        self.show_indent_guides
18497    }
18498
18499    pub fn toggle_line_numbers(
18500        &mut self,
18501        _: &ToggleLineNumbers,
18502        _: &mut Window,
18503        cx: &mut Context<Self>,
18504    ) {
18505        let mut editor_settings = EditorSettings::get_global(cx).clone();
18506        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18507        EditorSettings::override_global(editor_settings, cx);
18508    }
18509
18510    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18511        if let Some(show_line_numbers) = self.show_line_numbers {
18512            return show_line_numbers;
18513        }
18514        EditorSettings::get_global(cx).gutter.line_numbers
18515    }
18516
18517    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18518        self.use_relative_line_numbers
18519            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18520    }
18521
18522    pub fn toggle_relative_line_numbers(
18523        &mut self,
18524        _: &ToggleRelativeLineNumbers,
18525        _: &mut Window,
18526        cx: &mut Context<Self>,
18527    ) {
18528        let is_relative = self.should_use_relative_line_numbers(cx);
18529        self.set_relative_line_number(Some(!is_relative), cx)
18530    }
18531
18532    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18533        self.use_relative_line_numbers = is_relative;
18534        cx.notify();
18535    }
18536
18537    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18538        self.show_gutter = show_gutter;
18539        cx.notify();
18540    }
18541
18542    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18543        self.show_scrollbars = ScrollbarAxes {
18544            horizontal: show,
18545            vertical: show,
18546        };
18547        cx.notify();
18548    }
18549
18550    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18551        self.show_scrollbars.vertical = show;
18552        cx.notify();
18553    }
18554
18555    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18556        self.show_scrollbars.horizontal = show;
18557        cx.notify();
18558    }
18559
18560    pub fn set_minimap_visibility(
18561        &mut self,
18562        minimap_visibility: MinimapVisibility,
18563        window: &mut Window,
18564        cx: &mut Context<Self>,
18565    ) {
18566        if self.minimap_visibility != minimap_visibility {
18567            if minimap_visibility.visible() && self.minimap.is_none() {
18568                let minimap_settings = EditorSettings::get_global(cx).minimap;
18569                self.minimap =
18570                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18571            }
18572            self.minimap_visibility = minimap_visibility;
18573            cx.notify();
18574        }
18575    }
18576
18577    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18578        self.set_show_scrollbars(false, cx);
18579        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18580    }
18581
18582    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18583        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18584    }
18585
18586    /// Normally the text in full mode and auto height editors is padded on the
18587    /// left side by roughly half a character width for improved hit testing.
18588    ///
18589    /// Use this method to disable this for cases where this is not wanted (e.g.
18590    /// if you want to align the editor text with some other text above or below)
18591    /// or if you want to add this padding to single-line editors.
18592    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18593        self.offset_content = offset_content;
18594        cx.notify();
18595    }
18596
18597    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18598        self.show_line_numbers = Some(show_line_numbers);
18599        cx.notify();
18600    }
18601
18602    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18603        self.disable_expand_excerpt_buttons = true;
18604        cx.notify();
18605    }
18606
18607    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18608        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18609        cx.notify();
18610    }
18611
18612    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18613        self.show_code_actions = Some(show_code_actions);
18614        cx.notify();
18615    }
18616
18617    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18618        self.show_runnables = Some(show_runnables);
18619        cx.notify();
18620    }
18621
18622    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18623        self.show_breakpoints = Some(show_breakpoints);
18624        cx.notify();
18625    }
18626
18627    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18628        if self.display_map.read(cx).masked != masked {
18629            self.display_map.update(cx, |map, _| map.masked = masked);
18630        }
18631        cx.notify()
18632    }
18633
18634    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18635        self.show_wrap_guides = Some(show_wrap_guides);
18636        cx.notify();
18637    }
18638
18639    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18640        self.show_indent_guides = Some(show_indent_guides);
18641        cx.notify();
18642    }
18643
18644    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18645        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18646            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18647                && let Some(dir) = file.abs_path(cx).parent()
18648            {
18649                return Some(dir.to_owned());
18650            }
18651
18652            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18653                return Some(project_path.path.to_path_buf());
18654            }
18655        }
18656
18657        None
18658    }
18659
18660    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18661        self.active_excerpt(cx)?
18662            .1
18663            .read(cx)
18664            .file()
18665            .and_then(|f| f.as_local())
18666    }
18667
18668    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18669        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18670            let buffer = buffer.read(cx);
18671            if let Some(project_path) = buffer.project_path(cx) {
18672                let project = self.project()?.read(cx);
18673                project.absolute_path(&project_path, cx)
18674            } else {
18675                buffer
18676                    .file()
18677                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18678            }
18679        })
18680    }
18681
18682    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18683        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18684            let project_path = buffer.read(cx).project_path(cx)?;
18685            let project = self.project()?.read(cx);
18686            let entry = project.entry_for_path(&project_path, cx)?;
18687            let path = entry.path.to_path_buf();
18688            Some(path)
18689        })
18690    }
18691
18692    pub fn reveal_in_finder(
18693        &mut self,
18694        _: &RevealInFileManager,
18695        _window: &mut Window,
18696        cx: &mut Context<Self>,
18697    ) {
18698        if let Some(target) = self.target_file(cx) {
18699            cx.reveal_path(&target.abs_path(cx));
18700        }
18701    }
18702
18703    pub fn copy_path(
18704        &mut self,
18705        _: &zed_actions::workspace::CopyPath,
18706        _window: &mut Window,
18707        cx: &mut Context<Self>,
18708    ) {
18709        if let Some(path) = self.target_file_abs_path(cx)
18710            && let Some(path) = path.to_str()
18711        {
18712            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18713        }
18714    }
18715
18716    pub fn copy_relative_path(
18717        &mut self,
18718        _: &zed_actions::workspace::CopyRelativePath,
18719        _window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) {
18722        if let Some(path) = self.target_file_path(cx)
18723            && let Some(path) = path.to_str()
18724        {
18725            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18726        }
18727    }
18728
18729    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18730        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18731            buffer.read(cx).project_path(cx)
18732        } else {
18733            None
18734        }
18735    }
18736
18737    // Returns true if the editor handled a go-to-line request
18738    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18739        maybe!({
18740            let breakpoint_store = self.breakpoint_store.as_ref()?;
18741
18742            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18743            else {
18744                self.clear_row_highlights::<ActiveDebugLine>();
18745                return None;
18746            };
18747
18748            let position = active_stack_frame.position;
18749            let buffer_id = position.buffer_id?;
18750            let snapshot = self
18751                .project
18752                .as_ref()?
18753                .read(cx)
18754                .buffer_for_id(buffer_id, cx)?
18755                .read(cx)
18756                .snapshot();
18757
18758            let mut handled = false;
18759            for (id, ExcerptRange { context, .. }) in
18760                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18761            {
18762                if context.start.cmp(&position, &snapshot).is_ge()
18763                    || context.end.cmp(&position, &snapshot).is_lt()
18764                {
18765                    continue;
18766                }
18767                let snapshot = self.buffer.read(cx).snapshot(cx);
18768                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18769
18770                handled = true;
18771                self.clear_row_highlights::<ActiveDebugLine>();
18772
18773                self.go_to_line::<ActiveDebugLine>(
18774                    multibuffer_anchor,
18775                    Some(cx.theme().colors().editor_debugger_active_line_background),
18776                    window,
18777                    cx,
18778                );
18779
18780                cx.notify();
18781            }
18782
18783            handled.then_some(())
18784        })
18785        .is_some()
18786    }
18787
18788    pub fn copy_file_name_without_extension(
18789        &mut self,
18790        _: &CopyFileNameWithoutExtension,
18791        _: &mut Window,
18792        cx: &mut Context<Self>,
18793    ) {
18794        if let Some(file) = self.target_file(cx)
18795            && let Some(file_stem) = file.path().file_stem()
18796            && let Some(name) = file_stem.to_str()
18797        {
18798            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18799        }
18800    }
18801
18802    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18803        if let Some(file) = self.target_file(cx)
18804            && let Some(file_name) = file.path().file_name()
18805            && let Some(name) = file_name.to_str()
18806        {
18807            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18808        }
18809    }
18810
18811    pub fn toggle_git_blame(
18812        &mut self,
18813        _: &::git::Blame,
18814        window: &mut Window,
18815        cx: &mut Context<Self>,
18816    ) {
18817        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18818
18819        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18820            self.start_git_blame(true, window, cx);
18821        }
18822
18823        cx.notify();
18824    }
18825
18826    pub fn toggle_git_blame_inline(
18827        &mut self,
18828        _: &ToggleGitBlameInline,
18829        window: &mut Window,
18830        cx: &mut Context<Self>,
18831    ) {
18832        self.toggle_git_blame_inline_internal(true, window, cx);
18833        cx.notify();
18834    }
18835
18836    pub fn open_git_blame_commit(
18837        &mut self,
18838        _: &OpenGitBlameCommit,
18839        window: &mut Window,
18840        cx: &mut Context<Self>,
18841    ) {
18842        self.open_git_blame_commit_internal(window, cx);
18843    }
18844
18845    fn open_git_blame_commit_internal(
18846        &mut self,
18847        window: &mut Window,
18848        cx: &mut Context<Self>,
18849    ) -> Option<()> {
18850        let blame = self.blame.as_ref()?;
18851        let snapshot = self.snapshot(window, cx);
18852        let cursor = self.selections.newest::<Point>(cx).head();
18853        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18854        let blame_entry = blame
18855            .update(cx, |blame, cx| {
18856                blame
18857                    .blame_for_rows(
18858                        &[RowInfo {
18859                            buffer_id: Some(buffer.remote_id()),
18860                            buffer_row: Some(point.row),
18861                            ..Default::default()
18862                        }],
18863                        cx,
18864                    )
18865                    .next()
18866            })
18867            .flatten()?;
18868        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18869        let repo = blame.read(cx).repository(cx)?;
18870        let workspace = self.workspace()?.downgrade();
18871        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18872        None
18873    }
18874
18875    pub fn git_blame_inline_enabled(&self) -> bool {
18876        self.git_blame_inline_enabled
18877    }
18878
18879    pub fn toggle_selection_menu(
18880        &mut self,
18881        _: &ToggleSelectionMenu,
18882        _: &mut Window,
18883        cx: &mut Context<Self>,
18884    ) {
18885        self.show_selection_menu = self
18886            .show_selection_menu
18887            .map(|show_selections_menu| !show_selections_menu)
18888            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18889
18890        cx.notify();
18891    }
18892
18893    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18894        self.show_selection_menu
18895            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18896    }
18897
18898    fn start_git_blame(
18899        &mut self,
18900        user_triggered: bool,
18901        window: &mut Window,
18902        cx: &mut Context<Self>,
18903    ) {
18904        if let Some(project) = self.project() {
18905            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18906                return;
18907            };
18908
18909            if buffer.read(cx).file().is_none() {
18910                return;
18911            }
18912
18913            let focused = self.focus_handle(cx).contains_focused(window, cx);
18914
18915            let project = project.clone();
18916            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18917            self.blame_subscription =
18918                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18919            self.blame = Some(blame);
18920        }
18921    }
18922
18923    fn toggle_git_blame_inline_internal(
18924        &mut self,
18925        user_triggered: bool,
18926        window: &mut Window,
18927        cx: &mut Context<Self>,
18928    ) {
18929        if self.git_blame_inline_enabled {
18930            self.git_blame_inline_enabled = false;
18931            self.show_git_blame_inline = false;
18932            self.show_git_blame_inline_delay_task.take();
18933        } else {
18934            self.git_blame_inline_enabled = true;
18935            self.start_git_blame_inline(user_triggered, window, cx);
18936        }
18937
18938        cx.notify();
18939    }
18940
18941    fn start_git_blame_inline(
18942        &mut self,
18943        user_triggered: bool,
18944        window: &mut Window,
18945        cx: &mut Context<Self>,
18946    ) {
18947        self.start_git_blame(user_triggered, window, cx);
18948
18949        if ProjectSettings::get_global(cx)
18950            .git
18951            .inline_blame_delay()
18952            .is_some()
18953        {
18954            self.start_inline_blame_timer(window, cx);
18955        } else {
18956            self.show_git_blame_inline = true
18957        }
18958    }
18959
18960    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18961        self.blame.as_ref()
18962    }
18963
18964    pub fn show_git_blame_gutter(&self) -> bool {
18965        self.show_git_blame_gutter
18966    }
18967
18968    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18969        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18970    }
18971
18972    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18973        self.show_git_blame_inline
18974            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18975            && !self.newest_selection_head_on_empty_line(cx)
18976            && self.has_blame_entries(cx)
18977    }
18978
18979    fn has_blame_entries(&self, cx: &App) -> bool {
18980        self.blame()
18981            .is_some_and(|blame| blame.read(cx).has_generated_entries())
18982    }
18983
18984    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18985        let cursor_anchor = self.selections.newest_anchor().head();
18986
18987        let snapshot = self.buffer.read(cx).snapshot(cx);
18988        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18989
18990        snapshot.line_len(buffer_row) == 0
18991    }
18992
18993    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18994        let buffer_and_selection = maybe!({
18995            let selection = self.selections.newest::<Point>(cx);
18996            let selection_range = selection.range();
18997
18998            let multi_buffer = self.buffer().read(cx);
18999            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19000            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19001
19002            let (buffer, range, _) = if selection.reversed {
19003                buffer_ranges.first()
19004            } else {
19005                buffer_ranges.last()
19006            }?;
19007
19008            let selection = text::ToPoint::to_point(&range.start, buffer).row
19009                ..text::ToPoint::to_point(&range.end, buffer).row;
19010            Some((
19011                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
19012                selection,
19013            ))
19014        });
19015
19016        let Some((buffer, selection)) = buffer_and_selection else {
19017            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19018        };
19019
19020        let Some(project) = self.project() else {
19021            return Task::ready(Err(anyhow!("editor does not have project")));
19022        };
19023
19024        project.update(cx, |project, cx| {
19025            project.get_permalink_to_line(&buffer, selection, cx)
19026        })
19027    }
19028
19029    pub fn copy_permalink_to_line(
19030        &mut self,
19031        _: &CopyPermalinkToLine,
19032        window: &mut Window,
19033        cx: &mut Context<Self>,
19034    ) {
19035        let permalink_task = self.get_permalink_to_line(cx);
19036        let workspace = self.workspace();
19037
19038        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19039            Ok(permalink) => {
19040                cx.update(|_, cx| {
19041                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19042                })
19043                .ok();
19044            }
19045            Err(err) => {
19046                let message = format!("Failed to copy permalink: {err}");
19047
19048                anyhow::Result::<()>::Err(err).log_err();
19049
19050                if let Some(workspace) = workspace {
19051                    workspace
19052                        .update_in(cx, |workspace, _, cx| {
19053                            struct CopyPermalinkToLine;
19054
19055                            workspace.show_toast(
19056                                Toast::new(
19057                                    NotificationId::unique::<CopyPermalinkToLine>(),
19058                                    message,
19059                                ),
19060                                cx,
19061                            )
19062                        })
19063                        .ok();
19064                }
19065            }
19066        })
19067        .detach();
19068    }
19069
19070    pub fn copy_file_location(
19071        &mut self,
19072        _: &CopyFileLocation,
19073        _: &mut Window,
19074        cx: &mut Context<Self>,
19075    ) {
19076        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19077        if let Some(file) = self.target_file(cx)
19078            && let Some(path) = file.path().to_str()
19079        {
19080            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19081        }
19082    }
19083
19084    pub fn open_permalink_to_line(
19085        &mut self,
19086        _: &OpenPermalinkToLine,
19087        window: &mut Window,
19088        cx: &mut Context<Self>,
19089    ) {
19090        let permalink_task = self.get_permalink_to_line(cx);
19091        let workspace = self.workspace();
19092
19093        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19094            Ok(permalink) => {
19095                cx.update(|_, cx| {
19096                    cx.open_url(permalink.as_ref());
19097                })
19098                .ok();
19099            }
19100            Err(err) => {
19101                let message = format!("Failed to open permalink: {err}");
19102
19103                anyhow::Result::<()>::Err(err).log_err();
19104
19105                if let Some(workspace) = workspace {
19106                    workspace
19107                        .update(cx, |workspace, cx| {
19108                            struct OpenPermalinkToLine;
19109
19110                            workspace.show_toast(
19111                                Toast::new(
19112                                    NotificationId::unique::<OpenPermalinkToLine>(),
19113                                    message,
19114                                ),
19115                                cx,
19116                            )
19117                        })
19118                        .ok();
19119                }
19120            }
19121        })
19122        .detach();
19123    }
19124
19125    pub fn insert_uuid_v4(
19126        &mut self,
19127        _: &InsertUuidV4,
19128        window: &mut Window,
19129        cx: &mut Context<Self>,
19130    ) {
19131        self.insert_uuid(UuidVersion::V4, window, cx);
19132    }
19133
19134    pub fn insert_uuid_v7(
19135        &mut self,
19136        _: &InsertUuidV7,
19137        window: &mut Window,
19138        cx: &mut Context<Self>,
19139    ) {
19140        self.insert_uuid(UuidVersion::V7, window, cx);
19141    }
19142
19143    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19144        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19145        self.transact(window, cx, |this, window, cx| {
19146            let edits = this
19147                .selections
19148                .all::<Point>(cx)
19149                .into_iter()
19150                .map(|selection| {
19151                    let uuid = match version {
19152                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19153                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19154                    };
19155
19156                    (selection.range(), uuid.to_string())
19157                });
19158            this.edit(edits, cx);
19159            this.refresh_edit_prediction(true, false, window, cx);
19160        });
19161    }
19162
19163    pub fn open_selections_in_multibuffer(
19164        &mut self,
19165        _: &OpenSelectionsInMultibuffer,
19166        window: &mut Window,
19167        cx: &mut Context<Self>,
19168    ) {
19169        let multibuffer = self.buffer.read(cx);
19170
19171        let Some(buffer) = multibuffer.as_singleton() else {
19172            return;
19173        };
19174
19175        let Some(workspace) = self.workspace() else {
19176            return;
19177        };
19178
19179        let title = multibuffer.title(cx).to_string();
19180
19181        let locations = self
19182            .selections
19183            .all_anchors(cx)
19184            .iter()
19185            .map(|selection| Location {
19186                buffer: buffer.clone(),
19187                range: selection.start.text_anchor..selection.end.text_anchor,
19188            })
19189            .collect::<Vec<_>>();
19190
19191        cx.spawn_in(window, async move |_, cx| {
19192            workspace.update_in(cx, |workspace, window, cx| {
19193                Self::open_locations_in_multibuffer(
19194                    workspace,
19195                    locations,
19196                    format!("Selections for '{title}'"),
19197                    false,
19198                    MultibufferSelectionMode::All,
19199                    window,
19200                    cx,
19201                );
19202            })
19203        })
19204        .detach();
19205    }
19206
19207    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19208    /// last highlight added will be used.
19209    ///
19210    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19211    pub fn highlight_rows<T: 'static>(
19212        &mut self,
19213        range: Range<Anchor>,
19214        color: Hsla,
19215        options: RowHighlightOptions,
19216        cx: &mut Context<Self>,
19217    ) {
19218        let snapshot = self.buffer().read(cx).snapshot(cx);
19219        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19220        let ix = row_highlights.binary_search_by(|highlight| {
19221            Ordering::Equal
19222                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19223                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19224        });
19225
19226        if let Err(mut ix) = ix {
19227            let index = post_inc(&mut self.highlight_order);
19228
19229            // If this range intersects with the preceding highlight, then merge it with
19230            // the preceding highlight. Otherwise insert a new highlight.
19231            let mut merged = false;
19232            if ix > 0 {
19233                let prev_highlight = &mut row_highlights[ix - 1];
19234                if prev_highlight
19235                    .range
19236                    .end
19237                    .cmp(&range.start, &snapshot)
19238                    .is_ge()
19239                {
19240                    ix -= 1;
19241                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19242                        prev_highlight.range.end = range.end;
19243                    }
19244                    merged = true;
19245                    prev_highlight.index = index;
19246                    prev_highlight.color = color;
19247                    prev_highlight.options = options;
19248                }
19249            }
19250
19251            if !merged {
19252                row_highlights.insert(
19253                    ix,
19254                    RowHighlight {
19255                        range: range.clone(),
19256                        index,
19257                        color,
19258                        options,
19259                        type_id: TypeId::of::<T>(),
19260                    },
19261                );
19262            }
19263
19264            // If any of the following highlights intersect with this one, merge them.
19265            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19266                let highlight = &row_highlights[ix];
19267                if next_highlight
19268                    .range
19269                    .start
19270                    .cmp(&highlight.range.end, &snapshot)
19271                    .is_le()
19272                {
19273                    if next_highlight
19274                        .range
19275                        .end
19276                        .cmp(&highlight.range.end, &snapshot)
19277                        .is_gt()
19278                    {
19279                        row_highlights[ix].range.end = next_highlight.range.end;
19280                    }
19281                    row_highlights.remove(ix + 1);
19282                } else {
19283                    break;
19284                }
19285            }
19286        }
19287    }
19288
19289    /// Remove any highlighted row ranges of the given type that intersect the
19290    /// given ranges.
19291    pub fn remove_highlighted_rows<T: 'static>(
19292        &mut self,
19293        ranges_to_remove: Vec<Range<Anchor>>,
19294        cx: &mut Context<Self>,
19295    ) {
19296        let snapshot = self.buffer().read(cx).snapshot(cx);
19297        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19298        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19299        row_highlights.retain(|highlight| {
19300            while let Some(range_to_remove) = ranges_to_remove.peek() {
19301                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19302                    Ordering::Less | Ordering::Equal => {
19303                        ranges_to_remove.next();
19304                    }
19305                    Ordering::Greater => {
19306                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19307                            Ordering::Less | Ordering::Equal => {
19308                                return false;
19309                            }
19310                            Ordering::Greater => break,
19311                        }
19312                    }
19313                }
19314            }
19315
19316            true
19317        })
19318    }
19319
19320    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19321    pub fn clear_row_highlights<T: 'static>(&mut self) {
19322        self.highlighted_rows.remove(&TypeId::of::<T>());
19323    }
19324
19325    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19326    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19327        self.highlighted_rows
19328            .get(&TypeId::of::<T>())
19329            .map_or(&[] as &[_], |vec| vec.as_slice())
19330            .iter()
19331            .map(|highlight| (highlight.range.clone(), highlight.color))
19332    }
19333
19334    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19335    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19336    /// Allows to ignore certain kinds of highlights.
19337    pub fn highlighted_display_rows(
19338        &self,
19339        window: &mut Window,
19340        cx: &mut App,
19341    ) -> BTreeMap<DisplayRow, LineHighlight> {
19342        let snapshot = self.snapshot(window, cx);
19343        let mut used_highlight_orders = HashMap::default();
19344        self.highlighted_rows
19345            .iter()
19346            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19347            .fold(
19348                BTreeMap::<DisplayRow, LineHighlight>::new(),
19349                |mut unique_rows, highlight| {
19350                    let start = highlight.range.start.to_display_point(&snapshot);
19351                    let end = highlight.range.end.to_display_point(&snapshot);
19352                    let start_row = start.row().0;
19353                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19354                        && end.column() == 0
19355                    {
19356                        end.row().0.saturating_sub(1)
19357                    } else {
19358                        end.row().0
19359                    };
19360                    for row in start_row..=end_row {
19361                        let used_index =
19362                            used_highlight_orders.entry(row).or_insert(highlight.index);
19363                        if highlight.index >= *used_index {
19364                            *used_index = highlight.index;
19365                            unique_rows.insert(
19366                                DisplayRow(row),
19367                                LineHighlight {
19368                                    include_gutter: highlight.options.include_gutter,
19369                                    border: None,
19370                                    background: highlight.color.into(),
19371                                    type_id: Some(highlight.type_id),
19372                                },
19373                            );
19374                        }
19375                    }
19376                    unique_rows
19377                },
19378            )
19379    }
19380
19381    pub fn highlighted_display_row_for_autoscroll(
19382        &self,
19383        snapshot: &DisplaySnapshot,
19384    ) -> Option<DisplayRow> {
19385        self.highlighted_rows
19386            .values()
19387            .flat_map(|highlighted_rows| highlighted_rows.iter())
19388            .filter_map(|highlight| {
19389                if highlight.options.autoscroll {
19390                    Some(highlight.range.start.to_display_point(snapshot).row())
19391                } else {
19392                    None
19393                }
19394            })
19395            .min()
19396    }
19397
19398    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19399        self.highlight_background::<SearchWithinRange>(
19400            ranges,
19401            |colors| colors.colors().editor_document_highlight_read_background,
19402            cx,
19403        )
19404    }
19405
19406    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19407        self.breadcrumb_header = Some(new_header);
19408    }
19409
19410    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19411        self.clear_background_highlights::<SearchWithinRange>(cx);
19412    }
19413
19414    pub fn highlight_background<T: 'static>(
19415        &mut self,
19416        ranges: &[Range<Anchor>],
19417        color_fetcher: fn(&Theme) -> Hsla,
19418        cx: &mut Context<Self>,
19419    ) {
19420        self.background_highlights.insert(
19421            HighlightKey::Type(TypeId::of::<T>()),
19422            (color_fetcher, Arc::from(ranges)),
19423        );
19424        self.scrollbar_marker_state.dirty = true;
19425        cx.notify();
19426    }
19427
19428    pub fn highlight_background_key<T: 'static>(
19429        &mut self,
19430        key: usize,
19431        ranges: &[Range<Anchor>],
19432        color_fetcher: fn(&Theme) -> Hsla,
19433        cx: &mut Context<Self>,
19434    ) {
19435        self.background_highlights.insert(
19436            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19437            (color_fetcher, Arc::from(ranges)),
19438        );
19439        self.scrollbar_marker_state.dirty = true;
19440        cx.notify();
19441    }
19442
19443    pub fn clear_background_highlights<T: 'static>(
19444        &mut self,
19445        cx: &mut Context<Self>,
19446    ) -> Option<BackgroundHighlight> {
19447        let text_highlights = self
19448            .background_highlights
19449            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19450        if !text_highlights.1.is_empty() {
19451            self.scrollbar_marker_state.dirty = true;
19452            cx.notify();
19453        }
19454        Some(text_highlights)
19455    }
19456
19457    pub fn highlight_gutter<T: 'static>(
19458        &mut self,
19459        ranges: impl Into<Vec<Range<Anchor>>>,
19460        color_fetcher: fn(&App) -> Hsla,
19461        cx: &mut Context<Self>,
19462    ) {
19463        self.gutter_highlights
19464            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19465        cx.notify();
19466    }
19467
19468    pub fn clear_gutter_highlights<T: 'static>(
19469        &mut self,
19470        cx: &mut Context<Self>,
19471    ) -> Option<GutterHighlight> {
19472        cx.notify();
19473        self.gutter_highlights.remove(&TypeId::of::<T>())
19474    }
19475
19476    pub fn insert_gutter_highlight<T: 'static>(
19477        &mut self,
19478        range: Range<Anchor>,
19479        color_fetcher: fn(&App) -> Hsla,
19480        cx: &mut Context<Self>,
19481    ) {
19482        let snapshot = self.buffer().read(cx).snapshot(cx);
19483        let mut highlights = self
19484            .gutter_highlights
19485            .remove(&TypeId::of::<T>())
19486            .map(|(_, highlights)| highlights)
19487            .unwrap_or_default();
19488        let ix = highlights.binary_search_by(|highlight| {
19489            Ordering::Equal
19490                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19491                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19492        });
19493        if let Err(ix) = ix {
19494            highlights.insert(ix, range);
19495        }
19496        self.gutter_highlights
19497            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19498    }
19499
19500    pub fn remove_gutter_highlights<T: 'static>(
19501        &mut self,
19502        ranges_to_remove: Vec<Range<Anchor>>,
19503        cx: &mut Context<Self>,
19504    ) {
19505        let snapshot = self.buffer().read(cx).snapshot(cx);
19506        let Some((color_fetcher, mut gutter_highlights)) =
19507            self.gutter_highlights.remove(&TypeId::of::<T>())
19508        else {
19509            return;
19510        };
19511        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19512        gutter_highlights.retain(|highlight| {
19513            while let Some(range_to_remove) = ranges_to_remove.peek() {
19514                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19515                    Ordering::Less | Ordering::Equal => {
19516                        ranges_to_remove.next();
19517                    }
19518                    Ordering::Greater => {
19519                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19520                            Ordering::Less | Ordering::Equal => {
19521                                return false;
19522                            }
19523                            Ordering::Greater => break,
19524                        }
19525                    }
19526                }
19527            }
19528
19529            true
19530        });
19531        self.gutter_highlights
19532            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19533    }
19534
19535    #[cfg(feature = "test-support")]
19536    pub fn all_text_highlights(
19537        &self,
19538        window: &mut Window,
19539        cx: &mut Context<Self>,
19540    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19541        let snapshot = self.snapshot(window, cx);
19542        self.display_map.update(cx, |display_map, _| {
19543            display_map
19544                .all_text_highlights()
19545                .map(|highlight| {
19546                    let (style, ranges) = highlight.as_ref();
19547                    (
19548                        *style,
19549                        ranges
19550                            .iter()
19551                            .map(|range| range.clone().to_display_points(&snapshot))
19552                            .collect(),
19553                    )
19554                })
19555                .collect()
19556        })
19557    }
19558
19559    #[cfg(feature = "test-support")]
19560    pub fn all_text_background_highlights(
19561        &self,
19562        window: &mut Window,
19563        cx: &mut Context<Self>,
19564    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19565        let snapshot = self.snapshot(window, cx);
19566        let buffer = &snapshot.buffer_snapshot;
19567        let start = buffer.anchor_before(0);
19568        let end = buffer.anchor_after(buffer.len());
19569        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19570    }
19571
19572    #[cfg(feature = "test-support")]
19573    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19574        let snapshot = self.buffer().read(cx).snapshot(cx);
19575
19576        let highlights = self
19577            .background_highlights
19578            .get(&HighlightKey::Type(TypeId::of::<
19579                items::BufferSearchHighlights,
19580            >()));
19581
19582        if let Some((_color, ranges)) = highlights {
19583            ranges
19584                .iter()
19585                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19586                .collect_vec()
19587        } else {
19588            vec![]
19589        }
19590    }
19591
19592    fn document_highlights_for_position<'a>(
19593        &'a self,
19594        position: Anchor,
19595        buffer: &'a MultiBufferSnapshot,
19596    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19597        let read_highlights = self
19598            .background_highlights
19599            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19600            .map(|h| &h.1);
19601        let write_highlights = self
19602            .background_highlights
19603            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19604            .map(|h| &h.1);
19605        let left_position = position.bias_left(buffer);
19606        let right_position = position.bias_right(buffer);
19607        read_highlights
19608            .into_iter()
19609            .chain(write_highlights)
19610            .flat_map(move |ranges| {
19611                let start_ix = match ranges.binary_search_by(|probe| {
19612                    let cmp = probe.end.cmp(&left_position, buffer);
19613                    if cmp.is_ge() {
19614                        Ordering::Greater
19615                    } else {
19616                        Ordering::Less
19617                    }
19618                }) {
19619                    Ok(i) | Err(i) => i,
19620                };
19621
19622                ranges[start_ix..]
19623                    .iter()
19624                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19625            })
19626    }
19627
19628    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19629        self.background_highlights
19630            .get(&HighlightKey::Type(TypeId::of::<T>()))
19631            .is_some_and(|(_, highlights)| !highlights.is_empty())
19632    }
19633
19634    pub fn background_highlights_in_range(
19635        &self,
19636        search_range: Range<Anchor>,
19637        display_snapshot: &DisplaySnapshot,
19638        theme: &Theme,
19639    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19640        let mut results = Vec::new();
19641        for (color_fetcher, ranges) in self.background_highlights.values() {
19642            let color = color_fetcher(theme);
19643            let start_ix = match ranges.binary_search_by(|probe| {
19644                let cmp = probe
19645                    .end
19646                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19647                if cmp.is_gt() {
19648                    Ordering::Greater
19649                } else {
19650                    Ordering::Less
19651                }
19652            }) {
19653                Ok(i) | Err(i) => i,
19654            };
19655            for range in &ranges[start_ix..] {
19656                if range
19657                    .start
19658                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19659                    .is_ge()
19660                {
19661                    break;
19662                }
19663
19664                let start = range.start.to_display_point(display_snapshot);
19665                let end = range.end.to_display_point(display_snapshot);
19666                results.push((start..end, color))
19667            }
19668        }
19669        results
19670    }
19671
19672    pub fn background_highlight_row_ranges<T: 'static>(
19673        &self,
19674        search_range: Range<Anchor>,
19675        display_snapshot: &DisplaySnapshot,
19676        count: usize,
19677    ) -> Vec<RangeInclusive<DisplayPoint>> {
19678        let mut results = Vec::new();
19679        let Some((_, ranges)) = self
19680            .background_highlights
19681            .get(&HighlightKey::Type(TypeId::of::<T>()))
19682        else {
19683            return vec![];
19684        };
19685
19686        let start_ix = match ranges.binary_search_by(|probe| {
19687            let cmp = probe
19688                .end
19689                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19690            if cmp.is_gt() {
19691                Ordering::Greater
19692            } else {
19693                Ordering::Less
19694            }
19695        }) {
19696            Ok(i) | Err(i) => i,
19697        };
19698        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19699            if let (Some(start_display), Some(end_display)) = (start, end) {
19700                results.push(
19701                    start_display.to_display_point(display_snapshot)
19702                        ..=end_display.to_display_point(display_snapshot),
19703                );
19704            }
19705        };
19706        let mut start_row: Option<Point> = None;
19707        let mut end_row: Option<Point> = None;
19708        if ranges.len() > count {
19709            return Vec::new();
19710        }
19711        for range in &ranges[start_ix..] {
19712            if range
19713                .start
19714                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19715                .is_ge()
19716            {
19717                break;
19718            }
19719            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19720            if let Some(current_row) = &end_row
19721                && end.row == current_row.row
19722            {
19723                continue;
19724            }
19725            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19726            if start_row.is_none() {
19727                assert_eq!(end_row, None);
19728                start_row = Some(start);
19729                end_row = Some(end);
19730                continue;
19731            }
19732            if let Some(current_end) = end_row.as_mut() {
19733                if start.row > current_end.row + 1 {
19734                    push_region(start_row, end_row);
19735                    start_row = Some(start);
19736                    end_row = Some(end);
19737                } else {
19738                    // Merge two hunks.
19739                    *current_end = end;
19740                }
19741            } else {
19742                unreachable!();
19743            }
19744        }
19745        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19746        push_region(start_row, end_row);
19747        results
19748    }
19749
19750    pub fn gutter_highlights_in_range(
19751        &self,
19752        search_range: Range<Anchor>,
19753        display_snapshot: &DisplaySnapshot,
19754        cx: &App,
19755    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19756        let mut results = Vec::new();
19757        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19758            let color = color_fetcher(cx);
19759            let start_ix = match ranges.binary_search_by(|probe| {
19760                let cmp = probe
19761                    .end
19762                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19763                if cmp.is_gt() {
19764                    Ordering::Greater
19765                } else {
19766                    Ordering::Less
19767                }
19768            }) {
19769                Ok(i) | Err(i) => i,
19770            };
19771            for range in &ranges[start_ix..] {
19772                if range
19773                    .start
19774                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19775                    .is_ge()
19776                {
19777                    break;
19778                }
19779
19780                let start = range.start.to_display_point(display_snapshot);
19781                let end = range.end.to_display_point(display_snapshot);
19782                results.push((start..end, color))
19783            }
19784        }
19785        results
19786    }
19787
19788    /// Get the text ranges corresponding to the redaction query
19789    pub fn redacted_ranges(
19790        &self,
19791        search_range: Range<Anchor>,
19792        display_snapshot: &DisplaySnapshot,
19793        cx: &App,
19794    ) -> Vec<Range<DisplayPoint>> {
19795        display_snapshot
19796            .buffer_snapshot
19797            .redacted_ranges(search_range, |file| {
19798                if let Some(file) = file {
19799                    file.is_private()
19800                        && EditorSettings::get(
19801                            Some(SettingsLocation {
19802                                worktree_id: file.worktree_id(cx),
19803                                path: file.path().as_ref(),
19804                            }),
19805                            cx,
19806                        )
19807                        .redact_private_values
19808                } else {
19809                    false
19810                }
19811            })
19812            .map(|range| {
19813                range.start.to_display_point(display_snapshot)
19814                    ..range.end.to_display_point(display_snapshot)
19815            })
19816            .collect()
19817    }
19818
19819    pub fn highlight_text_key<T: 'static>(
19820        &mut self,
19821        key: usize,
19822        ranges: Vec<Range<Anchor>>,
19823        style: HighlightStyle,
19824        cx: &mut Context<Self>,
19825    ) {
19826        self.display_map.update(cx, |map, _| {
19827            map.highlight_text(
19828                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19829                ranges,
19830                style,
19831            );
19832        });
19833        cx.notify();
19834    }
19835
19836    pub fn highlight_text<T: 'static>(
19837        &mut self,
19838        ranges: Vec<Range<Anchor>>,
19839        style: HighlightStyle,
19840        cx: &mut Context<Self>,
19841    ) {
19842        self.display_map.update(cx, |map, _| {
19843            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19844        });
19845        cx.notify();
19846    }
19847
19848    pub(crate) fn highlight_inlays<T: 'static>(
19849        &mut self,
19850        highlights: Vec<InlayHighlight>,
19851        style: HighlightStyle,
19852        cx: &mut Context<Self>,
19853    ) {
19854        self.display_map.update(cx, |map, _| {
19855            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19856        });
19857        cx.notify();
19858    }
19859
19860    pub fn text_highlights<'a, T: 'static>(
19861        &'a self,
19862        cx: &'a App,
19863    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19864        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19865    }
19866
19867    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19868        let cleared = self
19869            .display_map
19870            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19871        if cleared {
19872            cx.notify();
19873        }
19874    }
19875
19876    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19877        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19878            && self.focus_handle.is_focused(window)
19879    }
19880
19881    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19882        self.show_cursor_when_unfocused = is_enabled;
19883        cx.notify();
19884    }
19885
19886    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19887        cx.notify();
19888    }
19889
19890    fn on_debug_session_event(
19891        &mut self,
19892        _session: Entity<Session>,
19893        event: &SessionEvent,
19894        cx: &mut Context<Self>,
19895    ) {
19896        if let SessionEvent::InvalidateInlineValue = event {
19897            self.refresh_inline_values(cx);
19898        }
19899    }
19900
19901    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19902        let Some(project) = self.project.clone() else {
19903            return;
19904        };
19905
19906        if !self.inline_value_cache.enabled {
19907            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19908            self.splice_inlays(&inlays, Vec::new(), cx);
19909            return;
19910        }
19911
19912        let current_execution_position = self
19913            .highlighted_rows
19914            .get(&TypeId::of::<ActiveDebugLine>())
19915            .and_then(|lines| lines.last().map(|line| line.range.end));
19916
19917        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19918            let inline_values = editor
19919                .update(cx, |editor, cx| {
19920                    let Some(current_execution_position) = current_execution_position else {
19921                        return Some(Task::ready(Ok(Vec::new())));
19922                    };
19923
19924                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19925                        let snapshot = buffer.snapshot(cx);
19926
19927                        let excerpt = snapshot.excerpt_containing(
19928                            current_execution_position..current_execution_position,
19929                        )?;
19930
19931                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19932                    })?;
19933
19934                    let range =
19935                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19936
19937                    project.inline_values(buffer, range, cx)
19938                })
19939                .ok()
19940                .flatten()?
19941                .await
19942                .context("refreshing debugger inlays")
19943                .log_err()?;
19944
19945            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19946
19947            for (buffer_id, inline_value) in inline_values
19948                .into_iter()
19949                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19950            {
19951                buffer_inline_values
19952                    .entry(buffer_id)
19953                    .or_default()
19954                    .push(inline_value);
19955            }
19956
19957            editor
19958                .update(cx, |editor, cx| {
19959                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19960                    let mut new_inlays = Vec::default();
19961
19962                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19963                        let buffer_id = buffer_snapshot.remote_id();
19964                        buffer_inline_values
19965                            .get(&buffer_id)
19966                            .into_iter()
19967                            .flatten()
19968                            .for_each(|hint| {
19969                                let inlay = Inlay::debugger(
19970                                    post_inc(&mut editor.next_inlay_id),
19971                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19972                                    hint.text(),
19973                                );
19974                                if !inlay.text.chars().contains(&'\n') {
19975                                    new_inlays.push(inlay);
19976                                }
19977                            });
19978                    }
19979
19980                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19981                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19982
19983                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19984                })
19985                .ok()?;
19986            Some(())
19987        });
19988    }
19989
19990    fn on_buffer_event(
19991        &mut self,
19992        multibuffer: &Entity<MultiBuffer>,
19993        event: &multi_buffer::Event,
19994        window: &mut Window,
19995        cx: &mut Context<Self>,
19996    ) {
19997        match event {
19998            multi_buffer::Event::Edited {
19999                singleton_buffer_edited,
20000                edited_buffer,
20001            } => {
20002                self.scrollbar_marker_state.dirty = true;
20003                self.active_indent_guides_state.dirty = true;
20004                self.refresh_active_diagnostics(cx);
20005                self.refresh_code_actions(window, cx);
20006                self.refresh_selected_text_highlights(true, window, cx);
20007                self.refresh_single_line_folds(window, cx);
20008                refresh_matching_bracket_highlights(self, window, cx);
20009                if self.has_active_edit_prediction() {
20010                    self.update_visible_edit_prediction(window, cx);
20011                }
20012                if let Some(project) = self.project.as_ref()
20013                    && let Some(edited_buffer) = edited_buffer
20014                {
20015                    project.update(cx, |project, cx| {
20016                        self.registered_buffers
20017                            .entry(edited_buffer.read(cx).remote_id())
20018                            .or_insert_with(|| {
20019                                project.register_buffer_with_language_servers(edited_buffer, cx)
20020                            });
20021                    });
20022                }
20023                cx.emit(EditorEvent::BufferEdited);
20024                cx.emit(SearchEvent::MatchesInvalidated);
20025
20026                if let Some(buffer) = edited_buffer {
20027                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20028                }
20029
20030                if *singleton_buffer_edited {
20031                    if let Some(buffer) = edited_buffer
20032                        && buffer.read(cx).file().is_none()
20033                    {
20034                        cx.emit(EditorEvent::TitleChanged);
20035                    }
20036                    if let Some(project) = &self.project {
20037                        #[allow(clippy::mutable_key_type)]
20038                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20039                            multibuffer
20040                                .all_buffers()
20041                                .into_iter()
20042                                .filter_map(|buffer| {
20043                                    buffer.update(cx, |buffer, cx| {
20044                                        let language = buffer.language()?;
20045                                        let should_discard = project.update(cx, |project, cx| {
20046                                            project.is_local()
20047                                                && !project.has_language_servers_for(buffer, cx)
20048                                        });
20049                                        should_discard.not().then_some(language.clone())
20050                                    })
20051                                })
20052                                .collect::<HashSet<_>>()
20053                        });
20054                        if !languages_affected.is_empty() {
20055                            self.refresh_inlay_hints(
20056                                InlayHintRefreshReason::BufferEdited(languages_affected),
20057                                cx,
20058                            );
20059                        }
20060                    }
20061                }
20062
20063                let Some(project) = &self.project else { return };
20064                let (telemetry, is_via_ssh) = {
20065                    let project = project.read(cx);
20066                    let telemetry = project.client().telemetry().clone();
20067                    let is_via_ssh = project.is_via_ssh();
20068                    (telemetry, is_via_ssh)
20069                };
20070                refresh_linked_ranges(self, window, cx);
20071                telemetry.log_edit_event("editor", is_via_ssh);
20072            }
20073            multi_buffer::Event::ExcerptsAdded {
20074                buffer,
20075                predecessor,
20076                excerpts,
20077            } => {
20078                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20079                let buffer_id = buffer.read(cx).remote_id();
20080                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20081                    && let Some(project) = &self.project
20082                {
20083                    update_uncommitted_diff_for_buffer(
20084                        cx.entity(),
20085                        project,
20086                        [buffer.clone()],
20087                        self.buffer.clone(),
20088                        cx,
20089                    )
20090                    .detach();
20091                }
20092                self.update_lsp_data(false, Some(buffer_id), window, cx);
20093                cx.emit(EditorEvent::ExcerptsAdded {
20094                    buffer: buffer.clone(),
20095                    predecessor: *predecessor,
20096                    excerpts: excerpts.clone(),
20097                });
20098                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20099            }
20100            multi_buffer::Event::ExcerptsRemoved {
20101                ids,
20102                removed_buffer_ids,
20103            } => {
20104                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20105                let buffer = self.buffer.read(cx);
20106                self.registered_buffers
20107                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20108                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20109                cx.emit(EditorEvent::ExcerptsRemoved {
20110                    ids: ids.clone(),
20111                    removed_buffer_ids: removed_buffer_ids.clone(),
20112                });
20113            }
20114            multi_buffer::Event::ExcerptsEdited {
20115                excerpt_ids,
20116                buffer_ids,
20117            } => {
20118                self.display_map.update(cx, |map, cx| {
20119                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20120                });
20121                cx.emit(EditorEvent::ExcerptsEdited {
20122                    ids: excerpt_ids.clone(),
20123                });
20124            }
20125            multi_buffer::Event::ExcerptsExpanded { ids } => {
20126                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20127                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20128            }
20129            multi_buffer::Event::Reparsed(buffer_id) => {
20130                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20131                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20132
20133                cx.emit(EditorEvent::Reparsed(*buffer_id));
20134            }
20135            multi_buffer::Event::DiffHunksToggled => {
20136                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20137            }
20138            multi_buffer::Event::LanguageChanged(buffer_id) => {
20139                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20140                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20141                cx.emit(EditorEvent::Reparsed(*buffer_id));
20142                cx.notify();
20143            }
20144            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20145            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20146            multi_buffer::Event::FileHandleChanged
20147            | multi_buffer::Event::Reloaded
20148            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20149            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20150            multi_buffer::Event::DiagnosticsUpdated => {
20151                self.update_diagnostics_state(window, cx);
20152            }
20153            _ => {}
20154        };
20155    }
20156
20157    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20158        if !self.diagnostics_enabled() {
20159            return;
20160        }
20161        self.refresh_active_diagnostics(cx);
20162        self.refresh_inline_diagnostics(true, window, cx);
20163        self.scrollbar_marker_state.dirty = true;
20164        cx.notify();
20165    }
20166
20167    pub fn start_temporary_diff_override(&mut self) {
20168        self.load_diff_task.take();
20169        self.temporary_diff_override = true;
20170    }
20171
20172    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20173        self.temporary_diff_override = false;
20174        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20175        self.buffer.update(cx, |buffer, cx| {
20176            buffer.set_all_diff_hunks_collapsed(cx);
20177        });
20178
20179        if let Some(project) = self.project.clone() {
20180            self.load_diff_task = Some(
20181                update_uncommitted_diff_for_buffer(
20182                    cx.entity(),
20183                    &project,
20184                    self.buffer.read(cx).all_buffers(),
20185                    self.buffer.clone(),
20186                    cx,
20187                )
20188                .shared(),
20189            );
20190        }
20191    }
20192
20193    fn on_display_map_changed(
20194        &mut self,
20195        _: Entity<DisplayMap>,
20196        _: &mut Window,
20197        cx: &mut Context<Self>,
20198    ) {
20199        cx.notify();
20200    }
20201
20202    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20203        if self.diagnostics_enabled() {
20204            let new_severity = EditorSettings::get_global(cx)
20205                .diagnostics_max_severity
20206                .unwrap_or(DiagnosticSeverity::Hint);
20207            self.set_max_diagnostics_severity(new_severity, cx);
20208        }
20209        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20210        self.update_edit_prediction_settings(cx);
20211        self.refresh_edit_prediction(true, false, window, cx);
20212        self.refresh_inline_values(cx);
20213        self.refresh_inlay_hints(
20214            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20215                self.selections.newest_anchor().head(),
20216                &self.buffer.read(cx).snapshot(cx),
20217                cx,
20218            )),
20219            cx,
20220        );
20221
20222        let old_cursor_shape = self.cursor_shape;
20223        let old_show_breadcrumbs = self.show_breadcrumbs;
20224
20225        {
20226            let editor_settings = EditorSettings::get_global(cx);
20227            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20228            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20229            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20230            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20231        }
20232
20233        if old_cursor_shape != self.cursor_shape {
20234            cx.emit(EditorEvent::CursorShapeChanged);
20235        }
20236
20237        if old_show_breadcrumbs != self.show_breadcrumbs {
20238            cx.emit(EditorEvent::BreadcrumbsChanged);
20239        }
20240
20241        let project_settings = ProjectSettings::get_global(cx);
20242        self.serialize_dirty_buffers =
20243            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20244
20245        if self.mode.is_full() {
20246            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20247            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20248            if self.show_inline_diagnostics != show_inline_diagnostics {
20249                self.show_inline_diagnostics = show_inline_diagnostics;
20250                self.refresh_inline_diagnostics(false, window, cx);
20251            }
20252
20253            if self.git_blame_inline_enabled != inline_blame_enabled {
20254                self.toggle_git_blame_inline_internal(false, window, cx);
20255            }
20256
20257            let minimap_settings = EditorSettings::get_global(cx).minimap;
20258            if self.minimap_visibility != MinimapVisibility::Disabled {
20259                if self.minimap_visibility.settings_visibility()
20260                    != minimap_settings.minimap_enabled()
20261                {
20262                    self.set_minimap_visibility(
20263                        MinimapVisibility::for_mode(self.mode(), cx),
20264                        window,
20265                        cx,
20266                    );
20267                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20268                    minimap_entity.update(cx, |minimap_editor, cx| {
20269                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20270                    })
20271                }
20272            }
20273        }
20274
20275        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20276            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20277        }) {
20278            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20279                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20280            }
20281            self.refresh_colors(false, None, window, cx);
20282        }
20283
20284        cx.notify();
20285    }
20286
20287    pub fn set_searchable(&mut self, searchable: bool) {
20288        self.searchable = searchable;
20289    }
20290
20291    pub fn searchable(&self) -> bool {
20292        self.searchable
20293    }
20294
20295    fn open_proposed_changes_editor(
20296        &mut self,
20297        _: &OpenProposedChangesEditor,
20298        window: &mut Window,
20299        cx: &mut Context<Self>,
20300    ) {
20301        let Some(workspace) = self.workspace() else {
20302            cx.propagate();
20303            return;
20304        };
20305
20306        let selections = self.selections.all::<usize>(cx);
20307        let multi_buffer = self.buffer.read(cx);
20308        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20309        let mut new_selections_by_buffer = HashMap::default();
20310        for selection in selections {
20311            for (buffer, range, _) in
20312                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20313            {
20314                let mut range = range.to_point(buffer);
20315                range.start.column = 0;
20316                range.end.column = buffer.line_len(range.end.row);
20317                new_selections_by_buffer
20318                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20319                    .or_insert(Vec::new())
20320                    .push(range)
20321            }
20322        }
20323
20324        let proposed_changes_buffers = new_selections_by_buffer
20325            .into_iter()
20326            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20327            .collect::<Vec<_>>();
20328        let proposed_changes_editor = cx.new(|cx| {
20329            ProposedChangesEditor::new(
20330                "Proposed changes",
20331                proposed_changes_buffers,
20332                self.project.clone(),
20333                window,
20334                cx,
20335            )
20336        });
20337
20338        window.defer(cx, move |window, cx| {
20339            workspace.update(cx, |workspace, cx| {
20340                workspace.active_pane().update(cx, |pane, cx| {
20341                    pane.add_item(
20342                        Box::new(proposed_changes_editor),
20343                        true,
20344                        true,
20345                        None,
20346                        window,
20347                        cx,
20348                    );
20349                });
20350            });
20351        });
20352    }
20353
20354    pub fn open_excerpts_in_split(
20355        &mut self,
20356        _: &OpenExcerptsSplit,
20357        window: &mut Window,
20358        cx: &mut Context<Self>,
20359    ) {
20360        self.open_excerpts_common(None, true, window, cx)
20361    }
20362
20363    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20364        self.open_excerpts_common(None, false, window, cx)
20365    }
20366
20367    fn open_excerpts_common(
20368        &mut self,
20369        jump_data: Option<JumpData>,
20370        split: bool,
20371        window: &mut Window,
20372        cx: &mut Context<Self>,
20373    ) {
20374        let Some(workspace) = self.workspace() else {
20375            cx.propagate();
20376            return;
20377        };
20378
20379        if self.buffer.read(cx).is_singleton() {
20380            cx.propagate();
20381            return;
20382        }
20383
20384        let mut new_selections_by_buffer = HashMap::default();
20385        match &jump_data {
20386            Some(JumpData::MultiBufferPoint {
20387                excerpt_id,
20388                position,
20389                anchor,
20390                line_offset_from_top,
20391            }) => {
20392                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20393                if let Some(buffer) = multi_buffer_snapshot
20394                    .buffer_id_for_excerpt(*excerpt_id)
20395                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20396                {
20397                    let buffer_snapshot = buffer.read(cx).snapshot();
20398                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20399                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20400                    } else {
20401                        buffer_snapshot.clip_point(*position, Bias::Left)
20402                    };
20403                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20404                    new_selections_by_buffer.insert(
20405                        buffer,
20406                        (
20407                            vec![jump_to_offset..jump_to_offset],
20408                            Some(*line_offset_from_top),
20409                        ),
20410                    );
20411                }
20412            }
20413            Some(JumpData::MultiBufferRow {
20414                row,
20415                line_offset_from_top,
20416            }) => {
20417                let point = MultiBufferPoint::new(row.0, 0);
20418                if let Some((buffer, buffer_point, _)) =
20419                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20420                {
20421                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20422                    new_selections_by_buffer
20423                        .entry(buffer)
20424                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20425                        .0
20426                        .push(buffer_offset..buffer_offset)
20427                }
20428            }
20429            None => {
20430                let selections = self.selections.all::<usize>(cx);
20431                let multi_buffer = self.buffer.read(cx);
20432                for selection in selections {
20433                    for (snapshot, range, _, anchor) in multi_buffer
20434                        .snapshot(cx)
20435                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20436                    {
20437                        if let Some(anchor) = anchor {
20438                            // selection is in a deleted hunk
20439                            let Some(buffer_id) = anchor.buffer_id else {
20440                                continue;
20441                            };
20442                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20443                                continue;
20444                            };
20445                            let offset = text::ToOffset::to_offset(
20446                                &anchor.text_anchor,
20447                                &buffer_handle.read(cx).snapshot(),
20448                            );
20449                            let range = offset..offset;
20450                            new_selections_by_buffer
20451                                .entry(buffer_handle)
20452                                .or_insert((Vec::new(), None))
20453                                .0
20454                                .push(range)
20455                        } else {
20456                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20457                            else {
20458                                continue;
20459                            };
20460                            new_selections_by_buffer
20461                                .entry(buffer_handle)
20462                                .or_insert((Vec::new(), None))
20463                                .0
20464                                .push(range)
20465                        }
20466                    }
20467                }
20468            }
20469        }
20470
20471        new_selections_by_buffer
20472            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20473
20474        if new_selections_by_buffer.is_empty() {
20475            return;
20476        }
20477
20478        // We defer the pane interaction because we ourselves are a workspace item
20479        // and activating a new item causes the pane to call a method on us reentrantly,
20480        // which panics if we're on the stack.
20481        window.defer(cx, move |window, cx| {
20482            workspace.update(cx, |workspace, cx| {
20483                let pane = if split {
20484                    workspace.adjacent_pane(window, cx)
20485                } else {
20486                    workspace.active_pane().clone()
20487                };
20488
20489                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20490                    let editor = buffer
20491                        .read(cx)
20492                        .file()
20493                        .is_none()
20494                        .then(|| {
20495                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20496                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20497                            // Instead, we try to activate the existing editor in the pane first.
20498                            let (editor, pane_item_index) =
20499                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20500                                    let editor = item.downcast::<Editor>()?;
20501                                    let singleton_buffer =
20502                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20503                                    if singleton_buffer == buffer {
20504                                        Some((editor, i))
20505                                    } else {
20506                                        None
20507                                    }
20508                                })?;
20509                            pane.update(cx, |pane, cx| {
20510                                pane.activate_item(pane_item_index, true, true, window, cx)
20511                            });
20512                            Some(editor)
20513                        })
20514                        .flatten()
20515                        .unwrap_or_else(|| {
20516                            workspace.open_project_item::<Self>(
20517                                pane.clone(),
20518                                buffer,
20519                                true,
20520                                true,
20521                                window,
20522                                cx,
20523                            )
20524                        });
20525
20526                    editor.update(cx, |editor, cx| {
20527                        let autoscroll = match scroll_offset {
20528                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20529                            None => Autoscroll::newest(),
20530                        };
20531                        let nav_history = editor.nav_history.take();
20532                        editor.change_selections(
20533                            SelectionEffects::scroll(autoscroll),
20534                            window,
20535                            cx,
20536                            |s| {
20537                                s.select_ranges(ranges);
20538                            },
20539                        );
20540                        editor.nav_history = nav_history;
20541                    });
20542                }
20543            })
20544        });
20545    }
20546
20547    // For now, don't allow opening excerpts in buffers that aren't backed by
20548    // regular project files.
20549    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20550        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20551    }
20552
20553    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20554        let snapshot = self.buffer.read(cx).read(cx);
20555        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20556        Some(
20557            ranges
20558                .iter()
20559                .map(move |range| {
20560                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20561                })
20562                .collect(),
20563        )
20564    }
20565
20566    fn selection_replacement_ranges(
20567        &self,
20568        range: Range<OffsetUtf16>,
20569        cx: &mut App,
20570    ) -> Vec<Range<OffsetUtf16>> {
20571        let selections = self.selections.all::<OffsetUtf16>(cx);
20572        let newest_selection = selections
20573            .iter()
20574            .max_by_key(|selection| selection.id)
20575            .unwrap();
20576        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20577        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20578        let snapshot = self.buffer.read(cx).read(cx);
20579        selections
20580            .into_iter()
20581            .map(|mut selection| {
20582                selection.start.0 =
20583                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20584                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20585                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20586                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20587            })
20588            .collect()
20589    }
20590
20591    fn report_editor_event(
20592        &self,
20593        reported_event: ReportEditorEvent,
20594        file_extension: Option<String>,
20595        cx: &App,
20596    ) {
20597        if cfg!(any(test, feature = "test-support")) {
20598            return;
20599        }
20600
20601        let Some(project) = &self.project else { return };
20602
20603        // If None, we are in a file without an extension
20604        let file = self
20605            .buffer
20606            .read(cx)
20607            .as_singleton()
20608            .and_then(|b| b.read(cx).file());
20609        let file_extension = file_extension.or(file
20610            .as_ref()
20611            .and_then(|file| Path::new(file.file_name(cx)).extension())
20612            .and_then(|e| e.to_str())
20613            .map(|a| a.to_string()));
20614
20615        let vim_mode = vim_enabled(cx);
20616
20617        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20618        let copilot_enabled = edit_predictions_provider
20619            == language::language_settings::EditPredictionProvider::Copilot;
20620        let copilot_enabled_for_language = self
20621            .buffer
20622            .read(cx)
20623            .language_settings(cx)
20624            .show_edit_predictions;
20625
20626        let project = project.read(cx);
20627        let event_type = reported_event.event_type();
20628
20629        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20630            telemetry::event!(
20631                event_type,
20632                type = if auto_saved {"autosave"} else {"manual"},
20633                file_extension,
20634                vim_mode,
20635                copilot_enabled,
20636                copilot_enabled_for_language,
20637                edit_predictions_provider,
20638                is_via_ssh = project.is_via_ssh(),
20639            );
20640        } else {
20641            telemetry::event!(
20642                event_type,
20643                file_extension,
20644                vim_mode,
20645                copilot_enabled,
20646                copilot_enabled_for_language,
20647                edit_predictions_provider,
20648                is_via_ssh = project.is_via_ssh(),
20649            );
20650        };
20651    }
20652
20653    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20654    /// with each line being an array of {text, highlight} objects.
20655    fn copy_highlight_json(
20656        &mut self,
20657        _: &CopyHighlightJson,
20658        window: &mut Window,
20659        cx: &mut Context<Self>,
20660    ) {
20661        #[derive(Serialize)]
20662        struct Chunk<'a> {
20663            text: String,
20664            highlight: Option<&'a str>,
20665        }
20666
20667        let snapshot = self.buffer.read(cx).snapshot(cx);
20668        let range = self
20669            .selected_text_range(false, window, cx)
20670            .and_then(|selection| {
20671                if selection.range.is_empty() {
20672                    None
20673                } else {
20674                    Some(selection.range)
20675                }
20676            })
20677            .unwrap_or_else(|| 0..snapshot.len());
20678
20679        let chunks = snapshot.chunks(range, true);
20680        let mut lines = Vec::new();
20681        let mut line: VecDeque<Chunk> = VecDeque::new();
20682
20683        let Some(style) = self.style.as_ref() else {
20684            return;
20685        };
20686
20687        for chunk in chunks {
20688            let highlight = chunk
20689                .syntax_highlight_id
20690                .and_then(|id| id.name(&style.syntax));
20691            let mut chunk_lines = chunk.text.split('\n').peekable();
20692            while let Some(text) = chunk_lines.next() {
20693                let mut merged_with_last_token = false;
20694                if let Some(last_token) = line.back_mut()
20695                    && last_token.highlight == highlight
20696                {
20697                    last_token.text.push_str(text);
20698                    merged_with_last_token = true;
20699                }
20700
20701                if !merged_with_last_token {
20702                    line.push_back(Chunk {
20703                        text: text.into(),
20704                        highlight,
20705                    });
20706                }
20707
20708                if chunk_lines.peek().is_some() {
20709                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20710                        line.pop_front();
20711                    }
20712                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20713                        line.pop_back();
20714                    }
20715
20716                    lines.push(mem::take(&mut line));
20717                }
20718            }
20719        }
20720
20721        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20722            return;
20723        };
20724        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20725    }
20726
20727    pub fn open_context_menu(
20728        &mut self,
20729        _: &OpenContextMenu,
20730        window: &mut Window,
20731        cx: &mut Context<Self>,
20732    ) {
20733        self.request_autoscroll(Autoscroll::newest(), cx);
20734        let position = self.selections.newest_display(cx).start;
20735        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20736    }
20737
20738    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20739        &self.inlay_hint_cache
20740    }
20741
20742    pub fn replay_insert_event(
20743        &mut self,
20744        text: &str,
20745        relative_utf16_range: Option<Range<isize>>,
20746        window: &mut Window,
20747        cx: &mut Context<Self>,
20748    ) {
20749        if !self.input_enabled {
20750            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20751            return;
20752        }
20753        if let Some(relative_utf16_range) = relative_utf16_range {
20754            let selections = self.selections.all::<OffsetUtf16>(cx);
20755            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20756                let new_ranges = selections.into_iter().map(|range| {
20757                    let start = OffsetUtf16(
20758                        range
20759                            .head()
20760                            .0
20761                            .saturating_add_signed(relative_utf16_range.start),
20762                    );
20763                    let end = OffsetUtf16(
20764                        range
20765                            .head()
20766                            .0
20767                            .saturating_add_signed(relative_utf16_range.end),
20768                    );
20769                    start..end
20770                });
20771                s.select_ranges(new_ranges);
20772            });
20773        }
20774
20775        self.handle_input(text, window, cx);
20776    }
20777
20778    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20779        let Some(provider) = self.semantics_provider.as_ref() else {
20780            return false;
20781        };
20782
20783        let mut supports = false;
20784        self.buffer().update(cx, |this, cx| {
20785            this.for_each_buffer(|buffer| {
20786                supports |= provider.supports_inlay_hints(buffer, cx);
20787            });
20788        });
20789
20790        supports
20791    }
20792
20793    pub fn is_focused(&self, window: &Window) -> bool {
20794        self.focus_handle.is_focused(window)
20795    }
20796
20797    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20798        cx.emit(EditorEvent::Focused);
20799
20800        if let Some(descendant) = self
20801            .last_focused_descendant
20802            .take()
20803            .and_then(|descendant| descendant.upgrade())
20804        {
20805            window.focus(&descendant);
20806        } else {
20807            if let Some(blame) = self.blame.as_ref() {
20808                blame.update(cx, GitBlame::focus)
20809            }
20810
20811            self.blink_manager.update(cx, BlinkManager::enable);
20812            self.show_cursor_names(window, cx);
20813            self.buffer.update(cx, |buffer, cx| {
20814                buffer.finalize_last_transaction(cx);
20815                if self.leader_id.is_none() {
20816                    buffer.set_active_selections(
20817                        &self.selections.disjoint_anchors(),
20818                        self.selections.line_mode,
20819                        self.cursor_shape,
20820                        cx,
20821                    );
20822                }
20823            });
20824        }
20825    }
20826
20827    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20828        cx.emit(EditorEvent::FocusedIn)
20829    }
20830
20831    fn handle_focus_out(
20832        &mut self,
20833        event: FocusOutEvent,
20834        _window: &mut Window,
20835        cx: &mut Context<Self>,
20836    ) {
20837        if event.blurred != self.focus_handle {
20838            self.last_focused_descendant = Some(event.blurred);
20839        }
20840        self.selection_drag_state = SelectionDragState::None;
20841        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20842    }
20843
20844    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20845        self.blink_manager.update(cx, BlinkManager::disable);
20846        self.buffer
20847            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20848
20849        if let Some(blame) = self.blame.as_ref() {
20850            blame.update(cx, GitBlame::blur)
20851        }
20852        if !self.hover_state.focused(window, cx) {
20853            hide_hover(self, cx);
20854        }
20855        if !self
20856            .context_menu
20857            .borrow()
20858            .as_ref()
20859            .is_some_and(|context_menu| context_menu.focused(window, cx))
20860        {
20861            self.hide_context_menu(window, cx);
20862        }
20863        self.discard_edit_prediction(false, cx);
20864        cx.emit(EditorEvent::Blurred);
20865        cx.notify();
20866    }
20867
20868    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20869        let mut pending: String = window
20870            .pending_input_keystrokes()
20871            .into_iter()
20872            .flatten()
20873            .filter_map(|keystroke| {
20874                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20875                    keystroke.key_char.clone()
20876                } else {
20877                    None
20878                }
20879            })
20880            .collect();
20881
20882        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20883            pending = "".to_string();
20884        }
20885
20886        let existing_pending = self
20887            .text_highlights::<PendingInput>(cx)
20888            .map(|(_, ranges)| ranges.to_vec());
20889        if existing_pending.is_none() && pending.is_empty() {
20890            return;
20891        }
20892        let transaction =
20893            self.transact(window, cx, |this, window, cx| {
20894                let selections = this.selections.all::<usize>(cx);
20895                let edits = selections
20896                    .iter()
20897                    .map(|selection| (selection.end..selection.end, pending.clone()));
20898                this.edit(edits, cx);
20899                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20900                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20901                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20902                    }));
20903                });
20904                if let Some(existing_ranges) = existing_pending {
20905                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20906                    this.edit(edits, cx);
20907                }
20908            });
20909
20910        let snapshot = self.snapshot(window, cx);
20911        let ranges = self
20912            .selections
20913            .all::<usize>(cx)
20914            .into_iter()
20915            .map(|selection| {
20916                snapshot.buffer_snapshot.anchor_after(selection.end)
20917                    ..snapshot
20918                        .buffer_snapshot
20919                        .anchor_before(selection.end + pending.len())
20920            })
20921            .collect();
20922
20923        if pending.is_empty() {
20924            self.clear_highlights::<PendingInput>(cx);
20925        } else {
20926            self.highlight_text::<PendingInput>(
20927                ranges,
20928                HighlightStyle {
20929                    underline: Some(UnderlineStyle {
20930                        thickness: px(1.),
20931                        color: None,
20932                        wavy: false,
20933                    }),
20934                    ..Default::default()
20935                },
20936                cx,
20937            );
20938        }
20939
20940        self.ime_transaction = self.ime_transaction.or(transaction);
20941        if let Some(transaction) = self.ime_transaction {
20942            self.buffer.update(cx, |buffer, cx| {
20943                buffer.group_until_transaction(transaction, cx);
20944            });
20945        }
20946
20947        if self.text_highlights::<PendingInput>(cx).is_none() {
20948            self.ime_transaction.take();
20949        }
20950    }
20951
20952    pub fn register_action_renderer(
20953        &mut self,
20954        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20955    ) -> Subscription {
20956        let id = self.next_editor_action_id.post_inc();
20957        self.editor_actions
20958            .borrow_mut()
20959            .insert(id, Box::new(listener));
20960
20961        let editor_actions = self.editor_actions.clone();
20962        Subscription::new(move || {
20963            editor_actions.borrow_mut().remove(&id);
20964        })
20965    }
20966
20967    pub fn register_action<A: Action>(
20968        &mut self,
20969        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20970    ) -> Subscription {
20971        let id = self.next_editor_action_id.post_inc();
20972        let listener = Arc::new(listener);
20973        self.editor_actions.borrow_mut().insert(
20974            id,
20975            Box::new(move |_, window, _| {
20976                let listener = listener.clone();
20977                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20978                    let action = action.downcast_ref().unwrap();
20979                    if phase == DispatchPhase::Bubble {
20980                        listener(action, window, cx)
20981                    }
20982                })
20983            }),
20984        );
20985
20986        let editor_actions = self.editor_actions.clone();
20987        Subscription::new(move || {
20988            editor_actions.borrow_mut().remove(&id);
20989        })
20990    }
20991
20992    pub fn file_header_size(&self) -> u32 {
20993        FILE_HEADER_HEIGHT
20994    }
20995
20996    pub fn restore(
20997        &mut self,
20998        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20999        window: &mut Window,
21000        cx: &mut Context<Self>,
21001    ) {
21002        let workspace = self.workspace();
21003        let project = self.project();
21004        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21005            let mut tasks = Vec::new();
21006            for (buffer_id, changes) in revert_changes {
21007                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21008                    buffer.update(cx, |buffer, cx| {
21009                        buffer.edit(
21010                            changes
21011                                .into_iter()
21012                                .map(|(range, text)| (range, text.to_string())),
21013                            None,
21014                            cx,
21015                        );
21016                    });
21017
21018                    if let Some(project) =
21019                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21020                    {
21021                        project.update(cx, |project, cx| {
21022                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21023                        })
21024                    }
21025                }
21026            }
21027            tasks
21028        });
21029        cx.spawn_in(window, async move |_, cx| {
21030            for (buffer, task) in save_tasks {
21031                let result = task.await;
21032                if result.is_err() {
21033                    let Some(path) = buffer
21034                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21035                        .ok()
21036                    else {
21037                        continue;
21038                    };
21039                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21040                        let Some(task) = cx
21041                            .update_window_entity(workspace, |workspace, window, cx| {
21042                                workspace
21043                                    .open_path_preview(path, None, false, false, false, window, cx)
21044                            })
21045                            .ok()
21046                        else {
21047                            continue;
21048                        };
21049                        task.await.log_err();
21050                    }
21051                }
21052            }
21053        })
21054        .detach();
21055        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21056            selections.refresh()
21057        });
21058    }
21059
21060    pub fn to_pixel_point(
21061        &self,
21062        source: multi_buffer::Anchor,
21063        editor_snapshot: &EditorSnapshot,
21064        window: &mut Window,
21065    ) -> Option<gpui::Point<Pixels>> {
21066        let source_point = source.to_display_point(editor_snapshot);
21067        self.display_to_pixel_point(source_point, editor_snapshot, window)
21068    }
21069
21070    pub fn display_to_pixel_point(
21071        &self,
21072        source: DisplayPoint,
21073        editor_snapshot: &EditorSnapshot,
21074        window: &mut Window,
21075    ) -> Option<gpui::Point<Pixels>> {
21076        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21077        let text_layout_details = self.text_layout_details(window);
21078        let scroll_top = text_layout_details
21079            .scroll_anchor
21080            .scroll_position(editor_snapshot)
21081            .y;
21082
21083        if source.row().as_f32() < scroll_top.floor() {
21084            return None;
21085        }
21086        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21087        let source_y = line_height * (source.row().as_f32() - scroll_top);
21088        Some(gpui::Point::new(source_x, source_y))
21089    }
21090
21091    pub fn has_visible_completions_menu(&self) -> bool {
21092        !self.edit_prediction_preview_is_active()
21093            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21094                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21095            })
21096    }
21097
21098    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21099        if self.mode.is_minimap() {
21100            return;
21101        }
21102        self.addons
21103            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21104    }
21105
21106    pub fn unregister_addon<T: Addon>(&mut self) {
21107        self.addons.remove(&std::any::TypeId::of::<T>());
21108    }
21109
21110    pub fn addon<T: Addon>(&self) -> Option<&T> {
21111        let type_id = std::any::TypeId::of::<T>();
21112        self.addons
21113            .get(&type_id)
21114            .and_then(|item| item.to_any().downcast_ref::<T>())
21115    }
21116
21117    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21118        let type_id = std::any::TypeId::of::<T>();
21119        self.addons
21120            .get_mut(&type_id)
21121            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21122    }
21123
21124    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21125        let text_layout_details = self.text_layout_details(window);
21126        let style = &text_layout_details.editor_style;
21127        let font_id = window.text_system().resolve_font(&style.text.font());
21128        let font_size = style.text.font_size.to_pixels(window.rem_size());
21129        let line_height = style.text.line_height_in_pixels(window.rem_size());
21130        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21131        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21132
21133        CharacterDimensions {
21134            em_width,
21135            em_advance,
21136            line_height,
21137        }
21138    }
21139
21140    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21141        self.load_diff_task.clone()
21142    }
21143
21144    fn read_metadata_from_db(
21145        &mut self,
21146        item_id: u64,
21147        workspace_id: WorkspaceId,
21148        window: &mut Window,
21149        cx: &mut Context<Editor>,
21150    ) {
21151        if self.is_singleton(cx)
21152            && !self.mode.is_minimap()
21153            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21154        {
21155            let buffer_snapshot = OnceCell::new();
21156
21157            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21158                && !folds.is_empty()
21159            {
21160                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21161                self.fold_ranges(
21162                    folds
21163                        .into_iter()
21164                        .map(|(start, end)| {
21165                            snapshot.clip_offset(start, Bias::Left)
21166                                ..snapshot.clip_offset(end, Bias::Right)
21167                        })
21168                        .collect(),
21169                    false,
21170                    window,
21171                    cx,
21172                );
21173            }
21174
21175            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21176                && !selections.is_empty()
21177            {
21178                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21179                // skip adding the initial selection to selection history
21180                self.selection_history.mode = SelectionHistoryMode::Skipping;
21181                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21182                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21183                        snapshot.clip_offset(start, Bias::Left)
21184                            ..snapshot.clip_offset(end, Bias::Right)
21185                    }));
21186                });
21187                self.selection_history.mode = SelectionHistoryMode::Normal;
21188            };
21189        }
21190
21191        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21192    }
21193
21194    fn update_lsp_data(
21195        &mut self,
21196        ignore_cache: bool,
21197        for_buffer: Option<BufferId>,
21198        window: &mut Window,
21199        cx: &mut Context<'_, Self>,
21200    ) {
21201        self.pull_diagnostics(for_buffer, window, cx);
21202        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21203    }
21204}
21205
21206fn vim_enabled(cx: &App) -> bool {
21207    cx.global::<SettingsStore>()
21208        .raw_user_settings()
21209        .get("vim_mode")
21210        == Some(&serde_json::Value::Bool(true))
21211}
21212
21213fn process_completion_for_edit(
21214    completion: &Completion,
21215    intent: CompletionIntent,
21216    buffer: &Entity<Buffer>,
21217    cursor_position: &text::Anchor,
21218    cx: &mut Context<Editor>,
21219) -> CompletionEdit {
21220    let buffer = buffer.read(cx);
21221    let buffer_snapshot = buffer.snapshot();
21222    let (snippet, new_text) = if completion.is_snippet() {
21223        // Workaround for typescript language server issues so that methods don't expand within
21224        // strings and functions with type expressions. The previous point is used because the query
21225        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21226        let mut snippet_source = completion.new_text.clone();
21227        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21228        previous_point.column = previous_point.column.saturating_sub(1);
21229        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21230            && scope.prefers_label_for_snippet_in_completion()
21231            && let Some(label) = completion.label()
21232            && matches!(
21233                completion.kind(),
21234                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21235            )
21236        {
21237            snippet_source = label;
21238        }
21239        match Snippet::parse(&snippet_source).log_err() {
21240            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21241            None => (None, completion.new_text.clone()),
21242        }
21243    } else {
21244        (None, completion.new_text.clone())
21245    };
21246
21247    let mut range_to_replace = {
21248        let replace_range = &completion.replace_range;
21249        if let CompletionSource::Lsp {
21250            insert_range: Some(insert_range),
21251            ..
21252        } = &completion.source
21253        {
21254            debug_assert_eq!(
21255                insert_range.start, replace_range.start,
21256                "insert_range and replace_range should start at the same position"
21257            );
21258            debug_assert!(
21259                insert_range
21260                    .start
21261                    .cmp(cursor_position, &buffer_snapshot)
21262                    .is_le(),
21263                "insert_range should start before or at cursor position"
21264            );
21265            debug_assert!(
21266                replace_range
21267                    .start
21268                    .cmp(cursor_position, &buffer_snapshot)
21269                    .is_le(),
21270                "replace_range should start before or at cursor position"
21271            );
21272
21273            let should_replace = match intent {
21274                CompletionIntent::CompleteWithInsert => false,
21275                CompletionIntent::CompleteWithReplace => true,
21276                CompletionIntent::Complete | CompletionIntent::Compose => {
21277                    let insert_mode =
21278                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21279                            .completions
21280                            .lsp_insert_mode;
21281                    match insert_mode {
21282                        LspInsertMode::Insert => false,
21283                        LspInsertMode::Replace => true,
21284                        LspInsertMode::ReplaceSubsequence => {
21285                            let mut text_to_replace = buffer.chars_for_range(
21286                                buffer.anchor_before(replace_range.start)
21287                                    ..buffer.anchor_after(replace_range.end),
21288                            );
21289                            let mut current_needle = text_to_replace.next();
21290                            for haystack_ch in completion.label.text.chars() {
21291                                if let Some(needle_ch) = current_needle
21292                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21293                                {
21294                                    current_needle = text_to_replace.next();
21295                                }
21296                            }
21297                            current_needle.is_none()
21298                        }
21299                        LspInsertMode::ReplaceSuffix => {
21300                            if replace_range
21301                                .end
21302                                .cmp(cursor_position, &buffer_snapshot)
21303                                .is_gt()
21304                            {
21305                                let range_after_cursor = *cursor_position..replace_range.end;
21306                                let text_after_cursor = buffer
21307                                    .text_for_range(
21308                                        buffer.anchor_before(range_after_cursor.start)
21309                                            ..buffer.anchor_after(range_after_cursor.end),
21310                                    )
21311                                    .collect::<String>()
21312                                    .to_ascii_lowercase();
21313                                completion
21314                                    .label
21315                                    .text
21316                                    .to_ascii_lowercase()
21317                                    .ends_with(&text_after_cursor)
21318                            } else {
21319                                true
21320                            }
21321                        }
21322                    }
21323                }
21324            };
21325
21326            if should_replace {
21327                replace_range.clone()
21328            } else {
21329                insert_range.clone()
21330            }
21331        } else {
21332            replace_range.clone()
21333        }
21334    };
21335
21336    if range_to_replace
21337        .end
21338        .cmp(cursor_position, &buffer_snapshot)
21339        .is_lt()
21340    {
21341        range_to_replace.end = *cursor_position;
21342    }
21343
21344    CompletionEdit {
21345        new_text,
21346        replace_range: range_to_replace.to_offset(buffer),
21347        snippet,
21348    }
21349}
21350
21351struct CompletionEdit {
21352    new_text: String,
21353    replace_range: Range<usize>,
21354    snippet: Option<Snippet>,
21355}
21356
21357fn insert_extra_newline_brackets(
21358    buffer: &MultiBufferSnapshot,
21359    range: Range<usize>,
21360    language: &language::LanguageScope,
21361) -> bool {
21362    let leading_whitespace_len = buffer
21363        .reversed_chars_at(range.start)
21364        .take_while(|c| c.is_whitespace() && *c != '\n')
21365        .map(|c| c.len_utf8())
21366        .sum::<usize>();
21367    let trailing_whitespace_len = buffer
21368        .chars_at(range.end)
21369        .take_while(|c| c.is_whitespace() && *c != '\n')
21370        .map(|c| c.len_utf8())
21371        .sum::<usize>();
21372    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21373
21374    language.brackets().any(|(pair, enabled)| {
21375        let pair_start = pair.start.trim_end();
21376        let pair_end = pair.end.trim_start();
21377
21378        enabled
21379            && pair.newline
21380            && buffer.contains_str_at(range.end, pair_end)
21381            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21382    })
21383}
21384
21385fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21386    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21387        [(buffer, range, _)] => (*buffer, range.clone()),
21388        _ => return false,
21389    };
21390    let pair = {
21391        let mut result: Option<BracketMatch> = None;
21392
21393        for pair in buffer
21394            .all_bracket_ranges(range.clone())
21395            .filter(move |pair| {
21396                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21397            })
21398        {
21399            let len = pair.close_range.end - pair.open_range.start;
21400
21401            if let Some(existing) = &result {
21402                let existing_len = existing.close_range.end - existing.open_range.start;
21403                if len > existing_len {
21404                    continue;
21405                }
21406            }
21407
21408            result = Some(pair);
21409        }
21410
21411        result
21412    };
21413    let Some(pair) = pair else {
21414        return false;
21415    };
21416    pair.newline_only
21417        && buffer
21418            .chars_for_range(pair.open_range.end..range.start)
21419            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21420            .all(|c| c.is_whitespace() && c != '\n')
21421}
21422
21423fn update_uncommitted_diff_for_buffer(
21424    editor: Entity<Editor>,
21425    project: &Entity<Project>,
21426    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21427    buffer: Entity<MultiBuffer>,
21428    cx: &mut App,
21429) -> Task<()> {
21430    let mut tasks = Vec::new();
21431    project.update(cx, |project, cx| {
21432        for buffer in buffers {
21433            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21434                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21435            }
21436        }
21437    });
21438    cx.spawn(async move |cx| {
21439        let diffs = future::join_all(tasks).await;
21440        if editor
21441            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21442            .unwrap_or(false)
21443        {
21444            return;
21445        }
21446
21447        buffer
21448            .update(cx, |buffer, cx| {
21449                for diff in diffs.into_iter().flatten() {
21450                    buffer.add_diff(diff, cx);
21451                }
21452            })
21453            .ok();
21454    })
21455}
21456
21457fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21458    let tab_size = tab_size.get() as usize;
21459    let mut width = offset;
21460
21461    for ch in text.chars() {
21462        width += if ch == '\t' {
21463            tab_size - (width % tab_size)
21464        } else {
21465            1
21466        };
21467    }
21468
21469    width - offset
21470}
21471
21472#[cfg(test)]
21473mod tests {
21474    use super::*;
21475
21476    #[test]
21477    fn test_string_size_with_expanded_tabs() {
21478        let nz = |val| NonZeroU32::new(val).unwrap();
21479        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21480        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21481        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21482        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21483        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21484        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21485        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21486        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21487    }
21488}
21489
21490/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21491struct WordBreakingTokenizer<'a> {
21492    input: &'a str,
21493}
21494
21495impl<'a> WordBreakingTokenizer<'a> {
21496    fn new(input: &'a str) -> Self {
21497        Self { input }
21498    }
21499}
21500
21501fn is_char_ideographic(ch: char) -> bool {
21502    use unicode_script::Script::*;
21503    use unicode_script::UnicodeScript;
21504    matches!(ch.script(), Han | Tangut | Yi)
21505}
21506
21507fn is_grapheme_ideographic(text: &str) -> bool {
21508    text.chars().any(is_char_ideographic)
21509}
21510
21511fn is_grapheme_whitespace(text: &str) -> bool {
21512    text.chars().any(|x| x.is_whitespace())
21513}
21514
21515fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21516    text.chars()
21517        .next()
21518        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21519}
21520
21521#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21522enum WordBreakToken<'a> {
21523    Word { token: &'a str, grapheme_len: usize },
21524    InlineWhitespace { token: &'a str, grapheme_len: usize },
21525    Newline,
21526}
21527
21528impl<'a> Iterator for WordBreakingTokenizer<'a> {
21529    /// Yields a span, the count of graphemes in the token, and whether it was
21530    /// whitespace. Note that it also breaks at word boundaries.
21531    type Item = WordBreakToken<'a>;
21532
21533    fn next(&mut self) -> Option<Self::Item> {
21534        use unicode_segmentation::UnicodeSegmentation;
21535        if self.input.is_empty() {
21536            return None;
21537        }
21538
21539        let mut iter = self.input.graphemes(true).peekable();
21540        let mut offset = 0;
21541        let mut grapheme_len = 0;
21542        if let Some(first_grapheme) = iter.next() {
21543            let is_newline = first_grapheme == "\n";
21544            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21545            offset += first_grapheme.len();
21546            grapheme_len += 1;
21547            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21548                if let Some(grapheme) = iter.peek().copied()
21549                    && should_stay_with_preceding_ideograph(grapheme)
21550                {
21551                    offset += grapheme.len();
21552                    grapheme_len += 1;
21553                }
21554            } else {
21555                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21556                let mut next_word_bound = words.peek().copied();
21557                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21558                    next_word_bound = words.next();
21559                }
21560                while let Some(grapheme) = iter.peek().copied() {
21561                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21562                        break;
21563                    };
21564                    if is_grapheme_whitespace(grapheme) != is_whitespace
21565                        || (grapheme == "\n") != is_newline
21566                    {
21567                        break;
21568                    };
21569                    offset += grapheme.len();
21570                    grapheme_len += 1;
21571                    iter.next();
21572                }
21573            }
21574            let token = &self.input[..offset];
21575            self.input = &self.input[offset..];
21576            if token == "\n" {
21577                Some(WordBreakToken::Newline)
21578            } else if is_whitespace {
21579                Some(WordBreakToken::InlineWhitespace {
21580                    token,
21581                    grapheme_len,
21582                })
21583            } else {
21584                Some(WordBreakToken::Word {
21585                    token,
21586                    grapheme_len,
21587                })
21588            }
21589        } else {
21590            None
21591        }
21592    }
21593}
21594
21595#[test]
21596fn test_word_breaking_tokenizer() {
21597    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21598        ("", &[]),
21599        ("  ", &[whitespace("  ", 2)]),
21600        ("Ʒ", &[word("Ʒ", 1)]),
21601        ("Ǽ", &[word("Ǽ", 1)]),
21602        ("", &[word("", 1)]),
21603        ("⋑⋑", &[word("⋑⋑", 2)]),
21604        (
21605            "原理,进而",
21606            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21607        ),
21608        (
21609            "hello world",
21610            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21611        ),
21612        (
21613            "hello, world",
21614            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21615        ),
21616        (
21617            "  hello world",
21618            &[
21619                whitespace("  ", 2),
21620                word("hello", 5),
21621                whitespace(" ", 1),
21622                word("world", 5),
21623            ],
21624        ),
21625        (
21626            "这是什么 \n 钢笔",
21627            &[
21628                word("", 1),
21629                word("", 1),
21630                word("", 1),
21631                word("", 1),
21632                whitespace(" ", 1),
21633                newline(),
21634                whitespace(" ", 1),
21635                word("", 1),
21636                word("", 1),
21637            ],
21638        ),
21639        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21640    ];
21641
21642    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21643        WordBreakToken::Word {
21644            token,
21645            grapheme_len,
21646        }
21647    }
21648
21649    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21650        WordBreakToken::InlineWhitespace {
21651            token,
21652            grapheme_len,
21653        }
21654    }
21655
21656    fn newline() -> WordBreakToken<'static> {
21657        WordBreakToken::Newline
21658    }
21659
21660    for (input, result) in tests {
21661        assert_eq!(
21662            WordBreakingTokenizer::new(input)
21663                .collect::<Vec<_>>()
21664                .as_slice(),
21665            *result,
21666        );
21667    }
21668}
21669
21670fn wrap_with_prefix(
21671    first_line_prefix: String,
21672    subsequent_lines_prefix: String,
21673    unwrapped_text: String,
21674    wrap_column: usize,
21675    tab_size: NonZeroU32,
21676    preserve_existing_whitespace: bool,
21677) -> String {
21678    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21679    let subsequent_lines_prefix_len =
21680        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21681    let mut wrapped_text = String::new();
21682    let mut current_line = first_line_prefix.clone();
21683    let mut is_first_line = true;
21684
21685    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21686    let mut current_line_len = first_line_prefix_len;
21687    let mut in_whitespace = false;
21688    for token in tokenizer {
21689        let have_preceding_whitespace = in_whitespace;
21690        match token {
21691            WordBreakToken::Word {
21692                token,
21693                grapheme_len,
21694            } => {
21695                in_whitespace = false;
21696                let current_prefix_len = if is_first_line {
21697                    first_line_prefix_len
21698                } else {
21699                    subsequent_lines_prefix_len
21700                };
21701                if current_line_len + grapheme_len > wrap_column
21702                    && current_line_len != current_prefix_len
21703                {
21704                    wrapped_text.push_str(current_line.trim_end());
21705                    wrapped_text.push('\n');
21706                    is_first_line = false;
21707                    current_line = subsequent_lines_prefix.clone();
21708                    current_line_len = subsequent_lines_prefix_len;
21709                }
21710                current_line.push_str(token);
21711                current_line_len += grapheme_len;
21712            }
21713            WordBreakToken::InlineWhitespace {
21714                mut token,
21715                mut grapheme_len,
21716            } => {
21717                in_whitespace = true;
21718                if have_preceding_whitespace && !preserve_existing_whitespace {
21719                    continue;
21720                }
21721                if !preserve_existing_whitespace {
21722                    token = " ";
21723                    grapheme_len = 1;
21724                }
21725                let current_prefix_len = if is_first_line {
21726                    first_line_prefix_len
21727                } else {
21728                    subsequent_lines_prefix_len
21729                };
21730                if current_line_len + grapheme_len > wrap_column {
21731                    wrapped_text.push_str(current_line.trim_end());
21732                    wrapped_text.push('\n');
21733                    is_first_line = false;
21734                    current_line = subsequent_lines_prefix.clone();
21735                    current_line_len = subsequent_lines_prefix_len;
21736                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21737                    current_line.push_str(token);
21738                    current_line_len += grapheme_len;
21739                }
21740            }
21741            WordBreakToken::Newline => {
21742                in_whitespace = true;
21743                let current_prefix_len = if is_first_line {
21744                    first_line_prefix_len
21745                } else {
21746                    subsequent_lines_prefix_len
21747                };
21748                if preserve_existing_whitespace {
21749                    wrapped_text.push_str(current_line.trim_end());
21750                    wrapped_text.push('\n');
21751                    is_first_line = false;
21752                    current_line = subsequent_lines_prefix.clone();
21753                    current_line_len = subsequent_lines_prefix_len;
21754                } else if have_preceding_whitespace {
21755                    continue;
21756                } else if current_line_len + 1 > wrap_column
21757                    && current_line_len != current_prefix_len
21758                {
21759                    wrapped_text.push_str(current_line.trim_end());
21760                    wrapped_text.push('\n');
21761                    is_first_line = false;
21762                    current_line = subsequent_lines_prefix.clone();
21763                    current_line_len = subsequent_lines_prefix_len;
21764                } else if current_line_len != current_prefix_len {
21765                    current_line.push(' ');
21766                    current_line_len += 1;
21767                }
21768            }
21769        }
21770    }
21771
21772    if !current_line.is_empty() {
21773        wrapped_text.push_str(&current_line);
21774    }
21775    wrapped_text
21776}
21777
21778#[test]
21779fn test_wrap_with_prefix() {
21780    assert_eq!(
21781        wrap_with_prefix(
21782            "# ".to_string(),
21783            "# ".to_string(),
21784            "abcdefg".to_string(),
21785            4,
21786            NonZeroU32::new(4).unwrap(),
21787            false,
21788        ),
21789        "# abcdefg"
21790    );
21791    assert_eq!(
21792        wrap_with_prefix(
21793            "".to_string(),
21794            "".to_string(),
21795            "\thello world".to_string(),
21796            8,
21797            NonZeroU32::new(4).unwrap(),
21798            false,
21799        ),
21800        "hello\nworld"
21801    );
21802    assert_eq!(
21803        wrap_with_prefix(
21804            "// ".to_string(),
21805            "// ".to_string(),
21806            "xx \nyy zz aa bb cc".to_string(),
21807            12,
21808            NonZeroU32::new(4).unwrap(),
21809            false,
21810        ),
21811        "// xx yy zz\n// aa bb cc"
21812    );
21813    assert_eq!(
21814        wrap_with_prefix(
21815            String::new(),
21816            String::new(),
21817            "这是什么 \n 钢笔".to_string(),
21818            3,
21819            NonZeroU32::new(4).unwrap(),
21820            false,
21821        ),
21822        "这是什\n么 钢\n"
21823    );
21824}
21825
21826pub trait CollaborationHub {
21827    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21828    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21829    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21830}
21831
21832impl CollaborationHub for Entity<Project> {
21833    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21834        self.read(cx).collaborators()
21835    }
21836
21837    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21838        self.read(cx).user_store().read(cx).participant_indices()
21839    }
21840
21841    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21842        let this = self.read(cx);
21843        let user_ids = this.collaborators().values().map(|c| c.user_id);
21844        this.user_store().read(cx).participant_names(user_ids, cx)
21845    }
21846}
21847
21848pub trait SemanticsProvider {
21849    fn hover(
21850        &self,
21851        buffer: &Entity<Buffer>,
21852        position: text::Anchor,
21853        cx: &mut App,
21854    ) -> Option<Task<Vec<project::Hover>>>;
21855
21856    fn inline_values(
21857        &self,
21858        buffer_handle: Entity<Buffer>,
21859        range: Range<text::Anchor>,
21860        cx: &mut App,
21861    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21862
21863    fn inlay_hints(
21864        &self,
21865        buffer_handle: Entity<Buffer>,
21866        range: Range<text::Anchor>,
21867        cx: &mut App,
21868    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21869
21870    fn resolve_inlay_hint(
21871        &self,
21872        hint: InlayHint,
21873        buffer_handle: Entity<Buffer>,
21874        server_id: LanguageServerId,
21875        cx: &mut App,
21876    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21877
21878    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21879
21880    fn document_highlights(
21881        &self,
21882        buffer: &Entity<Buffer>,
21883        position: text::Anchor,
21884        cx: &mut App,
21885    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21886
21887    fn definitions(
21888        &self,
21889        buffer: &Entity<Buffer>,
21890        position: text::Anchor,
21891        kind: GotoDefinitionKind,
21892        cx: &mut App,
21893    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21894
21895    fn range_for_rename(
21896        &self,
21897        buffer: &Entity<Buffer>,
21898        position: text::Anchor,
21899        cx: &mut App,
21900    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21901
21902    fn perform_rename(
21903        &self,
21904        buffer: &Entity<Buffer>,
21905        position: text::Anchor,
21906        new_name: String,
21907        cx: &mut App,
21908    ) -> Option<Task<Result<ProjectTransaction>>>;
21909}
21910
21911pub trait CompletionProvider {
21912    fn completions(
21913        &self,
21914        excerpt_id: ExcerptId,
21915        buffer: &Entity<Buffer>,
21916        buffer_position: text::Anchor,
21917        trigger: CompletionContext,
21918        window: &mut Window,
21919        cx: &mut Context<Editor>,
21920    ) -> Task<Result<Vec<CompletionResponse>>>;
21921
21922    fn resolve_completions(
21923        &self,
21924        _buffer: Entity<Buffer>,
21925        _completion_indices: Vec<usize>,
21926        _completions: Rc<RefCell<Box<[Completion]>>>,
21927        _cx: &mut Context<Editor>,
21928    ) -> Task<Result<bool>> {
21929        Task::ready(Ok(false))
21930    }
21931
21932    fn apply_additional_edits_for_completion(
21933        &self,
21934        _buffer: Entity<Buffer>,
21935        _completions: Rc<RefCell<Box<[Completion]>>>,
21936        _completion_index: usize,
21937        _push_to_history: bool,
21938        _cx: &mut Context<Editor>,
21939    ) -> Task<Result<Option<language::Transaction>>> {
21940        Task::ready(Ok(None))
21941    }
21942
21943    fn is_completion_trigger(
21944        &self,
21945        buffer: &Entity<Buffer>,
21946        position: language::Anchor,
21947        text: &str,
21948        trigger_in_words: bool,
21949        menu_is_open: bool,
21950        cx: &mut Context<Editor>,
21951    ) -> bool;
21952
21953    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21954
21955    fn sort_completions(&self) -> bool {
21956        true
21957    }
21958
21959    fn filter_completions(&self) -> bool {
21960        true
21961    }
21962}
21963
21964pub trait CodeActionProvider {
21965    fn id(&self) -> Arc<str>;
21966
21967    fn code_actions(
21968        &self,
21969        buffer: &Entity<Buffer>,
21970        range: Range<text::Anchor>,
21971        window: &mut Window,
21972        cx: &mut App,
21973    ) -> Task<Result<Vec<CodeAction>>>;
21974
21975    fn apply_code_action(
21976        &self,
21977        buffer_handle: Entity<Buffer>,
21978        action: CodeAction,
21979        excerpt_id: ExcerptId,
21980        push_to_history: bool,
21981        window: &mut Window,
21982        cx: &mut App,
21983    ) -> Task<Result<ProjectTransaction>>;
21984}
21985
21986impl CodeActionProvider for Entity<Project> {
21987    fn id(&self) -> Arc<str> {
21988        "project".into()
21989    }
21990
21991    fn code_actions(
21992        &self,
21993        buffer: &Entity<Buffer>,
21994        range: Range<text::Anchor>,
21995        _window: &mut Window,
21996        cx: &mut App,
21997    ) -> Task<Result<Vec<CodeAction>>> {
21998        self.update(cx, |project, cx| {
21999            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22000            let code_actions = project.code_actions(buffer, range, None, cx);
22001            cx.background_spawn(async move {
22002                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22003                Ok(code_lens_actions
22004                    .context("code lens fetch")?
22005                    .into_iter()
22006                    .chain(code_actions.context("code action fetch")?)
22007                    .collect())
22008            })
22009        })
22010    }
22011
22012    fn apply_code_action(
22013        &self,
22014        buffer_handle: Entity<Buffer>,
22015        action: CodeAction,
22016        _excerpt_id: ExcerptId,
22017        push_to_history: bool,
22018        _window: &mut Window,
22019        cx: &mut App,
22020    ) -> Task<Result<ProjectTransaction>> {
22021        self.update(cx, |project, cx| {
22022            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22023        })
22024    }
22025}
22026
22027fn snippet_completions(
22028    project: &Project,
22029    buffer: &Entity<Buffer>,
22030    buffer_position: text::Anchor,
22031    cx: &mut App,
22032) -> Task<Result<CompletionResponse>> {
22033    let languages = buffer.read(cx).languages_at(buffer_position);
22034    let snippet_store = project.snippets().read(cx);
22035
22036    let scopes: Vec<_> = languages
22037        .iter()
22038        .filter_map(|language| {
22039            let language_name = language.lsp_id();
22040            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22041
22042            if snippets.is_empty() {
22043                None
22044            } else {
22045                Some((language.default_scope(), snippets))
22046            }
22047        })
22048        .collect();
22049
22050    if scopes.is_empty() {
22051        return Task::ready(Ok(CompletionResponse {
22052            completions: vec![],
22053            is_incomplete: false,
22054        }));
22055    }
22056
22057    let snapshot = buffer.read(cx).text_snapshot();
22058    let chars: String = snapshot
22059        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22060        .collect();
22061    let executor = cx.background_executor().clone();
22062
22063    cx.background_spawn(async move {
22064        let mut is_incomplete = false;
22065        let mut completions: Vec<Completion> = Vec::new();
22066        for (scope, snippets) in scopes.into_iter() {
22067            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22068            let mut last_word = chars
22069                .chars()
22070                .take_while(|c| classifier.is_word(*c))
22071                .collect::<String>();
22072            last_word = last_word.chars().rev().collect();
22073
22074            if last_word.is_empty() {
22075                return Ok(CompletionResponse {
22076                    completions: vec![],
22077                    is_incomplete: true,
22078                });
22079            }
22080
22081            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22082            let to_lsp = |point: &text::Anchor| {
22083                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22084                point_to_lsp(end)
22085            };
22086            let lsp_end = to_lsp(&buffer_position);
22087
22088            let candidates = snippets
22089                .iter()
22090                .enumerate()
22091                .flat_map(|(ix, snippet)| {
22092                    snippet
22093                        .prefix
22094                        .iter()
22095                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22096                })
22097                .collect::<Vec<StringMatchCandidate>>();
22098
22099            const MAX_RESULTS: usize = 100;
22100            let mut matches = fuzzy::match_strings(
22101                &candidates,
22102                &last_word,
22103                last_word.chars().any(|c| c.is_uppercase()),
22104                true,
22105                MAX_RESULTS,
22106                &Default::default(),
22107                executor.clone(),
22108            )
22109            .await;
22110
22111            if matches.len() >= MAX_RESULTS {
22112                is_incomplete = true;
22113            }
22114
22115            // Remove all candidates where the query's start does not match the start of any word in the candidate
22116            if let Some(query_start) = last_word.chars().next() {
22117                matches.retain(|string_match| {
22118                    split_words(&string_match.string).any(|word| {
22119                        // Check that the first codepoint of the word as lowercase matches the first
22120                        // codepoint of the query as lowercase
22121                        word.chars()
22122                            .flat_map(|codepoint| codepoint.to_lowercase())
22123                            .zip(query_start.to_lowercase())
22124                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22125                    })
22126                });
22127            }
22128
22129            let matched_strings = matches
22130                .into_iter()
22131                .map(|m| m.string)
22132                .collect::<HashSet<_>>();
22133
22134            completions.extend(snippets.iter().filter_map(|snippet| {
22135                let matching_prefix = snippet
22136                    .prefix
22137                    .iter()
22138                    .find(|prefix| matched_strings.contains(*prefix))?;
22139                let start = as_offset - last_word.len();
22140                let start = snapshot.anchor_before(start);
22141                let range = start..buffer_position;
22142                let lsp_start = to_lsp(&start);
22143                let lsp_range = lsp::Range {
22144                    start: lsp_start,
22145                    end: lsp_end,
22146                };
22147                Some(Completion {
22148                    replace_range: range,
22149                    new_text: snippet.body.clone(),
22150                    source: CompletionSource::Lsp {
22151                        insert_range: None,
22152                        server_id: LanguageServerId(usize::MAX),
22153                        resolved: true,
22154                        lsp_completion: Box::new(lsp::CompletionItem {
22155                            label: snippet.prefix.first().unwrap().clone(),
22156                            kind: Some(CompletionItemKind::SNIPPET),
22157                            label_details: snippet.description.as_ref().map(|description| {
22158                                lsp::CompletionItemLabelDetails {
22159                                    detail: Some(description.clone()),
22160                                    description: None,
22161                                }
22162                            }),
22163                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22164                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22165                                lsp::InsertReplaceEdit {
22166                                    new_text: snippet.body.clone(),
22167                                    insert: lsp_range,
22168                                    replace: lsp_range,
22169                                },
22170                            )),
22171                            filter_text: Some(snippet.body.clone()),
22172                            sort_text: Some(char::MAX.to_string()),
22173                            ..lsp::CompletionItem::default()
22174                        }),
22175                        lsp_defaults: None,
22176                    },
22177                    label: CodeLabel {
22178                        text: matching_prefix.clone(),
22179                        runs: Vec::new(),
22180                        filter_range: 0..matching_prefix.len(),
22181                    },
22182                    icon_path: None,
22183                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22184                        single_line: snippet.name.clone().into(),
22185                        plain_text: snippet
22186                            .description
22187                            .clone()
22188                            .map(|description| description.into()),
22189                    }),
22190                    insert_text_mode: None,
22191                    confirm: None,
22192                })
22193            }))
22194        }
22195
22196        Ok(CompletionResponse {
22197            completions,
22198            is_incomplete,
22199        })
22200    })
22201}
22202
22203impl CompletionProvider for Entity<Project> {
22204    fn completions(
22205        &self,
22206        _excerpt_id: ExcerptId,
22207        buffer: &Entity<Buffer>,
22208        buffer_position: text::Anchor,
22209        options: CompletionContext,
22210        _window: &mut Window,
22211        cx: &mut Context<Editor>,
22212    ) -> Task<Result<Vec<CompletionResponse>>> {
22213        self.update(cx, |project, cx| {
22214            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22215            let project_completions = project.completions(buffer, buffer_position, options, cx);
22216            cx.background_spawn(async move {
22217                let mut responses = project_completions.await?;
22218                let snippets = snippets.await?;
22219                if !snippets.completions.is_empty() {
22220                    responses.push(snippets);
22221                }
22222                Ok(responses)
22223            })
22224        })
22225    }
22226
22227    fn resolve_completions(
22228        &self,
22229        buffer: Entity<Buffer>,
22230        completion_indices: Vec<usize>,
22231        completions: Rc<RefCell<Box<[Completion]>>>,
22232        cx: &mut Context<Editor>,
22233    ) -> Task<Result<bool>> {
22234        self.update(cx, |project, cx| {
22235            project.lsp_store().update(cx, |lsp_store, cx| {
22236                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22237            })
22238        })
22239    }
22240
22241    fn apply_additional_edits_for_completion(
22242        &self,
22243        buffer: Entity<Buffer>,
22244        completions: Rc<RefCell<Box<[Completion]>>>,
22245        completion_index: usize,
22246        push_to_history: bool,
22247        cx: &mut Context<Editor>,
22248    ) -> Task<Result<Option<language::Transaction>>> {
22249        self.update(cx, |project, cx| {
22250            project.lsp_store().update(cx, |lsp_store, cx| {
22251                lsp_store.apply_additional_edits_for_completion(
22252                    buffer,
22253                    completions,
22254                    completion_index,
22255                    push_to_history,
22256                    cx,
22257                )
22258            })
22259        })
22260    }
22261
22262    fn is_completion_trigger(
22263        &self,
22264        buffer: &Entity<Buffer>,
22265        position: language::Anchor,
22266        text: &str,
22267        trigger_in_words: bool,
22268        menu_is_open: bool,
22269        cx: &mut Context<Editor>,
22270    ) -> bool {
22271        let mut chars = text.chars();
22272        let char = if let Some(char) = chars.next() {
22273            char
22274        } else {
22275            return false;
22276        };
22277        if chars.next().is_some() {
22278            return false;
22279        }
22280
22281        let buffer = buffer.read(cx);
22282        let snapshot = buffer.snapshot();
22283        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22284            return false;
22285        }
22286        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22287        if trigger_in_words && classifier.is_word(char) {
22288            return true;
22289        }
22290
22291        buffer.completion_triggers().contains(text)
22292    }
22293}
22294
22295impl SemanticsProvider for Entity<Project> {
22296    fn hover(
22297        &self,
22298        buffer: &Entity<Buffer>,
22299        position: text::Anchor,
22300        cx: &mut App,
22301    ) -> Option<Task<Vec<project::Hover>>> {
22302        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22303    }
22304
22305    fn document_highlights(
22306        &self,
22307        buffer: &Entity<Buffer>,
22308        position: text::Anchor,
22309        cx: &mut App,
22310    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22311        Some(self.update(cx, |project, cx| {
22312            project.document_highlights(buffer, position, cx)
22313        }))
22314    }
22315
22316    fn definitions(
22317        &self,
22318        buffer: &Entity<Buffer>,
22319        position: text::Anchor,
22320        kind: GotoDefinitionKind,
22321        cx: &mut App,
22322    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22323        Some(self.update(cx, |project, cx| match kind {
22324            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22325            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22326            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22327            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22328        }))
22329    }
22330
22331    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22332        self.update(cx, |project, cx| {
22333            if project
22334                .active_debug_session(cx)
22335                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22336            {
22337                return true;
22338            }
22339
22340            buffer.update(cx, |buffer, cx| {
22341                project.any_language_server_supports_inlay_hints(buffer, cx)
22342            })
22343        })
22344    }
22345
22346    fn inline_values(
22347        &self,
22348        buffer_handle: Entity<Buffer>,
22349        range: Range<text::Anchor>,
22350        cx: &mut App,
22351    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22352        self.update(cx, |project, cx| {
22353            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22354
22355            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22356        })
22357    }
22358
22359    fn inlay_hints(
22360        &self,
22361        buffer_handle: Entity<Buffer>,
22362        range: Range<text::Anchor>,
22363        cx: &mut App,
22364    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22365        Some(self.update(cx, |project, cx| {
22366            project.inlay_hints(buffer_handle, range, cx)
22367        }))
22368    }
22369
22370    fn resolve_inlay_hint(
22371        &self,
22372        hint: InlayHint,
22373        buffer_handle: Entity<Buffer>,
22374        server_id: LanguageServerId,
22375        cx: &mut App,
22376    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22377        Some(self.update(cx, |project, cx| {
22378            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22379        }))
22380    }
22381
22382    fn range_for_rename(
22383        &self,
22384        buffer: &Entity<Buffer>,
22385        position: text::Anchor,
22386        cx: &mut App,
22387    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22388        Some(self.update(cx, |project, cx| {
22389            let buffer = buffer.clone();
22390            let task = project.prepare_rename(buffer.clone(), position, cx);
22391            cx.spawn(async move |_, cx| {
22392                Ok(match task.await? {
22393                    PrepareRenameResponse::Success(range) => Some(range),
22394                    PrepareRenameResponse::InvalidPosition => None,
22395                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22396                        // Fallback on using TreeSitter info to determine identifier range
22397                        buffer.read_with(cx, |buffer, _| {
22398                            let snapshot = buffer.snapshot();
22399                            let (range, kind) = snapshot.surrounding_word(position, false);
22400                            if kind != Some(CharKind::Word) {
22401                                return None;
22402                            }
22403                            Some(
22404                                snapshot.anchor_before(range.start)
22405                                    ..snapshot.anchor_after(range.end),
22406                            )
22407                        })?
22408                    }
22409                })
22410            })
22411        }))
22412    }
22413
22414    fn perform_rename(
22415        &self,
22416        buffer: &Entity<Buffer>,
22417        position: text::Anchor,
22418        new_name: String,
22419        cx: &mut App,
22420    ) -> Option<Task<Result<ProjectTransaction>>> {
22421        Some(self.update(cx, |project, cx| {
22422            project.perform_rename(buffer.clone(), position, new_name, cx)
22423        }))
22424    }
22425}
22426
22427fn inlay_hint_settings(
22428    location: Anchor,
22429    snapshot: &MultiBufferSnapshot,
22430    cx: &mut Context<Editor>,
22431) -> InlayHintSettings {
22432    let file = snapshot.file_at(location);
22433    let language = snapshot.language_at(location).map(|l| l.name());
22434    language_settings(language, file, cx).inlay_hints
22435}
22436
22437fn consume_contiguous_rows(
22438    contiguous_row_selections: &mut Vec<Selection<Point>>,
22439    selection: &Selection<Point>,
22440    display_map: &DisplaySnapshot,
22441    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22442) -> (MultiBufferRow, MultiBufferRow) {
22443    contiguous_row_selections.push(selection.clone());
22444    let start_row = starting_row(selection, display_map);
22445    let mut end_row = ending_row(selection, display_map);
22446
22447    while let Some(next_selection) = selections.peek() {
22448        if next_selection.start.row <= end_row.0 {
22449            end_row = ending_row(next_selection, display_map);
22450            contiguous_row_selections.push(selections.next().unwrap().clone());
22451        } else {
22452            break;
22453        }
22454    }
22455    (start_row, end_row)
22456}
22457
22458fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22459    if selection.start.column > 0 {
22460        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22461    } else {
22462        MultiBufferRow(selection.start.row)
22463    }
22464}
22465
22466fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22467    if next_selection.end.column > 0 || next_selection.is_empty() {
22468        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22469    } else {
22470        MultiBufferRow(next_selection.end.row)
22471    }
22472}
22473
22474impl EditorSnapshot {
22475    pub fn remote_selections_in_range<'a>(
22476        &'a self,
22477        range: &'a Range<Anchor>,
22478        collaboration_hub: &dyn CollaborationHub,
22479        cx: &'a App,
22480    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22481        let participant_names = collaboration_hub.user_names(cx);
22482        let participant_indices = collaboration_hub.user_participant_indices(cx);
22483        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22484        let collaborators_by_replica_id = collaborators_by_peer_id
22485            .values()
22486            .map(|collaborator| (collaborator.replica_id, collaborator))
22487            .collect::<HashMap<_, _>>();
22488        self.buffer_snapshot
22489            .selections_in_range(range, false)
22490            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22491                if replica_id == AGENT_REPLICA_ID {
22492                    Some(RemoteSelection {
22493                        replica_id,
22494                        selection,
22495                        cursor_shape,
22496                        line_mode,
22497                        collaborator_id: CollaboratorId::Agent,
22498                        user_name: Some("Agent".into()),
22499                        color: cx.theme().players().agent(),
22500                    })
22501                } else {
22502                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22503                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22504                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22505                    Some(RemoteSelection {
22506                        replica_id,
22507                        selection,
22508                        cursor_shape,
22509                        line_mode,
22510                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22511                        user_name,
22512                        color: if let Some(index) = participant_index {
22513                            cx.theme().players().color_for_participant(index.0)
22514                        } else {
22515                            cx.theme().players().absent()
22516                        },
22517                    })
22518                }
22519            })
22520    }
22521
22522    pub fn hunks_for_ranges(
22523        &self,
22524        ranges: impl IntoIterator<Item = Range<Point>>,
22525    ) -> Vec<MultiBufferDiffHunk> {
22526        let mut hunks = Vec::new();
22527        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22528            HashMap::default();
22529        for query_range in ranges {
22530            let query_rows =
22531                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22532            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22533                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22534            ) {
22535                // Include deleted hunks that are adjacent to the query range, because
22536                // otherwise they would be missed.
22537                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22538                if hunk.status().is_deleted() {
22539                    intersects_range |= hunk.row_range.start == query_rows.end;
22540                    intersects_range |= hunk.row_range.end == query_rows.start;
22541                }
22542                if intersects_range {
22543                    if !processed_buffer_rows
22544                        .entry(hunk.buffer_id)
22545                        .or_default()
22546                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22547                    {
22548                        continue;
22549                    }
22550                    hunks.push(hunk);
22551                }
22552            }
22553        }
22554
22555        hunks
22556    }
22557
22558    fn display_diff_hunks_for_rows<'a>(
22559        &'a self,
22560        display_rows: Range<DisplayRow>,
22561        folded_buffers: &'a HashSet<BufferId>,
22562    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22563        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22564        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22565
22566        self.buffer_snapshot
22567            .diff_hunks_in_range(buffer_start..buffer_end)
22568            .filter_map(|hunk| {
22569                if folded_buffers.contains(&hunk.buffer_id) {
22570                    return None;
22571                }
22572
22573                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22574                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22575
22576                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22577                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22578
22579                let display_hunk = if hunk_display_start.column() != 0 {
22580                    DisplayDiffHunk::Folded {
22581                        display_row: hunk_display_start.row(),
22582                    }
22583                } else {
22584                    let mut end_row = hunk_display_end.row();
22585                    if hunk_display_end.column() > 0 {
22586                        end_row.0 += 1;
22587                    }
22588                    let is_created_file = hunk.is_created_file();
22589                    DisplayDiffHunk::Unfolded {
22590                        status: hunk.status(),
22591                        diff_base_byte_range: hunk.diff_base_byte_range,
22592                        display_row_range: hunk_display_start.row()..end_row,
22593                        multi_buffer_range: Anchor::range_in_buffer(
22594                            hunk.excerpt_id,
22595                            hunk.buffer_id,
22596                            hunk.buffer_range,
22597                        ),
22598                        is_created_file,
22599                    }
22600                };
22601
22602                Some(display_hunk)
22603            })
22604    }
22605
22606    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22607        self.display_snapshot.buffer_snapshot.language_at(position)
22608    }
22609
22610    pub fn is_focused(&self) -> bool {
22611        self.is_focused
22612    }
22613
22614    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22615        self.placeholder_text.as_ref()
22616    }
22617
22618    pub fn scroll_position(&self) -> gpui::Point<f32> {
22619        self.scroll_anchor.scroll_position(&self.display_snapshot)
22620    }
22621
22622    fn gutter_dimensions(
22623        &self,
22624        font_id: FontId,
22625        font_size: Pixels,
22626        max_line_number_width: Pixels,
22627        cx: &App,
22628    ) -> Option<GutterDimensions> {
22629        if !self.show_gutter {
22630            return None;
22631        }
22632
22633        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22634        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22635
22636        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22637            matches!(
22638                ProjectSettings::get_global(cx).git.git_gutter,
22639                Some(GitGutterSetting::TrackedFiles)
22640            )
22641        });
22642        let gutter_settings = EditorSettings::get_global(cx).gutter;
22643        let show_line_numbers = self
22644            .show_line_numbers
22645            .unwrap_or(gutter_settings.line_numbers);
22646        let line_gutter_width = if show_line_numbers {
22647            // Avoid flicker-like gutter resizes when the line number gains another digit by
22648            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22649            let min_width_for_number_on_gutter =
22650                ch_advance * gutter_settings.min_line_number_digits as f32;
22651            max_line_number_width.max(min_width_for_number_on_gutter)
22652        } else {
22653            0.0.into()
22654        };
22655
22656        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22657        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22658
22659        let git_blame_entries_width =
22660            self.git_blame_gutter_max_author_length
22661                .map(|max_author_length| {
22662                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22663                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22664
22665                    /// The number of characters to dedicate to gaps and margins.
22666                    const SPACING_WIDTH: usize = 4;
22667
22668                    let max_char_count = max_author_length.min(renderer.max_author_length())
22669                        + ::git::SHORT_SHA_LENGTH
22670                        + MAX_RELATIVE_TIMESTAMP.len()
22671                        + SPACING_WIDTH;
22672
22673                    ch_advance * max_char_count
22674                });
22675
22676        let is_singleton = self.buffer_snapshot.is_singleton();
22677
22678        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22679        left_padding += if !is_singleton {
22680            ch_width * 4.0
22681        } else if show_runnables || show_breakpoints {
22682            ch_width * 3.0
22683        } else if show_git_gutter && show_line_numbers {
22684            ch_width * 2.0
22685        } else if show_git_gutter || show_line_numbers {
22686            ch_width
22687        } else {
22688            px(0.)
22689        };
22690
22691        let shows_folds = is_singleton && gutter_settings.folds;
22692
22693        let right_padding = if shows_folds && show_line_numbers {
22694            ch_width * 4.0
22695        } else if shows_folds || (!is_singleton && show_line_numbers) {
22696            ch_width * 3.0
22697        } else if show_line_numbers {
22698            ch_width
22699        } else {
22700            px(0.)
22701        };
22702
22703        Some(GutterDimensions {
22704            left_padding,
22705            right_padding,
22706            width: line_gutter_width + left_padding + right_padding,
22707            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22708            git_blame_entries_width,
22709        })
22710    }
22711
22712    pub fn render_crease_toggle(
22713        &self,
22714        buffer_row: MultiBufferRow,
22715        row_contains_cursor: bool,
22716        editor: Entity<Editor>,
22717        window: &mut Window,
22718        cx: &mut App,
22719    ) -> Option<AnyElement> {
22720        let folded = self.is_line_folded(buffer_row);
22721        let mut is_foldable = false;
22722
22723        if let Some(crease) = self
22724            .crease_snapshot
22725            .query_row(buffer_row, &self.buffer_snapshot)
22726        {
22727            is_foldable = true;
22728            match crease {
22729                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22730                    if let Some(render_toggle) = render_toggle {
22731                        let toggle_callback =
22732                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22733                                if folded {
22734                                    editor.update(cx, |editor, cx| {
22735                                        editor.fold_at(buffer_row, window, cx)
22736                                    });
22737                                } else {
22738                                    editor.update(cx, |editor, cx| {
22739                                        editor.unfold_at(buffer_row, window, cx)
22740                                    });
22741                                }
22742                            });
22743                        return Some((render_toggle)(
22744                            buffer_row,
22745                            folded,
22746                            toggle_callback,
22747                            window,
22748                            cx,
22749                        ));
22750                    }
22751                }
22752            }
22753        }
22754
22755        is_foldable |= self.starts_indent(buffer_row);
22756
22757        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22758            Some(
22759                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22760                    .toggle_state(folded)
22761                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22762                        if folded {
22763                            this.unfold_at(buffer_row, window, cx);
22764                        } else {
22765                            this.fold_at(buffer_row, window, cx);
22766                        }
22767                    }))
22768                    .into_any_element(),
22769            )
22770        } else {
22771            None
22772        }
22773    }
22774
22775    pub fn render_crease_trailer(
22776        &self,
22777        buffer_row: MultiBufferRow,
22778        window: &mut Window,
22779        cx: &mut App,
22780    ) -> Option<AnyElement> {
22781        let folded = self.is_line_folded(buffer_row);
22782        if let Crease::Inline { render_trailer, .. } = self
22783            .crease_snapshot
22784            .query_row(buffer_row, &self.buffer_snapshot)?
22785        {
22786            let render_trailer = render_trailer.as_ref()?;
22787            Some(render_trailer(buffer_row, folded, window, cx))
22788        } else {
22789            None
22790        }
22791    }
22792}
22793
22794impl Deref for EditorSnapshot {
22795    type Target = DisplaySnapshot;
22796
22797    fn deref(&self) -> &Self::Target {
22798        &self.display_snapshot
22799    }
22800}
22801
22802#[derive(Clone, Debug, PartialEq, Eq)]
22803pub enum EditorEvent {
22804    InputIgnored {
22805        text: Arc<str>,
22806    },
22807    InputHandled {
22808        utf16_range_to_replace: Option<Range<isize>>,
22809        text: Arc<str>,
22810    },
22811    ExcerptsAdded {
22812        buffer: Entity<Buffer>,
22813        predecessor: ExcerptId,
22814        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22815    },
22816    ExcerptsRemoved {
22817        ids: Vec<ExcerptId>,
22818        removed_buffer_ids: Vec<BufferId>,
22819    },
22820    BufferFoldToggled {
22821        ids: Vec<ExcerptId>,
22822        folded: bool,
22823    },
22824    ExcerptsEdited {
22825        ids: Vec<ExcerptId>,
22826    },
22827    ExcerptsExpanded {
22828        ids: Vec<ExcerptId>,
22829    },
22830    BufferEdited,
22831    Edited {
22832        transaction_id: clock::Lamport,
22833    },
22834    Reparsed(BufferId),
22835    Focused,
22836    FocusedIn,
22837    Blurred,
22838    DirtyChanged,
22839    Saved,
22840    TitleChanged,
22841    DiffBaseChanged,
22842    SelectionsChanged {
22843        local: bool,
22844    },
22845    ScrollPositionChanged {
22846        local: bool,
22847        autoscroll: bool,
22848    },
22849    Closed,
22850    TransactionUndone {
22851        transaction_id: clock::Lamport,
22852    },
22853    TransactionBegun {
22854        transaction_id: clock::Lamport,
22855    },
22856    Reloaded,
22857    CursorShapeChanged,
22858    BreadcrumbsChanged,
22859    PushedToNavHistory {
22860        anchor: Anchor,
22861        is_deactivate: bool,
22862    },
22863}
22864
22865impl EventEmitter<EditorEvent> for Editor {}
22866
22867impl Focusable for Editor {
22868    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22869        self.focus_handle.clone()
22870    }
22871}
22872
22873impl Render for Editor {
22874    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22875        let settings = ThemeSettings::get_global(cx);
22876
22877        let mut text_style = match self.mode {
22878            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22879                color: cx.theme().colors().editor_foreground,
22880                font_family: settings.ui_font.family.clone(),
22881                font_features: settings.ui_font.features.clone(),
22882                font_fallbacks: settings.ui_font.fallbacks.clone(),
22883                font_size: rems(0.875).into(),
22884                font_weight: settings.ui_font.weight,
22885                line_height: relative(settings.buffer_line_height.value()),
22886                ..Default::default()
22887            },
22888            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22889                color: cx.theme().colors().editor_foreground,
22890                font_family: settings.buffer_font.family.clone(),
22891                font_features: settings.buffer_font.features.clone(),
22892                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22893                font_size: settings.buffer_font_size(cx).into(),
22894                font_weight: settings.buffer_font.weight,
22895                line_height: relative(settings.buffer_line_height.value()),
22896                ..Default::default()
22897            },
22898        };
22899        if let Some(text_style_refinement) = &self.text_style_refinement {
22900            text_style.refine(text_style_refinement)
22901        }
22902
22903        let background = match self.mode {
22904            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22905            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22906            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22907            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22908        };
22909
22910        EditorElement::new(
22911            &cx.entity(),
22912            EditorStyle {
22913                background,
22914                border: cx.theme().colors().border,
22915                local_player: cx.theme().players().local(),
22916                text: text_style,
22917                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22918                syntax: cx.theme().syntax().clone(),
22919                status: cx.theme().status().clone(),
22920                inlay_hints_style: make_inlay_hints_style(cx),
22921                edit_prediction_styles: make_suggestion_styles(cx),
22922                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22923                show_underlines: self.diagnostics_enabled(),
22924            },
22925        )
22926    }
22927}
22928
22929impl EntityInputHandler for Editor {
22930    fn text_for_range(
22931        &mut self,
22932        range_utf16: Range<usize>,
22933        adjusted_range: &mut Option<Range<usize>>,
22934        _: &mut Window,
22935        cx: &mut Context<Self>,
22936    ) -> Option<String> {
22937        let snapshot = self.buffer.read(cx).read(cx);
22938        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22939        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22940        if (start.0..end.0) != range_utf16 {
22941            adjusted_range.replace(start.0..end.0);
22942        }
22943        Some(snapshot.text_for_range(start..end).collect())
22944    }
22945
22946    fn selected_text_range(
22947        &mut self,
22948        ignore_disabled_input: bool,
22949        _: &mut Window,
22950        cx: &mut Context<Self>,
22951    ) -> Option<UTF16Selection> {
22952        // Prevent the IME menu from appearing when holding down an alphabetic key
22953        // while input is disabled.
22954        if !ignore_disabled_input && !self.input_enabled {
22955            return None;
22956        }
22957
22958        let selection = self.selections.newest::<OffsetUtf16>(cx);
22959        let range = selection.range();
22960
22961        Some(UTF16Selection {
22962            range: range.start.0..range.end.0,
22963            reversed: selection.reversed,
22964        })
22965    }
22966
22967    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22968        let snapshot = self.buffer.read(cx).read(cx);
22969        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22970        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22971    }
22972
22973    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22974        self.clear_highlights::<InputComposition>(cx);
22975        self.ime_transaction.take();
22976    }
22977
22978    fn replace_text_in_range(
22979        &mut self,
22980        range_utf16: Option<Range<usize>>,
22981        text: &str,
22982        window: &mut Window,
22983        cx: &mut Context<Self>,
22984    ) {
22985        if !self.input_enabled {
22986            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22987            return;
22988        }
22989
22990        self.transact(window, cx, |this, window, cx| {
22991            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22992                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22993                Some(this.selection_replacement_ranges(range_utf16, cx))
22994            } else {
22995                this.marked_text_ranges(cx)
22996            };
22997
22998            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22999                let newest_selection_id = this.selections.newest_anchor().id;
23000                this.selections
23001                    .all::<OffsetUtf16>(cx)
23002                    .iter()
23003                    .zip(ranges_to_replace.iter())
23004                    .find_map(|(selection, range)| {
23005                        if selection.id == newest_selection_id {
23006                            Some(
23007                                (range.start.0 as isize - selection.head().0 as isize)
23008                                    ..(range.end.0 as isize - selection.head().0 as isize),
23009                            )
23010                        } else {
23011                            None
23012                        }
23013                    })
23014            });
23015
23016            cx.emit(EditorEvent::InputHandled {
23017                utf16_range_to_replace: range_to_replace,
23018                text: text.into(),
23019            });
23020
23021            if let Some(new_selected_ranges) = new_selected_ranges {
23022                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23023                    selections.select_ranges(new_selected_ranges)
23024                });
23025                this.backspace(&Default::default(), window, cx);
23026            }
23027
23028            this.handle_input(text, window, cx);
23029        });
23030
23031        if let Some(transaction) = self.ime_transaction {
23032            self.buffer.update(cx, |buffer, cx| {
23033                buffer.group_until_transaction(transaction, cx);
23034            });
23035        }
23036
23037        self.unmark_text(window, cx);
23038    }
23039
23040    fn replace_and_mark_text_in_range(
23041        &mut self,
23042        range_utf16: Option<Range<usize>>,
23043        text: &str,
23044        new_selected_range_utf16: Option<Range<usize>>,
23045        window: &mut Window,
23046        cx: &mut Context<Self>,
23047    ) {
23048        if !self.input_enabled {
23049            return;
23050        }
23051
23052        let transaction = self.transact(window, cx, |this, window, cx| {
23053            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23054                let snapshot = this.buffer.read(cx).read(cx);
23055                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23056                    for marked_range in &mut marked_ranges {
23057                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23058                        marked_range.start.0 += relative_range_utf16.start;
23059                        marked_range.start =
23060                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23061                        marked_range.end =
23062                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23063                    }
23064                }
23065                Some(marked_ranges)
23066            } else if let Some(range_utf16) = range_utf16 {
23067                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23068                Some(this.selection_replacement_ranges(range_utf16, cx))
23069            } else {
23070                None
23071            };
23072
23073            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23074                let newest_selection_id = this.selections.newest_anchor().id;
23075                this.selections
23076                    .all::<OffsetUtf16>(cx)
23077                    .iter()
23078                    .zip(ranges_to_replace.iter())
23079                    .find_map(|(selection, range)| {
23080                        if selection.id == newest_selection_id {
23081                            Some(
23082                                (range.start.0 as isize - selection.head().0 as isize)
23083                                    ..(range.end.0 as isize - selection.head().0 as isize),
23084                            )
23085                        } else {
23086                            None
23087                        }
23088                    })
23089            });
23090
23091            cx.emit(EditorEvent::InputHandled {
23092                utf16_range_to_replace: range_to_replace,
23093                text: text.into(),
23094            });
23095
23096            if let Some(ranges) = ranges_to_replace {
23097                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23098                    s.select_ranges(ranges)
23099                });
23100            }
23101
23102            let marked_ranges = {
23103                let snapshot = this.buffer.read(cx).read(cx);
23104                this.selections
23105                    .disjoint_anchors()
23106                    .iter()
23107                    .map(|selection| {
23108                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23109                    })
23110                    .collect::<Vec<_>>()
23111            };
23112
23113            if text.is_empty() {
23114                this.unmark_text(window, cx);
23115            } else {
23116                this.highlight_text::<InputComposition>(
23117                    marked_ranges.clone(),
23118                    HighlightStyle {
23119                        underline: Some(UnderlineStyle {
23120                            thickness: px(1.),
23121                            color: None,
23122                            wavy: false,
23123                        }),
23124                        ..Default::default()
23125                    },
23126                    cx,
23127                );
23128            }
23129
23130            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23131            let use_autoclose = this.use_autoclose;
23132            let use_auto_surround = this.use_auto_surround;
23133            this.set_use_autoclose(false);
23134            this.set_use_auto_surround(false);
23135            this.handle_input(text, window, cx);
23136            this.set_use_autoclose(use_autoclose);
23137            this.set_use_auto_surround(use_auto_surround);
23138
23139            if let Some(new_selected_range) = new_selected_range_utf16 {
23140                let snapshot = this.buffer.read(cx).read(cx);
23141                let new_selected_ranges = marked_ranges
23142                    .into_iter()
23143                    .map(|marked_range| {
23144                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23145                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23146                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23147                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23148                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23149                    })
23150                    .collect::<Vec<_>>();
23151
23152                drop(snapshot);
23153                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23154                    selections.select_ranges(new_selected_ranges)
23155                });
23156            }
23157        });
23158
23159        self.ime_transaction = self.ime_transaction.or(transaction);
23160        if let Some(transaction) = self.ime_transaction {
23161            self.buffer.update(cx, |buffer, cx| {
23162                buffer.group_until_transaction(transaction, cx);
23163            });
23164        }
23165
23166        if self.text_highlights::<InputComposition>(cx).is_none() {
23167            self.ime_transaction.take();
23168        }
23169    }
23170
23171    fn bounds_for_range(
23172        &mut self,
23173        range_utf16: Range<usize>,
23174        element_bounds: gpui::Bounds<Pixels>,
23175        window: &mut Window,
23176        cx: &mut Context<Self>,
23177    ) -> Option<gpui::Bounds<Pixels>> {
23178        let text_layout_details = self.text_layout_details(window);
23179        let CharacterDimensions {
23180            em_width,
23181            em_advance,
23182            line_height,
23183        } = self.character_dimensions(window);
23184
23185        let snapshot = self.snapshot(window, cx);
23186        let scroll_position = snapshot.scroll_position();
23187        let scroll_left = scroll_position.x * em_advance;
23188
23189        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23190        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23191            + self.gutter_dimensions.full_width();
23192        let y = line_height * (start.row().as_f32() - scroll_position.y);
23193
23194        Some(Bounds {
23195            origin: element_bounds.origin + point(x, y),
23196            size: size(em_width, line_height),
23197        })
23198    }
23199
23200    fn character_index_for_point(
23201        &mut self,
23202        point: gpui::Point<Pixels>,
23203        _window: &mut Window,
23204        _cx: &mut Context<Self>,
23205    ) -> Option<usize> {
23206        let position_map = self.last_position_map.as_ref()?;
23207        if !position_map.text_hitbox.contains(&point) {
23208            return None;
23209        }
23210        let display_point = position_map.point_for_position(point).previous_valid;
23211        let anchor = position_map
23212            .snapshot
23213            .display_point_to_anchor(display_point, Bias::Left);
23214        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23215        Some(utf16_offset.0)
23216    }
23217}
23218
23219trait SelectionExt {
23220    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23221    fn spanned_rows(
23222        &self,
23223        include_end_if_at_line_start: bool,
23224        map: &DisplaySnapshot,
23225    ) -> Range<MultiBufferRow>;
23226}
23227
23228impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23229    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23230        let start = self
23231            .start
23232            .to_point(&map.buffer_snapshot)
23233            .to_display_point(map);
23234        let end = self
23235            .end
23236            .to_point(&map.buffer_snapshot)
23237            .to_display_point(map);
23238        if self.reversed {
23239            end..start
23240        } else {
23241            start..end
23242        }
23243    }
23244
23245    fn spanned_rows(
23246        &self,
23247        include_end_if_at_line_start: bool,
23248        map: &DisplaySnapshot,
23249    ) -> Range<MultiBufferRow> {
23250        let start = self.start.to_point(&map.buffer_snapshot);
23251        let mut end = self.end.to_point(&map.buffer_snapshot);
23252        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23253            end.row -= 1;
23254        }
23255
23256        let buffer_start = map.prev_line_boundary(start).0;
23257        let buffer_end = map.next_line_boundary(end).0;
23258        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23259    }
23260}
23261
23262impl<T: InvalidationRegion> InvalidationStack<T> {
23263    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23264    where
23265        S: Clone + ToOffset,
23266    {
23267        while let Some(region) = self.last() {
23268            let all_selections_inside_invalidation_ranges =
23269                if selections.len() == region.ranges().len() {
23270                    selections
23271                        .iter()
23272                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23273                        .all(|(selection, invalidation_range)| {
23274                            let head = selection.head().to_offset(buffer);
23275                            invalidation_range.start <= head && invalidation_range.end >= head
23276                        })
23277                } else {
23278                    false
23279                };
23280
23281            if all_selections_inside_invalidation_ranges {
23282                break;
23283            } else {
23284                self.pop();
23285            }
23286        }
23287    }
23288}
23289
23290impl<T> Default for InvalidationStack<T> {
23291    fn default() -> Self {
23292        Self(Default::default())
23293    }
23294}
23295
23296impl<T> Deref for InvalidationStack<T> {
23297    type Target = Vec<T>;
23298
23299    fn deref(&self) -> &Self::Target {
23300        &self.0
23301    }
23302}
23303
23304impl<T> DerefMut for InvalidationStack<T> {
23305    fn deref_mut(&mut self) -> &mut Self::Target {
23306        &mut self.0
23307    }
23308}
23309
23310impl InvalidationRegion for SnippetState {
23311    fn ranges(&self) -> &[Range<Anchor>] {
23312        &self.ranges[self.active_index]
23313    }
23314}
23315
23316fn edit_prediction_edit_text(
23317    current_snapshot: &BufferSnapshot,
23318    edits: &[(Range<Anchor>, String)],
23319    edit_preview: &EditPreview,
23320    include_deletions: bool,
23321    cx: &App,
23322) -> HighlightedText {
23323    let edits = edits
23324        .iter()
23325        .map(|(anchor, text)| {
23326            (
23327                anchor.start.text_anchor..anchor.end.text_anchor,
23328                text.clone(),
23329            )
23330        })
23331        .collect::<Vec<_>>();
23332
23333    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23334}
23335
23336fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23337    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23338    // Just show the raw edit text with basic styling
23339    let mut text = String::new();
23340    let mut highlights = Vec::new();
23341
23342    let insertion_highlight_style = HighlightStyle {
23343        color: Some(cx.theme().colors().text),
23344        ..Default::default()
23345    };
23346
23347    for (_, edit_text) in edits {
23348        let start_offset = text.len();
23349        text.push_str(edit_text);
23350        let end_offset = text.len();
23351
23352        if start_offset < end_offset {
23353            highlights.push((start_offset..end_offset, insertion_highlight_style));
23354        }
23355    }
23356
23357    HighlightedText {
23358        text: text.into(),
23359        highlights,
23360    }
23361}
23362
23363pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23364    match severity {
23365        lsp::DiagnosticSeverity::ERROR => colors.error,
23366        lsp::DiagnosticSeverity::WARNING => colors.warning,
23367        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23368        lsp::DiagnosticSeverity::HINT => colors.info,
23369        _ => colors.ignored,
23370    }
23371}
23372
23373pub fn styled_runs_for_code_label<'a>(
23374    label: &'a CodeLabel,
23375    syntax_theme: &'a theme::SyntaxTheme,
23376) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23377    let fade_out = HighlightStyle {
23378        fade_out: Some(0.35),
23379        ..Default::default()
23380    };
23381
23382    let mut prev_end = label.filter_range.end;
23383    label
23384        .runs
23385        .iter()
23386        .enumerate()
23387        .flat_map(move |(ix, (range, highlight_id))| {
23388            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23389                style
23390            } else {
23391                return Default::default();
23392            };
23393            let mut muted_style = style;
23394            muted_style.highlight(fade_out);
23395
23396            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23397            if range.start >= label.filter_range.end {
23398                if range.start > prev_end {
23399                    runs.push((prev_end..range.start, fade_out));
23400                }
23401                runs.push((range.clone(), muted_style));
23402            } else if range.end <= label.filter_range.end {
23403                runs.push((range.clone(), style));
23404            } else {
23405                runs.push((range.start..label.filter_range.end, style));
23406                runs.push((label.filter_range.end..range.end, muted_style));
23407            }
23408            prev_end = cmp::max(prev_end, range.end);
23409
23410            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23411                runs.push((prev_end..label.text.len(), fade_out));
23412            }
23413
23414            runs
23415        })
23416}
23417
23418pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23419    let mut prev_index = 0;
23420    let mut prev_codepoint: Option<char> = None;
23421    text.char_indices()
23422        .chain([(text.len(), '\0')])
23423        .filter_map(move |(index, codepoint)| {
23424            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23425            let is_boundary = index == text.len()
23426                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23427                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23428            if is_boundary {
23429                let chunk = &text[prev_index..index];
23430                prev_index = index;
23431                Some(chunk)
23432            } else {
23433                None
23434            }
23435        })
23436}
23437
23438pub trait RangeToAnchorExt: Sized {
23439    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23440
23441    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23442        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23443        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23444    }
23445}
23446
23447impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23448    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23449        let start_offset = self.start.to_offset(snapshot);
23450        let end_offset = self.end.to_offset(snapshot);
23451        if start_offset == end_offset {
23452            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23453        } else {
23454            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23455        }
23456    }
23457}
23458
23459pub trait RowExt {
23460    fn as_f32(&self) -> f32;
23461
23462    fn next_row(&self) -> Self;
23463
23464    fn previous_row(&self) -> Self;
23465
23466    fn minus(&self, other: Self) -> u32;
23467}
23468
23469impl RowExt for DisplayRow {
23470    fn as_f32(&self) -> f32 {
23471        self.0 as f32
23472    }
23473
23474    fn next_row(&self) -> Self {
23475        Self(self.0 + 1)
23476    }
23477
23478    fn previous_row(&self) -> Self {
23479        Self(self.0.saturating_sub(1))
23480    }
23481
23482    fn minus(&self, other: Self) -> u32 {
23483        self.0 - other.0
23484    }
23485}
23486
23487impl RowExt for MultiBufferRow {
23488    fn as_f32(&self) -> f32 {
23489        self.0 as f32
23490    }
23491
23492    fn next_row(&self) -> Self {
23493        Self(self.0 + 1)
23494    }
23495
23496    fn previous_row(&self) -> Self {
23497        Self(self.0.saturating_sub(1))
23498    }
23499
23500    fn minus(&self, other: Self) -> u32 {
23501        self.0 - other.0
23502    }
23503}
23504
23505trait RowRangeExt {
23506    type Row;
23507
23508    fn len(&self) -> usize;
23509
23510    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23511}
23512
23513impl RowRangeExt for Range<MultiBufferRow> {
23514    type Row = MultiBufferRow;
23515
23516    fn len(&self) -> usize {
23517        (self.end.0 - self.start.0) as usize
23518    }
23519
23520    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23521        (self.start.0..self.end.0).map(MultiBufferRow)
23522    }
23523}
23524
23525impl RowRangeExt for Range<DisplayRow> {
23526    type Row = DisplayRow;
23527
23528    fn len(&self) -> usize {
23529        (self.end.0 - self.start.0) as usize
23530    }
23531
23532    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23533        (self.start.0..self.end.0).map(DisplayRow)
23534    }
23535}
23536
23537/// If select range has more than one line, we
23538/// just point the cursor to range.start.
23539fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23540    if range.start.row == range.end.row {
23541        range
23542    } else {
23543        range.start..range.start
23544    }
23545}
23546pub struct KillRing(ClipboardItem);
23547impl Global for KillRing {}
23548
23549const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23550
23551enum BreakpointPromptEditAction {
23552    Log,
23553    Condition,
23554    HitCondition,
23555}
23556
23557struct BreakpointPromptEditor {
23558    pub(crate) prompt: Entity<Editor>,
23559    editor: WeakEntity<Editor>,
23560    breakpoint_anchor: Anchor,
23561    breakpoint: Breakpoint,
23562    edit_action: BreakpointPromptEditAction,
23563    block_ids: HashSet<CustomBlockId>,
23564    editor_margins: Arc<Mutex<EditorMargins>>,
23565    _subscriptions: Vec<Subscription>,
23566}
23567
23568impl BreakpointPromptEditor {
23569    const MAX_LINES: u8 = 4;
23570
23571    fn new(
23572        editor: WeakEntity<Editor>,
23573        breakpoint_anchor: Anchor,
23574        breakpoint: Breakpoint,
23575        edit_action: BreakpointPromptEditAction,
23576        window: &mut Window,
23577        cx: &mut Context<Self>,
23578    ) -> Self {
23579        let base_text = match edit_action {
23580            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23581            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23582            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23583        }
23584        .map(|msg| msg.to_string())
23585        .unwrap_or_default();
23586
23587        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23588        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23589
23590        let prompt = cx.new(|cx| {
23591            let mut prompt = Editor::new(
23592                EditorMode::AutoHeight {
23593                    min_lines: 1,
23594                    max_lines: Some(Self::MAX_LINES as usize),
23595                },
23596                buffer,
23597                None,
23598                window,
23599                cx,
23600            );
23601            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23602            prompt.set_show_cursor_when_unfocused(false, cx);
23603            prompt.set_placeholder_text(
23604                match edit_action {
23605                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23606                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23607                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23608                },
23609                cx,
23610            );
23611
23612            prompt
23613        });
23614
23615        Self {
23616            prompt,
23617            editor,
23618            breakpoint_anchor,
23619            breakpoint,
23620            edit_action,
23621            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23622            block_ids: Default::default(),
23623            _subscriptions: vec![],
23624        }
23625    }
23626
23627    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23628        self.block_ids.extend(block_ids)
23629    }
23630
23631    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23632        if let Some(editor) = self.editor.upgrade() {
23633            let message = self
23634                .prompt
23635                .read(cx)
23636                .buffer
23637                .read(cx)
23638                .as_singleton()
23639                .expect("A multi buffer in breakpoint prompt isn't possible")
23640                .read(cx)
23641                .as_rope()
23642                .to_string();
23643
23644            editor.update(cx, |editor, cx| {
23645                editor.edit_breakpoint_at_anchor(
23646                    self.breakpoint_anchor,
23647                    self.breakpoint.clone(),
23648                    match self.edit_action {
23649                        BreakpointPromptEditAction::Log => {
23650                            BreakpointEditAction::EditLogMessage(message.into())
23651                        }
23652                        BreakpointPromptEditAction::Condition => {
23653                            BreakpointEditAction::EditCondition(message.into())
23654                        }
23655                        BreakpointPromptEditAction::HitCondition => {
23656                            BreakpointEditAction::EditHitCondition(message.into())
23657                        }
23658                    },
23659                    cx,
23660                );
23661
23662                editor.remove_blocks(self.block_ids.clone(), None, cx);
23663                cx.focus_self(window);
23664            });
23665        }
23666    }
23667
23668    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23669        self.editor
23670            .update(cx, |editor, cx| {
23671                editor.remove_blocks(self.block_ids.clone(), None, cx);
23672                window.focus(&editor.focus_handle);
23673            })
23674            .log_err();
23675    }
23676
23677    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23678        let settings = ThemeSettings::get_global(cx);
23679        let text_style = TextStyle {
23680            color: if self.prompt.read(cx).read_only(cx) {
23681                cx.theme().colors().text_disabled
23682            } else {
23683                cx.theme().colors().text
23684            },
23685            font_family: settings.buffer_font.family.clone(),
23686            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23687            font_size: settings.buffer_font_size(cx).into(),
23688            font_weight: settings.buffer_font.weight,
23689            line_height: relative(settings.buffer_line_height.value()),
23690            ..Default::default()
23691        };
23692        EditorElement::new(
23693            &self.prompt,
23694            EditorStyle {
23695                background: cx.theme().colors().editor_background,
23696                local_player: cx.theme().players().local(),
23697                text: text_style,
23698                ..Default::default()
23699            },
23700        )
23701    }
23702}
23703
23704impl Render for BreakpointPromptEditor {
23705    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23706        let editor_margins = *self.editor_margins.lock();
23707        let gutter_dimensions = editor_margins.gutter;
23708        h_flex()
23709            .key_context("Editor")
23710            .bg(cx.theme().colors().editor_background)
23711            .border_y_1()
23712            .border_color(cx.theme().status().info_border)
23713            .size_full()
23714            .py(window.line_height() / 2.5)
23715            .on_action(cx.listener(Self::confirm))
23716            .on_action(cx.listener(Self::cancel))
23717            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23718            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23719    }
23720}
23721
23722impl Focusable for BreakpointPromptEditor {
23723    fn focus_handle(&self, cx: &App) -> FocusHandle {
23724        self.prompt.focus_handle(cx)
23725    }
23726}
23727
23728fn all_edits_insertions_or_deletions(
23729    edits: &Vec<(Range<Anchor>, String)>,
23730    snapshot: &MultiBufferSnapshot,
23731) -> bool {
23732    let mut all_insertions = true;
23733    let mut all_deletions = true;
23734
23735    for (range, new_text) in edits.iter() {
23736        let range_is_empty = range.to_offset(snapshot).is_empty();
23737        let text_is_empty = new_text.is_empty();
23738
23739        if range_is_empty != text_is_empty {
23740            if range_is_empty {
23741                all_deletions = false;
23742            } else {
23743                all_insertions = false;
23744            }
23745        } else {
23746            return false;
23747        }
23748
23749        if !all_insertions && !all_deletions {
23750            return false;
23751        }
23752    }
23753    all_insertions || all_deletions
23754}
23755
23756struct MissingEditPredictionKeybindingTooltip;
23757
23758impl Render for MissingEditPredictionKeybindingTooltip {
23759    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23760        ui::tooltip_container(window, cx, |container, _, cx| {
23761            container
23762                .flex_shrink_0()
23763                .max_w_80()
23764                .min_h(rems_from_px(124.))
23765                .justify_between()
23766                .child(
23767                    v_flex()
23768                        .flex_1()
23769                        .text_ui_sm(cx)
23770                        .child(Label::new("Conflict with Accept Keybinding"))
23771                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23772                )
23773                .child(
23774                    h_flex()
23775                        .pb_1()
23776                        .gap_1()
23777                        .items_end()
23778                        .w_full()
23779                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23780                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23781                        }))
23782                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23783                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23784                        })),
23785                )
23786        })
23787    }
23788}
23789
23790#[derive(Debug, Clone, Copy, PartialEq)]
23791pub struct LineHighlight {
23792    pub background: Background,
23793    pub border: Option<gpui::Hsla>,
23794    pub include_gutter: bool,
23795    pub type_id: Option<TypeId>,
23796}
23797
23798struct LineManipulationResult {
23799    pub new_text: String,
23800    pub line_count_before: usize,
23801    pub line_count_after: usize,
23802}
23803
23804fn render_diff_hunk_controls(
23805    row: u32,
23806    status: &DiffHunkStatus,
23807    hunk_range: Range<Anchor>,
23808    is_created_file: bool,
23809    line_height: Pixels,
23810    editor: &Entity<Editor>,
23811    _window: &mut Window,
23812    cx: &mut App,
23813) -> AnyElement {
23814    h_flex()
23815        .h(line_height)
23816        .mr_1()
23817        .gap_1()
23818        .px_0p5()
23819        .pb_1()
23820        .border_x_1()
23821        .border_b_1()
23822        .border_color(cx.theme().colors().border_variant)
23823        .rounded_b_lg()
23824        .bg(cx.theme().colors().editor_background)
23825        .gap_1()
23826        .block_mouse_except_scroll()
23827        .shadow_md()
23828        .child(if status.has_secondary_hunk() {
23829            Button::new(("stage", row as u64), "Stage")
23830                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23831                .tooltip({
23832                    let focus_handle = editor.focus_handle(cx);
23833                    move |window, cx| {
23834                        Tooltip::for_action_in(
23835                            "Stage Hunk",
23836                            &::git::ToggleStaged,
23837                            &focus_handle,
23838                            window,
23839                            cx,
23840                        )
23841                    }
23842                })
23843                .on_click({
23844                    let editor = editor.clone();
23845                    move |_event, _window, cx| {
23846                        editor.update(cx, |editor, cx| {
23847                            editor.stage_or_unstage_diff_hunks(
23848                                true,
23849                                vec![hunk_range.start..hunk_range.start],
23850                                cx,
23851                            );
23852                        });
23853                    }
23854                })
23855        } else {
23856            Button::new(("unstage", row as u64), "Unstage")
23857                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23858                .tooltip({
23859                    let focus_handle = editor.focus_handle(cx);
23860                    move |window, cx| {
23861                        Tooltip::for_action_in(
23862                            "Unstage Hunk",
23863                            &::git::ToggleStaged,
23864                            &focus_handle,
23865                            window,
23866                            cx,
23867                        )
23868                    }
23869                })
23870                .on_click({
23871                    let editor = editor.clone();
23872                    move |_event, _window, cx| {
23873                        editor.update(cx, |editor, cx| {
23874                            editor.stage_or_unstage_diff_hunks(
23875                                false,
23876                                vec![hunk_range.start..hunk_range.start],
23877                                cx,
23878                            );
23879                        });
23880                    }
23881                })
23882        })
23883        .child(
23884            Button::new(("restore", row as u64), "Restore")
23885                .tooltip({
23886                    let focus_handle = editor.focus_handle(cx);
23887                    move |window, cx| {
23888                        Tooltip::for_action_in(
23889                            "Restore Hunk",
23890                            &::git::Restore,
23891                            &focus_handle,
23892                            window,
23893                            cx,
23894                        )
23895                    }
23896                })
23897                .on_click({
23898                    let editor = editor.clone();
23899                    move |_event, window, cx| {
23900                        editor.update(cx, |editor, cx| {
23901                            let snapshot = editor.snapshot(window, cx);
23902                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23903                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23904                        });
23905                    }
23906                })
23907                .disabled(is_created_file),
23908        )
23909        .when(
23910            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23911            |el| {
23912                el.child(
23913                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23914                        .shape(IconButtonShape::Square)
23915                        .icon_size(IconSize::Small)
23916                        // .disabled(!has_multiple_hunks)
23917                        .tooltip({
23918                            let focus_handle = editor.focus_handle(cx);
23919                            move |window, cx| {
23920                                Tooltip::for_action_in(
23921                                    "Next Hunk",
23922                                    &GoToHunk,
23923                                    &focus_handle,
23924                                    window,
23925                                    cx,
23926                                )
23927                            }
23928                        })
23929                        .on_click({
23930                            let editor = editor.clone();
23931                            move |_event, window, cx| {
23932                                editor.update(cx, |editor, cx| {
23933                                    let snapshot = editor.snapshot(window, cx);
23934                                    let position =
23935                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23936                                    editor.go_to_hunk_before_or_after_position(
23937                                        &snapshot,
23938                                        position,
23939                                        Direction::Next,
23940                                        window,
23941                                        cx,
23942                                    );
23943                                    editor.expand_selected_diff_hunks(cx);
23944                                });
23945                            }
23946                        }),
23947                )
23948                .child(
23949                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23950                        .shape(IconButtonShape::Square)
23951                        .icon_size(IconSize::Small)
23952                        // .disabled(!has_multiple_hunks)
23953                        .tooltip({
23954                            let focus_handle = editor.focus_handle(cx);
23955                            move |window, cx| {
23956                                Tooltip::for_action_in(
23957                                    "Previous Hunk",
23958                                    &GoToPreviousHunk,
23959                                    &focus_handle,
23960                                    window,
23961                                    cx,
23962                                )
23963                            }
23964                        })
23965                        .on_click({
23966                            let editor = editor.clone();
23967                            move |_event, window, cx| {
23968                                editor.update(cx, |editor, cx| {
23969                                    let snapshot = editor.snapshot(window, cx);
23970                                    let point =
23971                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23972                                    editor.go_to_hunk_before_or_after_position(
23973                                        &snapshot,
23974                                        point,
23975                                        Direction::Prev,
23976                                        window,
23977                                        cx,
23978                                    );
23979                                    editor.expand_selected_diff_hunks(cx);
23980                                });
23981                            }
23982                        }),
23983                )
23984            },
23985        )
23986        .into_any_element()
23987}