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            if let Some(current) = last.current.as_mut() {
  947                mem::swap(&mut last.original, current);
  948            }
  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            .map_or(true, |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            .map_or(true, |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 {
 1865            if let Some(project) = project.as_ref() {
 1866                project_subscriptions.push(cx.subscribe_in(
 1867                    project,
 1868                    window,
 1869                    |editor, _, event, window, cx| match event {
 1870                        project::Event::RefreshCodeLens => {
 1871                            // we always query lens with actions, without storing them, always refreshing them
 1872                        }
 1873                        project::Event::RefreshInlayHints => {
 1874                            editor
 1875                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1876                        }
 1877                        project::Event::LanguageServerAdded(..)
 1878                        | project::Event::LanguageServerRemoved(..) => {
 1879                            if editor.tasks_update_task.is_none() {
 1880                                editor.tasks_update_task =
 1881                                    Some(editor.refresh_runnables(window, cx));
 1882                            }
 1883                        }
 1884                        project::Event::SnippetEdit(id, snippet_edits) => {
 1885                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1886                                let focus_handle = editor.focus_handle(cx);
 1887                                if focus_handle.is_focused(window) {
 1888                                    let snapshot = buffer.read(cx).snapshot();
 1889                                    for (range, snippet) in snippet_edits {
 1890                                        let editor_range =
 1891                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1892                                        editor
 1893                                            .insert_snippet(
 1894                                                &[editor_range],
 1895                                                snippet.clone(),
 1896                                                window,
 1897                                                cx,
 1898                                            )
 1899                                            .ok();
 1900                                    }
 1901                                }
 1902                            }
 1903                        }
 1904                        project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1905                            if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1906                                editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1907                            }
 1908                        }
 1909                        _ => {}
 1910                    },
 1911                ));
 1912                if let Some(task_inventory) = project
 1913                    .read(cx)
 1914                    .task_store()
 1915                    .read(cx)
 1916                    .task_inventory()
 1917                    .cloned()
 1918                {
 1919                    project_subscriptions.push(cx.observe_in(
 1920                        &task_inventory,
 1921                        window,
 1922                        |editor, _, window, cx| {
 1923                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1924                        },
 1925                    ));
 1926                };
 1927
 1928                project_subscriptions.push(cx.subscribe_in(
 1929                    &project.read(cx).breakpoint_store(),
 1930                    window,
 1931                    |editor, _, event, window, cx| match event {
 1932                        BreakpointStoreEvent::ClearDebugLines => {
 1933                            editor.clear_row_highlights::<ActiveDebugLine>();
 1934                            editor.refresh_inline_values(cx);
 1935                        }
 1936                        BreakpointStoreEvent::SetDebugLine => {
 1937                            if editor.go_to_active_debug_line(window, cx) {
 1938                                cx.stop_propagation();
 1939                            }
 1940
 1941                            editor.refresh_inline_values(cx);
 1942                        }
 1943                        _ => {}
 1944                    },
 1945                ));
 1946                let git_store = project.read(cx).git_store().clone();
 1947                let project = project.clone();
 1948                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1949                    match event {
 1950                        GitStoreEvent::RepositoryUpdated(
 1951                            _,
 1952                            RepositoryEvent::Updated {
 1953                                new_instance: true, ..
 1954                            },
 1955                            _,
 1956                        ) => {
 1957                            this.load_diff_task = Some(
 1958                                update_uncommitted_diff_for_buffer(
 1959                                    cx.entity(),
 1960                                    &project,
 1961                                    this.buffer.read(cx).all_buffers(),
 1962                                    this.buffer.clone(),
 1963                                    cx,
 1964                                )
 1965                                .shared(),
 1966                            );
 1967                        }
 1968                        _ => {}
 1969                    }
 1970                }));
 1971            }
 1972        }
 1973
 1974        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1975
 1976        let inlay_hint_settings =
 1977            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1978        let focus_handle = cx.focus_handle();
 1979        if !is_minimap {
 1980            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1981                .detach();
 1982            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1983                .detach();
 1984            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1985                .detach();
 1986            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1987                .detach();
 1988            cx.observe_pending_input(window, Self::observe_pending_input)
 1989                .detach();
 1990        }
 1991
 1992        let show_indent_guides = if matches!(
 1993            mode,
 1994            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1995        ) {
 1996            Some(false)
 1997        } else {
 1998            None
 1999        };
 2000
 2001        let breakpoint_store = match (&mode, project.as_ref()) {
 2002            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2003            _ => None,
 2004        };
 2005
 2006        let mut code_action_providers = Vec::new();
 2007        let mut load_uncommitted_diff = None;
 2008        if let Some(project) = project.clone() {
 2009            load_uncommitted_diff = Some(
 2010                update_uncommitted_diff_for_buffer(
 2011                    cx.entity(),
 2012                    &project,
 2013                    buffer.read(cx).all_buffers(),
 2014                    buffer.clone(),
 2015                    cx,
 2016                )
 2017                .shared(),
 2018            );
 2019            code_action_providers.push(Rc::new(project) as Rc<_>);
 2020        }
 2021
 2022        let mut editor = Self {
 2023            focus_handle,
 2024            show_cursor_when_unfocused: false,
 2025            last_focused_descendant: None,
 2026            buffer: buffer.clone(),
 2027            display_map: display_map.clone(),
 2028            selections,
 2029            scroll_manager: ScrollManager::new(cx),
 2030            columnar_selection_state: None,
 2031            add_selections_state: None,
 2032            select_next_state: None,
 2033            select_prev_state: None,
 2034            selection_history: SelectionHistory::default(),
 2035            defer_selection_effects: false,
 2036            deferred_selection_effects_state: None,
 2037            autoclose_regions: Vec::new(),
 2038            snippet_stack: InvalidationStack::default(),
 2039            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2040            ime_transaction: None,
 2041            active_diagnostics: ActiveDiagnostic::None,
 2042            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2043            inline_diagnostics_update: Task::ready(()),
 2044            inline_diagnostics: Vec::new(),
 2045            soft_wrap_mode_override,
 2046            diagnostics_max_severity,
 2047            hard_wrap: None,
 2048            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2049            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2050            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2051            project,
 2052            blink_manager: blink_manager.clone(),
 2053            show_local_selections: true,
 2054            show_scrollbars: ScrollbarAxes {
 2055                horizontal: full_mode,
 2056                vertical: full_mode,
 2057            },
 2058            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2059            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2060            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2061            show_gutter: full_mode,
 2062            show_line_numbers: (!full_mode).then_some(false),
 2063            use_relative_line_numbers: None,
 2064            disable_expand_excerpt_buttons: !full_mode,
 2065            show_git_diff_gutter: None,
 2066            show_code_actions: None,
 2067            show_runnables: None,
 2068            show_breakpoints: None,
 2069            show_wrap_guides: None,
 2070            show_indent_guides,
 2071            placeholder_text: None,
 2072            highlight_order: 0,
 2073            highlighted_rows: HashMap::default(),
 2074            background_highlights: TreeMap::default(),
 2075            gutter_highlights: TreeMap::default(),
 2076            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2077            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2078            nav_history: None,
 2079            context_menu: RefCell::new(None),
 2080            context_menu_options: None,
 2081            mouse_context_menu: None,
 2082            completion_tasks: Vec::new(),
 2083            inline_blame_popover: None,
 2084            inline_blame_popover_show_task: None,
 2085            signature_help_state: SignatureHelpState::default(),
 2086            auto_signature_help: None,
 2087            find_all_references_task_sources: Vec::new(),
 2088            next_completion_id: 0,
 2089            next_inlay_id: 0,
 2090            code_action_providers,
 2091            available_code_actions: None,
 2092            code_actions_task: None,
 2093            quick_selection_highlight_task: None,
 2094            debounced_selection_highlight_task: None,
 2095            document_highlights_task: None,
 2096            linked_editing_range_task: None,
 2097            pending_rename: None,
 2098            searchable: !is_minimap,
 2099            cursor_shape: EditorSettings::get_global(cx)
 2100                .cursor_shape
 2101                .unwrap_or_default(),
 2102            current_line_highlight: None,
 2103            autoindent_mode: Some(AutoindentMode::EachLine),
 2104            collapse_matches: false,
 2105            workspace: None,
 2106            input_enabled: !is_minimap,
 2107            use_modal_editing: full_mode,
 2108            read_only: is_minimap,
 2109            use_autoclose: true,
 2110            use_auto_surround: true,
 2111            auto_replace_emoji_shortcode: false,
 2112            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2113            leader_id: None,
 2114            remote_id: None,
 2115            hover_state: HoverState::default(),
 2116            pending_mouse_down: None,
 2117            hovered_link_state: None,
 2118            edit_prediction_provider: None,
 2119            active_edit_prediction: None,
 2120            stale_edit_prediction_in_menu: None,
 2121            edit_prediction_preview: EditPredictionPreview::Inactive {
 2122                released_too_fast: false,
 2123            },
 2124            inline_diagnostics_enabled: full_mode,
 2125            diagnostics_enabled: full_mode,
 2126            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2127            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2128            gutter_hovered: false,
 2129            pixel_position_of_newest_cursor: None,
 2130            last_bounds: None,
 2131            last_position_map: None,
 2132            expect_bounds_change: None,
 2133            gutter_dimensions: GutterDimensions::default(),
 2134            style: None,
 2135            show_cursor_names: false,
 2136            hovered_cursors: HashMap::default(),
 2137            next_editor_action_id: EditorActionId::default(),
 2138            editor_actions: Rc::default(),
 2139            edit_predictions_hidden_for_vim_mode: false,
 2140            show_edit_predictions_override: None,
 2141            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2142            edit_prediction_settings: EditPredictionSettings::Disabled,
 2143            edit_prediction_indent_conflict: false,
 2144            edit_prediction_requires_modifier_in_indent_conflict: true,
 2145            custom_context_menu: None,
 2146            show_git_blame_gutter: false,
 2147            show_git_blame_inline: false,
 2148            show_selection_menu: None,
 2149            show_git_blame_inline_delay_task: None,
 2150            git_blame_inline_enabled: full_mode
 2151                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2152            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2153            serialize_dirty_buffers: !is_minimap
 2154                && ProjectSettings::get_global(cx)
 2155                    .session
 2156                    .restore_unsaved_buffers,
 2157            blame: None,
 2158            blame_subscription: None,
 2159            tasks: BTreeMap::default(),
 2160
 2161            breakpoint_store,
 2162            gutter_breakpoint_indicator: (None, None),
 2163            hovered_diff_hunk_row: None,
 2164            _subscriptions: (!is_minimap)
 2165                .then(|| {
 2166                    vec![
 2167                        cx.observe(&buffer, Self::on_buffer_changed),
 2168                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2169                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2170                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2171                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2172                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2173                        cx.observe_window_activation(window, |editor, window, cx| {
 2174                            let active = window.is_window_active();
 2175                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2176                                if active {
 2177                                    blink_manager.enable(cx);
 2178                                } else {
 2179                                    blink_manager.disable(cx);
 2180                                }
 2181                            });
 2182                            if active {
 2183                                editor.show_mouse_cursor(cx);
 2184                            }
 2185                        }),
 2186                    ]
 2187                })
 2188                .unwrap_or_default(),
 2189            tasks_update_task: None,
 2190            pull_diagnostics_task: Task::ready(()),
 2191            colors: None,
 2192            next_color_inlay_id: 0,
 2193            linked_edit_ranges: Default::default(),
 2194            in_project_search: false,
 2195            previous_search_ranges: None,
 2196            breadcrumb_header: None,
 2197            focused_block: None,
 2198            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2199            addons: HashMap::default(),
 2200            registered_buffers: HashMap::default(),
 2201            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2202            selection_mark_mode: false,
 2203            toggle_fold_multiple_buffers: Task::ready(()),
 2204            serialize_selections: Task::ready(()),
 2205            serialize_folds: Task::ready(()),
 2206            text_style_refinement: None,
 2207            load_diff_task: load_uncommitted_diff,
 2208            temporary_diff_override: false,
 2209            mouse_cursor_hidden: false,
 2210            minimap: None,
 2211            hide_mouse_mode: EditorSettings::get_global(cx)
 2212                .hide_mouse
 2213                .unwrap_or_default(),
 2214            change_list: ChangeList::new(),
 2215            mode,
 2216            selection_drag_state: SelectionDragState::None,
 2217            folding_newlines: Task::ready(()),
 2218        };
 2219
 2220        if is_minimap {
 2221            return editor;
 2222        }
 2223
 2224        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2225            editor
 2226                ._subscriptions
 2227                .push(cx.observe(breakpoints, |_, _, cx| {
 2228                    cx.notify();
 2229                }));
 2230        }
 2231        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2232        editor._subscriptions.extend(project_subscriptions);
 2233
 2234        editor._subscriptions.push(cx.subscribe_in(
 2235            &cx.entity(),
 2236            window,
 2237            |editor, _, e: &EditorEvent, window, cx| match e {
 2238                EditorEvent::ScrollPositionChanged { local, .. } => {
 2239                    if *local {
 2240                        let new_anchor = editor.scroll_manager.anchor();
 2241                        let snapshot = editor.snapshot(window, cx);
 2242                        editor.update_restoration_data(cx, move |data| {
 2243                            data.scroll_position = (
 2244                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2245                                new_anchor.offset,
 2246                            );
 2247                        });
 2248                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2249                        editor.inline_blame_popover.take();
 2250                    }
 2251                }
 2252                EditorEvent::Edited { .. } => {
 2253                    if !vim_enabled(cx) {
 2254                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2255                        let pop_state = editor
 2256                            .change_list
 2257                            .last()
 2258                            .map(|previous| {
 2259                                previous.len() == selections.len()
 2260                                    && previous.iter().enumerate().all(|(ix, p)| {
 2261                                        p.to_display_point(&map).row()
 2262                                            == selections[ix].head().row()
 2263                                    })
 2264                            })
 2265                            .unwrap_or(false);
 2266                        let new_positions = selections
 2267                            .into_iter()
 2268                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2269                            .collect();
 2270                        editor
 2271                            .change_list
 2272                            .push_to_change_list(pop_state, new_positions);
 2273                    }
 2274                }
 2275                _ => (),
 2276            },
 2277        ));
 2278
 2279        if let Some(dap_store) = editor
 2280            .project
 2281            .as_ref()
 2282            .map(|project| project.read(cx).dap_store())
 2283        {
 2284            let weak_editor = cx.weak_entity();
 2285
 2286            editor
 2287                ._subscriptions
 2288                .push(
 2289                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2290                        let session_entity = cx.entity();
 2291                        weak_editor
 2292                            .update(cx, |editor, cx| {
 2293                                editor._subscriptions.push(
 2294                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2295                                );
 2296                            })
 2297                            .ok();
 2298                    }),
 2299                );
 2300
 2301            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2302                editor
 2303                    ._subscriptions
 2304                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2305            }
 2306        }
 2307
 2308        // skip adding the initial selection to selection history
 2309        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2310        editor.end_selection(window, cx);
 2311        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2312
 2313        editor.scroll_manager.show_scrollbars(window, cx);
 2314        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2315
 2316        if full_mode {
 2317            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2318            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2319
 2320            if editor.git_blame_inline_enabled {
 2321                editor.start_git_blame_inline(false, window, cx);
 2322            }
 2323
 2324            editor.go_to_active_debug_line(window, cx);
 2325
 2326            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2327                if let Some(project) = editor.project() {
 2328                    let handle = project.update(cx, |project, cx| {
 2329                        project.register_buffer_with_language_servers(&buffer, cx)
 2330                    });
 2331                    editor
 2332                        .registered_buffers
 2333                        .insert(buffer.read(cx).remote_id(), handle);
 2334                }
 2335            }
 2336
 2337            editor.minimap =
 2338                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2339            editor.colors = Some(LspColorData::new(cx));
 2340            editor.update_lsp_data(false, None, window, cx);
 2341        }
 2342
 2343        if editor.mode.is_full() {
 2344            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2345        }
 2346
 2347        editor
 2348    }
 2349
 2350    pub fn deploy_mouse_context_menu(
 2351        &mut self,
 2352        position: gpui::Point<Pixels>,
 2353        context_menu: Entity<ContextMenu>,
 2354        window: &mut Window,
 2355        cx: &mut Context<Self>,
 2356    ) {
 2357        self.mouse_context_menu = Some(MouseContextMenu::new(
 2358            self,
 2359            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2360            context_menu,
 2361            window,
 2362            cx,
 2363        ));
 2364    }
 2365
 2366    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2367        self.mouse_context_menu
 2368            .as_ref()
 2369            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2370    }
 2371
 2372    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2373        if self
 2374            .selections
 2375            .pending
 2376            .as_ref()
 2377            .is_some_and(|pending_selection| {
 2378                let snapshot = self.buffer().read(cx).snapshot(cx);
 2379                pending_selection
 2380                    .selection
 2381                    .range()
 2382                    .includes(range, &snapshot)
 2383            })
 2384        {
 2385            return true;
 2386        }
 2387
 2388        self.selections
 2389            .disjoint_in_range::<usize>(range.clone(), cx)
 2390            .into_iter()
 2391            .any(|selection| {
 2392                // This is needed to cover a corner case, if we just check for an existing
 2393                // selection in the fold range, having a cursor at the start of the fold
 2394                // marks it as selected. Non-empty selections don't cause this.
 2395                let length = selection.end - selection.start;
 2396                length > 0
 2397            })
 2398    }
 2399
 2400    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2401        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2402    }
 2403
 2404    fn key_context_internal(
 2405        &self,
 2406        has_active_edit_prediction: bool,
 2407        window: &Window,
 2408        cx: &App,
 2409    ) -> KeyContext {
 2410        let mut key_context = KeyContext::new_with_defaults();
 2411        key_context.add("Editor");
 2412        let mode = match self.mode {
 2413            EditorMode::SingleLine { .. } => "single_line",
 2414            EditorMode::AutoHeight { .. } => "auto_height",
 2415            EditorMode::Minimap { .. } => "minimap",
 2416            EditorMode::Full { .. } => "full",
 2417        };
 2418
 2419        if EditorSettings::jupyter_enabled(cx) {
 2420            key_context.add("jupyter");
 2421        }
 2422
 2423        key_context.set("mode", mode);
 2424        if self.pending_rename.is_some() {
 2425            key_context.add("renaming");
 2426        }
 2427
 2428        match self.context_menu.borrow().as_ref() {
 2429            Some(CodeContextMenu::Completions(menu)) => {
 2430                if menu.visible() {
 2431                    key_context.add("menu");
 2432                    key_context.add("showing_completions");
 2433                }
 2434            }
 2435            Some(CodeContextMenu::CodeActions(menu)) => {
 2436                if menu.visible() {
 2437                    key_context.add("menu");
 2438                    key_context.add("showing_code_actions")
 2439                }
 2440            }
 2441            None => {}
 2442        }
 2443
 2444        if self.signature_help_state.has_multiple_signatures() {
 2445            key_context.add("showing_signature_help");
 2446        }
 2447
 2448        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2449        if !self.focus_handle(cx).contains_focused(window, cx)
 2450            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2451        {
 2452            for addon in self.addons.values() {
 2453                addon.extend_key_context(&mut key_context, cx)
 2454            }
 2455        }
 2456
 2457        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2458            if let Some(extension) = singleton_buffer
 2459                .read(cx)
 2460                .file()
 2461                .and_then(|file| file.path().extension()?.to_str())
 2462            {
 2463                key_context.set("extension", extension.to_string());
 2464            }
 2465        } else {
 2466            key_context.add("multibuffer");
 2467        }
 2468
 2469        if has_active_edit_prediction {
 2470            if self.edit_prediction_in_conflict() {
 2471                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2472            } else {
 2473                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2474                key_context.add("copilot_suggestion");
 2475            }
 2476        }
 2477
 2478        if self.selection_mark_mode {
 2479            key_context.add("selection_mode");
 2480        }
 2481
 2482        key_context
 2483    }
 2484
 2485    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2486        if self.mouse_cursor_hidden {
 2487            self.mouse_cursor_hidden = false;
 2488            cx.notify();
 2489        }
 2490    }
 2491
 2492    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2493        let hide_mouse_cursor = match origin {
 2494            HideMouseCursorOrigin::TypingAction => {
 2495                matches!(
 2496                    self.hide_mouse_mode,
 2497                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2498                )
 2499            }
 2500            HideMouseCursorOrigin::MovementAction => {
 2501                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2502            }
 2503        };
 2504        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2505            self.mouse_cursor_hidden = hide_mouse_cursor;
 2506            cx.notify();
 2507        }
 2508    }
 2509
 2510    pub fn edit_prediction_in_conflict(&self) -> bool {
 2511        if !self.show_edit_predictions_in_menu() {
 2512            return false;
 2513        }
 2514
 2515        let showing_completions = self
 2516            .context_menu
 2517            .borrow()
 2518            .as_ref()
 2519            .map_or(false, |context| {
 2520                matches!(context, CodeContextMenu::Completions(_))
 2521            });
 2522
 2523        showing_completions
 2524            || self.edit_prediction_requires_modifier()
 2525            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2526            // bindings to insert tab characters.
 2527            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2528    }
 2529
 2530    pub fn accept_edit_prediction_keybind(
 2531        &self,
 2532        accept_partial: bool,
 2533        window: &Window,
 2534        cx: &App,
 2535    ) -> AcceptEditPredictionBinding {
 2536        let key_context = self.key_context_internal(true, window, cx);
 2537        let in_conflict = self.edit_prediction_in_conflict();
 2538
 2539        let bindings = if accept_partial {
 2540            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2541        } else {
 2542            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2543        };
 2544
 2545        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2546        // just the first one.
 2547        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2548            !in_conflict
 2549                || binding
 2550                    .keystrokes()
 2551                    .first()
 2552                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2553        }))
 2554    }
 2555
 2556    pub fn new_file(
 2557        workspace: &mut Workspace,
 2558        _: &workspace::NewFile,
 2559        window: &mut Window,
 2560        cx: &mut Context<Workspace>,
 2561    ) {
 2562        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2563            "Failed to create buffer",
 2564            window,
 2565            cx,
 2566            |e, _, _| match e.error_code() {
 2567                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2568                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2569                e.error_tag("required").unwrap_or("the latest version")
 2570            )),
 2571                _ => None,
 2572            },
 2573        );
 2574    }
 2575
 2576    pub fn new_in_workspace(
 2577        workspace: &mut Workspace,
 2578        window: &mut Window,
 2579        cx: &mut Context<Workspace>,
 2580    ) -> Task<Result<Entity<Editor>>> {
 2581        let project = workspace.project().clone();
 2582        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2583
 2584        cx.spawn_in(window, async move |workspace, cx| {
 2585            let buffer = create.await?;
 2586            workspace.update_in(cx, |workspace, window, cx| {
 2587                let editor =
 2588                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2589                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2590                editor
 2591            })
 2592        })
 2593    }
 2594
 2595    fn new_file_vertical(
 2596        workspace: &mut Workspace,
 2597        _: &workspace::NewFileSplitVertical,
 2598        window: &mut Window,
 2599        cx: &mut Context<Workspace>,
 2600    ) {
 2601        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2602    }
 2603
 2604    fn new_file_horizontal(
 2605        workspace: &mut Workspace,
 2606        _: &workspace::NewFileSplitHorizontal,
 2607        window: &mut Window,
 2608        cx: &mut Context<Workspace>,
 2609    ) {
 2610        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2611    }
 2612
 2613    fn new_file_in_direction(
 2614        workspace: &mut Workspace,
 2615        direction: SplitDirection,
 2616        window: &mut Window,
 2617        cx: &mut Context<Workspace>,
 2618    ) {
 2619        let project = workspace.project().clone();
 2620        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2621
 2622        cx.spawn_in(window, async move |workspace, cx| {
 2623            let buffer = create.await?;
 2624            workspace.update_in(cx, move |workspace, window, cx| {
 2625                workspace.split_item(
 2626                    direction,
 2627                    Box::new(
 2628                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2629                    ),
 2630                    window,
 2631                    cx,
 2632                )
 2633            })?;
 2634            anyhow::Ok(())
 2635        })
 2636        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2637            match e.error_code() {
 2638                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2639                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2640                e.error_tag("required").unwrap_or("the latest version")
 2641            )),
 2642                _ => None,
 2643            }
 2644        });
 2645    }
 2646
 2647    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2648        self.leader_id
 2649    }
 2650
 2651    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2652        &self.buffer
 2653    }
 2654
 2655    pub fn project(&self) -> Option<&Entity<Project>> {
 2656        self.project.as_ref()
 2657    }
 2658
 2659    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2660        self.workspace.as_ref()?.0.upgrade()
 2661    }
 2662
 2663    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2664        self.buffer().read(cx).title(cx)
 2665    }
 2666
 2667    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2668        let git_blame_gutter_max_author_length = self
 2669            .render_git_blame_gutter(cx)
 2670            .then(|| {
 2671                if let Some(blame) = self.blame.as_ref() {
 2672                    let max_author_length =
 2673                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2674                    Some(max_author_length)
 2675                } else {
 2676                    None
 2677                }
 2678            })
 2679            .flatten();
 2680
 2681        EditorSnapshot {
 2682            mode: self.mode.clone(),
 2683            show_gutter: self.show_gutter,
 2684            show_line_numbers: self.show_line_numbers,
 2685            show_git_diff_gutter: self.show_git_diff_gutter,
 2686            show_code_actions: self.show_code_actions,
 2687            show_runnables: self.show_runnables,
 2688            show_breakpoints: self.show_breakpoints,
 2689            git_blame_gutter_max_author_length,
 2690            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2691            scroll_anchor: self.scroll_manager.anchor(),
 2692            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2693            placeholder_text: self.placeholder_text.clone(),
 2694            is_focused: self.focus_handle.is_focused(window),
 2695            current_line_highlight: self
 2696                .current_line_highlight
 2697                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2698            gutter_hovered: self.gutter_hovered,
 2699        }
 2700    }
 2701
 2702    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2703        self.buffer.read(cx).language_at(point, cx)
 2704    }
 2705
 2706    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2707        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2708    }
 2709
 2710    pub fn active_excerpt(
 2711        &self,
 2712        cx: &App,
 2713    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2714        self.buffer
 2715            .read(cx)
 2716            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2717    }
 2718
 2719    pub fn mode(&self) -> &EditorMode {
 2720        &self.mode
 2721    }
 2722
 2723    pub fn set_mode(&mut self, mode: EditorMode) {
 2724        self.mode = mode;
 2725    }
 2726
 2727    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2728        self.collaboration_hub.as_deref()
 2729    }
 2730
 2731    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2732        self.collaboration_hub = Some(hub);
 2733    }
 2734
 2735    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2736        self.in_project_search = in_project_search;
 2737    }
 2738
 2739    pub fn set_custom_context_menu(
 2740        &mut self,
 2741        f: impl 'static
 2742        + Fn(
 2743            &mut Self,
 2744            DisplayPoint,
 2745            &mut Window,
 2746            &mut Context<Self>,
 2747        ) -> Option<Entity<ui::ContextMenu>>,
 2748    ) {
 2749        self.custom_context_menu = Some(Box::new(f))
 2750    }
 2751
 2752    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2753        self.completion_provider = provider;
 2754    }
 2755
 2756    #[cfg(any(test, feature = "test-support"))]
 2757    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2758        self.completion_provider.clone()
 2759    }
 2760
 2761    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2762        self.semantics_provider.clone()
 2763    }
 2764
 2765    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2766        self.semantics_provider = provider;
 2767    }
 2768
 2769    pub fn set_edit_prediction_provider<T>(
 2770        &mut self,
 2771        provider: Option<Entity<T>>,
 2772        window: &mut Window,
 2773        cx: &mut Context<Self>,
 2774    ) where
 2775        T: EditPredictionProvider,
 2776    {
 2777        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2778            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2779                if this.focus_handle.is_focused(window) {
 2780                    this.update_visible_edit_prediction(window, cx);
 2781                }
 2782            }),
 2783            provider: Arc::new(provider),
 2784        });
 2785        self.update_edit_prediction_settings(cx);
 2786        self.refresh_edit_prediction(false, false, window, cx);
 2787    }
 2788
 2789    pub fn placeholder_text(&self) -> Option<&str> {
 2790        self.placeholder_text.as_deref()
 2791    }
 2792
 2793    pub fn set_placeholder_text(
 2794        &mut self,
 2795        placeholder_text: impl Into<Arc<str>>,
 2796        cx: &mut Context<Self>,
 2797    ) {
 2798        let placeholder_text = Some(placeholder_text.into());
 2799        if self.placeholder_text != placeholder_text {
 2800            self.placeholder_text = placeholder_text;
 2801            cx.notify();
 2802        }
 2803    }
 2804
 2805    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2806        self.cursor_shape = cursor_shape;
 2807
 2808        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2809        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2810
 2811        cx.notify();
 2812    }
 2813
 2814    pub fn set_current_line_highlight(
 2815        &mut self,
 2816        current_line_highlight: Option<CurrentLineHighlight>,
 2817    ) {
 2818        self.current_line_highlight = current_line_highlight;
 2819    }
 2820
 2821    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2822        self.collapse_matches = collapse_matches;
 2823    }
 2824
 2825    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2826        let buffers = self.buffer.read(cx).all_buffers();
 2827        let Some(project) = self.project.as_ref() else {
 2828            return;
 2829        };
 2830        project.update(cx, |project, cx| {
 2831            for buffer in buffers {
 2832                self.registered_buffers
 2833                    .entry(buffer.read(cx).remote_id())
 2834                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2835            }
 2836        })
 2837    }
 2838
 2839    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2840        if self.collapse_matches {
 2841            return range.start..range.start;
 2842        }
 2843        range.clone()
 2844    }
 2845
 2846    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2847        if self.display_map.read(cx).clip_at_line_ends != clip {
 2848            self.display_map
 2849                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2850        }
 2851    }
 2852
 2853    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2854        self.input_enabled = input_enabled;
 2855    }
 2856
 2857    pub fn set_edit_predictions_hidden_for_vim_mode(
 2858        &mut self,
 2859        hidden: bool,
 2860        window: &mut Window,
 2861        cx: &mut Context<Self>,
 2862    ) {
 2863        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2864            self.edit_predictions_hidden_for_vim_mode = hidden;
 2865            if hidden {
 2866                self.update_visible_edit_prediction(window, cx);
 2867            } else {
 2868                self.refresh_edit_prediction(true, false, window, cx);
 2869            }
 2870        }
 2871    }
 2872
 2873    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2874        self.menu_edit_predictions_policy = value;
 2875    }
 2876
 2877    pub fn set_autoindent(&mut self, autoindent: bool) {
 2878        if autoindent {
 2879            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2880        } else {
 2881            self.autoindent_mode = None;
 2882        }
 2883    }
 2884
 2885    pub fn read_only(&self, cx: &App) -> bool {
 2886        self.read_only || self.buffer.read(cx).read_only()
 2887    }
 2888
 2889    pub fn set_read_only(&mut self, read_only: bool) {
 2890        self.read_only = read_only;
 2891    }
 2892
 2893    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2894        self.use_autoclose = autoclose;
 2895    }
 2896
 2897    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2898        self.use_auto_surround = auto_surround;
 2899    }
 2900
 2901    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2902        self.auto_replace_emoji_shortcode = auto_replace;
 2903    }
 2904
 2905    pub fn toggle_edit_predictions(
 2906        &mut self,
 2907        _: &ToggleEditPrediction,
 2908        window: &mut Window,
 2909        cx: &mut Context<Self>,
 2910    ) {
 2911        if self.show_edit_predictions_override.is_some() {
 2912            self.set_show_edit_predictions(None, window, cx);
 2913        } else {
 2914            let show_edit_predictions = !self.edit_predictions_enabled();
 2915            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2916        }
 2917    }
 2918
 2919    pub fn set_show_edit_predictions(
 2920        &mut self,
 2921        show_edit_predictions: Option<bool>,
 2922        window: &mut Window,
 2923        cx: &mut Context<Self>,
 2924    ) {
 2925        self.show_edit_predictions_override = show_edit_predictions;
 2926        self.update_edit_prediction_settings(cx);
 2927
 2928        if let Some(false) = show_edit_predictions {
 2929            self.discard_edit_prediction(false, cx);
 2930        } else {
 2931            self.refresh_edit_prediction(false, true, window, cx);
 2932        }
 2933    }
 2934
 2935    fn edit_predictions_disabled_in_scope(
 2936        &self,
 2937        buffer: &Entity<Buffer>,
 2938        buffer_position: language::Anchor,
 2939        cx: &App,
 2940    ) -> bool {
 2941        let snapshot = buffer.read(cx).snapshot();
 2942        let settings = snapshot.settings_at(buffer_position, cx);
 2943
 2944        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2945            return false;
 2946        };
 2947
 2948        scope.override_name().map_or(false, |scope_name| {
 2949            settings
 2950                .edit_predictions_disabled_in
 2951                .iter()
 2952                .any(|s| s == scope_name)
 2953        })
 2954    }
 2955
 2956    pub fn set_use_modal_editing(&mut self, to: bool) {
 2957        self.use_modal_editing = to;
 2958    }
 2959
 2960    pub fn use_modal_editing(&self) -> bool {
 2961        self.use_modal_editing
 2962    }
 2963
 2964    fn selections_did_change(
 2965        &mut self,
 2966        local: bool,
 2967        old_cursor_position: &Anchor,
 2968        effects: SelectionEffects,
 2969        window: &mut Window,
 2970        cx: &mut Context<Self>,
 2971    ) {
 2972        window.invalidate_character_coordinates();
 2973
 2974        // Copy selections to primary selection buffer
 2975        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2976        if local {
 2977            let selections = self.selections.all::<usize>(cx);
 2978            let buffer_handle = self.buffer.read(cx).read(cx);
 2979
 2980            let mut text = String::new();
 2981            for (index, selection) in selections.iter().enumerate() {
 2982                let text_for_selection = buffer_handle
 2983                    .text_for_range(selection.start..selection.end)
 2984                    .collect::<String>();
 2985
 2986                text.push_str(&text_for_selection);
 2987                if index != selections.len() - 1 {
 2988                    text.push('\n');
 2989                }
 2990            }
 2991
 2992            if !text.is_empty() {
 2993                cx.write_to_primary(ClipboardItem::new_string(text));
 2994            }
 2995        }
 2996
 2997        let selection_anchors = self.selections.disjoint_anchors();
 2998
 2999        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3000            self.buffer.update(cx, |buffer, cx| {
 3001                buffer.set_active_selections(
 3002                    &selection_anchors,
 3003                    self.selections.line_mode,
 3004                    self.cursor_shape,
 3005                    cx,
 3006                )
 3007            });
 3008        }
 3009        let display_map = self
 3010            .display_map
 3011            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3012        let buffer = &display_map.buffer_snapshot;
 3013        if self.selections.count() == 1 {
 3014            self.add_selections_state = None;
 3015        }
 3016        self.select_next_state = None;
 3017        self.select_prev_state = None;
 3018        self.select_syntax_node_history.try_clear();
 3019        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3020        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3021        self.take_rename(false, window, cx);
 3022
 3023        let newest_selection = self.selections.newest_anchor();
 3024        let new_cursor_position = newest_selection.head();
 3025        let selection_start = newest_selection.start;
 3026
 3027        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3028            self.push_to_nav_history(
 3029                *old_cursor_position,
 3030                Some(new_cursor_position.to_point(buffer)),
 3031                false,
 3032                effects.nav_history == Some(true),
 3033                cx,
 3034            );
 3035        }
 3036
 3037        if local {
 3038            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3039                if !self.registered_buffers.contains_key(&buffer_id) {
 3040                    if let Some(project) = self.project.as_ref() {
 3041                        project.update(cx, |project, cx| {
 3042                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3043                                return;
 3044                            };
 3045                            self.registered_buffers.insert(
 3046                                buffer_id,
 3047                                project.register_buffer_with_language_servers(&buffer, cx),
 3048                            );
 3049                        })
 3050                    }
 3051                }
 3052            }
 3053
 3054            let mut context_menu = self.context_menu.borrow_mut();
 3055            let completion_menu = match context_menu.as_ref() {
 3056                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3057                Some(CodeContextMenu::CodeActions(_)) => {
 3058                    *context_menu = None;
 3059                    None
 3060                }
 3061                None => None,
 3062            };
 3063            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3064            drop(context_menu);
 3065
 3066            if effects.completions {
 3067                if let Some(completion_position) = completion_position {
 3068                    let start_offset = selection_start.to_offset(buffer);
 3069                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3070                    let continue_showing = if position_matches {
 3071                        if self.snippet_stack.is_empty() {
 3072                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3073                        } else {
 3074                            // Snippet choices can be shown even when the cursor is in whitespace.
 3075                            // Dismissing the menu with actions like backspace is handled by
 3076                            // invalidation regions.
 3077                            true
 3078                        }
 3079                    } else {
 3080                        false
 3081                    };
 3082
 3083                    if continue_showing {
 3084                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3085                    } else {
 3086                        self.hide_context_menu(window, cx);
 3087                    }
 3088                }
 3089            }
 3090
 3091            hide_hover(self, cx);
 3092
 3093            if old_cursor_position.to_display_point(&display_map).row()
 3094                != new_cursor_position.to_display_point(&display_map).row()
 3095            {
 3096                self.available_code_actions.take();
 3097            }
 3098            self.refresh_code_actions(window, cx);
 3099            self.refresh_document_highlights(cx);
 3100            self.refresh_selected_text_highlights(false, window, cx);
 3101            refresh_matching_bracket_highlights(self, window, cx);
 3102            self.update_visible_edit_prediction(window, cx);
 3103            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3104            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3105            self.inline_blame_popover.take();
 3106            if self.git_blame_inline_enabled {
 3107                self.start_inline_blame_timer(window, cx);
 3108            }
 3109        }
 3110
 3111        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3112        cx.emit(EditorEvent::SelectionsChanged { local });
 3113
 3114        let selections = &self.selections.disjoint;
 3115        if selections.len() == 1 {
 3116            cx.emit(SearchEvent::ActiveMatchChanged)
 3117        }
 3118        if local {
 3119            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3120                let inmemory_selections = selections
 3121                    .iter()
 3122                    .map(|s| {
 3123                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3124                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3125                    })
 3126                    .collect();
 3127                self.update_restoration_data(cx, |data| {
 3128                    data.selections = inmemory_selections;
 3129                });
 3130
 3131                if WorkspaceSettings::get(None, cx).restore_on_startup
 3132                    != RestoreOnStartupBehavior::None
 3133                {
 3134                    if let Some(workspace_id) =
 3135                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3136                    {
 3137                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3138                        let selections = selections.clone();
 3139                        let background_executor = cx.background_executor().clone();
 3140                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3141                        self.serialize_selections = cx.background_spawn(async move {
 3142                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3143                            let db_selections = selections
 3144                                .iter()
 3145                                .map(|selection| {
 3146                                    (
 3147                                        selection.start.to_offset(&snapshot),
 3148                                        selection.end.to_offset(&snapshot),
 3149                                    )
 3150                                })
 3151                                .collect();
 3152
 3153                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3154                                .await
 3155                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3156                                .log_err();
 3157                        });
 3158                    }
 3159                }
 3160            }
 3161        }
 3162
 3163        cx.notify();
 3164    }
 3165
 3166    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3167        use text::ToOffset as _;
 3168        use text::ToPoint as _;
 3169
 3170        if self.mode.is_minimap()
 3171            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3172        {
 3173            return;
 3174        }
 3175
 3176        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3177            return;
 3178        };
 3179
 3180        let snapshot = singleton.read(cx).snapshot();
 3181        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3182            let display_snapshot = display_map.snapshot(cx);
 3183
 3184            display_snapshot
 3185                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3186                .map(|fold| {
 3187                    fold.range.start.text_anchor.to_point(&snapshot)
 3188                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3189                })
 3190                .collect()
 3191        });
 3192        self.update_restoration_data(cx, |data| {
 3193            data.folds = inmemory_folds;
 3194        });
 3195
 3196        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3197            return;
 3198        };
 3199        let background_executor = cx.background_executor().clone();
 3200        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3201        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3202            display_map
 3203                .snapshot(cx)
 3204                .folds_in_range(0..snapshot.len())
 3205                .map(|fold| {
 3206                    (
 3207                        fold.range.start.text_anchor.to_offset(&snapshot),
 3208                        fold.range.end.text_anchor.to_offset(&snapshot),
 3209                    )
 3210                })
 3211                .collect()
 3212        });
 3213        self.serialize_folds = cx.background_spawn(async move {
 3214            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3215            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3216                .await
 3217                .with_context(|| {
 3218                    format!(
 3219                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3220                    )
 3221                })
 3222                .log_err();
 3223        });
 3224    }
 3225
 3226    pub fn sync_selections(
 3227        &mut self,
 3228        other: Entity<Editor>,
 3229        cx: &mut Context<Self>,
 3230    ) -> gpui::Subscription {
 3231        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3232        self.selections.change_with(cx, |selections| {
 3233            selections.select_anchors(other_selections);
 3234        });
 3235
 3236        let other_subscription =
 3237            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3238                EditorEvent::SelectionsChanged { local: true } => {
 3239                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3240                    if other_selections.is_empty() {
 3241                        return;
 3242                    }
 3243                    this.selections.change_with(cx, |selections| {
 3244                        selections.select_anchors(other_selections);
 3245                    });
 3246                }
 3247                _ => {}
 3248            });
 3249
 3250        let this_subscription =
 3251            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3252                EditorEvent::SelectionsChanged { local: true } => {
 3253                    let these_selections = this.selections.disjoint.to_vec();
 3254                    if these_selections.is_empty() {
 3255                        return;
 3256                    }
 3257                    other.update(cx, |other_editor, cx| {
 3258                        other_editor.selections.change_with(cx, |selections| {
 3259                            selections.select_anchors(these_selections);
 3260                        })
 3261                    });
 3262                }
 3263                _ => {}
 3264            });
 3265
 3266        Subscription::join(other_subscription, this_subscription)
 3267    }
 3268
 3269    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3270    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3271    /// effects of selection change occur at the end of the transaction.
 3272    pub fn change_selections<R>(
 3273        &mut self,
 3274        effects: SelectionEffects,
 3275        window: &mut Window,
 3276        cx: &mut Context<Self>,
 3277        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3278    ) -> R {
 3279        if let Some(state) = &mut self.deferred_selection_effects_state {
 3280            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3281            state.effects.completions = effects.completions;
 3282            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3283            let (changed, result) = self.selections.change_with(cx, change);
 3284            state.changed |= changed;
 3285            return result;
 3286        }
 3287        let mut state = DeferredSelectionEffectsState {
 3288            changed: false,
 3289            effects,
 3290            old_cursor_position: self.selections.newest_anchor().head(),
 3291            history_entry: SelectionHistoryEntry {
 3292                selections: self.selections.disjoint_anchors(),
 3293                select_next_state: self.select_next_state.clone(),
 3294                select_prev_state: self.select_prev_state.clone(),
 3295                add_selections_state: self.add_selections_state.clone(),
 3296            },
 3297        };
 3298        let (changed, result) = self.selections.change_with(cx, change);
 3299        state.changed = state.changed || changed;
 3300        if self.defer_selection_effects {
 3301            self.deferred_selection_effects_state = Some(state);
 3302        } else {
 3303            self.apply_selection_effects(state, window, cx);
 3304        }
 3305        result
 3306    }
 3307
 3308    /// Defers the effects of selection change, so that the effects of multiple calls to
 3309    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3310    /// to selection history and the state of popovers based on selection position aren't
 3311    /// erroneously updated.
 3312    pub fn with_selection_effects_deferred<R>(
 3313        &mut self,
 3314        window: &mut Window,
 3315        cx: &mut Context<Self>,
 3316        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3317    ) -> R {
 3318        let already_deferred = self.defer_selection_effects;
 3319        self.defer_selection_effects = true;
 3320        let result = update(self, window, cx);
 3321        if !already_deferred {
 3322            self.defer_selection_effects = false;
 3323            if let Some(state) = self.deferred_selection_effects_state.take() {
 3324                self.apply_selection_effects(state, window, cx);
 3325            }
 3326        }
 3327        result
 3328    }
 3329
 3330    fn apply_selection_effects(
 3331        &mut self,
 3332        state: DeferredSelectionEffectsState,
 3333        window: &mut Window,
 3334        cx: &mut Context<Self>,
 3335    ) {
 3336        if state.changed {
 3337            self.selection_history.push(state.history_entry);
 3338
 3339            if let Some(autoscroll) = state.effects.scroll {
 3340                self.request_autoscroll(autoscroll, cx);
 3341            }
 3342
 3343            let old_cursor_position = &state.old_cursor_position;
 3344
 3345            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3346
 3347            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3348                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3349            }
 3350        }
 3351    }
 3352
 3353    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3354    where
 3355        I: IntoIterator<Item = (Range<S>, T)>,
 3356        S: ToOffset,
 3357        T: Into<Arc<str>>,
 3358    {
 3359        if self.read_only(cx) {
 3360            return;
 3361        }
 3362
 3363        self.buffer
 3364            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3365    }
 3366
 3367    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3368    where
 3369        I: IntoIterator<Item = (Range<S>, T)>,
 3370        S: ToOffset,
 3371        T: Into<Arc<str>>,
 3372    {
 3373        if self.read_only(cx) {
 3374            return;
 3375        }
 3376
 3377        self.buffer.update(cx, |buffer, cx| {
 3378            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3379        });
 3380    }
 3381
 3382    pub fn edit_with_block_indent<I, S, T>(
 3383        &mut self,
 3384        edits: I,
 3385        original_indent_columns: Vec<Option<u32>>,
 3386        cx: &mut Context<Self>,
 3387    ) where
 3388        I: IntoIterator<Item = (Range<S>, T)>,
 3389        S: ToOffset,
 3390        T: Into<Arc<str>>,
 3391    {
 3392        if self.read_only(cx) {
 3393            return;
 3394        }
 3395
 3396        self.buffer.update(cx, |buffer, cx| {
 3397            buffer.edit(
 3398                edits,
 3399                Some(AutoindentMode::Block {
 3400                    original_indent_columns,
 3401                }),
 3402                cx,
 3403            )
 3404        });
 3405    }
 3406
 3407    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3408        self.hide_context_menu(window, cx);
 3409
 3410        match phase {
 3411            SelectPhase::Begin {
 3412                position,
 3413                add,
 3414                click_count,
 3415            } => self.begin_selection(position, add, click_count, window, cx),
 3416            SelectPhase::BeginColumnar {
 3417                position,
 3418                goal_column,
 3419                reset,
 3420                mode,
 3421            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3422            SelectPhase::Extend {
 3423                position,
 3424                click_count,
 3425            } => self.extend_selection(position, click_count, window, cx),
 3426            SelectPhase::Update {
 3427                position,
 3428                goal_column,
 3429                scroll_delta,
 3430            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3431            SelectPhase::End => self.end_selection(window, cx),
 3432        }
 3433    }
 3434
 3435    fn extend_selection(
 3436        &mut self,
 3437        position: DisplayPoint,
 3438        click_count: usize,
 3439        window: &mut Window,
 3440        cx: &mut Context<Self>,
 3441    ) {
 3442        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3443        let tail = self.selections.newest::<usize>(cx).tail();
 3444        self.begin_selection(position, false, click_count, window, cx);
 3445
 3446        let position = position.to_offset(&display_map, Bias::Left);
 3447        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3448
 3449        let mut pending_selection = self
 3450            .selections
 3451            .pending_anchor()
 3452            .expect("extend_selection not called with pending selection");
 3453        if position >= tail {
 3454            pending_selection.start = tail_anchor;
 3455        } else {
 3456            pending_selection.end = tail_anchor;
 3457            pending_selection.reversed = true;
 3458        }
 3459
 3460        let mut pending_mode = self.selections.pending_mode().unwrap();
 3461        match &mut pending_mode {
 3462            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3463            _ => {}
 3464        }
 3465
 3466        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3467            SelectionEffects::scroll(Autoscroll::fit())
 3468        } else {
 3469            SelectionEffects::no_scroll()
 3470        };
 3471
 3472        self.change_selections(effects, window, cx, |s| {
 3473            s.set_pending(pending_selection, pending_mode)
 3474        });
 3475    }
 3476
 3477    fn begin_selection(
 3478        &mut self,
 3479        position: DisplayPoint,
 3480        add: bool,
 3481        click_count: usize,
 3482        window: &mut Window,
 3483        cx: &mut Context<Self>,
 3484    ) {
 3485        if !self.focus_handle.is_focused(window) {
 3486            self.last_focused_descendant = None;
 3487            window.focus(&self.focus_handle);
 3488        }
 3489
 3490        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3491        let buffer = &display_map.buffer_snapshot;
 3492        let position = display_map.clip_point(position, Bias::Left);
 3493
 3494        let start;
 3495        let end;
 3496        let mode;
 3497        let mut auto_scroll;
 3498        match click_count {
 3499            1 => {
 3500                start = buffer.anchor_before(position.to_point(&display_map));
 3501                end = start;
 3502                mode = SelectMode::Character;
 3503                auto_scroll = true;
 3504            }
 3505            2 => {
 3506                let position = display_map
 3507                    .clip_point(position, Bias::Left)
 3508                    .to_offset(&display_map, Bias::Left);
 3509                let (range, _) = buffer.surrounding_word(position, false);
 3510                start = buffer.anchor_before(range.start);
 3511                end = buffer.anchor_before(range.end);
 3512                mode = SelectMode::Word(start..end);
 3513                auto_scroll = true;
 3514            }
 3515            3 => {
 3516                let position = display_map
 3517                    .clip_point(position, Bias::Left)
 3518                    .to_point(&display_map);
 3519                let line_start = display_map.prev_line_boundary(position).0;
 3520                let next_line_start = buffer.clip_point(
 3521                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3522                    Bias::Left,
 3523                );
 3524                start = buffer.anchor_before(line_start);
 3525                end = buffer.anchor_before(next_line_start);
 3526                mode = SelectMode::Line(start..end);
 3527                auto_scroll = true;
 3528            }
 3529            _ => {
 3530                start = buffer.anchor_before(0);
 3531                end = buffer.anchor_before(buffer.len());
 3532                mode = SelectMode::All;
 3533                auto_scroll = false;
 3534            }
 3535        }
 3536        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3537
 3538        let point_to_delete: Option<usize> = {
 3539            let selected_points: Vec<Selection<Point>> =
 3540                self.selections.disjoint_in_range(start..end, cx);
 3541
 3542            if !add || click_count > 1 {
 3543                None
 3544            } else if !selected_points.is_empty() {
 3545                Some(selected_points[0].id)
 3546            } else {
 3547                let clicked_point_already_selected =
 3548                    self.selections.disjoint.iter().find(|selection| {
 3549                        selection.start.to_point(buffer) == start.to_point(buffer)
 3550                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3551                    });
 3552
 3553                clicked_point_already_selected.map(|selection| selection.id)
 3554            }
 3555        };
 3556
 3557        let selections_count = self.selections.count();
 3558        let effects = if auto_scroll {
 3559            SelectionEffects::default()
 3560        } else {
 3561            SelectionEffects::no_scroll()
 3562        };
 3563
 3564        self.change_selections(effects, window, cx, |s| {
 3565            if let Some(point_to_delete) = point_to_delete {
 3566                s.delete(point_to_delete);
 3567
 3568                if selections_count == 1 {
 3569                    s.set_pending_anchor_range(start..end, mode);
 3570                }
 3571            } else {
 3572                if !add {
 3573                    s.clear_disjoint();
 3574                }
 3575
 3576                s.set_pending_anchor_range(start..end, mode);
 3577            }
 3578        });
 3579    }
 3580
 3581    fn begin_columnar_selection(
 3582        &mut self,
 3583        position: DisplayPoint,
 3584        goal_column: u32,
 3585        reset: bool,
 3586        mode: ColumnarMode,
 3587        window: &mut Window,
 3588        cx: &mut Context<Self>,
 3589    ) {
 3590        if !self.focus_handle.is_focused(window) {
 3591            self.last_focused_descendant = None;
 3592            window.focus(&self.focus_handle);
 3593        }
 3594
 3595        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3596
 3597        if reset {
 3598            let pointer_position = display_map
 3599                .buffer_snapshot
 3600                .anchor_before(position.to_point(&display_map));
 3601
 3602            self.change_selections(
 3603                SelectionEffects::scroll(Autoscroll::newest()),
 3604                window,
 3605                cx,
 3606                |s| {
 3607                    s.clear_disjoint();
 3608                    s.set_pending_anchor_range(
 3609                        pointer_position..pointer_position,
 3610                        SelectMode::Character,
 3611                    );
 3612                },
 3613            );
 3614        };
 3615
 3616        let tail = self.selections.newest::<Point>(cx).tail();
 3617        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3618        self.columnar_selection_state = match mode {
 3619            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3620                selection_tail: selection_anchor,
 3621                display_point: if reset {
 3622                    if position.column() != goal_column {
 3623                        Some(DisplayPoint::new(position.row(), goal_column))
 3624                    } else {
 3625                        None
 3626                    }
 3627                } else {
 3628                    None
 3629                },
 3630            }),
 3631            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3632                selection_tail: selection_anchor,
 3633            }),
 3634        };
 3635
 3636        if !reset {
 3637            self.select_columns(position, goal_column, &display_map, window, cx);
 3638        }
 3639    }
 3640
 3641    fn update_selection(
 3642        &mut self,
 3643        position: DisplayPoint,
 3644        goal_column: u32,
 3645        scroll_delta: gpui::Point<f32>,
 3646        window: &mut Window,
 3647        cx: &mut Context<Self>,
 3648    ) {
 3649        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3650
 3651        if self.columnar_selection_state.is_some() {
 3652            self.select_columns(position, goal_column, &display_map, window, cx);
 3653        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3654            let buffer = &display_map.buffer_snapshot;
 3655            let head;
 3656            let tail;
 3657            let mode = self.selections.pending_mode().unwrap();
 3658            match &mode {
 3659                SelectMode::Character => {
 3660                    head = position.to_point(&display_map);
 3661                    tail = pending.tail().to_point(buffer);
 3662                }
 3663                SelectMode::Word(original_range) => {
 3664                    let offset = display_map
 3665                        .clip_point(position, Bias::Left)
 3666                        .to_offset(&display_map, Bias::Left);
 3667                    let original_range = original_range.to_offset(buffer);
 3668
 3669                    let head_offset = if buffer.is_inside_word(offset, false)
 3670                        || original_range.contains(&offset)
 3671                    {
 3672                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3673                        if word_range.start < original_range.start {
 3674                            word_range.start
 3675                        } else {
 3676                            word_range.end
 3677                        }
 3678                    } else {
 3679                        offset
 3680                    };
 3681
 3682                    head = head_offset.to_point(buffer);
 3683                    if head_offset <= original_range.start {
 3684                        tail = original_range.end.to_point(buffer);
 3685                    } else {
 3686                        tail = original_range.start.to_point(buffer);
 3687                    }
 3688                }
 3689                SelectMode::Line(original_range) => {
 3690                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3691
 3692                    let position = display_map
 3693                        .clip_point(position, Bias::Left)
 3694                        .to_point(&display_map);
 3695                    let line_start = display_map.prev_line_boundary(position).0;
 3696                    let next_line_start = buffer.clip_point(
 3697                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3698                        Bias::Left,
 3699                    );
 3700
 3701                    if line_start < original_range.start {
 3702                        head = line_start
 3703                    } else {
 3704                        head = next_line_start
 3705                    }
 3706
 3707                    if head <= original_range.start {
 3708                        tail = original_range.end;
 3709                    } else {
 3710                        tail = original_range.start;
 3711                    }
 3712                }
 3713                SelectMode::All => {
 3714                    return;
 3715                }
 3716            };
 3717
 3718            if head < tail {
 3719                pending.start = buffer.anchor_before(head);
 3720                pending.end = buffer.anchor_before(tail);
 3721                pending.reversed = true;
 3722            } else {
 3723                pending.start = buffer.anchor_before(tail);
 3724                pending.end = buffer.anchor_before(head);
 3725                pending.reversed = false;
 3726            }
 3727
 3728            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3729                s.set_pending(pending, mode);
 3730            });
 3731        } else {
 3732            log::error!("update_selection dispatched with no pending selection");
 3733            return;
 3734        }
 3735
 3736        self.apply_scroll_delta(scroll_delta, window, cx);
 3737        cx.notify();
 3738    }
 3739
 3740    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3741        self.columnar_selection_state.take();
 3742        if self.selections.pending_anchor().is_some() {
 3743            let selections = self.selections.all::<usize>(cx);
 3744            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3745                s.select(selections);
 3746                s.clear_pending();
 3747            });
 3748        }
 3749    }
 3750
 3751    fn select_columns(
 3752        &mut self,
 3753        head: DisplayPoint,
 3754        goal_column: u32,
 3755        display_map: &DisplaySnapshot,
 3756        window: &mut Window,
 3757        cx: &mut Context<Self>,
 3758    ) {
 3759        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3760            return;
 3761        };
 3762
 3763        let tail = match columnar_state {
 3764            ColumnarSelectionState::FromMouse {
 3765                selection_tail,
 3766                display_point,
 3767            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3768            ColumnarSelectionState::FromSelection { selection_tail } => {
 3769                selection_tail.to_display_point(display_map)
 3770            }
 3771        };
 3772
 3773        let start_row = cmp::min(tail.row(), head.row());
 3774        let end_row = cmp::max(tail.row(), head.row());
 3775        let start_column = cmp::min(tail.column(), goal_column);
 3776        let end_column = cmp::max(tail.column(), goal_column);
 3777        let reversed = start_column < tail.column();
 3778
 3779        let selection_ranges = (start_row.0..=end_row.0)
 3780            .map(DisplayRow)
 3781            .filter_map(|row| {
 3782                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3783                    || start_column <= display_map.line_len(row))
 3784                    && !display_map.is_block_line(row)
 3785                {
 3786                    let start = display_map
 3787                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3788                        .to_point(display_map);
 3789                    let end = display_map
 3790                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3791                        .to_point(display_map);
 3792                    if reversed {
 3793                        Some(end..start)
 3794                    } else {
 3795                        Some(start..end)
 3796                    }
 3797                } else {
 3798                    None
 3799                }
 3800            })
 3801            .collect::<Vec<_>>();
 3802
 3803        let ranges = match columnar_state {
 3804            ColumnarSelectionState::FromMouse { .. } => {
 3805                let mut non_empty_ranges = selection_ranges
 3806                    .iter()
 3807                    .filter(|selection_range| selection_range.start != selection_range.end)
 3808                    .peekable();
 3809                if non_empty_ranges.peek().is_some() {
 3810                    non_empty_ranges.cloned().collect()
 3811                } else {
 3812                    selection_ranges
 3813                }
 3814            }
 3815            _ => selection_ranges,
 3816        };
 3817
 3818        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3819            s.select_ranges(ranges);
 3820        });
 3821        cx.notify();
 3822    }
 3823
 3824    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3825        self.selections
 3826            .all_adjusted(cx)
 3827            .iter()
 3828            .any(|selection| !selection.is_empty())
 3829    }
 3830
 3831    pub fn has_pending_nonempty_selection(&self) -> bool {
 3832        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3833            Some(Selection { start, end, .. }) => start != end,
 3834            None => false,
 3835        };
 3836
 3837        pending_nonempty_selection
 3838            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3839    }
 3840
 3841    pub fn has_pending_selection(&self) -> bool {
 3842        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3843    }
 3844
 3845    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3846        self.selection_mark_mode = false;
 3847        self.selection_drag_state = SelectionDragState::None;
 3848
 3849        if self.clear_expanded_diff_hunks(cx) {
 3850            cx.notify();
 3851            return;
 3852        }
 3853        if self.dismiss_menus_and_popups(true, window, cx) {
 3854            return;
 3855        }
 3856
 3857        if self.mode.is_full()
 3858            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3859        {
 3860            return;
 3861        }
 3862
 3863        cx.propagate();
 3864    }
 3865
 3866    pub fn dismiss_menus_and_popups(
 3867        &mut self,
 3868        is_user_requested: bool,
 3869        window: &mut Window,
 3870        cx: &mut Context<Self>,
 3871    ) -> bool {
 3872        if self.take_rename(false, window, cx).is_some() {
 3873            return true;
 3874        }
 3875
 3876        if hide_hover(self, cx) {
 3877            return true;
 3878        }
 3879
 3880        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3881            return true;
 3882        }
 3883
 3884        if self.hide_context_menu(window, cx).is_some() {
 3885            return true;
 3886        }
 3887
 3888        if self.mouse_context_menu.take().is_some() {
 3889            return true;
 3890        }
 3891
 3892        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3893            return true;
 3894        }
 3895
 3896        if self.snippet_stack.pop().is_some() {
 3897            return true;
 3898        }
 3899
 3900        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3901            self.dismiss_diagnostics(cx);
 3902            return true;
 3903        }
 3904
 3905        false
 3906    }
 3907
 3908    fn linked_editing_ranges_for(
 3909        &self,
 3910        selection: Range<text::Anchor>,
 3911        cx: &App,
 3912    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3913        if self.linked_edit_ranges.is_empty() {
 3914            return None;
 3915        }
 3916        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3917            selection.end.buffer_id.and_then(|end_buffer_id| {
 3918                if selection.start.buffer_id != Some(end_buffer_id) {
 3919                    return None;
 3920                }
 3921                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3922                let snapshot = buffer.read(cx).snapshot();
 3923                self.linked_edit_ranges
 3924                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3925                    .map(|ranges| (ranges, snapshot, buffer))
 3926            })?;
 3927        use text::ToOffset as TO;
 3928        // find offset from the start of current range to current cursor position
 3929        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3930
 3931        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3932        let start_difference = start_offset - start_byte_offset;
 3933        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3934        let end_difference = end_offset - start_byte_offset;
 3935        // Current range has associated linked ranges.
 3936        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3937        for range in linked_ranges.iter() {
 3938            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3939            let end_offset = start_offset + end_difference;
 3940            let start_offset = start_offset + start_difference;
 3941            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3942                continue;
 3943            }
 3944            if self.selections.disjoint_anchor_ranges().any(|s| {
 3945                if s.start.buffer_id != selection.start.buffer_id
 3946                    || s.end.buffer_id != selection.end.buffer_id
 3947                {
 3948                    return false;
 3949                }
 3950                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3951                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3952            }) {
 3953                continue;
 3954            }
 3955            let start = buffer_snapshot.anchor_after(start_offset);
 3956            let end = buffer_snapshot.anchor_after(end_offset);
 3957            linked_edits
 3958                .entry(buffer.clone())
 3959                .or_default()
 3960                .push(start..end);
 3961        }
 3962        Some(linked_edits)
 3963    }
 3964
 3965    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3966        let text: Arc<str> = text.into();
 3967
 3968        if self.read_only(cx) {
 3969            return;
 3970        }
 3971
 3972        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3973
 3974        let selections = self.selections.all_adjusted(cx);
 3975        let mut bracket_inserted = false;
 3976        let mut edits = Vec::new();
 3977        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3978        let mut new_selections = Vec::with_capacity(selections.len());
 3979        let mut new_autoclose_regions = Vec::new();
 3980        let snapshot = self.buffer.read(cx).read(cx);
 3981        let mut clear_linked_edit_ranges = false;
 3982
 3983        for (selection, autoclose_region) in
 3984            self.selections_with_autoclose_regions(selections, &snapshot)
 3985        {
 3986            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3987                // Determine if the inserted text matches the opening or closing
 3988                // bracket of any of this language's bracket pairs.
 3989                let mut bracket_pair = None;
 3990                let mut is_bracket_pair_start = false;
 3991                let mut is_bracket_pair_end = false;
 3992                if !text.is_empty() {
 3993                    let mut bracket_pair_matching_end = None;
 3994                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3995                    //  and they are removing the character that triggered IME popup.
 3996                    for (pair, enabled) in scope.brackets() {
 3997                        if !pair.close && !pair.surround {
 3998                            continue;
 3999                        }
 4000
 4001                        if enabled && pair.start.ends_with(text.as_ref()) {
 4002                            let prefix_len = pair.start.len() - text.len();
 4003                            let preceding_text_matches_prefix = prefix_len == 0
 4004                                || (selection.start.column >= (prefix_len as u32)
 4005                                    && snapshot.contains_str_at(
 4006                                        Point::new(
 4007                                            selection.start.row,
 4008                                            selection.start.column - (prefix_len as u32),
 4009                                        ),
 4010                                        &pair.start[..prefix_len],
 4011                                    ));
 4012                            if preceding_text_matches_prefix {
 4013                                bracket_pair = Some(pair.clone());
 4014                                is_bracket_pair_start = true;
 4015                                break;
 4016                            }
 4017                        }
 4018                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4019                        {
 4020                            // take first bracket pair matching end, but don't break in case a later bracket
 4021                            // pair matches start
 4022                            bracket_pair_matching_end = Some(pair.clone());
 4023                        }
 4024                    }
 4025                    if let Some(end) = bracket_pair_matching_end
 4026                        && bracket_pair.is_none()
 4027                    {
 4028                        bracket_pair = Some(end);
 4029                        is_bracket_pair_end = true;
 4030                    }
 4031                }
 4032
 4033                if let Some(bracket_pair) = bracket_pair {
 4034                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4035                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4036                    let auto_surround =
 4037                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4038                    if selection.is_empty() {
 4039                        if is_bracket_pair_start {
 4040                            // If the inserted text is a suffix of an opening bracket and the
 4041                            // selection is preceded by the rest of the opening bracket, then
 4042                            // insert the closing bracket.
 4043                            let following_text_allows_autoclose = snapshot
 4044                                .chars_at(selection.start)
 4045                                .next()
 4046                                .map_or(true, |c| scope.should_autoclose_before(c));
 4047
 4048                            let preceding_text_allows_autoclose = selection.start.column == 0
 4049                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 4050                                    true,
 4051                                    |c| {
 4052                                        bracket_pair.start != bracket_pair.end
 4053                                            || !snapshot
 4054                                                .char_classifier_at(selection.start)
 4055                                                .is_word(c)
 4056                                    },
 4057                                );
 4058
 4059                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4060                                && bracket_pair.start.len() == 1
 4061                            {
 4062                                let target = bracket_pair.start.chars().next().unwrap();
 4063                                let current_line_count = snapshot
 4064                                    .reversed_chars_at(selection.start)
 4065                                    .take_while(|&c| c != '\n')
 4066                                    .filter(|&c| c == target)
 4067                                    .count();
 4068                                current_line_count % 2 == 1
 4069                            } else {
 4070                                false
 4071                            };
 4072
 4073                            if autoclose
 4074                                && bracket_pair.close
 4075                                && following_text_allows_autoclose
 4076                                && preceding_text_allows_autoclose
 4077                                && !is_closing_quote
 4078                            {
 4079                                let anchor = snapshot.anchor_before(selection.end);
 4080                                new_selections.push((selection.map(|_| anchor), text.len()));
 4081                                new_autoclose_regions.push((
 4082                                    anchor,
 4083                                    text.len(),
 4084                                    selection.id,
 4085                                    bracket_pair.clone(),
 4086                                ));
 4087                                edits.push((
 4088                                    selection.range(),
 4089                                    format!("{}{}", text, bracket_pair.end).into(),
 4090                                ));
 4091                                bracket_inserted = true;
 4092                                continue;
 4093                            }
 4094                        }
 4095
 4096                        if let Some(region) = autoclose_region {
 4097                            // If the selection is followed by an auto-inserted closing bracket,
 4098                            // then don't insert that closing bracket again; just move the selection
 4099                            // past the closing bracket.
 4100                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4101                                && text.as_ref() == region.pair.end.as_str()
 4102                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4103                            if should_skip {
 4104                                let anchor = snapshot.anchor_after(selection.end);
 4105                                new_selections
 4106                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4107                                continue;
 4108                            }
 4109                        }
 4110
 4111                        let always_treat_brackets_as_autoclosed = snapshot
 4112                            .language_settings_at(selection.start, cx)
 4113                            .always_treat_brackets_as_autoclosed;
 4114                        if always_treat_brackets_as_autoclosed
 4115                            && is_bracket_pair_end
 4116                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4117                        {
 4118                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4119                            // and the inserted text is a closing bracket and the selection is followed
 4120                            // by the closing bracket then move the selection past the closing bracket.
 4121                            let anchor = snapshot.anchor_after(selection.end);
 4122                            new_selections.push((selection.map(|_| anchor), text.len()));
 4123                            continue;
 4124                        }
 4125                    }
 4126                    // If an opening bracket is 1 character long and is typed while
 4127                    // text is selected, then surround that text with the bracket pair.
 4128                    else if auto_surround
 4129                        && bracket_pair.surround
 4130                        && is_bracket_pair_start
 4131                        && bracket_pair.start.chars().count() == 1
 4132                    {
 4133                        edits.push((selection.start..selection.start, text.clone()));
 4134                        edits.push((
 4135                            selection.end..selection.end,
 4136                            bracket_pair.end.as_str().into(),
 4137                        ));
 4138                        bracket_inserted = true;
 4139                        new_selections.push((
 4140                            Selection {
 4141                                id: selection.id,
 4142                                start: snapshot.anchor_after(selection.start),
 4143                                end: snapshot.anchor_before(selection.end),
 4144                                reversed: selection.reversed,
 4145                                goal: selection.goal,
 4146                            },
 4147                            0,
 4148                        ));
 4149                        continue;
 4150                    }
 4151                }
 4152            }
 4153
 4154            if self.auto_replace_emoji_shortcode
 4155                && selection.is_empty()
 4156                && text.as_ref().ends_with(':')
 4157            {
 4158                if let Some(possible_emoji_short_code) =
 4159                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4160                {
 4161                    if !possible_emoji_short_code.is_empty() {
 4162                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4163                            let emoji_shortcode_start = Point::new(
 4164                                selection.start.row,
 4165                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4166                            );
 4167
 4168                            // Remove shortcode from buffer
 4169                            edits.push((
 4170                                emoji_shortcode_start..selection.start,
 4171                                "".to_string().into(),
 4172                            ));
 4173                            new_selections.push((
 4174                                Selection {
 4175                                    id: selection.id,
 4176                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4177                                    end: snapshot.anchor_before(selection.start),
 4178                                    reversed: selection.reversed,
 4179                                    goal: selection.goal,
 4180                                },
 4181                                0,
 4182                            ));
 4183
 4184                            // Insert emoji
 4185                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4186                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4187                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4188
 4189                            continue;
 4190                        }
 4191                    }
 4192                }
 4193            }
 4194
 4195            // If not handling any auto-close operation, then just replace the selected
 4196            // text with the given input and move the selection to the end of the
 4197            // newly inserted text.
 4198            let anchor = snapshot.anchor_after(selection.end);
 4199            if !self.linked_edit_ranges.is_empty() {
 4200                let start_anchor = snapshot.anchor_before(selection.start);
 4201
 4202                let is_word_char = text.chars().next().map_or(true, |char| {
 4203                    let classifier = snapshot
 4204                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4205                        .ignore_punctuation(true);
 4206                    classifier.is_word(char)
 4207                });
 4208
 4209                if is_word_char {
 4210                    if let Some(ranges) = self
 4211                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4212                    {
 4213                        for (buffer, edits) in ranges {
 4214                            linked_edits
 4215                                .entry(buffer.clone())
 4216                                .or_default()
 4217                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4218                        }
 4219                    }
 4220                } else {
 4221                    clear_linked_edit_ranges = true;
 4222                }
 4223            }
 4224
 4225            new_selections.push((selection.map(|_| anchor), 0));
 4226            edits.push((selection.start..selection.end, text.clone()));
 4227        }
 4228
 4229        drop(snapshot);
 4230
 4231        self.transact(window, cx, |this, window, cx| {
 4232            if clear_linked_edit_ranges {
 4233                this.linked_edit_ranges.clear();
 4234            }
 4235            let initial_buffer_versions =
 4236                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4237
 4238            this.buffer.update(cx, |buffer, cx| {
 4239                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4240            });
 4241            for (buffer, edits) in linked_edits {
 4242                buffer.update(cx, |buffer, cx| {
 4243                    let snapshot = buffer.snapshot();
 4244                    let edits = edits
 4245                        .into_iter()
 4246                        .map(|(range, text)| {
 4247                            use text::ToPoint as TP;
 4248                            let end_point = TP::to_point(&range.end, &snapshot);
 4249                            let start_point = TP::to_point(&range.start, &snapshot);
 4250                            (start_point..end_point, text)
 4251                        })
 4252                        .sorted_by_key(|(range, _)| range.start);
 4253                    buffer.edit(edits, None, cx);
 4254                })
 4255            }
 4256            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4257            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4258            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4259            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4260                .zip(new_selection_deltas)
 4261                .map(|(selection, delta)| Selection {
 4262                    id: selection.id,
 4263                    start: selection.start + delta,
 4264                    end: selection.end + delta,
 4265                    reversed: selection.reversed,
 4266                    goal: SelectionGoal::None,
 4267                })
 4268                .collect::<Vec<_>>();
 4269
 4270            let mut i = 0;
 4271            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4272                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4273                let start = map.buffer_snapshot.anchor_before(position);
 4274                let end = map.buffer_snapshot.anchor_after(position);
 4275                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4276                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4277                        Ordering::Less => i += 1,
 4278                        Ordering::Greater => break,
 4279                        Ordering::Equal => {
 4280                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4281                                Ordering::Less => i += 1,
 4282                                Ordering::Equal => break,
 4283                                Ordering::Greater => break,
 4284                            }
 4285                        }
 4286                    }
 4287                }
 4288                this.autoclose_regions.insert(
 4289                    i,
 4290                    AutocloseRegion {
 4291                        selection_id,
 4292                        range: start..end,
 4293                        pair,
 4294                    },
 4295                );
 4296            }
 4297
 4298            let had_active_edit_prediction = this.has_active_edit_prediction();
 4299            this.change_selections(
 4300                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4301                window,
 4302                cx,
 4303                |s| s.select(new_selections),
 4304            );
 4305
 4306            if !bracket_inserted {
 4307                if let Some(on_type_format_task) =
 4308                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4309                {
 4310                    on_type_format_task.detach_and_log_err(cx);
 4311                }
 4312            }
 4313
 4314            let editor_settings = EditorSettings::get_global(cx);
 4315            if bracket_inserted
 4316                && (editor_settings.auto_signature_help
 4317                    || editor_settings.show_signature_help_after_edits)
 4318            {
 4319                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4320            }
 4321
 4322            let trigger_in_words =
 4323                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4324            if this.hard_wrap.is_some() {
 4325                let latest: Range<Point> = this.selections.newest(cx).range();
 4326                if latest.is_empty()
 4327                    && this
 4328                        .buffer()
 4329                        .read(cx)
 4330                        .snapshot(cx)
 4331                        .line_len(MultiBufferRow(latest.start.row))
 4332                        == latest.start.column
 4333                {
 4334                    this.rewrap_impl(
 4335                        RewrapOptions {
 4336                            override_language_settings: true,
 4337                            preserve_existing_whitespace: true,
 4338                        },
 4339                        cx,
 4340                    )
 4341                }
 4342            }
 4343            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4344            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4345            this.refresh_edit_prediction(true, false, window, cx);
 4346            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4347        });
 4348    }
 4349
 4350    fn find_possible_emoji_shortcode_at_position(
 4351        snapshot: &MultiBufferSnapshot,
 4352        position: Point,
 4353    ) -> Option<String> {
 4354        let mut chars = Vec::new();
 4355        let mut found_colon = false;
 4356        for char in snapshot.reversed_chars_at(position).take(100) {
 4357            // Found a possible emoji shortcode in the middle of the buffer
 4358            if found_colon {
 4359                if char.is_whitespace() {
 4360                    chars.reverse();
 4361                    return Some(chars.iter().collect());
 4362                }
 4363                // If the previous character is not a whitespace, we are in the middle of a word
 4364                // and we only want to complete the shortcode if the word is made up of other emojis
 4365                let mut containing_word = String::new();
 4366                for ch in snapshot
 4367                    .reversed_chars_at(position)
 4368                    .skip(chars.len() + 1)
 4369                    .take(100)
 4370                {
 4371                    if ch.is_whitespace() {
 4372                        break;
 4373                    }
 4374                    containing_word.push(ch);
 4375                }
 4376                let containing_word = containing_word.chars().rev().collect::<String>();
 4377                if util::word_consists_of_emojis(containing_word.as_str()) {
 4378                    chars.reverse();
 4379                    return Some(chars.iter().collect());
 4380                }
 4381            }
 4382
 4383            if char.is_whitespace() || !char.is_ascii() {
 4384                return None;
 4385            }
 4386            if char == ':' {
 4387                found_colon = true;
 4388            } else {
 4389                chars.push(char);
 4390            }
 4391        }
 4392        // Found a possible emoji shortcode at the beginning of the buffer
 4393        chars.reverse();
 4394        Some(chars.iter().collect())
 4395    }
 4396
 4397    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4399        self.transact(window, cx, |this, window, cx| {
 4400            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4401                let selections = this.selections.all::<usize>(cx);
 4402                let multi_buffer = this.buffer.read(cx);
 4403                let buffer = multi_buffer.snapshot(cx);
 4404                selections
 4405                    .iter()
 4406                    .map(|selection| {
 4407                        let start_point = selection.start.to_point(&buffer);
 4408                        let mut existing_indent =
 4409                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4410                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4411                        let start = selection.start;
 4412                        let end = selection.end;
 4413                        let selection_is_empty = start == end;
 4414                        let language_scope = buffer.language_scope_at(start);
 4415                        let (
 4416                            comment_delimiter,
 4417                            doc_delimiter,
 4418                            insert_extra_newline,
 4419                            indent_on_newline,
 4420                            indent_on_extra_newline,
 4421                        ) = if let Some(language) = &language_scope {
 4422                            let mut insert_extra_newline =
 4423                                insert_extra_newline_brackets(&buffer, start..end, language)
 4424                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4425
 4426                            // Comment extension on newline is allowed only for cursor selections
 4427                            let comment_delimiter = maybe!({
 4428                                if !selection_is_empty {
 4429                                    return None;
 4430                                }
 4431
 4432                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4433                                    return None;
 4434                                }
 4435
 4436                                let delimiters = language.line_comment_prefixes();
 4437                                let max_len_of_delimiter =
 4438                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4439                                let (snapshot, range) =
 4440                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4441
 4442                                let num_of_whitespaces = snapshot
 4443                                    .chars_for_range(range.clone())
 4444                                    .take_while(|c| c.is_whitespace())
 4445                                    .count();
 4446                                let comment_candidate = snapshot
 4447                                    .chars_for_range(range.clone())
 4448                                    .skip(num_of_whitespaces)
 4449                                    .take(max_len_of_delimiter)
 4450                                    .collect::<String>();
 4451                                let (delimiter, trimmed_len) = delimiters
 4452                                    .iter()
 4453                                    .filter_map(|delimiter| {
 4454                                        let prefix = delimiter.trim_end();
 4455                                        if comment_candidate.starts_with(prefix) {
 4456                                            Some((delimiter, prefix.len()))
 4457                                        } else {
 4458                                            None
 4459                                        }
 4460                                    })
 4461                                    .max_by_key(|(_, len)| *len)?;
 4462
 4463                                if let Some(BlockCommentConfig {
 4464                                    start: block_start, ..
 4465                                }) = language.block_comment()
 4466                                {
 4467                                    let block_start_trimmed = block_start.trim_end();
 4468                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4469                                        let line_content = snapshot
 4470                                            .chars_for_range(range)
 4471                                            .skip(num_of_whitespaces)
 4472                                            .take(block_start_trimmed.len())
 4473                                            .collect::<String>();
 4474
 4475                                        if line_content.starts_with(block_start_trimmed) {
 4476                                            return None;
 4477                                        }
 4478                                    }
 4479                                }
 4480
 4481                                let cursor_is_placed_after_comment_marker =
 4482                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4483                                if cursor_is_placed_after_comment_marker {
 4484                                    Some(delimiter.clone())
 4485                                } else {
 4486                                    None
 4487                                }
 4488                            });
 4489
 4490                            let mut indent_on_newline = IndentSize::spaces(0);
 4491                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4492
 4493                            let doc_delimiter = maybe!({
 4494                                if !selection_is_empty {
 4495                                    return None;
 4496                                }
 4497
 4498                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4499                                    return None;
 4500                                }
 4501
 4502                                let BlockCommentConfig {
 4503                                    start: start_tag,
 4504                                    end: end_tag,
 4505                                    prefix: delimiter,
 4506                                    tab_size: len,
 4507                                } = language.documentation_comment()?;
 4508                                let is_within_block_comment = buffer
 4509                                    .language_scope_at(start_point)
 4510                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4511                                if !is_within_block_comment {
 4512                                    return None;
 4513                                }
 4514
 4515                                let (snapshot, range) =
 4516                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4517
 4518                                let num_of_whitespaces = snapshot
 4519                                    .chars_for_range(range.clone())
 4520                                    .take_while(|c| c.is_whitespace())
 4521                                    .count();
 4522
 4523                                // 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.
 4524                                let column = start_point.column;
 4525                                let cursor_is_after_start_tag = {
 4526                                    let start_tag_len = start_tag.len();
 4527                                    let start_tag_line = snapshot
 4528                                        .chars_for_range(range.clone())
 4529                                        .skip(num_of_whitespaces)
 4530                                        .take(start_tag_len)
 4531                                        .collect::<String>();
 4532                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4533                                        num_of_whitespaces + start_tag_len <= column as usize
 4534                                    } else {
 4535                                        false
 4536                                    }
 4537                                };
 4538
 4539                                let cursor_is_after_delimiter = {
 4540                                    let delimiter_trim = delimiter.trim_end();
 4541                                    let delimiter_line = snapshot
 4542                                        .chars_for_range(range.clone())
 4543                                        .skip(num_of_whitespaces)
 4544                                        .take(delimiter_trim.len())
 4545                                        .collect::<String>();
 4546                                    if delimiter_line.starts_with(delimiter_trim) {
 4547                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4548                                    } else {
 4549                                        false
 4550                                    }
 4551                                };
 4552
 4553                                let cursor_is_before_end_tag_if_exists = {
 4554                                    let mut char_position = 0u32;
 4555                                    let mut end_tag_offset = None;
 4556
 4557                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4558                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4559                                            let chars_before_match =
 4560                                                chunk[..byte_pos].chars().count() as u32;
 4561                                            end_tag_offset =
 4562                                                Some(char_position + chars_before_match);
 4563                                            break 'outer;
 4564                                        }
 4565                                        char_position += chunk.chars().count() as u32;
 4566                                    }
 4567
 4568                                    if let Some(end_tag_offset) = end_tag_offset {
 4569                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4570                                        if cursor_is_after_start_tag {
 4571                                            if cursor_is_before_end_tag {
 4572                                                insert_extra_newline = true;
 4573                                            }
 4574                                            let cursor_is_at_start_of_end_tag =
 4575                                                column == end_tag_offset;
 4576                                            if cursor_is_at_start_of_end_tag {
 4577                                                indent_on_extra_newline.len = *len;
 4578                                            }
 4579                                        }
 4580                                        cursor_is_before_end_tag
 4581                                    } else {
 4582                                        true
 4583                                    }
 4584                                };
 4585
 4586                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4587                                    && cursor_is_before_end_tag_if_exists
 4588                                {
 4589                                    if cursor_is_after_start_tag {
 4590                                        indent_on_newline.len = *len;
 4591                                    }
 4592                                    Some(delimiter.clone())
 4593                                } else {
 4594                                    None
 4595                                }
 4596                            });
 4597
 4598                            (
 4599                                comment_delimiter,
 4600                                doc_delimiter,
 4601                                insert_extra_newline,
 4602                                indent_on_newline,
 4603                                indent_on_extra_newline,
 4604                            )
 4605                        } else {
 4606                            (
 4607                                None,
 4608                                None,
 4609                                false,
 4610                                IndentSize::default(),
 4611                                IndentSize::default(),
 4612                            )
 4613                        };
 4614
 4615                        let prevent_auto_indent = doc_delimiter.is_some();
 4616                        let delimiter = comment_delimiter.or(doc_delimiter);
 4617
 4618                        let capacity_for_delimiter =
 4619                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4620                        let mut new_text = String::with_capacity(
 4621                            1 + capacity_for_delimiter
 4622                                + existing_indent.len as usize
 4623                                + indent_on_newline.len as usize
 4624                                + indent_on_extra_newline.len as usize,
 4625                        );
 4626                        new_text.push('\n');
 4627                        new_text.extend(existing_indent.chars());
 4628                        new_text.extend(indent_on_newline.chars());
 4629
 4630                        if let Some(delimiter) = &delimiter {
 4631                            new_text.push_str(delimiter);
 4632                        }
 4633
 4634                        if insert_extra_newline {
 4635                            new_text.push('\n');
 4636                            new_text.extend(existing_indent.chars());
 4637                            new_text.extend(indent_on_extra_newline.chars());
 4638                        }
 4639
 4640                        let anchor = buffer.anchor_after(end);
 4641                        let new_selection = selection.map(|_| anchor);
 4642                        (
 4643                            ((start..end, new_text), prevent_auto_indent),
 4644                            (insert_extra_newline, new_selection),
 4645                        )
 4646                    })
 4647                    .unzip()
 4648            };
 4649
 4650            let mut auto_indent_edits = Vec::new();
 4651            let mut edits = Vec::new();
 4652            for (edit, prevent_auto_indent) in edits_with_flags {
 4653                if prevent_auto_indent {
 4654                    edits.push(edit);
 4655                } else {
 4656                    auto_indent_edits.push(edit);
 4657                }
 4658            }
 4659            if !edits.is_empty() {
 4660                this.edit(edits, cx);
 4661            }
 4662            if !auto_indent_edits.is_empty() {
 4663                this.edit_with_autoindent(auto_indent_edits, cx);
 4664            }
 4665
 4666            let buffer = this.buffer.read(cx).snapshot(cx);
 4667            let new_selections = selection_info
 4668                .into_iter()
 4669                .map(|(extra_newline_inserted, new_selection)| {
 4670                    let mut cursor = new_selection.end.to_point(&buffer);
 4671                    if extra_newline_inserted {
 4672                        cursor.row -= 1;
 4673                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4674                    }
 4675                    new_selection.map(|_| cursor)
 4676                })
 4677                .collect();
 4678
 4679            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4680            this.refresh_edit_prediction(true, false, window, cx);
 4681        });
 4682    }
 4683
 4684    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4685        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4686
 4687        let buffer = self.buffer.read(cx);
 4688        let snapshot = buffer.snapshot(cx);
 4689
 4690        let mut edits = Vec::new();
 4691        let mut rows = Vec::new();
 4692
 4693        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4694            let cursor = selection.head();
 4695            let row = cursor.row;
 4696
 4697            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4698
 4699            let newline = "\n".to_string();
 4700            edits.push((start_of_line..start_of_line, newline));
 4701
 4702            rows.push(row + rows_inserted as u32);
 4703        }
 4704
 4705        self.transact(window, cx, |editor, window, cx| {
 4706            editor.edit(edits, cx);
 4707
 4708            editor.change_selections(Default::default(), window, cx, |s| {
 4709                let mut index = 0;
 4710                s.move_cursors_with(|map, _, _| {
 4711                    let row = rows[index];
 4712                    index += 1;
 4713
 4714                    let point = Point::new(row, 0);
 4715                    let boundary = map.next_line_boundary(point).1;
 4716                    let clipped = map.clip_point(boundary, Bias::Left);
 4717
 4718                    (clipped, SelectionGoal::None)
 4719                });
 4720            });
 4721
 4722            let mut indent_edits = Vec::new();
 4723            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4724            for row in rows {
 4725                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4726                for (row, indent) in indents {
 4727                    if indent.len == 0 {
 4728                        continue;
 4729                    }
 4730
 4731                    let text = match indent.kind {
 4732                        IndentKind::Space => " ".repeat(indent.len as usize),
 4733                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4734                    };
 4735                    let point = Point::new(row.0, 0);
 4736                    indent_edits.push((point..point, text));
 4737                }
 4738            }
 4739            editor.edit(indent_edits, cx);
 4740        });
 4741    }
 4742
 4743    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4744        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4745
 4746        let buffer = self.buffer.read(cx);
 4747        let snapshot = buffer.snapshot(cx);
 4748
 4749        let mut edits = Vec::new();
 4750        let mut rows = Vec::new();
 4751        let mut rows_inserted = 0;
 4752
 4753        for selection in self.selections.all_adjusted(cx) {
 4754            let cursor = selection.head();
 4755            let row = cursor.row;
 4756
 4757            let point = Point::new(row + 1, 0);
 4758            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4759
 4760            let newline = "\n".to_string();
 4761            edits.push((start_of_line..start_of_line, newline));
 4762
 4763            rows_inserted += 1;
 4764            rows.push(row + rows_inserted);
 4765        }
 4766
 4767        self.transact(window, cx, |editor, window, cx| {
 4768            editor.edit(edits, cx);
 4769
 4770            editor.change_selections(Default::default(), window, cx, |s| {
 4771                let mut index = 0;
 4772                s.move_cursors_with(|map, _, _| {
 4773                    let row = rows[index];
 4774                    index += 1;
 4775
 4776                    let point = Point::new(row, 0);
 4777                    let boundary = map.next_line_boundary(point).1;
 4778                    let clipped = map.clip_point(boundary, Bias::Left);
 4779
 4780                    (clipped, SelectionGoal::None)
 4781                });
 4782            });
 4783
 4784            let mut indent_edits = Vec::new();
 4785            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4786            for row in rows {
 4787                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4788                for (row, indent) in indents {
 4789                    if indent.len == 0 {
 4790                        continue;
 4791                    }
 4792
 4793                    let text = match indent.kind {
 4794                        IndentKind::Space => " ".repeat(indent.len as usize),
 4795                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4796                    };
 4797                    let point = Point::new(row.0, 0);
 4798                    indent_edits.push((point..point, text));
 4799                }
 4800            }
 4801            editor.edit(indent_edits, cx);
 4802        });
 4803    }
 4804
 4805    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4806        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4807            original_indent_columns: Vec::new(),
 4808        });
 4809        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4810    }
 4811
 4812    fn insert_with_autoindent_mode(
 4813        &mut self,
 4814        text: &str,
 4815        autoindent_mode: Option<AutoindentMode>,
 4816        window: &mut Window,
 4817        cx: &mut Context<Self>,
 4818    ) {
 4819        if self.read_only(cx) {
 4820            return;
 4821        }
 4822
 4823        let text: Arc<str> = text.into();
 4824        self.transact(window, cx, |this, window, cx| {
 4825            let old_selections = this.selections.all_adjusted(cx);
 4826            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4827                let anchors = {
 4828                    let snapshot = buffer.read(cx);
 4829                    old_selections
 4830                        .iter()
 4831                        .map(|s| {
 4832                            let anchor = snapshot.anchor_after(s.head());
 4833                            s.map(|_| anchor)
 4834                        })
 4835                        .collect::<Vec<_>>()
 4836                };
 4837                buffer.edit(
 4838                    old_selections
 4839                        .iter()
 4840                        .map(|s| (s.start..s.end, text.clone())),
 4841                    autoindent_mode,
 4842                    cx,
 4843                );
 4844                anchors
 4845            });
 4846
 4847            this.change_selections(Default::default(), window, cx, |s| {
 4848                s.select_anchors(selection_anchors);
 4849            });
 4850
 4851            cx.notify();
 4852        });
 4853    }
 4854
 4855    fn trigger_completion_on_input(
 4856        &mut self,
 4857        text: &str,
 4858        trigger_in_words: bool,
 4859        window: &mut Window,
 4860        cx: &mut Context<Self>,
 4861    ) {
 4862        let completions_source = self
 4863            .context_menu
 4864            .borrow()
 4865            .as_ref()
 4866            .and_then(|menu| match menu {
 4867                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4868                CodeContextMenu::CodeActions(_) => None,
 4869            });
 4870
 4871        match completions_source {
 4872            Some(CompletionsMenuSource::Words) => {
 4873                self.show_word_completions(&ShowWordCompletions, window, cx)
 4874            }
 4875            Some(CompletionsMenuSource::Normal)
 4876            | Some(CompletionsMenuSource::SnippetChoices)
 4877            | None
 4878                if self.is_completion_trigger(
 4879                    text,
 4880                    trigger_in_words,
 4881                    completions_source.is_some(),
 4882                    cx,
 4883                ) =>
 4884            {
 4885                self.show_completions(
 4886                    &ShowCompletions {
 4887                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4888                    },
 4889                    window,
 4890                    cx,
 4891                )
 4892            }
 4893            _ => {
 4894                self.hide_context_menu(window, cx);
 4895            }
 4896        }
 4897    }
 4898
 4899    fn is_completion_trigger(
 4900        &self,
 4901        text: &str,
 4902        trigger_in_words: bool,
 4903        menu_is_open: bool,
 4904        cx: &mut Context<Self>,
 4905    ) -> bool {
 4906        let position = self.selections.newest_anchor().head();
 4907        let multibuffer = self.buffer.read(cx);
 4908        let Some(buffer) = position
 4909            .buffer_id
 4910            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4911        else {
 4912            return false;
 4913        };
 4914
 4915        if let Some(completion_provider) = &self.completion_provider {
 4916            completion_provider.is_completion_trigger(
 4917                &buffer,
 4918                position.text_anchor,
 4919                text,
 4920                trigger_in_words,
 4921                menu_is_open,
 4922                cx,
 4923            )
 4924        } else {
 4925            false
 4926        }
 4927    }
 4928
 4929    /// If any empty selections is touching the start of its innermost containing autoclose
 4930    /// region, expand it to select the brackets.
 4931    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4932        let selections = self.selections.all::<usize>(cx);
 4933        let buffer = self.buffer.read(cx).read(cx);
 4934        let new_selections = self
 4935            .selections_with_autoclose_regions(selections, &buffer)
 4936            .map(|(mut selection, region)| {
 4937                if !selection.is_empty() {
 4938                    return selection;
 4939                }
 4940
 4941                if let Some(region) = region {
 4942                    let mut range = region.range.to_offset(&buffer);
 4943                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4944                        range.start -= region.pair.start.len();
 4945                        if buffer.contains_str_at(range.start, &region.pair.start)
 4946                            && buffer.contains_str_at(range.end, &region.pair.end)
 4947                        {
 4948                            range.end += region.pair.end.len();
 4949                            selection.start = range.start;
 4950                            selection.end = range.end;
 4951
 4952                            return selection;
 4953                        }
 4954                    }
 4955                }
 4956
 4957                let always_treat_brackets_as_autoclosed = buffer
 4958                    .language_settings_at(selection.start, cx)
 4959                    .always_treat_brackets_as_autoclosed;
 4960
 4961                if !always_treat_brackets_as_autoclosed {
 4962                    return selection;
 4963                }
 4964
 4965                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4966                    for (pair, enabled) in scope.brackets() {
 4967                        if !enabled || !pair.close {
 4968                            continue;
 4969                        }
 4970
 4971                        if buffer.contains_str_at(selection.start, &pair.end) {
 4972                            let pair_start_len = pair.start.len();
 4973                            if buffer.contains_str_at(
 4974                                selection.start.saturating_sub(pair_start_len),
 4975                                &pair.start,
 4976                            ) {
 4977                                selection.start -= pair_start_len;
 4978                                selection.end += pair.end.len();
 4979
 4980                                return selection;
 4981                            }
 4982                        }
 4983                    }
 4984                }
 4985
 4986                selection
 4987            })
 4988            .collect();
 4989
 4990        drop(buffer);
 4991        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4992            selections.select(new_selections)
 4993        });
 4994    }
 4995
 4996    /// Iterate the given selections, and for each one, find the smallest surrounding
 4997    /// autoclose region. This uses the ordering of the selections and the autoclose
 4998    /// regions to avoid repeated comparisons.
 4999    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5000        &'a self,
 5001        selections: impl IntoIterator<Item = Selection<D>>,
 5002        buffer: &'a MultiBufferSnapshot,
 5003    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5004        let mut i = 0;
 5005        let mut regions = self.autoclose_regions.as_slice();
 5006        selections.into_iter().map(move |selection| {
 5007            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5008
 5009            let mut enclosing = None;
 5010            while let Some(pair_state) = regions.get(i) {
 5011                if pair_state.range.end.to_offset(buffer) < range.start {
 5012                    regions = &regions[i + 1..];
 5013                    i = 0;
 5014                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5015                    break;
 5016                } else {
 5017                    if pair_state.selection_id == selection.id {
 5018                        enclosing = Some(pair_state);
 5019                    }
 5020                    i += 1;
 5021                }
 5022            }
 5023
 5024            (selection, enclosing)
 5025        })
 5026    }
 5027
 5028    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5029    fn invalidate_autoclose_regions(
 5030        &mut self,
 5031        mut selections: &[Selection<Anchor>],
 5032        buffer: &MultiBufferSnapshot,
 5033    ) {
 5034        self.autoclose_regions.retain(|state| {
 5035            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5036                return false;
 5037            }
 5038
 5039            let mut i = 0;
 5040            while let Some(selection) = selections.get(i) {
 5041                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5042                    selections = &selections[1..];
 5043                    continue;
 5044                }
 5045                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5046                    break;
 5047                }
 5048                if selection.id == state.selection_id {
 5049                    return true;
 5050                } else {
 5051                    i += 1;
 5052                }
 5053            }
 5054            false
 5055        });
 5056    }
 5057
 5058    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5059        let offset = position.to_offset(buffer);
 5060        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5061        if offset > word_range.start && kind == Some(CharKind::Word) {
 5062            Some(
 5063                buffer
 5064                    .text_for_range(word_range.start..offset)
 5065                    .collect::<String>(),
 5066            )
 5067        } else {
 5068            None
 5069        }
 5070    }
 5071
 5072    pub fn toggle_inline_values(
 5073        &mut self,
 5074        _: &ToggleInlineValues,
 5075        _: &mut Window,
 5076        cx: &mut Context<Self>,
 5077    ) {
 5078        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5079
 5080        self.refresh_inline_values(cx);
 5081    }
 5082
 5083    pub fn toggle_inlay_hints(
 5084        &mut self,
 5085        _: &ToggleInlayHints,
 5086        _: &mut Window,
 5087        cx: &mut Context<Self>,
 5088    ) {
 5089        self.refresh_inlay_hints(
 5090            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5091            cx,
 5092        );
 5093    }
 5094
 5095    pub fn inlay_hints_enabled(&self) -> bool {
 5096        self.inlay_hint_cache.enabled
 5097    }
 5098
 5099    pub fn inline_values_enabled(&self) -> bool {
 5100        self.inline_value_cache.enabled
 5101    }
 5102
 5103    #[cfg(any(test, feature = "test-support"))]
 5104    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5105        self.display_map
 5106            .read(cx)
 5107            .current_inlays()
 5108            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5109            .cloned()
 5110            .collect()
 5111    }
 5112
 5113    #[cfg(any(test, feature = "test-support"))]
 5114    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5115        self.display_map
 5116            .read(cx)
 5117            .current_inlays()
 5118            .cloned()
 5119            .collect()
 5120    }
 5121
 5122    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5123        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5124            return;
 5125        }
 5126
 5127        let reason_description = reason.description();
 5128        let ignore_debounce = matches!(
 5129            reason,
 5130            InlayHintRefreshReason::SettingsChange(_)
 5131                | InlayHintRefreshReason::Toggle(_)
 5132                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5133                | InlayHintRefreshReason::ModifiersChanged(_)
 5134        );
 5135        let (invalidate_cache, required_languages) = match reason {
 5136            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5137                match self.inlay_hint_cache.modifiers_override(enabled) {
 5138                    Some(enabled) => {
 5139                        if enabled {
 5140                            (InvalidationStrategy::RefreshRequested, None)
 5141                        } else {
 5142                            self.splice_inlays(
 5143                                &self
 5144                                    .visible_inlay_hints(cx)
 5145                                    .iter()
 5146                                    .map(|inlay| inlay.id)
 5147                                    .collect::<Vec<InlayId>>(),
 5148                                Vec::new(),
 5149                                cx,
 5150                            );
 5151                            return;
 5152                        }
 5153                    }
 5154                    None => return,
 5155                }
 5156            }
 5157            InlayHintRefreshReason::Toggle(enabled) => {
 5158                if self.inlay_hint_cache.toggle(enabled) {
 5159                    if enabled {
 5160                        (InvalidationStrategy::RefreshRequested, None)
 5161                    } else {
 5162                        self.splice_inlays(
 5163                            &self
 5164                                .visible_inlay_hints(cx)
 5165                                .iter()
 5166                                .map(|inlay| inlay.id)
 5167                                .collect::<Vec<InlayId>>(),
 5168                            Vec::new(),
 5169                            cx,
 5170                        );
 5171                        return;
 5172                    }
 5173                } else {
 5174                    return;
 5175                }
 5176            }
 5177            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5178                match self.inlay_hint_cache.update_settings(
 5179                    &self.buffer,
 5180                    new_settings,
 5181                    self.visible_inlay_hints(cx),
 5182                    cx,
 5183                ) {
 5184                    ControlFlow::Break(Some(InlaySplice {
 5185                        to_remove,
 5186                        to_insert,
 5187                    })) => {
 5188                        self.splice_inlays(&to_remove, to_insert, cx);
 5189                        return;
 5190                    }
 5191                    ControlFlow::Break(None) => return,
 5192                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5193                }
 5194            }
 5195            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5196                if let Some(InlaySplice {
 5197                    to_remove,
 5198                    to_insert,
 5199                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5200                {
 5201                    self.splice_inlays(&to_remove, to_insert, cx);
 5202                }
 5203                self.display_map.update(cx, |display_map, _| {
 5204                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5205                });
 5206                return;
 5207            }
 5208            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5209            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5210                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5211            }
 5212            InlayHintRefreshReason::RefreshRequested => {
 5213                (InvalidationStrategy::RefreshRequested, None)
 5214            }
 5215        };
 5216
 5217        if let Some(InlaySplice {
 5218            to_remove,
 5219            to_insert,
 5220        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5221            reason_description,
 5222            self.visible_excerpts(required_languages.as_ref(), cx),
 5223            invalidate_cache,
 5224            ignore_debounce,
 5225            cx,
 5226        ) {
 5227            self.splice_inlays(&to_remove, to_insert, cx);
 5228        }
 5229    }
 5230
 5231    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5232        self.display_map
 5233            .read(cx)
 5234            .current_inlays()
 5235            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5236            .cloned()
 5237            .collect()
 5238    }
 5239
 5240    pub fn visible_excerpts(
 5241        &self,
 5242        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5243        cx: &mut Context<Editor>,
 5244    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5245        let Some(project) = self.project() else {
 5246            return HashMap::default();
 5247        };
 5248        let project = project.read(cx);
 5249        let multi_buffer = self.buffer().read(cx);
 5250        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5251        let multi_buffer_visible_start = self
 5252            .scroll_manager
 5253            .anchor()
 5254            .anchor
 5255            .to_point(&multi_buffer_snapshot);
 5256        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5257            multi_buffer_visible_start
 5258                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5259            Bias::Left,
 5260        );
 5261        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5262        multi_buffer_snapshot
 5263            .range_to_buffer_ranges(multi_buffer_visible_range)
 5264            .into_iter()
 5265            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5266            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5267                let buffer_file = project::File::from_dyn(buffer.file())?;
 5268                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5269                let worktree_entry = buffer_worktree
 5270                    .read(cx)
 5271                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5272                if worktree_entry.is_ignored {
 5273                    return None;
 5274                }
 5275
 5276                let language = buffer.language()?;
 5277                if let Some(restrict_to_languages) = restrict_to_languages {
 5278                    if !restrict_to_languages.contains(language) {
 5279                        return None;
 5280                    }
 5281                }
 5282                Some((
 5283                    excerpt_id,
 5284                    (
 5285                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5286                        buffer.version().clone(),
 5287                        excerpt_visible_range,
 5288                    ),
 5289                ))
 5290            })
 5291            .collect()
 5292    }
 5293
 5294    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5295        TextLayoutDetails {
 5296            text_system: window.text_system().clone(),
 5297            editor_style: self.style.clone().unwrap(),
 5298            rem_size: window.rem_size(),
 5299            scroll_anchor: self.scroll_manager.anchor(),
 5300            visible_rows: self.visible_line_count(),
 5301            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5302        }
 5303    }
 5304
 5305    pub fn splice_inlays(
 5306        &self,
 5307        to_remove: &[InlayId],
 5308        to_insert: Vec<Inlay>,
 5309        cx: &mut Context<Self>,
 5310    ) {
 5311        self.display_map.update(cx, |display_map, cx| {
 5312            display_map.splice_inlays(to_remove, to_insert, cx)
 5313        });
 5314        cx.notify();
 5315    }
 5316
 5317    fn trigger_on_type_formatting(
 5318        &self,
 5319        input: String,
 5320        window: &mut Window,
 5321        cx: &mut Context<Self>,
 5322    ) -> Option<Task<Result<()>>> {
 5323        if input.len() != 1 {
 5324            return None;
 5325        }
 5326
 5327        let project = self.project()?;
 5328        let position = self.selections.newest_anchor().head();
 5329        let (buffer, buffer_position) = self
 5330            .buffer
 5331            .read(cx)
 5332            .text_anchor_for_position(position, cx)?;
 5333
 5334        let settings = language_settings::language_settings(
 5335            buffer
 5336                .read(cx)
 5337                .language_at(buffer_position)
 5338                .map(|l| l.name()),
 5339            buffer.read(cx).file(),
 5340            cx,
 5341        );
 5342        if !settings.use_on_type_format {
 5343            return None;
 5344        }
 5345
 5346        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5347        // hence we do LSP request & edit on host side only — add formats to host's history.
 5348        let push_to_lsp_host_history = true;
 5349        // If this is not the host, append its history with new edits.
 5350        let push_to_client_history = project.read(cx).is_via_collab();
 5351
 5352        let on_type_formatting = project.update(cx, |project, cx| {
 5353            project.on_type_format(
 5354                buffer.clone(),
 5355                buffer_position,
 5356                input,
 5357                push_to_lsp_host_history,
 5358                cx,
 5359            )
 5360        });
 5361        Some(cx.spawn_in(window, async move |editor, cx| {
 5362            if let Some(transaction) = on_type_formatting.await? {
 5363                if push_to_client_history {
 5364                    buffer
 5365                        .update(cx, |buffer, _| {
 5366                            buffer.push_transaction(transaction, Instant::now());
 5367                            buffer.finalize_last_transaction();
 5368                        })
 5369                        .ok();
 5370                }
 5371                editor.update(cx, |editor, cx| {
 5372                    editor.refresh_document_highlights(cx);
 5373                })?;
 5374            }
 5375            Ok(())
 5376        }))
 5377    }
 5378
 5379    pub fn show_word_completions(
 5380        &mut self,
 5381        _: &ShowWordCompletions,
 5382        window: &mut Window,
 5383        cx: &mut Context<Self>,
 5384    ) {
 5385        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5386    }
 5387
 5388    pub fn show_completions(
 5389        &mut self,
 5390        options: &ShowCompletions,
 5391        window: &mut Window,
 5392        cx: &mut Context<Self>,
 5393    ) {
 5394        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5395    }
 5396
 5397    fn open_or_update_completions_menu(
 5398        &mut self,
 5399        requested_source: Option<CompletionsMenuSource>,
 5400        trigger: Option<&str>,
 5401        window: &mut Window,
 5402        cx: &mut Context<Self>,
 5403    ) {
 5404        if self.pending_rename.is_some() {
 5405            return;
 5406        }
 5407
 5408        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5409
 5410        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5411        // inserted and selected. To handle that case, the start of the selection is used so that
 5412        // the menu starts with all choices.
 5413        let position = self
 5414            .selections
 5415            .newest_anchor()
 5416            .start
 5417            .bias_right(&multibuffer_snapshot);
 5418        if position.diff_base_anchor.is_some() {
 5419            return;
 5420        }
 5421        let (buffer, buffer_position) =
 5422            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5423                output
 5424            } else {
 5425                return;
 5426            };
 5427        let buffer_snapshot = buffer.read(cx).snapshot();
 5428
 5429        let query: Option<Arc<String>> =
 5430            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5431
 5432        drop(multibuffer_snapshot);
 5433
 5434        let provider = match requested_source {
 5435            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5436            Some(CompletionsMenuSource::Words) => None,
 5437            Some(CompletionsMenuSource::SnippetChoices) => {
 5438                log::error!("bug: SnippetChoices requested_source is not handled");
 5439                None
 5440            }
 5441        };
 5442
 5443        let sort_completions = provider
 5444            .as_ref()
 5445            .map_or(false, |provider| provider.sort_completions());
 5446
 5447        let filter_completions = provider
 5448            .as_ref()
 5449            .map_or(true, |provider| provider.filter_completions());
 5450
 5451        let trigger_kind = match trigger {
 5452            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5453                CompletionTriggerKind::TRIGGER_CHARACTER
 5454            }
 5455            _ => CompletionTriggerKind::INVOKED,
 5456        };
 5457        let completion_context = CompletionContext {
 5458            trigger_character: trigger.and_then(|trigger| {
 5459                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5460                    Some(String::from(trigger))
 5461                } else {
 5462                    None
 5463                }
 5464            }),
 5465            trigger_kind,
 5466        };
 5467
 5468        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5469        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5470        // involve trigger chars, so this is skipped in that case.
 5471        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5472        {
 5473            let menu_is_open = matches!(
 5474                self.context_menu.borrow().as_ref(),
 5475                Some(CodeContextMenu::Completions(_))
 5476            );
 5477            if menu_is_open {
 5478                self.hide_context_menu(window, cx);
 5479            }
 5480        }
 5481
 5482        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5483            if filter_completions {
 5484                menu.filter(query.clone(), provider.clone(), window, cx);
 5485            }
 5486            // When `is_incomplete` is false, no need to re-query completions when the current query
 5487            // is a suffix of the initial query.
 5488            if !menu.is_incomplete {
 5489                // If the new query is a suffix of the old query (typing more characters) and
 5490                // the previous result was complete, the existing completions can be filtered.
 5491                //
 5492                // Note that this is always true for snippet completions.
 5493                let query_matches = match (&menu.initial_query, &query) {
 5494                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5495                    (None, _) => true,
 5496                    _ => false,
 5497                };
 5498                if query_matches {
 5499                    let position_matches = if menu.initial_position == position {
 5500                        true
 5501                    } else {
 5502                        let snapshot = self.buffer.read(cx).read(cx);
 5503                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5504                    };
 5505                    if position_matches {
 5506                        return;
 5507                    }
 5508                }
 5509            }
 5510        };
 5511
 5512        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5513            buffer_snapshot.surrounding_word(buffer_position, false)
 5514        {
 5515            let word_to_exclude = buffer_snapshot
 5516                .text_for_range(word_range.clone())
 5517                .collect::<String>();
 5518            (
 5519                buffer_snapshot.anchor_before(word_range.start)
 5520                    ..buffer_snapshot.anchor_after(buffer_position),
 5521                Some(word_to_exclude),
 5522            )
 5523        } else {
 5524            (buffer_position..buffer_position, None)
 5525        };
 5526
 5527        let language = buffer_snapshot
 5528            .language_at(buffer_position)
 5529            .map(|language| language.name());
 5530
 5531        let completion_settings =
 5532            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5533
 5534        let show_completion_documentation = buffer_snapshot
 5535            .settings_at(buffer_position, cx)
 5536            .show_completion_documentation;
 5537
 5538        // The document can be large, so stay in reasonable bounds when searching for words,
 5539        // otherwise completion pop-up might be slow to appear.
 5540        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5541        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5542        let min_word_search = buffer_snapshot.clip_point(
 5543            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5544            Bias::Left,
 5545        );
 5546        let max_word_search = buffer_snapshot.clip_point(
 5547            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5548            Bias::Right,
 5549        );
 5550        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5551            ..buffer_snapshot.point_to_offset(max_word_search);
 5552
 5553        let skip_digits = query
 5554            .as_ref()
 5555            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5556
 5557        let (mut words, provider_responses) = match &provider {
 5558            Some(provider) => {
 5559                let provider_responses = provider.completions(
 5560                    position.excerpt_id,
 5561                    &buffer,
 5562                    buffer_position,
 5563                    completion_context,
 5564                    window,
 5565                    cx,
 5566                );
 5567
 5568                let words = match completion_settings.words {
 5569                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5570                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5571                        .background_spawn(async move {
 5572                            buffer_snapshot.words_in_range(WordsQuery {
 5573                                fuzzy_contents: None,
 5574                                range: word_search_range,
 5575                                skip_digits,
 5576                            })
 5577                        }),
 5578                };
 5579
 5580                (words, provider_responses)
 5581            }
 5582            None => (
 5583                cx.background_spawn(async move {
 5584                    buffer_snapshot.words_in_range(WordsQuery {
 5585                        fuzzy_contents: None,
 5586                        range: word_search_range,
 5587                        skip_digits,
 5588                    })
 5589                }),
 5590                Task::ready(Ok(Vec::new())),
 5591            ),
 5592        };
 5593
 5594        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5595
 5596        let id = post_inc(&mut self.next_completion_id);
 5597        let task = cx.spawn_in(window, async move |editor, cx| {
 5598            let Ok(()) = editor.update(cx, |this, _| {
 5599                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5600            }) else {
 5601                return;
 5602            };
 5603
 5604            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5605            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5606            let mut completions = Vec::new();
 5607            let mut is_incomplete = false;
 5608            if let Some(provider_responses) = provider_responses.await.log_err() {
 5609                if !provider_responses.is_empty() {
 5610                    for response in provider_responses {
 5611                        completions.extend(response.completions);
 5612                        is_incomplete = is_incomplete || response.is_incomplete;
 5613                    }
 5614                    if completion_settings.words == WordsCompletionMode::Fallback {
 5615                        words = Task::ready(BTreeMap::default());
 5616                    }
 5617                }
 5618            }
 5619
 5620            let mut words = words.await;
 5621            if let Some(word_to_exclude) = &word_to_exclude {
 5622                words.remove(word_to_exclude);
 5623            }
 5624            for lsp_completion in &completions {
 5625                words.remove(&lsp_completion.new_text);
 5626            }
 5627            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5628                replace_range: word_replace_range.clone(),
 5629                new_text: word.clone(),
 5630                label: CodeLabel::plain(word, None),
 5631                icon_path: None,
 5632                documentation: None,
 5633                source: CompletionSource::BufferWord {
 5634                    word_range,
 5635                    resolved: false,
 5636                },
 5637                insert_text_mode: Some(InsertTextMode::AS_IS),
 5638                confirm: None,
 5639            }));
 5640
 5641            let menu = if completions.is_empty() {
 5642                None
 5643            } else {
 5644                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5645                    let languages = editor
 5646                        .workspace
 5647                        .as_ref()
 5648                        .and_then(|(workspace, _)| workspace.upgrade())
 5649                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5650                    let menu = CompletionsMenu::new(
 5651                        id,
 5652                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5653                        sort_completions,
 5654                        show_completion_documentation,
 5655                        position,
 5656                        query.clone(),
 5657                        is_incomplete,
 5658                        buffer.clone(),
 5659                        completions.into(),
 5660                        snippet_sort_order,
 5661                        languages,
 5662                        language,
 5663                        cx,
 5664                    );
 5665
 5666                    let query = if filter_completions { query } else { None };
 5667                    let matches_task = if let Some(query) = query {
 5668                        menu.do_async_filtering(query, cx)
 5669                    } else {
 5670                        Task::ready(menu.unfiltered_matches())
 5671                    };
 5672                    (menu, matches_task)
 5673                }) else {
 5674                    return;
 5675                };
 5676
 5677                let matches = matches_task.await;
 5678
 5679                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5680                    // Newer menu already set, so exit.
 5681                    match editor.context_menu.borrow().as_ref() {
 5682                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5683                            if prev_menu.id > id {
 5684                                return;
 5685                            }
 5686                        }
 5687                        _ => {}
 5688                    };
 5689
 5690                    // Only valid to take prev_menu because it the new menu is immediately set
 5691                    // below, or the menu is hidden.
 5692                    match editor.context_menu.borrow_mut().take() {
 5693                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5694                            let position_matches =
 5695                                if prev_menu.initial_position == menu.initial_position {
 5696                                    true
 5697                                } else {
 5698                                    let snapshot = editor.buffer.read(cx).read(cx);
 5699                                    prev_menu.initial_position.to_offset(&snapshot)
 5700                                        == menu.initial_position.to_offset(&snapshot)
 5701                                };
 5702                            if position_matches {
 5703                                // Preserve markdown cache before `set_filter_results` because it will
 5704                                // try to populate the documentation cache.
 5705                                menu.preserve_markdown_cache(prev_menu);
 5706                            }
 5707                        }
 5708                        _ => {}
 5709                    };
 5710
 5711                    menu.set_filter_results(matches, provider, window, cx);
 5712                }) else {
 5713                    return;
 5714                };
 5715
 5716                menu.visible().then_some(menu)
 5717            };
 5718
 5719            editor
 5720                .update_in(cx, |editor, window, cx| {
 5721                    if editor.focus_handle.is_focused(window) {
 5722                        if let Some(menu) = menu {
 5723                            *editor.context_menu.borrow_mut() =
 5724                                Some(CodeContextMenu::Completions(menu));
 5725
 5726                            crate::hover_popover::hide_hover(editor, cx);
 5727                            if editor.show_edit_predictions_in_menu() {
 5728                                editor.update_visible_edit_prediction(window, cx);
 5729                            } else {
 5730                                editor.discard_edit_prediction(false, cx);
 5731                            }
 5732
 5733                            cx.notify();
 5734                            return;
 5735                        }
 5736                    }
 5737
 5738                    if editor.completion_tasks.len() <= 1 {
 5739                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5740                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5741                        // If it was already hidden and we don't show edit predictions in the menu,
 5742                        // we should also show the edit prediction when available.
 5743                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5744                            editor.update_visible_edit_prediction(window, cx);
 5745                        }
 5746                    }
 5747                })
 5748                .ok();
 5749        });
 5750
 5751        self.completion_tasks.push((id, task));
 5752    }
 5753
 5754    #[cfg(feature = "test-support")]
 5755    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5756        let menu = self.context_menu.borrow();
 5757        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5758            let completions = menu.completions.borrow();
 5759            Some(completions.to_vec())
 5760        } else {
 5761            None
 5762        }
 5763    }
 5764
 5765    pub fn with_completions_menu_matching_id<R>(
 5766        &self,
 5767        id: CompletionId,
 5768        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5769    ) -> R {
 5770        let mut context_menu = self.context_menu.borrow_mut();
 5771        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5772            return f(None);
 5773        };
 5774        if completions_menu.id != id {
 5775            return f(None);
 5776        }
 5777        f(Some(completions_menu))
 5778    }
 5779
 5780    pub fn confirm_completion(
 5781        &mut self,
 5782        action: &ConfirmCompletion,
 5783        window: &mut Window,
 5784        cx: &mut Context<Self>,
 5785    ) -> Option<Task<Result<()>>> {
 5786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5787        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5788    }
 5789
 5790    pub fn confirm_completion_insert(
 5791        &mut self,
 5792        _: &ConfirmCompletionInsert,
 5793        window: &mut Window,
 5794        cx: &mut Context<Self>,
 5795    ) -> Option<Task<Result<()>>> {
 5796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5797        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5798    }
 5799
 5800    pub fn confirm_completion_replace(
 5801        &mut self,
 5802        _: &ConfirmCompletionReplace,
 5803        window: &mut Window,
 5804        cx: &mut Context<Self>,
 5805    ) -> Option<Task<Result<()>>> {
 5806        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5807        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5808    }
 5809
 5810    pub fn compose_completion(
 5811        &mut self,
 5812        action: &ComposeCompletion,
 5813        window: &mut Window,
 5814        cx: &mut Context<Self>,
 5815    ) -> Option<Task<Result<()>>> {
 5816        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5817        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5818    }
 5819
 5820    fn do_completion(
 5821        &mut self,
 5822        item_ix: Option<usize>,
 5823        intent: CompletionIntent,
 5824        window: &mut Window,
 5825        cx: &mut Context<Editor>,
 5826    ) -> Option<Task<Result<()>>> {
 5827        use language::ToOffset as _;
 5828
 5829        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5830        else {
 5831            return None;
 5832        };
 5833
 5834        let candidate_id = {
 5835            let entries = completions_menu.entries.borrow();
 5836            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5837            if self.show_edit_predictions_in_menu() {
 5838                self.discard_edit_prediction(true, cx);
 5839            }
 5840            mat.candidate_id
 5841        };
 5842
 5843        let completion = completions_menu
 5844            .completions
 5845            .borrow()
 5846            .get(candidate_id)?
 5847            .clone();
 5848        cx.stop_propagation();
 5849
 5850        let buffer_handle = completions_menu.buffer.clone();
 5851
 5852        let CompletionEdit {
 5853            new_text,
 5854            snippet,
 5855            replace_range,
 5856        } = process_completion_for_edit(
 5857            &completion,
 5858            intent,
 5859            &buffer_handle,
 5860            &completions_menu.initial_position.text_anchor,
 5861            cx,
 5862        );
 5863
 5864        let buffer = buffer_handle.read(cx);
 5865        let snapshot = self.buffer.read(cx).snapshot(cx);
 5866        let newest_anchor = self.selections.newest_anchor();
 5867        let replace_range_multibuffer = {
 5868            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5869            let multibuffer_anchor = snapshot
 5870                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5871                .unwrap()
 5872                ..snapshot
 5873                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5874                    .unwrap();
 5875            multibuffer_anchor.start.to_offset(&snapshot)
 5876                ..multibuffer_anchor.end.to_offset(&snapshot)
 5877        };
 5878        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5879            return None;
 5880        }
 5881
 5882        let old_text = buffer
 5883            .text_for_range(replace_range.clone())
 5884            .collect::<String>();
 5885        let lookbehind = newest_anchor
 5886            .start
 5887            .text_anchor
 5888            .to_offset(buffer)
 5889            .saturating_sub(replace_range.start);
 5890        let lookahead = replace_range
 5891            .end
 5892            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5893        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5894        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5895
 5896        let selections = self.selections.all::<usize>(cx);
 5897        let mut ranges = Vec::new();
 5898        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5899
 5900        for selection in &selections {
 5901            let range = if selection.id == newest_anchor.id {
 5902                replace_range_multibuffer.clone()
 5903            } else {
 5904                let mut range = selection.range();
 5905
 5906                // if prefix is present, don't duplicate it
 5907                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5908                    range.start = range.start.saturating_sub(lookbehind);
 5909
 5910                    // if suffix is also present, mimic the newest cursor and replace it
 5911                    if selection.id != newest_anchor.id
 5912                        && snapshot.contains_str_at(range.end, suffix)
 5913                    {
 5914                        range.end += lookahead;
 5915                    }
 5916                }
 5917                range
 5918            };
 5919
 5920            ranges.push(range.clone());
 5921
 5922            if !self.linked_edit_ranges.is_empty() {
 5923                let start_anchor = snapshot.anchor_before(range.start);
 5924                let end_anchor = snapshot.anchor_after(range.end);
 5925                if let Some(ranges) = self
 5926                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5927                {
 5928                    for (buffer, edits) in ranges {
 5929                        linked_edits
 5930                            .entry(buffer.clone())
 5931                            .or_default()
 5932                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5933                    }
 5934                }
 5935            }
 5936        }
 5937
 5938        let common_prefix_len = old_text
 5939            .chars()
 5940            .zip(new_text.chars())
 5941            .take_while(|(a, b)| a == b)
 5942            .map(|(a, _)| a.len_utf8())
 5943            .sum::<usize>();
 5944
 5945        cx.emit(EditorEvent::InputHandled {
 5946            utf16_range_to_replace: None,
 5947            text: new_text[common_prefix_len..].into(),
 5948        });
 5949
 5950        self.transact(window, cx, |editor, window, cx| {
 5951            if let Some(mut snippet) = snippet {
 5952                snippet.text = new_text.to_string();
 5953                editor
 5954                    .insert_snippet(&ranges, snippet, window, cx)
 5955                    .log_err();
 5956            } else {
 5957                editor.buffer.update(cx, |multi_buffer, cx| {
 5958                    let auto_indent = match completion.insert_text_mode {
 5959                        Some(InsertTextMode::AS_IS) => None,
 5960                        _ => editor.autoindent_mode.clone(),
 5961                    };
 5962                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5963                    multi_buffer.edit(edits, auto_indent, cx);
 5964                });
 5965            }
 5966            for (buffer, edits) in linked_edits {
 5967                buffer.update(cx, |buffer, cx| {
 5968                    let snapshot = buffer.snapshot();
 5969                    let edits = edits
 5970                        .into_iter()
 5971                        .map(|(range, text)| {
 5972                            use text::ToPoint as TP;
 5973                            let end_point = TP::to_point(&range.end, &snapshot);
 5974                            let start_point = TP::to_point(&range.start, &snapshot);
 5975                            (start_point..end_point, text)
 5976                        })
 5977                        .sorted_by_key(|(range, _)| range.start);
 5978                    buffer.edit(edits, None, cx);
 5979                })
 5980            }
 5981
 5982            editor.refresh_edit_prediction(true, false, window, cx);
 5983        });
 5984        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5985
 5986        let show_new_completions_on_confirm = completion
 5987            .confirm
 5988            .as_ref()
 5989            .map_or(false, |confirm| confirm(intent, window, cx));
 5990        if show_new_completions_on_confirm {
 5991            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5992        }
 5993
 5994        let provider = self.completion_provider.as_ref()?;
 5995        drop(completion);
 5996        let apply_edits = provider.apply_additional_edits_for_completion(
 5997            buffer_handle,
 5998            completions_menu.completions.clone(),
 5999            candidate_id,
 6000            true,
 6001            cx,
 6002        );
 6003
 6004        let editor_settings = EditorSettings::get_global(cx);
 6005        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6006            // After the code completion is finished, users often want to know what signatures are needed.
 6007            // so we should automatically call signature_help
 6008            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6009        }
 6010
 6011        Some(cx.foreground_executor().spawn(async move {
 6012            apply_edits.await?;
 6013            Ok(())
 6014        }))
 6015    }
 6016
 6017    pub fn toggle_code_actions(
 6018        &mut self,
 6019        action: &ToggleCodeActions,
 6020        window: &mut Window,
 6021        cx: &mut Context<Self>,
 6022    ) {
 6023        let quick_launch = action.quick_launch;
 6024        let mut context_menu = self.context_menu.borrow_mut();
 6025        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6026            if code_actions.deployed_from == action.deployed_from {
 6027                // Toggle if we're selecting the same one
 6028                *context_menu = None;
 6029                cx.notify();
 6030                return;
 6031            } else {
 6032                // Otherwise, clear it and start a new one
 6033                *context_menu = None;
 6034                cx.notify();
 6035            }
 6036        }
 6037        drop(context_menu);
 6038        let snapshot = self.snapshot(window, cx);
 6039        let deployed_from = action.deployed_from.clone();
 6040        let action = action.clone();
 6041        self.completion_tasks.clear();
 6042        self.discard_edit_prediction(false, cx);
 6043
 6044        let multibuffer_point = match &action.deployed_from {
 6045            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6046                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6047            }
 6048            _ => self.selections.newest::<Point>(cx).head(),
 6049        };
 6050        let Some((buffer, buffer_row)) = snapshot
 6051            .buffer_snapshot
 6052            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6053            .and_then(|(buffer_snapshot, range)| {
 6054                self.buffer()
 6055                    .read(cx)
 6056                    .buffer(buffer_snapshot.remote_id())
 6057                    .map(|buffer| (buffer, range.start.row))
 6058            })
 6059        else {
 6060            return;
 6061        };
 6062        let buffer_id = buffer.read(cx).remote_id();
 6063        let tasks = self
 6064            .tasks
 6065            .get(&(buffer_id, buffer_row))
 6066            .map(|t| Arc::new(t.to_owned()));
 6067
 6068        if !self.focus_handle.is_focused(window) {
 6069            return;
 6070        }
 6071        let project = self.project.clone();
 6072
 6073        let code_actions_task = match deployed_from {
 6074            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6075            _ => self.code_actions(buffer_row, window, cx),
 6076        };
 6077
 6078        let runnable_task = match deployed_from {
 6079            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6080            _ => {
 6081                let mut task_context_task = Task::ready(None);
 6082                if let Some(tasks) = &tasks {
 6083                    if let Some(project) = project {
 6084                        task_context_task =
 6085                            Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6086                    }
 6087                }
 6088
 6089                cx.spawn_in(window, {
 6090                    let buffer = buffer.clone();
 6091                    async move |editor, cx| {
 6092                        let task_context = task_context_task.await;
 6093
 6094                        let resolved_tasks =
 6095                            tasks
 6096                                .zip(task_context.clone())
 6097                                .map(|(tasks, task_context)| ResolvedTasks {
 6098                                    templates: tasks.resolve(&task_context).collect(),
 6099                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6100                                        multibuffer_point.row,
 6101                                        tasks.column,
 6102                                    )),
 6103                                });
 6104                        let debug_scenarios = editor
 6105                            .update(cx, |editor, cx| {
 6106                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6107                            })?
 6108                            .await;
 6109                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6110                    }
 6111                })
 6112            }
 6113        };
 6114
 6115        cx.spawn_in(window, async move |editor, cx| {
 6116            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6117            let code_actions = code_actions_task.await;
 6118            let spawn_straight_away = quick_launch
 6119                && resolved_tasks
 6120                    .as_ref()
 6121                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6122                && code_actions
 6123                    .as_ref()
 6124                    .map_or(true, |actions| actions.is_empty())
 6125                && debug_scenarios.is_empty();
 6126
 6127            editor.update_in(cx, |editor, window, cx| {
 6128                crate::hover_popover::hide_hover(editor, cx);
 6129                let actions = CodeActionContents::new(
 6130                    resolved_tasks,
 6131                    code_actions,
 6132                    debug_scenarios,
 6133                    task_context.unwrap_or_default(),
 6134                );
 6135
 6136                // Don't show the menu if there are no actions available
 6137                if actions.is_empty() {
 6138                    cx.notify();
 6139                    return Task::ready(Ok(()));
 6140                }
 6141
 6142                *editor.context_menu.borrow_mut() =
 6143                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6144                        buffer,
 6145                        actions,
 6146                        selected_item: Default::default(),
 6147                        scroll_handle: UniformListScrollHandle::default(),
 6148                        deployed_from,
 6149                    }));
 6150                cx.notify();
 6151                if spawn_straight_away {
 6152                    if let Some(task) = editor.confirm_code_action(
 6153                        &ConfirmCodeAction { item_ix: Some(0) },
 6154                        window,
 6155                        cx,
 6156                    ) {
 6157                        return task;
 6158                    }
 6159                }
 6160
 6161                Task::ready(Ok(()))
 6162            })
 6163        })
 6164        .detach_and_log_err(cx);
 6165    }
 6166
 6167    fn debug_scenarios(
 6168        &mut self,
 6169        resolved_tasks: &Option<ResolvedTasks>,
 6170        buffer: &Entity<Buffer>,
 6171        cx: &mut App,
 6172    ) -> Task<Vec<task::DebugScenario>> {
 6173        maybe!({
 6174            let project = self.project()?;
 6175            let dap_store = project.read(cx).dap_store();
 6176            let mut scenarios = vec![];
 6177            let resolved_tasks = resolved_tasks.as_ref()?;
 6178            let buffer = buffer.read(cx);
 6179            let language = buffer.language()?;
 6180            let file = buffer.file();
 6181            let debug_adapter = language_settings(language.name().into(), file, cx)
 6182                .debuggers
 6183                .first()
 6184                .map(SharedString::from)
 6185                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6186
 6187            dap_store.update(cx, |dap_store, cx| {
 6188                for (_, task) in &resolved_tasks.templates {
 6189                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6190                        task.original_task().clone(),
 6191                        debug_adapter.clone().into(),
 6192                        task.display_label().to_owned().into(),
 6193                        cx,
 6194                    );
 6195                    scenarios.push(maybe_scenario);
 6196                }
 6197            });
 6198            Some(cx.background_spawn(async move {
 6199                let scenarios = futures::future::join_all(scenarios)
 6200                    .await
 6201                    .into_iter()
 6202                    .flatten()
 6203                    .collect::<Vec<_>>();
 6204                scenarios
 6205            }))
 6206        })
 6207        .unwrap_or_else(|| Task::ready(vec![]))
 6208    }
 6209
 6210    fn code_actions(
 6211        &mut self,
 6212        buffer_row: u32,
 6213        window: &mut Window,
 6214        cx: &mut Context<Self>,
 6215    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6216        let mut task = self.code_actions_task.take();
 6217        cx.spawn_in(window, async move |editor, cx| {
 6218            while let Some(prev_task) = task {
 6219                prev_task.await.log_err();
 6220                task = editor
 6221                    .update(cx, |this, _| this.code_actions_task.take())
 6222                    .ok()?;
 6223            }
 6224
 6225            editor
 6226                .update(cx, |editor, cx| {
 6227                    editor
 6228                        .available_code_actions
 6229                        .clone()
 6230                        .and_then(|(location, code_actions)| {
 6231                            let snapshot = location.buffer.read(cx).snapshot();
 6232                            let point_range = location.range.to_point(&snapshot);
 6233                            let point_range = point_range.start.row..=point_range.end.row;
 6234                            if point_range.contains(&buffer_row) {
 6235                                Some(code_actions)
 6236                            } else {
 6237                                None
 6238                            }
 6239                        })
 6240                })
 6241                .ok()
 6242                .flatten()
 6243        })
 6244    }
 6245
 6246    pub fn confirm_code_action(
 6247        &mut self,
 6248        action: &ConfirmCodeAction,
 6249        window: &mut Window,
 6250        cx: &mut Context<Self>,
 6251    ) -> Option<Task<Result<()>>> {
 6252        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6253
 6254        let actions_menu =
 6255            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6256                menu
 6257            } else {
 6258                return None;
 6259            };
 6260
 6261        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6262        let action = actions_menu.actions.get(action_ix)?;
 6263        let title = action.label();
 6264        let buffer = actions_menu.buffer;
 6265        let workspace = self.workspace()?;
 6266
 6267        match action {
 6268            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6269                workspace.update(cx, |workspace, cx| {
 6270                    workspace.schedule_resolved_task(
 6271                        task_source_kind,
 6272                        resolved_task,
 6273                        false,
 6274                        window,
 6275                        cx,
 6276                    );
 6277
 6278                    Some(Task::ready(Ok(())))
 6279                })
 6280            }
 6281            CodeActionsItem::CodeAction {
 6282                excerpt_id,
 6283                action,
 6284                provider,
 6285            } => {
 6286                let apply_code_action =
 6287                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6288                let workspace = workspace.downgrade();
 6289                Some(cx.spawn_in(window, async move |editor, cx| {
 6290                    let project_transaction = apply_code_action.await?;
 6291                    Self::open_project_transaction(
 6292                        &editor,
 6293                        workspace,
 6294                        project_transaction,
 6295                        title,
 6296                        cx,
 6297                    )
 6298                    .await
 6299                }))
 6300            }
 6301            CodeActionsItem::DebugScenario(scenario) => {
 6302                let context = actions_menu.actions.context.clone();
 6303
 6304                workspace.update(cx, |workspace, cx| {
 6305                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6306                    workspace.start_debug_session(
 6307                        scenario,
 6308                        context,
 6309                        Some(buffer),
 6310                        None,
 6311                        window,
 6312                        cx,
 6313                    );
 6314                });
 6315                Some(Task::ready(Ok(())))
 6316            }
 6317        }
 6318    }
 6319
 6320    pub async fn open_project_transaction(
 6321        this: &WeakEntity<Editor>,
 6322        workspace: WeakEntity<Workspace>,
 6323        transaction: ProjectTransaction,
 6324        title: String,
 6325        cx: &mut AsyncWindowContext,
 6326    ) -> Result<()> {
 6327        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6328        cx.update(|_, cx| {
 6329            entries.sort_unstable_by_key(|(buffer, _)| {
 6330                buffer.read(cx).file().map(|f| f.path().clone())
 6331            });
 6332        })?;
 6333
 6334        // If the project transaction's edits are all contained within this editor, then
 6335        // avoid opening a new editor to display them.
 6336
 6337        if let Some((buffer, transaction)) = entries.first() {
 6338            if entries.len() == 1 {
 6339                let excerpt = this.update(cx, |editor, cx| {
 6340                    editor
 6341                        .buffer()
 6342                        .read(cx)
 6343                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6344                })?;
 6345                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6346                    if excerpted_buffer == *buffer {
 6347                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6348                            let excerpt_range = excerpt_range.to_offset(buffer);
 6349                            buffer
 6350                                .edited_ranges_for_transaction::<usize>(transaction)
 6351                                .all(|range| {
 6352                                    excerpt_range.start <= range.start
 6353                                        && excerpt_range.end >= range.end
 6354                                })
 6355                        })?;
 6356
 6357                        if all_edits_within_excerpt {
 6358                            return Ok(());
 6359                        }
 6360                    }
 6361                }
 6362            }
 6363        } else {
 6364            return Ok(());
 6365        }
 6366
 6367        let mut ranges_to_highlight = Vec::new();
 6368        let excerpt_buffer = cx.new(|cx| {
 6369            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6370            for (buffer_handle, transaction) in &entries {
 6371                let edited_ranges = buffer_handle
 6372                    .read(cx)
 6373                    .edited_ranges_for_transaction::<Point>(transaction)
 6374                    .collect::<Vec<_>>();
 6375                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6376                    PathKey::for_buffer(buffer_handle, cx),
 6377                    buffer_handle.clone(),
 6378                    edited_ranges,
 6379                    DEFAULT_MULTIBUFFER_CONTEXT,
 6380                    cx,
 6381                );
 6382
 6383                ranges_to_highlight.extend(ranges);
 6384            }
 6385            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6386            multibuffer
 6387        })?;
 6388
 6389        workspace.update_in(cx, |workspace, window, cx| {
 6390            let project = workspace.project().clone();
 6391            let editor =
 6392                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6393            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6394            editor.update(cx, |editor, cx| {
 6395                editor.highlight_background::<Self>(
 6396                    &ranges_to_highlight,
 6397                    |theme| theme.colors().editor_highlighted_line_background,
 6398                    cx,
 6399                );
 6400            });
 6401        })?;
 6402
 6403        Ok(())
 6404    }
 6405
 6406    pub fn clear_code_action_providers(&mut self) {
 6407        self.code_action_providers.clear();
 6408        self.available_code_actions.take();
 6409    }
 6410
 6411    pub fn add_code_action_provider(
 6412        &mut self,
 6413        provider: Rc<dyn CodeActionProvider>,
 6414        window: &mut Window,
 6415        cx: &mut Context<Self>,
 6416    ) {
 6417        if self
 6418            .code_action_providers
 6419            .iter()
 6420            .any(|existing_provider| existing_provider.id() == provider.id())
 6421        {
 6422            return;
 6423        }
 6424
 6425        self.code_action_providers.push(provider);
 6426        self.refresh_code_actions(window, cx);
 6427    }
 6428
 6429    pub fn remove_code_action_provider(
 6430        &mut self,
 6431        id: Arc<str>,
 6432        window: &mut Window,
 6433        cx: &mut Context<Self>,
 6434    ) {
 6435        self.code_action_providers
 6436            .retain(|provider| provider.id() != id);
 6437        self.refresh_code_actions(window, cx);
 6438    }
 6439
 6440    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6441        !self.code_action_providers.is_empty()
 6442            && EditorSettings::get_global(cx).toolbar.code_actions
 6443    }
 6444
 6445    pub fn has_available_code_actions(&self) -> bool {
 6446        self.available_code_actions
 6447            .as_ref()
 6448            .is_some_and(|(_, actions)| !actions.is_empty())
 6449    }
 6450
 6451    fn render_inline_code_actions(
 6452        &self,
 6453        icon_size: ui::IconSize,
 6454        display_row: DisplayRow,
 6455        is_active: bool,
 6456        cx: &mut Context<Self>,
 6457    ) -> AnyElement {
 6458        let show_tooltip = !self.context_menu_visible();
 6459        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6460            .icon_size(icon_size)
 6461            .shape(ui::IconButtonShape::Square)
 6462            .icon_color(ui::Color::Hidden)
 6463            .toggle_state(is_active)
 6464            .when(show_tooltip, |this| {
 6465                this.tooltip({
 6466                    let focus_handle = self.focus_handle.clone();
 6467                    move |window, cx| {
 6468                        Tooltip::for_action_in(
 6469                            "Toggle Code Actions",
 6470                            &ToggleCodeActions {
 6471                                deployed_from: None,
 6472                                quick_launch: false,
 6473                            },
 6474                            &focus_handle,
 6475                            window,
 6476                            cx,
 6477                        )
 6478                    }
 6479                })
 6480            })
 6481            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6482                window.focus(&editor.focus_handle(cx));
 6483                editor.toggle_code_actions(
 6484                    &crate::actions::ToggleCodeActions {
 6485                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6486                            display_row,
 6487                        )),
 6488                        quick_launch: false,
 6489                    },
 6490                    window,
 6491                    cx,
 6492                );
 6493            }))
 6494            .into_any_element()
 6495    }
 6496
 6497    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6498        &self.context_menu
 6499    }
 6500
 6501    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6502        let newest_selection = self.selections.newest_anchor().clone();
 6503        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6504        let buffer = self.buffer.read(cx);
 6505        if newest_selection.head().diff_base_anchor.is_some() {
 6506            return None;
 6507        }
 6508        let (start_buffer, start) =
 6509            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6510        let (end_buffer, end) =
 6511            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6512        if start_buffer != end_buffer {
 6513            return None;
 6514        }
 6515
 6516        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6517            cx.background_executor()
 6518                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6519                .await;
 6520
 6521            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6522                let providers = this.code_action_providers.clone();
 6523                let tasks = this
 6524                    .code_action_providers
 6525                    .iter()
 6526                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6527                    .collect::<Vec<_>>();
 6528                (providers, tasks)
 6529            })?;
 6530
 6531            let mut actions = Vec::new();
 6532            for (provider, provider_actions) in
 6533                providers.into_iter().zip(future::join_all(tasks).await)
 6534            {
 6535                if let Some(provider_actions) = provider_actions.log_err() {
 6536                    actions.extend(provider_actions.into_iter().map(|action| {
 6537                        AvailableCodeAction {
 6538                            excerpt_id: newest_selection.start.excerpt_id,
 6539                            action,
 6540                            provider: provider.clone(),
 6541                        }
 6542                    }));
 6543                }
 6544            }
 6545
 6546            this.update(cx, |this, cx| {
 6547                this.available_code_actions = if actions.is_empty() {
 6548                    None
 6549                } else {
 6550                    Some((
 6551                        Location {
 6552                            buffer: start_buffer,
 6553                            range: start..end,
 6554                        },
 6555                        actions.into(),
 6556                    ))
 6557                };
 6558                cx.notify();
 6559            })
 6560        }));
 6561        None
 6562    }
 6563
 6564    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6565        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6566            self.show_git_blame_inline = false;
 6567
 6568            self.show_git_blame_inline_delay_task =
 6569                Some(cx.spawn_in(window, async move |this, cx| {
 6570                    cx.background_executor().timer(delay).await;
 6571
 6572                    this.update(cx, |this, cx| {
 6573                        this.show_git_blame_inline = true;
 6574                        cx.notify();
 6575                    })
 6576                    .log_err();
 6577                }));
 6578        }
 6579    }
 6580
 6581    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6582        let snapshot = self.snapshot(window, cx);
 6583        let cursor = self.selections.newest::<Point>(cx).head();
 6584        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6585        else {
 6586            return;
 6587        };
 6588
 6589        let Some(blame) = self.blame.as_ref() else {
 6590            return;
 6591        };
 6592
 6593        let row_info = RowInfo {
 6594            buffer_id: Some(buffer.remote_id()),
 6595            buffer_row: Some(point.row),
 6596            ..Default::default()
 6597        };
 6598        let Some(blame_entry) = blame
 6599            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6600            .flatten()
 6601        else {
 6602            return;
 6603        };
 6604
 6605        let anchor = self.selections.newest_anchor().head();
 6606        let position = self.to_pixel_point(anchor, &snapshot, window);
 6607        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6608            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6609        };
 6610    }
 6611
 6612    fn show_blame_popover(
 6613        &mut self,
 6614        blame_entry: &BlameEntry,
 6615        position: gpui::Point<Pixels>,
 6616        ignore_timeout: bool,
 6617        cx: &mut Context<Self>,
 6618    ) {
 6619        if let Some(state) = &mut self.inline_blame_popover {
 6620            state.hide_task.take();
 6621        } else {
 6622            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6623            let blame_entry = blame_entry.clone();
 6624            let show_task = cx.spawn(async move |editor, cx| {
 6625                if !ignore_timeout {
 6626                    cx.background_executor()
 6627                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6628                        .await;
 6629                }
 6630                editor
 6631                    .update(cx, |editor, cx| {
 6632                        editor.inline_blame_popover_show_task.take();
 6633                        let Some(blame) = editor.blame.as_ref() else {
 6634                            return;
 6635                        };
 6636                        let blame = blame.read(cx);
 6637                        let details = blame.details_for_entry(&blame_entry);
 6638                        let markdown = cx.new(|cx| {
 6639                            Markdown::new(
 6640                                details
 6641                                    .as_ref()
 6642                                    .map(|message| message.message.clone())
 6643                                    .unwrap_or_default(),
 6644                                None,
 6645                                None,
 6646                                cx,
 6647                            )
 6648                        });
 6649                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6650                            position,
 6651                            hide_task: None,
 6652                            popover_bounds: None,
 6653                            popover_state: InlineBlamePopoverState {
 6654                                scroll_handle: ScrollHandle::new(),
 6655                                commit_message: details,
 6656                                markdown,
 6657                            },
 6658                            keyboard_grace: ignore_timeout,
 6659                        });
 6660                        cx.notify();
 6661                    })
 6662                    .ok();
 6663            });
 6664            self.inline_blame_popover_show_task = Some(show_task);
 6665        }
 6666    }
 6667
 6668    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6669        self.inline_blame_popover_show_task.take();
 6670        if let Some(state) = &mut self.inline_blame_popover {
 6671            let hide_task = cx.spawn(async move |editor, cx| {
 6672                cx.background_executor()
 6673                    .timer(std::time::Duration::from_millis(100))
 6674                    .await;
 6675                editor
 6676                    .update(cx, |editor, cx| {
 6677                        editor.inline_blame_popover.take();
 6678                        cx.notify();
 6679                    })
 6680                    .ok();
 6681            });
 6682            state.hide_task = Some(hide_task);
 6683        }
 6684    }
 6685
 6686    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6687        if self.pending_rename.is_some() {
 6688            return None;
 6689        }
 6690
 6691        let provider = self.semantics_provider.clone()?;
 6692        let buffer = self.buffer.read(cx);
 6693        let newest_selection = self.selections.newest_anchor().clone();
 6694        let cursor_position = newest_selection.head();
 6695        let (cursor_buffer, cursor_buffer_position) =
 6696            buffer.text_anchor_for_position(cursor_position, cx)?;
 6697        let (tail_buffer, tail_buffer_position) =
 6698            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6699        if cursor_buffer != tail_buffer {
 6700            return None;
 6701        }
 6702
 6703        let snapshot = cursor_buffer.read(cx).snapshot();
 6704        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6705        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6706        if start_word_range != end_word_range {
 6707            self.document_highlights_task.take();
 6708            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6709            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6710            return None;
 6711        }
 6712
 6713        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6714        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6715            cx.background_executor()
 6716                .timer(Duration::from_millis(debounce))
 6717                .await;
 6718
 6719            let highlights = if let Some(highlights) = cx
 6720                .update(|cx| {
 6721                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6722                })
 6723                .ok()
 6724                .flatten()
 6725            {
 6726                highlights.await.log_err()
 6727            } else {
 6728                None
 6729            };
 6730
 6731            if let Some(highlights) = highlights {
 6732                this.update(cx, |this, cx| {
 6733                    if this.pending_rename.is_some() {
 6734                        return;
 6735                    }
 6736
 6737                    let buffer_id = cursor_position.buffer_id;
 6738                    let buffer = this.buffer.read(cx);
 6739                    if !buffer
 6740                        .text_anchor_for_position(cursor_position, cx)
 6741                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6742                    {
 6743                        return;
 6744                    }
 6745
 6746                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6747                    let mut write_ranges = Vec::new();
 6748                    let mut read_ranges = Vec::new();
 6749                    for highlight in highlights {
 6750                        for (excerpt_id, excerpt_range) in
 6751                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6752                        {
 6753                            let start = highlight
 6754                                .range
 6755                                .start
 6756                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6757                            let end = highlight
 6758                                .range
 6759                                .end
 6760                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6761                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6762                                continue;
 6763                            }
 6764
 6765                            let range = Anchor {
 6766                                buffer_id,
 6767                                excerpt_id,
 6768                                text_anchor: start,
 6769                                diff_base_anchor: None,
 6770                            }..Anchor {
 6771                                buffer_id,
 6772                                excerpt_id,
 6773                                text_anchor: end,
 6774                                diff_base_anchor: None,
 6775                            };
 6776                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6777                                write_ranges.push(range);
 6778                            } else {
 6779                                read_ranges.push(range);
 6780                            }
 6781                        }
 6782                    }
 6783
 6784                    this.highlight_background::<DocumentHighlightRead>(
 6785                        &read_ranges,
 6786                        |theme| theme.colors().editor_document_highlight_read_background,
 6787                        cx,
 6788                    );
 6789                    this.highlight_background::<DocumentHighlightWrite>(
 6790                        &write_ranges,
 6791                        |theme| theme.colors().editor_document_highlight_write_background,
 6792                        cx,
 6793                    );
 6794                    cx.notify();
 6795                })
 6796                .log_err();
 6797            }
 6798        }));
 6799        None
 6800    }
 6801
 6802    fn prepare_highlight_query_from_selection(
 6803        &mut self,
 6804        cx: &mut Context<Editor>,
 6805    ) -> Option<(String, Range<Anchor>)> {
 6806        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6807            return None;
 6808        }
 6809        if !EditorSettings::get_global(cx).selection_highlight {
 6810            return None;
 6811        }
 6812        if self.selections.count() != 1 || self.selections.line_mode {
 6813            return None;
 6814        }
 6815        let selection = self.selections.newest::<Point>(cx);
 6816        if selection.is_empty() || selection.start.row != selection.end.row {
 6817            return None;
 6818        }
 6819        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6820        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6821        let query = multi_buffer_snapshot
 6822            .text_for_range(selection_anchor_range.clone())
 6823            .collect::<String>();
 6824        if query.trim().is_empty() {
 6825            return None;
 6826        }
 6827        Some((query, selection_anchor_range))
 6828    }
 6829
 6830    fn update_selection_occurrence_highlights(
 6831        &mut self,
 6832        query_text: String,
 6833        query_range: Range<Anchor>,
 6834        multi_buffer_range_to_query: Range<Point>,
 6835        use_debounce: bool,
 6836        window: &mut Window,
 6837        cx: &mut Context<Editor>,
 6838    ) -> Task<()> {
 6839        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6840        cx.spawn_in(window, async move |editor, cx| {
 6841            if use_debounce {
 6842                cx.background_executor()
 6843                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6844                    .await;
 6845            }
 6846            let match_task = cx.background_spawn(async move {
 6847                let buffer_ranges = multi_buffer_snapshot
 6848                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6849                    .into_iter()
 6850                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6851                let mut match_ranges = Vec::new();
 6852                let Ok(regex) = project::search::SearchQuery::text(
 6853                    query_text.clone(),
 6854                    false,
 6855                    false,
 6856                    false,
 6857                    Default::default(),
 6858                    Default::default(),
 6859                    false,
 6860                    None,
 6861                ) else {
 6862                    return Vec::default();
 6863                };
 6864                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6865                    match_ranges.extend(
 6866                        regex
 6867                            .search(buffer_snapshot, Some(search_range.clone()))
 6868                            .await
 6869                            .into_iter()
 6870                            .filter_map(|match_range| {
 6871                                let match_start = buffer_snapshot
 6872                                    .anchor_after(search_range.start + match_range.start);
 6873                                let match_end = buffer_snapshot
 6874                                    .anchor_before(search_range.start + match_range.end);
 6875                                let match_anchor_range = Anchor::range_in_buffer(
 6876                                    excerpt_id,
 6877                                    buffer_snapshot.remote_id(),
 6878                                    match_start..match_end,
 6879                                );
 6880                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6881                            }),
 6882                    );
 6883                }
 6884                match_ranges
 6885            });
 6886            let match_ranges = match_task.await;
 6887            editor
 6888                .update_in(cx, |editor, _, cx| {
 6889                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6890                    if !match_ranges.is_empty() {
 6891                        editor.highlight_background::<SelectedTextHighlight>(
 6892                            &match_ranges,
 6893                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6894                            cx,
 6895                        )
 6896                    }
 6897                })
 6898                .log_err();
 6899        })
 6900    }
 6901
 6902    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6903        struct NewlineFold;
 6904        let type_id = std::any::TypeId::of::<NewlineFold>();
 6905        if !self.mode.is_single_line() {
 6906            return;
 6907        }
 6908        let snapshot = self.snapshot(window, cx);
 6909        if snapshot.buffer_snapshot.max_point().row == 0 {
 6910            return;
 6911        }
 6912        let task = cx.background_spawn(async move {
 6913            let new_newlines = snapshot
 6914                .buffer_chars_at(0)
 6915                .filter_map(|(c, i)| {
 6916                    if c == '\n' {
 6917                        Some(
 6918                            snapshot.buffer_snapshot.anchor_after(i)
 6919                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6920                        )
 6921                    } else {
 6922                        None
 6923                    }
 6924                })
 6925                .collect::<Vec<_>>();
 6926            let existing_newlines = snapshot
 6927                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6928                .filter_map(|fold| {
 6929                    if fold.placeholder.type_tag == Some(type_id) {
 6930                        Some(fold.range.start..fold.range.end)
 6931                    } else {
 6932                        None
 6933                    }
 6934                })
 6935                .collect::<Vec<_>>();
 6936
 6937            (new_newlines, existing_newlines)
 6938        });
 6939        self.folding_newlines = cx.spawn(async move |this, cx| {
 6940            let (new_newlines, existing_newlines) = task.await;
 6941            if new_newlines == existing_newlines {
 6942                return;
 6943            }
 6944            let placeholder = FoldPlaceholder {
 6945                render: Arc::new(move |_, _, cx| {
 6946                    div()
 6947                        .bg(cx.theme().status().hint_background)
 6948                        .border_b_1()
 6949                        .size_full()
 6950                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6951                        .border_color(cx.theme().status().hint)
 6952                        .child("\\n")
 6953                        .into_any()
 6954                }),
 6955                constrain_width: false,
 6956                merge_adjacent: false,
 6957                type_tag: Some(type_id),
 6958            };
 6959            let creases = new_newlines
 6960                .into_iter()
 6961                .map(|range| Crease::simple(range, placeholder.clone()))
 6962                .collect();
 6963            this.update(cx, |this, cx| {
 6964                this.display_map.update(cx, |display_map, cx| {
 6965                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6966                    display_map.fold(creases, cx);
 6967                });
 6968            })
 6969            .ok();
 6970        });
 6971    }
 6972
 6973    fn refresh_selected_text_highlights(
 6974        &mut self,
 6975        on_buffer_edit: bool,
 6976        window: &mut Window,
 6977        cx: &mut Context<Editor>,
 6978    ) {
 6979        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6980        else {
 6981            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6982            self.quick_selection_highlight_task.take();
 6983            self.debounced_selection_highlight_task.take();
 6984            return;
 6985        };
 6986        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6987        if on_buffer_edit
 6988            || self
 6989                .quick_selection_highlight_task
 6990                .as_ref()
 6991                .map_or(true, |(prev_anchor_range, _)| {
 6992                    prev_anchor_range != &query_range
 6993                })
 6994        {
 6995            let multi_buffer_visible_start = self
 6996                .scroll_manager
 6997                .anchor()
 6998                .anchor
 6999                .to_point(&multi_buffer_snapshot);
 7000            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7001                multi_buffer_visible_start
 7002                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7003                Bias::Left,
 7004            );
 7005            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7006            self.quick_selection_highlight_task = Some((
 7007                query_range.clone(),
 7008                self.update_selection_occurrence_highlights(
 7009                    query_text.clone(),
 7010                    query_range.clone(),
 7011                    multi_buffer_visible_range,
 7012                    false,
 7013                    window,
 7014                    cx,
 7015                ),
 7016            ));
 7017        }
 7018        if on_buffer_edit
 7019            || self
 7020                .debounced_selection_highlight_task
 7021                .as_ref()
 7022                .map_or(true, |(prev_anchor_range, _)| {
 7023                    prev_anchor_range != &query_range
 7024                })
 7025        {
 7026            let multi_buffer_start = multi_buffer_snapshot
 7027                .anchor_before(0)
 7028                .to_point(&multi_buffer_snapshot);
 7029            let multi_buffer_end = multi_buffer_snapshot
 7030                .anchor_after(multi_buffer_snapshot.len())
 7031                .to_point(&multi_buffer_snapshot);
 7032            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7033            self.debounced_selection_highlight_task = Some((
 7034                query_range.clone(),
 7035                self.update_selection_occurrence_highlights(
 7036                    query_text,
 7037                    query_range,
 7038                    multi_buffer_full_range,
 7039                    true,
 7040                    window,
 7041                    cx,
 7042                ),
 7043            ));
 7044        }
 7045    }
 7046
 7047    pub fn refresh_edit_prediction(
 7048        &mut self,
 7049        debounce: bool,
 7050        user_requested: bool,
 7051        window: &mut Window,
 7052        cx: &mut Context<Self>,
 7053    ) -> Option<()> {
 7054        if DisableAiSettings::get_global(cx).disable_ai {
 7055            return None;
 7056        }
 7057
 7058        let provider = self.edit_prediction_provider()?;
 7059        let cursor = self.selections.newest_anchor().head();
 7060        let (buffer, cursor_buffer_position) =
 7061            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7062
 7063        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7064            self.discard_edit_prediction(false, cx);
 7065            return None;
 7066        }
 7067
 7068        if !user_requested
 7069            && (!self.should_show_edit_predictions()
 7070                || !self.is_focused(window)
 7071                || buffer.read(cx).is_empty())
 7072        {
 7073            self.discard_edit_prediction(false, cx);
 7074            return None;
 7075        }
 7076
 7077        self.update_visible_edit_prediction(window, cx);
 7078        provider.refresh(
 7079            self.project.clone(),
 7080            buffer,
 7081            cursor_buffer_position,
 7082            debounce,
 7083            cx,
 7084        );
 7085        Some(())
 7086    }
 7087
 7088    fn show_edit_predictions_in_menu(&self) -> bool {
 7089        match self.edit_prediction_settings {
 7090            EditPredictionSettings::Disabled => false,
 7091            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7092        }
 7093    }
 7094
 7095    pub fn edit_predictions_enabled(&self) -> bool {
 7096        match self.edit_prediction_settings {
 7097            EditPredictionSettings::Disabled => false,
 7098            EditPredictionSettings::Enabled { .. } => true,
 7099        }
 7100    }
 7101
 7102    fn edit_prediction_requires_modifier(&self) -> bool {
 7103        match self.edit_prediction_settings {
 7104            EditPredictionSettings::Disabled => false,
 7105            EditPredictionSettings::Enabled {
 7106                preview_requires_modifier,
 7107                ..
 7108            } => preview_requires_modifier,
 7109        }
 7110    }
 7111
 7112    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7113        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7114            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7115            self.discard_edit_prediction(false, cx);
 7116        } else {
 7117            let selection = self.selections.newest_anchor();
 7118            let cursor = selection.head();
 7119
 7120            if let Some((buffer, cursor_buffer_position)) =
 7121                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7122            {
 7123                self.edit_prediction_settings =
 7124                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7125            }
 7126        }
 7127    }
 7128
 7129    fn edit_prediction_settings_at_position(
 7130        &self,
 7131        buffer: &Entity<Buffer>,
 7132        buffer_position: language::Anchor,
 7133        cx: &App,
 7134    ) -> EditPredictionSettings {
 7135        if !self.mode.is_full()
 7136            || !self.show_edit_predictions_override.unwrap_or(true)
 7137            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7138        {
 7139            return EditPredictionSettings::Disabled;
 7140        }
 7141
 7142        let buffer = buffer.read(cx);
 7143
 7144        let file = buffer.file();
 7145
 7146        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7147            return EditPredictionSettings::Disabled;
 7148        };
 7149
 7150        let by_provider = matches!(
 7151            self.menu_edit_predictions_policy,
 7152            MenuEditPredictionsPolicy::ByProvider
 7153        );
 7154
 7155        let show_in_menu = by_provider
 7156            && self
 7157                .edit_prediction_provider
 7158                .as_ref()
 7159                .map_or(false, |provider| {
 7160                    provider.provider.show_completions_in_menu()
 7161                });
 7162
 7163        let preview_requires_modifier =
 7164            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7165
 7166        EditPredictionSettings::Enabled {
 7167            show_in_menu,
 7168            preview_requires_modifier,
 7169        }
 7170    }
 7171
 7172    fn should_show_edit_predictions(&self) -> bool {
 7173        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7174    }
 7175
 7176    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7177        matches!(
 7178            self.edit_prediction_preview,
 7179            EditPredictionPreview::Active { .. }
 7180        )
 7181    }
 7182
 7183    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7184        let cursor = self.selections.newest_anchor().head();
 7185        if let Some((buffer, cursor_position)) =
 7186            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7187        {
 7188            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7189        } else {
 7190            false
 7191        }
 7192    }
 7193
 7194    pub fn supports_minimap(&self, cx: &App) -> bool {
 7195        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7196    }
 7197
 7198    fn edit_predictions_enabled_in_buffer(
 7199        &self,
 7200        buffer: &Entity<Buffer>,
 7201        buffer_position: language::Anchor,
 7202        cx: &App,
 7203    ) -> bool {
 7204        maybe!({
 7205            if self.read_only(cx) {
 7206                return Some(false);
 7207            }
 7208            let provider = self.edit_prediction_provider()?;
 7209            if !provider.is_enabled(buffer, buffer_position, cx) {
 7210                return Some(false);
 7211            }
 7212            let buffer = buffer.read(cx);
 7213            let Some(file) = buffer.file() else {
 7214                return Some(true);
 7215            };
 7216            let settings = all_language_settings(Some(file), cx);
 7217            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7218        })
 7219        .unwrap_or(false)
 7220    }
 7221
 7222    fn cycle_edit_prediction(
 7223        &mut self,
 7224        direction: Direction,
 7225        window: &mut Window,
 7226        cx: &mut Context<Self>,
 7227    ) -> Option<()> {
 7228        let provider = self.edit_prediction_provider()?;
 7229        let cursor = self.selections.newest_anchor().head();
 7230        let (buffer, cursor_buffer_position) =
 7231            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7232        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7233            return None;
 7234        }
 7235
 7236        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7237        self.update_visible_edit_prediction(window, cx);
 7238
 7239        Some(())
 7240    }
 7241
 7242    pub fn show_edit_prediction(
 7243        &mut self,
 7244        _: &ShowEditPrediction,
 7245        window: &mut Window,
 7246        cx: &mut Context<Self>,
 7247    ) {
 7248        if !self.has_active_edit_prediction() {
 7249            self.refresh_edit_prediction(false, true, window, cx);
 7250            return;
 7251        }
 7252
 7253        self.update_visible_edit_prediction(window, cx);
 7254    }
 7255
 7256    pub fn display_cursor_names(
 7257        &mut self,
 7258        _: &DisplayCursorNames,
 7259        window: &mut Window,
 7260        cx: &mut Context<Self>,
 7261    ) {
 7262        self.show_cursor_names(window, cx);
 7263    }
 7264
 7265    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7266        self.show_cursor_names = true;
 7267        cx.notify();
 7268        cx.spawn_in(window, async move |this, cx| {
 7269            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7270            this.update(cx, |this, cx| {
 7271                this.show_cursor_names = false;
 7272                cx.notify()
 7273            })
 7274            .ok()
 7275        })
 7276        .detach();
 7277    }
 7278
 7279    pub fn next_edit_prediction(
 7280        &mut self,
 7281        _: &NextEditPrediction,
 7282        window: &mut Window,
 7283        cx: &mut Context<Self>,
 7284    ) {
 7285        if self.has_active_edit_prediction() {
 7286            self.cycle_edit_prediction(Direction::Next, window, cx);
 7287        } else {
 7288            let is_copilot_disabled = self
 7289                .refresh_edit_prediction(false, true, window, cx)
 7290                .is_none();
 7291            if is_copilot_disabled {
 7292                cx.propagate();
 7293            }
 7294        }
 7295    }
 7296
 7297    pub fn previous_edit_prediction(
 7298        &mut self,
 7299        _: &PreviousEditPrediction,
 7300        window: &mut Window,
 7301        cx: &mut Context<Self>,
 7302    ) {
 7303        if self.has_active_edit_prediction() {
 7304            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7305        } else {
 7306            let is_copilot_disabled = self
 7307                .refresh_edit_prediction(false, true, window, cx)
 7308                .is_none();
 7309            if is_copilot_disabled {
 7310                cx.propagate();
 7311            }
 7312        }
 7313    }
 7314
 7315    pub fn accept_edit_prediction(
 7316        &mut self,
 7317        _: &AcceptEditPrediction,
 7318        window: &mut Window,
 7319        cx: &mut Context<Self>,
 7320    ) {
 7321        if self.show_edit_predictions_in_menu() {
 7322            self.hide_context_menu(window, cx);
 7323        }
 7324
 7325        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7326            return;
 7327        };
 7328
 7329        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7330
 7331        match &active_edit_prediction.completion {
 7332            EditPrediction::Move { target, .. } => {
 7333                let target = *target;
 7334
 7335                if let Some(position_map) = &self.last_position_map {
 7336                    if position_map
 7337                        .visible_row_range
 7338                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7339                        || !self.edit_prediction_requires_modifier()
 7340                    {
 7341                        self.unfold_ranges(&[target..target], true, false, cx);
 7342                        // Note that this is also done in vim's handler of the Tab action.
 7343                        self.change_selections(
 7344                            SelectionEffects::scroll(Autoscroll::newest()),
 7345                            window,
 7346                            cx,
 7347                            |selections| {
 7348                                selections.select_anchor_ranges([target..target]);
 7349                            },
 7350                        );
 7351                        self.clear_row_highlights::<EditPredictionPreview>();
 7352
 7353                        self.edit_prediction_preview
 7354                            .set_previous_scroll_position(None);
 7355                    } else {
 7356                        self.edit_prediction_preview
 7357                            .set_previous_scroll_position(Some(
 7358                                position_map.snapshot.scroll_anchor,
 7359                            ));
 7360
 7361                        self.highlight_rows::<EditPredictionPreview>(
 7362                            target..target,
 7363                            cx.theme().colors().editor_highlighted_line_background,
 7364                            RowHighlightOptions {
 7365                                autoscroll: true,
 7366                                ..Default::default()
 7367                            },
 7368                            cx,
 7369                        );
 7370                        self.request_autoscroll(Autoscroll::fit(), cx);
 7371                    }
 7372                }
 7373            }
 7374            EditPrediction::Edit { edits, .. } => {
 7375                if let Some(provider) = self.edit_prediction_provider() {
 7376                    provider.accept(cx);
 7377                }
 7378
 7379                // Store the transaction ID and selections before applying the edit
 7380                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7381
 7382                let snapshot = self.buffer.read(cx).snapshot(cx);
 7383                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7384
 7385                self.buffer.update(cx, |buffer, cx| {
 7386                    buffer.edit(edits.iter().cloned(), None, cx)
 7387                });
 7388
 7389                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7390                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7391                });
 7392
 7393                let selections = self.selections.disjoint_anchors();
 7394                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7395                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7396                    if has_new_transaction {
 7397                        self.selection_history
 7398                            .insert_transaction(transaction_id_now, selections);
 7399                    }
 7400                }
 7401
 7402                self.update_visible_edit_prediction(window, cx);
 7403                if self.active_edit_prediction.is_none() {
 7404                    self.refresh_edit_prediction(true, true, window, cx);
 7405                }
 7406
 7407                cx.notify();
 7408            }
 7409        }
 7410
 7411        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7412    }
 7413
 7414    pub fn accept_partial_edit_prediction(
 7415        &mut self,
 7416        _: &AcceptPartialEditPrediction,
 7417        window: &mut Window,
 7418        cx: &mut Context<Self>,
 7419    ) {
 7420        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7421            return;
 7422        };
 7423        if self.selections.count() != 1 {
 7424            return;
 7425        }
 7426
 7427        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7428
 7429        match &active_edit_prediction.completion {
 7430            EditPrediction::Move { target, .. } => {
 7431                let target = *target;
 7432                self.change_selections(
 7433                    SelectionEffects::scroll(Autoscroll::newest()),
 7434                    window,
 7435                    cx,
 7436                    |selections| {
 7437                        selections.select_anchor_ranges([target..target]);
 7438                    },
 7439                );
 7440            }
 7441            EditPrediction::Edit { edits, .. } => {
 7442                // Find an insertion that starts at the cursor position.
 7443                let snapshot = self.buffer.read(cx).snapshot(cx);
 7444                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7445                let insertion = edits.iter().find_map(|(range, text)| {
 7446                    let range = range.to_offset(&snapshot);
 7447                    if range.is_empty() && range.start == cursor_offset {
 7448                        Some(text)
 7449                    } else {
 7450                        None
 7451                    }
 7452                });
 7453
 7454                if let Some(text) = insertion {
 7455                    let mut partial_completion = text
 7456                        .chars()
 7457                        .by_ref()
 7458                        .take_while(|c| c.is_alphabetic())
 7459                        .collect::<String>();
 7460                    if partial_completion.is_empty() {
 7461                        partial_completion = text
 7462                            .chars()
 7463                            .by_ref()
 7464                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7465                            .collect::<String>();
 7466                    }
 7467
 7468                    cx.emit(EditorEvent::InputHandled {
 7469                        utf16_range_to_replace: None,
 7470                        text: partial_completion.clone().into(),
 7471                    });
 7472
 7473                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7474
 7475                    self.refresh_edit_prediction(true, true, window, cx);
 7476                    cx.notify();
 7477                } else {
 7478                    self.accept_edit_prediction(&Default::default(), window, cx);
 7479                }
 7480            }
 7481        }
 7482    }
 7483
 7484    fn discard_edit_prediction(
 7485        &mut self,
 7486        should_report_edit_prediction_event: bool,
 7487        cx: &mut Context<Self>,
 7488    ) -> bool {
 7489        if should_report_edit_prediction_event {
 7490            let completion_id = self
 7491                .active_edit_prediction
 7492                .as_ref()
 7493                .and_then(|active_completion| active_completion.completion_id.clone());
 7494
 7495            self.report_edit_prediction_event(completion_id, false, cx);
 7496        }
 7497
 7498        if let Some(provider) = self.edit_prediction_provider() {
 7499            provider.discard(cx);
 7500        }
 7501
 7502        self.take_active_edit_prediction(cx)
 7503    }
 7504
 7505    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7506        let Some(provider) = self.edit_prediction_provider() else {
 7507            return;
 7508        };
 7509
 7510        let Some((_, buffer, _)) = self
 7511            .buffer
 7512            .read(cx)
 7513            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7514        else {
 7515            return;
 7516        };
 7517
 7518        let extension = buffer
 7519            .read(cx)
 7520            .file()
 7521            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7522
 7523        let event_type = match accepted {
 7524            true => "Edit Prediction Accepted",
 7525            false => "Edit Prediction Discarded",
 7526        };
 7527        telemetry::event!(
 7528            event_type,
 7529            provider = provider.name(),
 7530            prediction_id = id,
 7531            suggestion_accepted = accepted,
 7532            file_extension = extension,
 7533        );
 7534    }
 7535
 7536    pub fn has_active_edit_prediction(&self) -> bool {
 7537        self.active_edit_prediction.is_some()
 7538    }
 7539
 7540    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7541        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7542            return false;
 7543        };
 7544
 7545        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7546        self.clear_highlights::<EditPredictionHighlight>(cx);
 7547        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7548        true
 7549    }
 7550
 7551    /// Returns true when we're displaying the edit prediction popover below the cursor
 7552    /// like we are not previewing and the LSP autocomplete menu is visible
 7553    /// or we are in `when_holding_modifier` mode.
 7554    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7555        if self.edit_prediction_preview_is_active()
 7556            || !self.show_edit_predictions_in_menu()
 7557            || !self.edit_predictions_enabled()
 7558        {
 7559            return false;
 7560        }
 7561
 7562        if self.has_visible_completions_menu() {
 7563            return true;
 7564        }
 7565
 7566        has_completion && self.edit_prediction_requires_modifier()
 7567    }
 7568
 7569    fn handle_modifiers_changed(
 7570        &mut self,
 7571        modifiers: Modifiers,
 7572        position_map: &PositionMap,
 7573        window: &mut Window,
 7574        cx: &mut Context<Self>,
 7575    ) {
 7576        if self.show_edit_predictions_in_menu() {
 7577            self.update_edit_prediction_preview(&modifiers, window, cx);
 7578        }
 7579
 7580        self.update_selection_mode(&modifiers, position_map, window, cx);
 7581
 7582        let mouse_position = window.mouse_position();
 7583        if !position_map.text_hitbox.is_hovered(window) {
 7584            return;
 7585        }
 7586
 7587        self.update_hovered_link(
 7588            position_map.point_for_position(mouse_position),
 7589            &position_map.snapshot,
 7590            modifiers,
 7591            window,
 7592            cx,
 7593        )
 7594    }
 7595
 7596    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7597        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7598        if invert {
 7599            match multi_cursor_setting {
 7600                MultiCursorModifier::Alt => modifiers.alt,
 7601                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7602            }
 7603        } else {
 7604            match multi_cursor_setting {
 7605                MultiCursorModifier::Alt => modifiers.secondary(),
 7606                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7607            }
 7608        }
 7609    }
 7610
 7611    fn columnar_selection_mode(
 7612        modifiers: &Modifiers,
 7613        cx: &mut Context<Self>,
 7614    ) -> Option<ColumnarMode> {
 7615        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7616            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7617                Some(ColumnarMode::FromMouse)
 7618            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7619                Some(ColumnarMode::FromSelection)
 7620            } else {
 7621                None
 7622            }
 7623        } else {
 7624            None
 7625        }
 7626    }
 7627
 7628    fn update_selection_mode(
 7629        &mut self,
 7630        modifiers: &Modifiers,
 7631        position_map: &PositionMap,
 7632        window: &mut Window,
 7633        cx: &mut Context<Self>,
 7634    ) {
 7635        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7636            return;
 7637        };
 7638        if self.selections.pending.is_none() {
 7639            return;
 7640        }
 7641
 7642        let mouse_position = window.mouse_position();
 7643        let point_for_position = position_map.point_for_position(mouse_position);
 7644        let position = point_for_position.previous_valid;
 7645
 7646        self.select(
 7647            SelectPhase::BeginColumnar {
 7648                position,
 7649                reset: false,
 7650                mode,
 7651                goal_column: point_for_position.exact_unclipped.column(),
 7652            },
 7653            window,
 7654            cx,
 7655        );
 7656    }
 7657
 7658    fn update_edit_prediction_preview(
 7659        &mut self,
 7660        modifiers: &Modifiers,
 7661        window: &mut Window,
 7662        cx: &mut Context<Self>,
 7663    ) {
 7664        let mut modifiers_held = false;
 7665        if let Some(accept_keystroke) = self
 7666            .accept_edit_prediction_keybind(false, window, cx)
 7667            .keystroke()
 7668        {
 7669            modifiers_held = modifiers_held
 7670                || (&accept_keystroke.modifiers == modifiers
 7671                    && accept_keystroke.modifiers.modified());
 7672        };
 7673        if let Some(accept_partial_keystroke) = self
 7674            .accept_edit_prediction_keybind(true, window, cx)
 7675            .keystroke()
 7676        {
 7677            modifiers_held = modifiers_held
 7678                || (&accept_partial_keystroke.modifiers == modifiers
 7679                    && accept_partial_keystroke.modifiers.modified());
 7680        }
 7681
 7682        if modifiers_held {
 7683            if matches!(
 7684                self.edit_prediction_preview,
 7685                EditPredictionPreview::Inactive { .. }
 7686            ) {
 7687                self.edit_prediction_preview = EditPredictionPreview::Active {
 7688                    previous_scroll_position: None,
 7689                    since: Instant::now(),
 7690                };
 7691
 7692                self.update_visible_edit_prediction(window, cx);
 7693                cx.notify();
 7694            }
 7695        } else if let EditPredictionPreview::Active {
 7696            previous_scroll_position,
 7697            since,
 7698        } = self.edit_prediction_preview
 7699        {
 7700            if let (Some(previous_scroll_position), Some(position_map)) =
 7701                (previous_scroll_position, self.last_position_map.as_ref())
 7702            {
 7703                self.set_scroll_position(
 7704                    previous_scroll_position
 7705                        .scroll_position(&position_map.snapshot.display_snapshot),
 7706                    window,
 7707                    cx,
 7708                );
 7709            }
 7710
 7711            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7712                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7713            };
 7714            self.clear_row_highlights::<EditPredictionPreview>();
 7715            self.update_visible_edit_prediction(window, cx);
 7716            cx.notify();
 7717        }
 7718    }
 7719
 7720    fn update_visible_edit_prediction(
 7721        &mut self,
 7722        _window: &mut Window,
 7723        cx: &mut Context<Self>,
 7724    ) -> Option<()> {
 7725        if DisableAiSettings::get_global(cx).disable_ai {
 7726            return None;
 7727        }
 7728
 7729        let selection = self.selections.newest_anchor();
 7730        let cursor = selection.head();
 7731        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7732        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7733        let excerpt_id = cursor.excerpt_id;
 7734
 7735        let show_in_menu = self.show_edit_predictions_in_menu();
 7736        let completions_menu_has_precedence = !show_in_menu
 7737            && (self.context_menu.borrow().is_some()
 7738                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7739
 7740        if completions_menu_has_precedence
 7741            || !offset_selection.is_empty()
 7742            || self
 7743                .active_edit_prediction
 7744                .as_ref()
 7745                .map_or(false, |completion| {
 7746                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7747                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7748                    !invalidation_range.contains(&offset_selection.head())
 7749                })
 7750        {
 7751            self.discard_edit_prediction(false, cx);
 7752            return None;
 7753        }
 7754
 7755        self.take_active_edit_prediction(cx);
 7756        let Some(provider) = self.edit_prediction_provider() else {
 7757            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7758            return None;
 7759        };
 7760
 7761        let (buffer, cursor_buffer_position) =
 7762            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7763
 7764        self.edit_prediction_settings =
 7765            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7766
 7767        match self.edit_prediction_settings {
 7768            EditPredictionSettings::Disabled => {
 7769                self.discard_edit_prediction(false, cx);
 7770                return None;
 7771            }
 7772            _ => {}
 7773        };
 7774
 7775        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7776
 7777        if self.edit_prediction_indent_conflict {
 7778            let cursor_point = cursor.to_point(&multibuffer);
 7779
 7780            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7781
 7782            if let Some((_, indent)) = indents.iter().next() {
 7783                if indent.len == cursor_point.column {
 7784                    self.edit_prediction_indent_conflict = false;
 7785                }
 7786            }
 7787        }
 7788
 7789        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7790        let edits = edit_prediction
 7791            .edits
 7792            .into_iter()
 7793            .flat_map(|(range, new_text)| {
 7794                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7795                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7796                Some((start..end, new_text))
 7797            })
 7798            .collect::<Vec<_>>();
 7799        if edits.is_empty() {
 7800            return None;
 7801        }
 7802
 7803        let first_edit_start = edits.first().unwrap().0.start;
 7804        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7805        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7806
 7807        let last_edit_end = edits.last().unwrap().0.end;
 7808        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7809        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7810
 7811        let cursor_row = cursor.to_point(&multibuffer).row;
 7812
 7813        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7814
 7815        let mut inlay_ids = Vec::new();
 7816        let invalidation_row_range;
 7817        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7818            Some(cursor_row..edit_end_row)
 7819        } else if cursor_row > edit_end_row {
 7820            Some(edit_start_row..cursor_row)
 7821        } else {
 7822            None
 7823        };
 7824        let supports_jump = self
 7825            .edit_prediction_provider
 7826            .as_ref()
 7827            .map(|provider| provider.provider.supports_jump_to_edit())
 7828            .unwrap_or(true);
 7829
 7830        let is_move = supports_jump
 7831            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7832        let completion = if is_move {
 7833            invalidation_row_range =
 7834                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7835            let target = first_edit_start;
 7836            EditPrediction::Move { target, snapshot }
 7837        } else {
 7838            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7839                && !self.edit_predictions_hidden_for_vim_mode;
 7840
 7841            if show_completions_in_buffer {
 7842                if edits
 7843                    .iter()
 7844                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7845                {
 7846                    let mut inlays = Vec::new();
 7847                    for (range, new_text) in &edits {
 7848                        let inlay = Inlay::edit_prediction(
 7849                            post_inc(&mut self.next_inlay_id),
 7850                            range.start,
 7851                            new_text.as_str(),
 7852                        );
 7853                        inlay_ids.push(inlay.id);
 7854                        inlays.push(inlay);
 7855                    }
 7856
 7857                    self.splice_inlays(&[], inlays, cx);
 7858                } else {
 7859                    let background_color = cx.theme().status().deleted_background;
 7860                    self.highlight_text::<EditPredictionHighlight>(
 7861                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7862                        HighlightStyle {
 7863                            background_color: Some(background_color),
 7864                            ..Default::default()
 7865                        },
 7866                        cx,
 7867                    );
 7868                }
 7869            }
 7870
 7871            invalidation_row_range = edit_start_row..edit_end_row;
 7872
 7873            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7874                if provider.show_tab_accept_marker() {
 7875                    EditDisplayMode::TabAccept
 7876                } else {
 7877                    EditDisplayMode::Inline
 7878                }
 7879            } else {
 7880                EditDisplayMode::DiffPopover
 7881            };
 7882
 7883            EditPrediction::Edit {
 7884                edits,
 7885                edit_preview: edit_prediction.edit_preview,
 7886                display_mode,
 7887                snapshot,
 7888            }
 7889        };
 7890
 7891        let invalidation_range = multibuffer
 7892            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7893            ..multibuffer.anchor_after(Point::new(
 7894                invalidation_row_range.end,
 7895                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7896            ));
 7897
 7898        self.stale_edit_prediction_in_menu = None;
 7899        self.active_edit_prediction = Some(EditPredictionState {
 7900            inlay_ids,
 7901            completion,
 7902            completion_id: edit_prediction.id,
 7903            invalidation_range,
 7904        });
 7905
 7906        cx.notify();
 7907
 7908        Some(())
 7909    }
 7910
 7911    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7912        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7913    }
 7914
 7915    fn clear_tasks(&mut self) {
 7916        self.tasks.clear()
 7917    }
 7918
 7919    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7920        if self.tasks.insert(key, value).is_some() {
 7921            // This case should hopefully be rare, but just in case...
 7922            log::error!(
 7923                "multiple different run targets found on a single line, only the last target will be rendered"
 7924            )
 7925        }
 7926    }
 7927
 7928    /// Get all display points of breakpoints that will be rendered within editor
 7929    ///
 7930    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7931    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7932    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7933    fn active_breakpoints(
 7934        &self,
 7935        range: Range<DisplayRow>,
 7936        window: &mut Window,
 7937        cx: &mut Context<Self>,
 7938    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7939        let mut breakpoint_display_points = HashMap::default();
 7940
 7941        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7942            return breakpoint_display_points;
 7943        };
 7944
 7945        let snapshot = self.snapshot(window, cx);
 7946
 7947        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7948        let Some(project) = self.project() else {
 7949            return breakpoint_display_points;
 7950        };
 7951
 7952        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7953            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7954
 7955        for (buffer_snapshot, range, excerpt_id) in
 7956            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7957        {
 7958            let Some(buffer) = project
 7959                .read(cx)
 7960                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7961            else {
 7962                continue;
 7963            };
 7964            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7965                &buffer,
 7966                Some(
 7967                    buffer_snapshot.anchor_before(range.start)
 7968                        ..buffer_snapshot.anchor_after(range.end),
 7969                ),
 7970                buffer_snapshot,
 7971                cx,
 7972            );
 7973            for (breakpoint, state) in breakpoints {
 7974                let multi_buffer_anchor =
 7975                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7976                let position = multi_buffer_anchor
 7977                    .to_point(multi_buffer_snapshot)
 7978                    .to_display_point(&snapshot);
 7979
 7980                breakpoint_display_points.insert(
 7981                    position.row(),
 7982                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7983                );
 7984            }
 7985        }
 7986
 7987        breakpoint_display_points
 7988    }
 7989
 7990    fn breakpoint_context_menu(
 7991        &self,
 7992        anchor: Anchor,
 7993        window: &mut Window,
 7994        cx: &mut Context<Self>,
 7995    ) -> Entity<ui::ContextMenu> {
 7996        let weak_editor = cx.weak_entity();
 7997        let focus_handle = self.focus_handle(cx);
 7998
 7999        let row = self
 8000            .buffer
 8001            .read(cx)
 8002            .snapshot(cx)
 8003            .summary_for_anchor::<Point>(&anchor)
 8004            .row;
 8005
 8006        let breakpoint = self
 8007            .breakpoint_at_row(row, window, cx)
 8008            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8009
 8010        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8011            "Edit Log Breakpoint"
 8012        } else {
 8013            "Set Log Breakpoint"
 8014        };
 8015
 8016        let condition_breakpoint_msg = if breakpoint
 8017            .as_ref()
 8018            .is_some_and(|bp| bp.1.condition.is_some())
 8019        {
 8020            "Edit Condition Breakpoint"
 8021        } else {
 8022            "Set Condition Breakpoint"
 8023        };
 8024
 8025        let hit_condition_breakpoint_msg = if breakpoint
 8026            .as_ref()
 8027            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8028        {
 8029            "Edit Hit Condition Breakpoint"
 8030        } else {
 8031            "Set Hit Condition Breakpoint"
 8032        };
 8033
 8034        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8035            "Unset Breakpoint"
 8036        } else {
 8037            "Set Breakpoint"
 8038        };
 8039
 8040        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8041
 8042        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8043            BreakpointState::Enabled => Some("Disable"),
 8044            BreakpointState::Disabled => Some("Enable"),
 8045        });
 8046
 8047        let (anchor, breakpoint) =
 8048            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8049
 8050        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8051            menu.on_blur_subscription(Subscription::new(|| {}))
 8052                .context(focus_handle)
 8053                .when(run_to_cursor, |this| {
 8054                    let weak_editor = weak_editor.clone();
 8055                    this.entry("Run to cursor", None, move |window, cx| {
 8056                        weak_editor
 8057                            .update(cx, |editor, cx| {
 8058                                editor.change_selections(
 8059                                    SelectionEffects::no_scroll(),
 8060                                    window,
 8061                                    cx,
 8062                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8063                                );
 8064                            })
 8065                            .ok();
 8066
 8067                        window.dispatch_action(Box::new(RunToCursor), cx);
 8068                    })
 8069                    .separator()
 8070                })
 8071                .when_some(toggle_state_msg, |this, msg| {
 8072                    this.entry(msg, None, {
 8073                        let weak_editor = weak_editor.clone();
 8074                        let breakpoint = breakpoint.clone();
 8075                        move |_window, cx| {
 8076                            weak_editor
 8077                                .update(cx, |this, cx| {
 8078                                    this.edit_breakpoint_at_anchor(
 8079                                        anchor,
 8080                                        breakpoint.as_ref().clone(),
 8081                                        BreakpointEditAction::InvertState,
 8082                                        cx,
 8083                                    );
 8084                                })
 8085                                .log_err();
 8086                        }
 8087                    })
 8088                })
 8089                .entry(set_breakpoint_msg, None, {
 8090                    let weak_editor = weak_editor.clone();
 8091                    let breakpoint = breakpoint.clone();
 8092                    move |_window, cx| {
 8093                        weak_editor
 8094                            .update(cx, |this, cx| {
 8095                                this.edit_breakpoint_at_anchor(
 8096                                    anchor,
 8097                                    breakpoint.as_ref().clone(),
 8098                                    BreakpointEditAction::Toggle,
 8099                                    cx,
 8100                                );
 8101                            })
 8102                            .log_err();
 8103                    }
 8104                })
 8105                .entry(log_breakpoint_msg, None, {
 8106                    let breakpoint = breakpoint.clone();
 8107                    let weak_editor = weak_editor.clone();
 8108                    move |window, cx| {
 8109                        weak_editor
 8110                            .update(cx, |this, cx| {
 8111                                this.add_edit_breakpoint_block(
 8112                                    anchor,
 8113                                    breakpoint.as_ref(),
 8114                                    BreakpointPromptEditAction::Log,
 8115                                    window,
 8116                                    cx,
 8117                                );
 8118                            })
 8119                            .log_err();
 8120                    }
 8121                })
 8122                .entry(condition_breakpoint_msg, None, {
 8123                    let breakpoint = breakpoint.clone();
 8124                    let weak_editor = weak_editor.clone();
 8125                    move |window, cx| {
 8126                        weak_editor
 8127                            .update(cx, |this, cx| {
 8128                                this.add_edit_breakpoint_block(
 8129                                    anchor,
 8130                                    breakpoint.as_ref(),
 8131                                    BreakpointPromptEditAction::Condition,
 8132                                    window,
 8133                                    cx,
 8134                                );
 8135                            })
 8136                            .log_err();
 8137                    }
 8138                })
 8139                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8140                    weak_editor
 8141                        .update(cx, |this, cx| {
 8142                            this.add_edit_breakpoint_block(
 8143                                anchor,
 8144                                breakpoint.as_ref(),
 8145                                BreakpointPromptEditAction::HitCondition,
 8146                                window,
 8147                                cx,
 8148                            );
 8149                        })
 8150                        .log_err();
 8151                })
 8152        })
 8153    }
 8154
 8155    fn render_breakpoint(
 8156        &self,
 8157        position: Anchor,
 8158        row: DisplayRow,
 8159        breakpoint: &Breakpoint,
 8160        state: Option<BreakpointSessionState>,
 8161        cx: &mut Context<Self>,
 8162    ) -> IconButton {
 8163        let is_rejected = state.is_some_and(|s| !s.verified);
 8164        // Is it a breakpoint that shows up when hovering over gutter?
 8165        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8166            (false, false),
 8167            |PhantomBreakpointIndicator {
 8168                 is_active,
 8169                 display_row,
 8170                 collides_with_existing_breakpoint,
 8171             }| {
 8172                (
 8173                    is_active && display_row == row,
 8174                    collides_with_existing_breakpoint,
 8175                )
 8176            },
 8177        );
 8178
 8179        let (color, icon) = {
 8180            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8181                (false, false) => ui::IconName::DebugBreakpoint,
 8182                (true, false) => ui::IconName::DebugLogBreakpoint,
 8183                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8184                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8185            };
 8186
 8187            let color = if is_phantom {
 8188                Color::Hint
 8189            } else if is_rejected {
 8190                Color::Disabled
 8191            } else {
 8192                Color::Debugger
 8193            };
 8194
 8195            (color, icon)
 8196        };
 8197
 8198        let breakpoint = Arc::from(breakpoint.clone());
 8199
 8200        let alt_as_text = gpui::Keystroke {
 8201            modifiers: Modifiers::secondary_key(),
 8202            ..Default::default()
 8203        };
 8204        let primary_action_text = if breakpoint.is_disabled() {
 8205            "Enable breakpoint"
 8206        } else if is_phantom && !collides_with_existing {
 8207            "Set breakpoint"
 8208        } else {
 8209            "Unset breakpoint"
 8210        };
 8211        let focus_handle = self.focus_handle.clone();
 8212
 8213        let meta = if is_rejected {
 8214            SharedString::from("No executable code is associated with this line.")
 8215        } else if collides_with_existing && !breakpoint.is_disabled() {
 8216            SharedString::from(format!(
 8217                "{alt_as_text}-click to disable,\nright-click for more options."
 8218            ))
 8219        } else {
 8220            SharedString::from("Right-click for more options.")
 8221        };
 8222        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8223            .icon_size(IconSize::XSmall)
 8224            .size(ui::ButtonSize::None)
 8225            .when(is_rejected, |this| {
 8226                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8227            })
 8228            .icon_color(color)
 8229            .style(ButtonStyle::Transparent)
 8230            .on_click(cx.listener({
 8231                let breakpoint = breakpoint.clone();
 8232
 8233                move |editor, event: &ClickEvent, window, cx| {
 8234                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8235                        BreakpointEditAction::InvertState
 8236                    } else {
 8237                        BreakpointEditAction::Toggle
 8238                    };
 8239
 8240                    window.focus(&editor.focus_handle(cx));
 8241                    editor.edit_breakpoint_at_anchor(
 8242                        position,
 8243                        breakpoint.as_ref().clone(),
 8244                        edit_action,
 8245                        cx,
 8246                    );
 8247                }
 8248            }))
 8249            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8250                editor.set_breakpoint_context_menu(
 8251                    row,
 8252                    Some(position),
 8253                    event.position(),
 8254                    window,
 8255                    cx,
 8256                );
 8257            }))
 8258            .tooltip(move |window, cx| {
 8259                Tooltip::with_meta_in(
 8260                    primary_action_text,
 8261                    Some(&ToggleBreakpoint),
 8262                    meta.clone(),
 8263                    &focus_handle,
 8264                    window,
 8265                    cx,
 8266                )
 8267            })
 8268    }
 8269
 8270    fn build_tasks_context(
 8271        project: &Entity<Project>,
 8272        buffer: &Entity<Buffer>,
 8273        buffer_row: u32,
 8274        tasks: &Arc<RunnableTasks>,
 8275        cx: &mut Context<Self>,
 8276    ) -> Task<Option<task::TaskContext>> {
 8277        let position = Point::new(buffer_row, tasks.column);
 8278        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8279        let location = Location {
 8280            buffer: buffer.clone(),
 8281            range: range_start..range_start,
 8282        };
 8283        // Fill in the environmental variables from the tree-sitter captures
 8284        let mut captured_task_variables = TaskVariables::default();
 8285        for (capture_name, value) in tasks.extra_variables.clone() {
 8286            captured_task_variables.insert(
 8287                task::VariableName::Custom(capture_name.into()),
 8288                value.clone(),
 8289            );
 8290        }
 8291        project.update(cx, |project, cx| {
 8292            project.task_store().update(cx, |task_store, cx| {
 8293                task_store.task_context_for_location(captured_task_variables, location, cx)
 8294            })
 8295        })
 8296    }
 8297
 8298    pub fn spawn_nearest_task(
 8299        &mut self,
 8300        action: &SpawnNearestTask,
 8301        window: &mut Window,
 8302        cx: &mut Context<Self>,
 8303    ) {
 8304        let Some((workspace, _)) = self.workspace.clone() else {
 8305            return;
 8306        };
 8307        let Some(project) = self.project.clone() else {
 8308            return;
 8309        };
 8310
 8311        // Try to find a closest, enclosing node using tree-sitter that has a task
 8312        let Some((buffer, buffer_row, tasks)) = self
 8313            .find_enclosing_node_task(cx)
 8314            // Or find the task that's closest in row-distance.
 8315            .or_else(|| self.find_closest_task(cx))
 8316        else {
 8317            return;
 8318        };
 8319
 8320        let reveal_strategy = action.reveal;
 8321        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8322        cx.spawn_in(window, async move |_, cx| {
 8323            let context = task_context.await?;
 8324            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8325
 8326            let resolved = &mut resolved_task.resolved;
 8327            resolved.reveal = reveal_strategy;
 8328
 8329            workspace
 8330                .update_in(cx, |workspace, window, cx| {
 8331                    workspace.schedule_resolved_task(
 8332                        task_source_kind,
 8333                        resolved_task,
 8334                        false,
 8335                        window,
 8336                        cx,
 8337                    );
 8338                })
 8339                .ok()
 8340        })
 8341        .detach();
 8342    }
 8343
 8344    fn find_closest_task(
 8345        &mut self,
 8346        cx: &mut Context<Self>,
 8347    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8348        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8349
 8350        let ((buffer_id, row), tasks) = self
 8351            .tasks
 8352            .iter()
 8353            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8354
 8355        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8356        let tasks = Arc::new(tasks.to_owned());
 8357        Some((buffer, *row, tasks))
 8358    }
 8359
 8360    fn find_enclosing_node_task(
 8361        &mut self,
 8362        cx: &mut Context<Self>,
 8363    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8364        let snapshot = self.buffer.read(cx).snapshot(cx);
 8365        let offset = self.selections.newest::<usize>(cx).head();
 8366        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8367        let buffer_id = excerpt.buffer().remote_id();
 8368
 8369        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8370        let mut cursor = layer.node().walk();
 8371
 8372        while cursor.goto_first_child_for_byte(offset).is_some() {
 8373            if cursor.node().end_byte() == offset {
 8374                cursor.goto_next_sibling();
 8375            }
 8376        }
 8377
 8378        // Ascend to the smallest ancestor that contains the range and has a task.
 8379        loop {
 8380            let node = cursor.node();
 8381            let node_range = node.byte_range();
 8382            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8383
 8384            // Check if this node contains our offset
 8385            if node_range.start <= offset && node_range.end >= offset {
 8386                // If it contains offset, check for task
 8387                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8388                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8389                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8390                }
 8391            }
 8392
 8393            if !cursor.goto_parent() {
 8394                break;
 8395            }
 8396        }
 8397        None
 8398    }
 8399
 8400    fn render_run_indicator(
 8401        &self,
 8402        _style: &EditorStyle,
 8403        is_active: bool,
 8404        row: DisplayRow,
 8405        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8406        cx: &mut Context<Self>,
 8407    ) -> IconButton {
 8408        let color = Color::Muted;
 8409        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8410
 8411        IconButton::new(
 8412            ("run_indicator", row.0 as usize),
 8413            ui::IconName::PlayOutlined,
 8414        )
 8415        .shape(ui::IconButtonShape::Square)
 8416        .icon_size(IconSize::XSmall)
 8417        .icon_color(color)
 8418        .toggle_state(is_active)
 8419        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8420            let quick_launch = match e {
 8421                ClickEvent::Keyboard(_) => true,
 8422                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8423            };
 8424
 8425            window.focus(&editor.focus_handle(cx));
 8426            editor.toggle_code_actions(
 8427                &ToggleCodeActions {
 8428                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8429                    quick_launch,
 8430                },
 8431                window,
 8432                cx,
 8433            );
 8434        }))
 8435        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8436            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8437        }))
 8438    }
 8439
 8440    pub fn context_menu_visible(&self) -> bool {
 8441        !self.edit_prediction_preview_is_active()
 8442            && self
 8443                .context_menu
 8444                .borrow()
 8445                .as_ref()
 8446                .map_or(false, |menu| menu.visible())
 8447    }
 8448
 8449    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8450        self.context_menu
 8451            .borrow()
 8452            .as_ref()
 8453            .map(|menu| menu.origin())
 8454    }
 8455
 8456    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8457        self.context_menu_options = Some(options);
 8458    }
 8459
 8460    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8461    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8462
 8463    fn render_edit_prediction_popover(
 8464        &mut self,
 8465        text_bounds: &Bounds<Pixels>,
 8466        content_origin: gpui::Point<Pixels>,
 8467        right_margin: Pixels,
 8468        editor_snapshot: &EditorSnapshot,
 8469        visible_row_range: Range<DisplayRow>,
 8470        scroll_top: f32,
 8471        scroll_bottom: f32,
 8472        line_layouts: &[LineWithInvisibles],
 8473        line_height: Pixels,
 8474        scroll_pixel_position: gpui::Point<Pixels>,
 8475        newest_selection_head: Option<DisplayPoint>,
 8476        editor_width: Pixels,
 8477        style: &EditorStyle,
 8478        window: &mut Window,
 8479        cx: &mut App,
 8480    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8481        if self.mode().is_minimap() {
 8482            return None;
 8483        }
 8484        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8485
 8486        if self.edit_prediction_visible_in_cursor_popover(true) {
 8487            return None;
 8488        }
 8489
 8490        match &active_edit_prediction.completion {
 8491            EditPrediction::Move { target, .. } => {
 8492                let target_display_point = target.to_display_point(editor_snapshot);
 8493
 8494                if self.edit_prediction_requires_modifier() {
 8495                    if !self.edit_prediction_preview_is_active() {
 8496                        return None;
 8497                    }
 8498
 8499                    self.render_edit_prediction_modifier_jump_popover(
 8500                        text_bounds,
 8501                        content_origin,
 8502                        visible_row_range,
 8503                        line_layouts,
 8504                        line_height,
 8505                        scroll_pixel_position,
 8506                        newest_selection_head,
 8507                        target_display_point,
 8508                        window,
 8509                        cx,
 8510                    )
 8511                } else {
 8512                    self.render_edit_prediction_eager_jump_popover(
 8513                        text_bounds,
 8514                        content_origin,
 8515                        editor_snapshot,
 8516                        visible_row_range,
 8517                        scroll_top,
 8518                        scroll_bottom,
 8519                        line_height,
 8520                        scroll_pixel_position,
 8521                        target_display_point,
 8522                        editor_width,
 8523                        window,
 8524                        cx,
 8525                    )
 8526                }
 8527            }
 8528            EditPrediction::Edit {
 8529                display_mode: EditDisplayMode::Inline,
 8530                ..
 8531            } => None,
 8532            EditPrediction::Edit {
 8533                display_mode: EditDisplayMode::TabAccept,
 8534                edits,
 8535                ..
 8536            } => {
 8537                let range = &edits.first()?.0;
 8538                let target_display_point = range.end.to_display_point(editor_snapshot);
 8539
 8540                self.render_edit_prediction_end_of_line_popover(
 8541                    "Accept",
 8542                    editor_snapshot,
 8543                    visible_row_range,
 8544                    target_display_point,
 8545                    line_height,
 8546                    scroll_pixel_position,
 8547                    content_origin,
 8548                    editor_width,
 8549                    window,
 8550                    cx,
 8551                )
 8552            }
 8553            EditPrediction::Edit {
 8554                edits,
 8555                edit_preview,
 8556                display_mode: EditDisplayMode::DiffPopover,
 8557                snapshot,
 8558            } => self.render_edit_prediction_diff_popover(
 8559                text_bounds,
 8560                content_origin,
 8561                right_margin,
 8562                editor_snapshot,
 8563                visible_row_range,
 8564                line_layouts,
 8565                line_height,
 8566                scroll_pixel_position,
 8567                newest_selection_head,
 8568                editor_width,
 8569                style,
 8570                edits,
 8571                edit_preview,
 8572                snapshot,
 8573                window,
 8574                cx,
 8575            ),
 8576        }
 8577    }
 8578
 8579    fn render_edit_prediction_modifier_jump_popover(
 8580        &mut self,
 8581        text_bounds: &Bounds<Pixels>,
 8582        content_origin: gpui::Point<Pixels>,
 8583        visible_row_range: Range<DisplayRow>,
 8584        line_layouts: &[LineWithInvisibles],
 8585        line_height: Pixels,
 8586        scroll_pixel_position: gpui::Point<Pixels>,
 8587        newest_selection_head: Option<DisplayPoint>,
 8588        target_display_point: DisplayPoint,
 8589        window: &mut Window,
 8590        cx: &mut App,
 8591    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8592        let scrolled_content_origin =
 8593            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8594
 8595        const SCROLL_PADDING_Y: Pixels = px(12.);
 8596
 8597        if target_display_point.row() < visible_row_range.start {
 8598            return self.render_edit_prediction_scroll_popover(
 8599                |_| SCROLL_PADDING_Y,
 8600                IconName::ArrowUp,
 8601                visible_row_range,
 8602                line_layouts,
 8603                newest_selection_head,
 8604                scrolled_content_origin,
 8605                window,
 8606                cx,
 8607            );
 8608        } else if target_display_point.row() >= visible_row_range.end {
 8609            return self.render_edit_prediction_scroll_popover(
 8610                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8611                IconName::ArrowDown,
 8612                visible_row_range,
 8613                line_layouts,
 8614                newest_selection_head,
 8615                scrolled_content_origin,
 8616                window,
 8617                cx,
 8618            );
 8619        }
 8620
 8621        const POLE_WIDTH: Pixels = px(2.);
 8622
 8623        let line_layout =
 8624            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8625        let target_column = target_display_point.column() as usize;
 8626
 8627        let target_x = line_layout.x_for_index(target_column);
 8628        let target_y =
 8629            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8630
 8631        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8632
 8633        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8634        border_color.l += 0.001;
 8635
 8636        let mut element = v_flex()
 8637            .items_end()
 8638            .when(flag_on_right, |el| el.items_start())
 8639            .child(if flag_on_right {
 8640                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8641                    .rounded_bl(px(0.))
 8642                    .rounded_tl(px(0.))
 8643                    .border_l_2()
 8644                    .border_color(border_color)
 8645            } else {
 8646                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8647                    .rounded_br(px(0.))
 8648                    .rounded_tr(px(0.))
 8649                    .border_r_2()
 8650                    .border_color(border_color)
 8651            })
 8652            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8653            .into_any();
 8654
 8655        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8656
 8657        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8658            - point(
 8659                if flag_on_right {
 8660                    POLE_WIDTH
 8661                } else {
 8662                    size.width - POLE_WIDTH
 8663                },
 8664                size.height - line_height,
 8665            );
 8666
 8667        origin.x = origin.x.max(content_origin.x);
 8668
 8669        element.prepaint_at(origin, window, cx);
 8670
 8671        Some((element, origin))
 8672    }
 8673
 8674    fn render_edit_prediction_scroll_popover(
 8675        &mut self,
 8676        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8677        scroll_icon: IconName,
 8678        visible_row_range: Range<DisplayRow>,
 8679        line_layouts: &[LineWithInvisibles],
 8680        newest_selection_head: Option<DisplayPoint>,
 8681        scrolled_content_origin: gpui::Point<Pixels>,
 8682        window: &mut Window,
 8683        cx: &mut App,
 8684    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8685        let mut element = self
 8686            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8687            .into_any();
 8688
 8689        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8690
 8691        let cursor = newest_selection_head?;
 8692        let cursor_row_layout =
 8693            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8694        let cursor_column = cursor.column() as usize;
 8695
 8696        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8697
 8698        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8699
 8700        element.prepaint_at(origin, window, cx);
 8701        Some((element, origin))
 8702    }
 8703
 8704    fn render_edit_prediction_eager_jump_popover(
 8705        &mut self,
 8706        text_bounds: &Bounds<Pixels>,
 8707        content_origin: gpui::Point<Pixels>,
 8708        editor_snapshot: &EditorSnapshot,
 8709        visible_row_range: Range<DisplayRow>,
 8710        scroll_top: f32,
 8711        scroll_bottom: f32,
 8712        line_height: Pixels,
 8713        scroll_pixel_position: gpui::Point<Pixels>,
 8714        target_display_point: DisplayPoint,
 8715        editor_width: Pixels,
 8716        window: &mut Window,
 8717        cx: &mut App,
 8718    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8719        if target_display_point.row().as_f32() < scroll_top {
 8720            let mut element = self
 8721                .render_edit_prediction_line_popover(
 8722                    "Jump to Edit",
 8723                    Some(IconName::ArrowUp),
 8724                    window,
 8725                    cx,
 8726                )?
 8727                .into_any();
 8728
 8729            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8730            let offset = point(
 8731                (text_bounds.size.width - size.width) / 2.,
 8732                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8733            );
 8734
 8735            let origin = text_bounds.origin + offset;
 8736            element.prepaint_at(origin, window, cx);
 8737            Some((element, origin))
 8738        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8739            let mut element = self
 8740                .render_edit_prediction_line_popover(
 8741                    "Jump to Edit",
 8742                    Some(IconName::ArrowDown),
 8743                    window,
 8744                    cx,
 8745                )?
 8746                .into_any();
 8747
 8748            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8749            let offset = point(
 8750                (text_bounds.size.width - size.width) / 2.,
 8751                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8752            );
 8753
 8754            let origin = text_bounds.origin + offset;
 8755            element.prepaint_at(origin, window, cx);
 8756            Some((element, origin))
 8757        } else {
 8758            self.render_edit_prediction_end_of_line_popover(
 8759                "Jump to Edit",
 8760                editor_snapshot,
 8761                visible_row_range,
 8762                target_display_point,
 8763                line_height,
 8764                scroll_pixel_position,
 8765                content_origin,
 8766                editor_width,
 8767                window,
 8768                cx,
 8769            )
 8770        }
 8771    }
 8772
 8773    fn render_edit_prediction_end_of_line_popover(
 8774        self: &mut Editor,
 8775        label: &'static str,
 8776        editor_snapshot: &EditorSnapshot,
 8777        visible_row_range: Range<DisplayRow>,
 8778        target_display_point: DisplayPoint,
 8779        line_height: Pixels,
 8780        scroll_pixel_position: gpui::Point<Pixels>,
 8781        content_origin: gpui::Point<Pixels>,
 8782        editor_width: Pixels,
 8783        window: &mut Window,
 8784        cx: &mut App,
 8785    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8786        let target_line_end = DisplayPoint::new(
 8787            target_display_point.row(),
 8788            editor_snapshot.line_len(target_display_point.row()),
 8789        );
 8790
 8791        let mut element = self
 8792            .render_edit_prediction_line_popover(label, None, window, cx)?
 8793            .into_any();
 8794
 8795        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8796
 8797        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8798
 8799        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8800        let mut origin = start_point
 8801            + line_origin
 8802            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8803        origin.x = origin.x.max(content_origin.x);
 8804
 8805        let max_x = content_origin.x + editor_width - size.width;
 8806
 8807        if origin.x > max_x {
 8808            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8809
 8810            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8811                origin.y += offset;
 8812                IconName::ArrowUp
 8813            } else {
 8814                origin.y -= offset;
 8815                IconName::ArrowDown
 8816            };
 8817
 8818            element = self
 8819                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8820                .into_any();
 8821
 8822            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8823
 8824            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8825        }
 8826
 8827        element.prepaint_at(origin, window, cx);
 8828        Some((element, origin))
 8829    }
 8830
 8831    fn render_edit_prediction_diff_popover(
 8832        self: &Editor,
 8833        text_bounds: &Bounds<Pixels>,
 8834        content_origin: gpui::Point<Pixels>,
 8835        right_margin: Pixels,
 8836        editor_snapshot: &EditorSnapshot,
 8837        visible_row_range: Range<DisplayRow>,
 8838        line_layouts: &[LineWithInvisibles],
 8839        line_height: Pixels,
 8840        scroll_pixel_position: gpui::Point<Pixels>,
 8841        newest_selection_head: Option<DisplayPoint>,
 8842        editor_width: Pixels,
 8843        style: &EditorStyle,
 8844        edits: &Vec<(Range<Anchor>, String)>,
 8845        edit_preview: &Option<language::EditPreview>,
 8846        snapshot: &language::BufferSnapshot,
 8847        window: &mut Window,
 8848        cx: &mut App,
 8849    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8850        let edit_start = edits
 8851            .first()
 8852            .unwrap()
 8853            .0
 8854            .start
 8855            .to_display_point(editor_snapshot);
 8856        let edit_end = edits
 8857            .last()
 8858            .unwrap()
 8859            .0
 8860            .end
 8861            .to_display_point(editor_snapshot);
 8862
 8863        let is_visible = visible_row_range.contains(&edit_start.row())
 8864            || visible_row_range.contains(&edit_end.row());
 8865        if !is_visible {
 8866            return None;
 8867        }
 8868
 8869        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8870            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8871        } else {
 8872            // Fallback for providers without edit_preview
 8873            crate::edit_prediction_fallback_text(edits, cx)
 8874        };
 8875
 8876        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8877        let line_count = highlighted_edits.text.lines().count();
 8878
 8879        const BORDER_WIDTH: Pixels = px(1.);
 8880
 8881        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8882        let has_keybind = keybind.is_some();
 8883
 8884        let mut element = h_flex()
 8885            .items_start()
 8886            .child(
 8887                h_flex()
 8888                    .bg(cx.theme().colors().editor_background)
 8889                    .border(BORDER_WIDTH)
 8890                    .shadow_xs()
 8891                    .border_color(cx.theme().colors().border)
 8892                    .rounded_l_lg()
 8893                    .when(line_count > 1, |el| el.rounded_br_lg())
 8894                    .pr_1()
 8895                    .child(styled_text),
 8896            )
 8897            .child(
 8898                h_flex()
 8899                    .h(line_height + BORDER_WIDTH * 2.)
 8900                    .px_1p5()
 8901                    .gap_1()
 8902                    // Workaround: For some reason, there's a gap if we don't do this
 8903                    .ml(-BORDER_WIDTH)
 8904                    .shadow(vec![gpui::BoxShadow {
 8905                        color: gpui::black().opacity(0.05),
 8906                        offset: point(px(1.), px(1.)),
 8907                        blur_radius: px(2.),
 8908                        spread_radius: px(0.),
 8909                    }])
 8910                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8911                    .border(BORDER_WIDTH)
 8912                    .border_color(cx.theme().colors().border)
 8913                    .rounded_r_lg()
 8914                    .id("edit_prediction_diff_popover_keybind")
 8915                    .when(!has_keybind, |el| {
 8916                        let status_colors = cx.theme().status();
 8917
 8918                        el.bg(status_colors.error_background)
 8919                            .border_color(status_colors.error.opacity(0.6))
 8920                            .child(Icon::new(IconName::Info).color(Color::Error))
 8921                            .cursor_default()
 8922                            .hoverable_tooltip(move |_window, cx| {
 8923                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8924                            })
 8925                    })
 8926                    .children(keybind),
 8927            )
 8928            .into_any();
 8929
 8930        let longest_row =
 8931            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8932        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8933            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8934        } else {
 8935            layout_line(
 8936                longest_row,
 8937                editor_snapshot,
 8938                style,
 8939                editor_width,
 8940                |_| false,
 8941                window,
 8942                cx,
 8943            )
 8944            .width
 8945        };
 8946
 8947        let viewport_bounds =
 8948            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8949                right: -right_margin,
 8950                ..Default::default()
 8951            });
 8952
 8953        let x_after_longest =
 8954            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8955                - scroll_pixel_position.x;
 8956
 8957        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8958
 8959        // Fully visible if it can be displayed within the window (allow overlapping other
 8960        // panes). However, this is only allowed if the popover starts within text_bounds.
 8961        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8962            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8963
 8964        let mut origin = if can_position_to_the_right {
 8965            point(
 8966                x_after_longest,
 8967                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8968                    - scroll_pixel_position.y,
 8969            )
 8970        } else {
 8971            let cursor_row = newest_selection_head.map(|head| head.row());
 8972            let above_edit = edit_start
 8973                .row()
 8974                .0
 8975                .checked_sub(line_count as u32)
 8976                .map(DisplayRow);
 8977            let below_edit = Some(edit_end.row() + 1);
 8978            let above_cursor =
 8979                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8980            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8981
 8982            // Place the edit popover adjacent to the edit if there is a location
 8983            // available that is onscreen and does not obscure the cursor. Otherwise,
 8984            // place it adjacent to the cursor.
 8985            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8986                .into_iter()
 8987                .flatten()
 8988                .find(|&start_row| {
 8989                    let end_row = start_row + line_count as u32;
 8990                    visible_row_range.contains(&start_row)
 8991                        && visible_row_range.contains(&end_row)
 8992                        && cursor_row.map_or(true, |cursor_row| {
 8993                            !((start_row..end_row).contains(&cursor_row))
 8994                        })
 8995                })?;
 8996
 8997            content_origin
 8998                + point(
 8999                    -scroll_pixel_position.x,
 9000                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9001                )
 9002        };
 9003
 9004        origin.x -= BORDER_WIDTH;
 9005
 9006        window.defer_draw(element, origin, 1);
 9007
 9008        // Do not return an element, since it will already be drawn due to defer_draw.
 9009        None
 9010    }
 9011
 9012    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9013        px(30.)
 9014    }
 9015
 9016    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9017        if self.read_only(cx) {
 9018            cx.theme().players().read_only()
 9019        } else {
 9020            self.style.as_ref().unwrap().local_player
 9021        }
 9022    }
 9023
 9024    fn render_edit_prediction_accept_keybind(
 9025        &self,
 9026        window: &mut Window,
 9027        cx: &App,
 9028    ) -> Option<AnyElement> {
 9029        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9030        let accept_keystroke = accept_binding.keystroke()?;
 9031
 9032        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9033
 9034        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 9035            Color::Accent
 9036        } else {
 9037            Color::Muted
 9038        };
 9039
 9040        h_flex()
 9041            .px_0p5()
 9042            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9043            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9044            .text_size(TextSize::XSmall.rems(cx))
 9045            .child(h_flex().children(ui::render_modifiers(
 9046                &accept_keystroke.modifiers,
 9047                PlatformStyle::platform(),
 9048                Some(modifiers_color),
 9049                Some(IconSize::XSmall.rems().into()),
 9050                true,
 9051            )))
 9052            .when(is_platform_style_mac, |parent| {
 9053                parent.child(accept_keystroke.key.clone())
 9054            })
 9055            .when(!is_platform_style_mac, |parent| {
 9056                parent.child(
 9057                    Key::new(
 9058                        util::capitalize(&accept_keystroke.key),
 9059                        Some(Color::Default),
 9060                    )
 9061                    .size(Some(IconSize::XSmall.rems().into())),
 9062                )
 9063            })
 9064            .into_any()
 9065            .into()
 9066    }
 9067
 9068    fn render_edit_prediction_line_popover(
 9069        &self,
 9070        label: impl Into<SharedString>,
 9071        icon: Option<IconName>,
 9072        window: &mut Window,
 9073        cx: &App,
 9074    ) -> Option<Stateful<Div>> {
 9075        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9076
 9077        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9078        let has_keybind = keybind.is_some();
 9079
 9080        let result = h_flex()
 9081            .id("ep-line-popover")
 9082            .py_0p5()
 9083            .pl_1()
 9084            .pr(padding_right)
 9085            .gap_1()
 9086            .rounded_md()
 9087            .border_1()
 9088            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9089            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9090            .shadow_xs()
 9091            .when(!has_keybind, |el| {
 9092                let status_colors = cx.theme().status();
 9093
 9094                el.bg(status_colors.error_background)
 9095                    .border_color(status_colors.error.opacity(0.6))
 9096                    .pl_2()
 9097                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9098                    .cursor_default()
 9099                    .hoverable_tooltip(move |_window, cx| {
 9100                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9101                    })
 9102            })
 9103            .children(keybind)
 9104            .child(
 9105                Label::new(label)
 9106                    .size(LabelSize::Small)
 9107                    .when(!has_keybind, |el| {
 9108                        el.color(cx.theme().status().error.into()).strikethrough()
 9109                    }),
 9110            )
 9111            .when(!has_keybind, |el| {
 9112                el.child(
 9113                    h_flex().ml_1().child(
 9114                        Icon::new(IconName::Info)
 9115                            .size(IconSize::Small)
 9116                            .color(cx.theme().status().error.into()),
 9117                    ),
 9118                )
 9119            })
 9120            .when_some(icon, |element, icon| {
 9121                element.child(
 9122                    div()
 9123                        .mt(px(1.5))
 9124                        .child(Icon::new(icon).size(IconSize::Small)),
 9125                )
 9126            });
 9127
 9128        Some(result)
 9129    }
 9130
 9131    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9132        let accent_color = cx.theme().colors().text_accent;
 9133        let editor_bg_color = cx.theme().colors().editor_background;
 9134        editor_bg_color.blend(accent_color.opacity(0.1))
 9135    }
 9136
 9137    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9138        let accent_color = cx.theme().colors().text_accent;
 9139        let editor_bg_color = cx.theme().colors().editor_background;
 9140        editor_bg_color.blend(accent_color.opacity(0.6))
 9141    }
 9142    fn get_prediction_provider_icon_name(
 9143        provider: &Option<RegisteredEditPredictionProvider>,
 9144    ) -> IconName {
 9145        match provider {
 9146            Some(provider) => match provider.provider.name() {
 9147                "copilot" => IconName::Copilot,
 9148                "supermaven" => IconName::Supermaven,
 9149                _ => IconName::ZedPredict,
 9150            },
 9151            None => IconName::ZedPredict,
 9152        }
 9153    }
 9154
 9155    fn render_edit_prediction_cursor_popover(
 9156        &self,
 9157        min_width: Pixels,
 9158        max_width: Pixels,
 9159        cursor_point: Point,
 9160        style: &EditorStyle,
 9161        accept_keystroke: Option<&gpui::Keystroke>,
 9162        _window: &Window,
 9163        cx: &mut Context<Editor>,
 9164    ) -> Option<AnyElement> {
 9165        let provider = self.edit_prediction_provider.as_ref()?;
 9166        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9167
 9168        if provider.provider.needs_terms_acceptance(cx) {
 9169            return Some(
 9170                h_flex()
 9171                    .min_w(min_width)
 9172                    .flex_1()
 9173                    .px_2()
 9174                    .py_1()
 9175                    .gap_3()
 9176                    .elevation_2(cx)
 9177                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9178                    .id("accept-terms")
 9179                    .cursor_pointer()
 9180                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9181                    .on_click(cx.listener(|this, _event, window, cx| {
 9182                        cx.stop_propagation();
 9183                        this.report_editor_event(ReportEditorEvent::ZetaTosClicked, None, cx);
 9184                        window.dispatch_action(
 9185                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9186                            cx,
 9187                        );
 9188                    }))
 9189                    .child(
 9190                        h_flex()
 9191                            .flex_1()
 9192                            .gap_2()
 9193                            .child(Icon::new(provider_icon))
 9194                            .child(Label::new("Accept Terms of Service"))
 9195                            .child(div().w_full())
 9196                            .child(
 9197                                Icon::new(IconName::ArrowUpRight)
 9198                                    .color(Color::Muted)
 9199                                    .size(IconSize::Small),
 9200                            )
 9201                            .into_any_element(),
 9202                    )
 9203                    .into_any(),
 9204            );
 9205        }
 9206
 9207        let is_refreshing = provider.provider.is_refreshing(cx);
 9208
 9209        fn pending_completion_container(icon: IconName) -> Div {
 9210            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9211        }
 9212
 9213        let completion = match &self.active_edit_prediction {
 9214            Some(prediction) => {
 9215                if !self.has_visible_completions_menu() {
 9216                    const RADIUS: Pixels = px(6.);
 9217                    const BORDER_WIDTH: Pixels = px(1.);
 9218
 9219                    return Some(
 9220                        h_flex()
 9221                            .elevation_2(cx)
 9222                            .border(BORDER_WIDTH)
 9223                            .border_color(cx.theme().colors().border)
 9224                            .when(accept_keystroke.is_none(), |el| {
 9225                                el.border_color(cx.theme().status().error)
 9226                            })
 9227                            .rounded(RADIUS)
 9228                            .rounded_tl(px(0.))
 9229                            .overflow_hidden()
 9230                            .child(div().px_1p5().child(match &prediction.completion {
 9231                                EditPrediction::Move { target, snapshot } => {
 9232                                    use text::ToPoint as _;
 9233                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9234                                    {
 9235                                        Icon::new(IconName::ZedPredictDown)
 9236                                    } else {
 9237                                        Icon::new(IconName::ZedPredictUp)
 9238                                    }
 9239                                }
 9240                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9241                            }))
 9242                            .child(
 9243                                h_flex()
 9244                                    .gap_1()
 9245                                    .py_1()
 9246                                    .px_2()
 9247                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9248                                    .border_l_1()
 9249                                    .border_color(cx.theme().colors().border)
 9250                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9251                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9252                                        el.child(
 9253                                            Label::new("Hold")
 9254                                                .size(LabelSize::Small)
 9255                                                .when(accept_keystroke.is_none(), |el| {
 9256                                                    el.strikethrough()
 9257                                                })
 9258                                                .line_height_style(LineHeightStyle::UiLabel),
 9259                                        )
 9260                                    })
 9261                                    .id("edit_prediction_cursor_popover_keybind")
 9262                                    .when(accept_keystroke.is_none(), |el| {
 9263                                        let status_colors = cx.theme().status();
 9264
 9265                                        el.bg(status_colors.error_background)
 9266                                            .border_color(status_colors.error.opacity(0.6))
 9267                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9268                                            .cursor_default()
 9269                                            .hoverable_tooltip(move |_window, cx| {
 9270                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9271                                                    .into()
 9272                                            })
 9273                                    })
 9274                                    .when_some(
 9275                                        accept_keystroke.as_ref(),
 9276                                        |el, accept_keystroke| {
 9277                                            el.child(h_flex().children(ui::render_modifiers(
 9278                                                &accept_keystroke.modifiers,
 9279                                                PlatformStyle::platform(),
 9280                                                Some(Color::Default),
 9281                                                Some(IconSize::XSmall.rems().into()),
 9282                                                false,
 9283                                            )))
 9284                                        },
 9285                                    ),
 9286                            )
 9287                            .into_any(),
 9288                    );
 9289                }
 9290
 9291                self.render_edit_prediction_cursor_popover_preview(
 9292                    prediction,
 9293                    cursor_point,
 9294                    style,
 9295                    cx,
 9296                )?
 9297            }
 9298
 9299            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9300                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9301                    stale_completion,
 9302                    cursor_point,
 9303                    style,
 9304                    cx,
 9305                )?,
 9306
 9307                None => pending_completion_container(provider_icon)
 9308                    .child(Label::new("...").size(LabelSize::Small)),
 9309            },
 9310
 9311            None => pending_completion_container(provider_icon)
 9312                .child(Label::new("...").size(LabelSize::Small)),
 9313        };
 9314
 9315        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9316            completion
 9317                .with_animation(
 9318                    "loading-completion",
 9319                    Animation::new(Duration::from_secs(2))
 9320                        .repeat()
 9321                        .with_easing(pulsating_between(0.4, 0.8)),
 9322                    |label, delta| label.opacity(delta),
 9323                )
 9324                .into_any_element()
 9325        } else {
 9326            completion.into_any_element()
 9327        };
 9328
 9329        let has_completion = self.active_edit_prediction.is_some();
 9330
 9331        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9332        Some(
 9333            h_flex()
 9334                .min_w(min_width)
 9335                .max_w(max_width)
 9336                .flex_1()
 9337                .elevation_2(cx)
 9338                .border_color(cx.theme().colors().border)
 9339                .child(
 9340                    div()
 9341                        .flex_1()
 9342                        .py_1()
 9343                        .px_2()
 9344                        .overflow_hidden()
 9345                        .child(completion),
 9346                )
 9347                .when_some(accept_keystroke, |el, accept_keystroke| {
 9348                    if !accept_keystroke.modifiers.modified() {
 9349                        return el;
 9350                    }
 9351
 9352                    el.child(
 9353                        h_flex()
 9354                            .h_full()
 9355                            .border_l_1()
 9356                            .rounded_r_lg()
 9357                            .border_color(cx.theme().colors().border)
 9358                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9359                            .gap_1()
 9360                            .py_1()
 9361                            .px_2()
 9362                            .child(
 9363                                h_flex()
 9364                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9365                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9366                                    .child(h_flex().children(ui::render_modifiers(
 9367                                        &accept_keystroke.modifiers,
 9368                                        PlatformStyle::platform(),
 9369                                        Some(if !has_completion {
 9370                                            Color::Muted
 9371                                        } else {
 9372                                            Color::Default
 9373                                        }),
 9374                                        None,
 9375                                        false,
 9376                                    ))),
 9377                            )
 9378                            .child(Label::new("Preview").into_any_element())
 9379                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9380                    )
 9381                })
 9382                .into_any(),
 9383        )
 9384    }
 9385
 9386    fn render_edit_prediction_cursor_popover_preview(
 9387        &self,
 9388        completion: &EditPredictionState,
 9389        cursor_point: Point,
 9390        style: &EditorStyle,
 9391        cx: &mut Context<Editor>,
 9392    ) -> Option<Div> {
 9393        use text::ToPoint as _;
 9394
 9395        fn render_relative_row_jump(
 9396            prefix: impl Into<String>,
 9397            current_row: u32,
 9398            target_row: u32,
 9399        ) -> Div {
 9400            let (row_diff, arrow) = if target_row < current_row {
 9401                (current_row - target_row, IconName::ArrowUp)
 9402            } else {
 9403                (target_row - current_row, IconName::ArrowDown)
 9404            };
 9405
 9406            h_flex()
 9407                .child(
 9408                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9409                        .color(Color::Muted)
 9410                        .size(LabelSize::Small),
 9411                )
 9412                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9413        }
 9414
 9415        let supports_jump = self
 9416            .edit_prediction_provider
 9417            .as_ref()
 9418            .map(|provider| provider.provider.supports_jump_to_edit())
 9419            .unwrap_or(true);
 9420
 9421        match &completion.completion {
 9422            EditPrediction::Move {
 9423                target, snapshot, ..
 9424            } => {
 9425                if !supports_jump {
 9426                    return None;
 9427                }
 9428
 9429                Some(
 9430                    h_flex()
 9431                        .px_2()
 9432                        .gap_2()
 9433                        .flex_1()
 9434                        .child(
 9435                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9436                                Icon::new(IconName::ZedPredictDown)
 9437                            } else {
 9438                                Icon::new(IconName::ZedPredictUp)
 9439                            },
 9440                        )
 9441                        .child(Label::new("Jump to Edit")),
 9442                )
 9443            }
 9444
 9445            EditPrediction::Edit {
 9446                edits,
 9447                edit_preview,
 9448                snapshot,
 9449                display_mode: _,
 9450            } => {
 9451                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9452
 9453                let (highlighted_edits, has_more_lines) =
 9454                    if let Some(edit_preview) = edit_preview.as_ref() {
 9455                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9456                            .first_line_preview()
 9457                    } else {
 9458                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9459                    };
 9460
 9461                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9462                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9463
 9464                let preview = h_flex()
 9465                    .gap_1()
 9466                    .min_w_16()
 9467                    .child(styled_text)
 9468                    .when(has_more_lines, |parent| parent.child(""));
 9469
 9470                let left = if supports_jump && first_edit_row != cursor_point.row {
 9471                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9472                        .into_any_element()
 9473                } else {
 9474                    let icon_name =
 9475                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9476                    Icon::new(icon_name).into_any_element()
 9477                };
 9478
 9479                Some(
 9480                    h_flex()
 9481                        .h_full()
 9482                        .flex_1()
 9483                        .gap_2()
 9484                        .pr_1()
 9485                        .overflow_x_hidden()
 9486                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9487                        .child(left)
 9488                        .child(preview),
 9489                )
 9490            }
 9491        }
 9492    }
 9493
 9494    pub fn render_context_menu(
 9495        &self,
 9496        style: &EditorStyle,
 9497        max_height_in_lines: u32,
 9498        window: &mut Window,
 9499        cx: &mut Context<Editor>,
 9500    ) -> Option<AnyElement> {
 9501        let menu = self.context_menu.borrow();
 9502        let menu = menu.as_ref()?;
 9503        if !menu.visible() {
 9504            return None;
 9505        };
 9506        Some(menu.render(style, max_height_in_lines, window, cx))
 9507    }
 9508
 9509    fn render_context_menu_aside(
 9510        &mut self,
 9511        max_size: Size<Pixels>,
 9512        window: &mut Window,
 9513        cx: &mut Context<Editor>,
 9514    ) -> Option<AnyElement> {
 9515        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9516            if menu.visible() {
 9517                menu.render_aside(max_size, window, cx)
 9518            } else {
 9519                None
 9520            }
 9521        })
 9522    }
 9523
 9524    fn hide_context_menu(
 9525        &mut self,
 9526        window: &mut Window,
 9527        cx: &mut Context<Self>,
 9528    ) -> Option<CodeContextMenu> {
 9529        cx.notify();
 9530        self.completion_tasks.clear();
 9531        let context_menu = self.context_menu.borrow_mut().take();
 9532        self.stale_edit_prediction_in_menu.take();
 9533        self.update_visible_edit_prediction(window, cx);
 9534        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9535            if let Some(completion_provider) = &self.completion_provider {
 9536                completion_provider.selection_changed(None, window, cx);
 9537            }
 9538        }
 9539        context_menu
 9540    }
 9541
 9542    fn show_snippet_choices(
 9543        &mut self,
 9544        choices: &Vec<String>,
 9545        selection: Range<Anchor>,
 9546        cx: &mut Context<Self>,
 9547    ) {
 9548        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9549            (Some(a), Some(b)) if a == b => a,
 9550            _ => {
 9551                log::error!("expected anchor range to have matching buffer IDs");
 9552                return;
 9553            }
 9554        };
 9555        let multi_buffer = self.buffer().read(cx);
 9556        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9557            return;
 9558        };
 9559
 9560        let id = post_inc(&mut self.next_completion_id);
 9561        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9562        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9563            CompletionsMenu::new_snippet_choices(
 9564                id,
 9565                true,
 9566                choices,
 9567                selection,
 9568                buffer,
 9569                snippet_sort_order,
 9570            ),
 9571        ));
 9572    }
 9573
 9574    pub fn insert_snippet(
 9575        &mut self,
 9576        insertion_ranges: &[Range<usize>],
 9577        snippet: Snippet,
 9578        window: &mut Window,
 9579        cx: &mut Context<Self>,
 9580    ) -> Result<()> {
 9581        struct Tabstop<T> {
 9582            is_end_tabstop: bool,
 9583            ranges: Vec<Range<T>>,
 9584            choices: Option<Vec<String>>,
 9585        }
 9586
 9587        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9588            let snippet_text: Arc<str> = snippet.text.clone().into();
 9589            let edits = insertion_ranges
 9590                .iter()
 9591                .cloned()
 9592                .map(|range| (range, snippet_text.clone()));
 9593            let autoindent_mode = AutoindentMode::Block {
 9594                original_indent_columns: Vec::new(),
 9595            };
 9596            buffer.edit(edits, Some(autoindent_mode), cx);
 9597
 9598            let snapshot = &*buffer.read(cx);
 9599            let snippet = &snippet;
 9600            snippet
 9601                .tabstops
 9602                .iter()
 9603                .map(|tabstop| {
 9604                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9605                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9606                    });
 9607                    let mut tabstop_ranges = tabstop
 9608                        .ranges
 9609                        .iter()
 9610                        .flat_map(|tabstop_range| {
 9611                            let mut delta = 0_isize;
 9612                            insertion_ranges.iter().map(move |insertion_range| {
 9613                                let insertion_start = insertion_range.start as isize + delta;
 9614                                delta +=
 9615                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9616
 9617                                let start = ((insertion_start + tabstop_range.start) as usize)
 9618                                    .min(snapshot.len());
 9619                                let end = ((insertion_start + tabstop_range.end) as usize)
 9620                                    .min(snapshot.len());
 9621                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9622                            })
 9623                        })
 9624                        .collect::<Vec<_>>();
 9625                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9626
 9627                    Tabstop {
 9628                        is_end_tabstop,
 9629                        ranges: tabstop_ranges,
 9630                        choices: tabstop.choices.clone(),
 9631                    }
 9632                })
 9633                .collect::<Vec<_>>()
 9634        });
 9635        if let Some(tabstop) = tabstops.first() {
 9636            self.change_selections(Default::default(), window, cx, |s| {
 9637                // Reverse order so that the first range is the newest created selection.
 9638                // Completions will use it and autoscroll will prioritize it.
 9639                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9640            });
 9641
 9642            if let Some(choices) = &tabstop.choices {
 9643                if let Some(selection) = tabstop.ranges.first() {
 9644                    self.show_snippet_choices(choices, selection.clone(), cx)
 9645                }
 9646            }
 9647
 9648            // If we're already at the last tabstop and it's at the end of the snippet,
 9649            // we're done, we don't need to keep the state around.
 9650            if !tabstop.is_end_tabstop {
 9651                let choices = tabstops
 9652                    .iter()
 9653                    .map(|tabstop| tabstop.choices.clone())
 9654                    .collect();
 9655
 9656                let ranges = tabstops
 9657                    .into_iter()
 9658                    .map(|tabstop| tabstop.ranges)
 9659                    .collect::<Vec<_>>();
 9660
 9661                self.snippet_stack.push(SnippetState {
 9662                    active_index: 0,
 9663                    ranges,
 9664                    choices,
 9665                });
 9666            }
 9667
 9668            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9669            if self.autoclose_regions.is_empty() {
 9670                let snapshot = self.buffer.read(cx).snapshot(cx);
 9671                let mut all_selections = self.selections.all::<Point>(cx);
 9672                for selection in &mut all_selections {
 9673                    let selection_head = selection.head();
 9674                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9675                        continue;
 9676                    };
 9677
 9678                    let mut bracket_pair = None;
 9679                    let max_lookup_length = scope
 9680                        .brackets()
 9681                        .map(|(pair, _)| {
 9682                            pair.start
 9683                                .as_str()
 9684                                .chars()
 9685                                .count()
 9686                                .max(pair.end.as_str().chars().count())
 9687                        })
 9688                        .max();
 9689                    if let Some(max_lookup_length) = max_lookup_length {
 9690                        let next_text = snapshot
 9691                            .chars_at(selection_head)
 9692                            .take(max_lookup_length)
 9693                            .collect::<String>();
 9694                        let prev_text = snapshot
 9695                            .reversed_chars_at(selection_head)
 9696                            .take(max_lookup_length)
 9697                            .collect::<String>();
 9698
 9699                        for (pair, enabled) in scope.brackets() {
 9700                            if enabled
 9701                                && pair.close
 9702                                && prev_text.starts_with(pair.start.as_str())
 9703                                && next_text.starts_with(pair.end.as_str())
 9704                            {
 9705                                bracket_pair = Some(pair.clone());
 9706                                break;
 9707                            }
 9708                        }
 9709                    }
 9710
 9711                    if let Some(pair) = bracket_pair {
 9712                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9713                        let autoclose_enabled =
 9714                            self.use_autoclose && snapshot_settings.use_autoclose;
 9715                        if autoclose_enabled {
 9716                            let start = snapshot.anchor_after(selection_head);
 9717                            let end = snapshot.anchor_after(selection_head);
 9718                            self.autoclose_regions.push(AutocloseRegion {
 9719                                selection_id: selection.id,
 9720                                range: start..end,
 9721                                pair,
 9722                            });
 9723                        }
 9724                    }
 9725                }
 9726            }
 9727        }
 9728        Ok(())
 9729    }
 9730
 9731    pub fn move_to_next_snippet_tabstop(
 9732        &mut self,
 9733        window: &mut Window,
 9734        cx: &mut Context<Self>,
 9735    ) -> bool {
 9736        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9737    }
 9738
 9739    pub fn move_to_prev_snippet_tabstop(
 9740        &mut self,
 9741        window: &mut Window,
 9742        cx: &mut Context<Self>,
 9743    ) -> bool {
 9744        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9745    }
 9746
 9747    pub fn move_to_snippet_tabstop(
 9748        &mut self,
 9749        bias: Bias,
 9750        window: &mut Window,
 9751        cx: &mut Context<Self>,
 9752    ) -> bool {
 9753        if let Some(mut snippet) = self.snippet_stack.pop() {
 9754            match bias {
 9755                Bias::Left => {
 9756                    if snippet.active_index > 0 {
 9757                        snippet.active_index -= 1;
 9758                    } else {
 9759                        self.snippet_stack.push(snippet);
 9760                        return false;
 9761                    }
 9762                }
 9763                Bias::Right => {
 9764                    if snippet.active_index + 1 < snippet.ranges.len() {
 9765                        snippet.active_index += 1;
 9766                    } else {
 9767                        self.snippet_stack.push(snippet);
 9768                        return false;
 9769                    }
 9770                }
 9771            }
 9772            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9773                self.change_selections(Default::default(), window, cx, |s| {
 9774                    // Reverse order so that the first range is the newest created selection.
 9775                    // Completions will use it and autoscroll will prioritize it.
 9776                    s.select_ranges(current_ranges.iter().rev().cloned())
 9777                });
 9778
 9779                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9780                    if let Some(selection) = current_ranges.first() {
 9781                        self.show_snippet_choices(choices, selection.clone(), cx);
 9782                    }
 9783                }
 9784
 9785                // If snippet state is not at the last tabstop, push it back on the stack
 9786                if snippet.active_index + 1 < snippet.ranges.len() {
 9787                    self.snippet_stack.push(snippet);
 9788                }
 9789                return true;
 9790            }
 9791        }
 9792
 9793        false
 9794    }
 9795
 9796    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9797        self.transact(window, cx, |this, window, cx| {
 9798            this.select_all(&SelectAll, window, cx);
 9799            this.insert("", window, cx);
 9800        });
 9801    }
 9802
 9803    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9804        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9805        self.transact(window, cx, |this, window, cx| {
 9806            this.select_autoclose_pair(window, cx);
 9807            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9808            if !this.linked_edit_ranges.is_empty() {
 9809                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9810                let snapshot = this.buffer.read(cx).snapshot(cx);
 9811
 9812                for selection in selections.iter() {
 9813                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9814                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9815                    if selection_start.buffer_id != selection_end.buffer_id {
 9816                        continue;
 9817                    }
 9818                    if let Some(ranges) =
 9819                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9820                    {
 9821                        for (buffer, entries) in ranges {
 9822                            linked_ranges.entry(buffer).or_default().extend(entries);
 9823                        }
 9824                    }
 9825                }
 9826            }
 9827
 9828            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9829            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9830            for selection in &mut selections {
 9831                if selection.is_empty() {
 9832                    let old_head = selection.head();
 9833                    let mut new_head =
 9834                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9835                            .to_point(&display_map);
 9836                    if let Some((buffer, line_buffer_range)) = display_map
 9837                        .buffer_snapshot
 9838                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9839                    {
 9840                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9841                        let indent_len = match indent_size.kind {
 9842                            IndentKind::Space => {
 9843                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9844                            }
 9845                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9846                        };
 9847                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9848                            let indent_len = indent_len.get();
 9849                            new_head = cmp::min(
 9850                                new_head,
 9851                                MultiBufferPoint::new(
 9852                                    old_head.row,
 9853                                    ((old_head.column - 1) / indent_len) * indent_len,
 9854                                ),
 9855                            );
 9856                        }
 9857                    }
 9858
 9859                    selection.set_head(new_head, SelectionGoal::None);
 9860                }
 9861            }
 9862
 9863            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9864            this.insert("", window, cx);
 9865            let empty_str: Arc<str> = Arc::from("");
 9866            for (buffer, edits) in linked_ranges {
 9867                let snapshot = buffer.read(cx).snapshot();
 9868                use text::ToPoint as TP;
 9869
 9870                let edits = edits
 9871                    .into_iter()
 9872                    .map(|range| {
 9873                        let end_point = TP::to_point(&range.end, &snapshot);
 9874                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9875
 9876                        if end_point == start_point {
 9877                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9878                                .saturating_sub(1);
 9879                            start_point =
 9880                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9881                        };
 9882
 9883                        (start_point..end_point, empty_str.clone())
 9884                    })
 9885                    .sorted_by_key(|(range, _)| range.start)
 9886                    .collect::<Vec<_>>();
 9887                buffer.update(cx, |this, cx| {
 9888                    this.edit(edits, None, cx);
 9889                })
 9890            }
 9891            this.refresh_edit_prediction(true, false, window, cx);
 9892            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9893        });
 9894    }
 9895
 9896    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9897        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9898        self.transact(window, cx, |this, window, cx| {
 9899            this.change_selections(Default::default(), window, cx, |s| {
 9900                s.move_with(|map, selection| {
 9901                    if selection.is_empty() {
 9902                        let cursor = movement::right(map, selection.head());
 9903                        selection.end = cursor;
 9904                        selection.reversed = true;
 9905                        selection.goal = SelectionGoal::None;
 9906                    }
 9907                })
 9908            });
 9909            this.insert("", window, cx);
 9910            this.refresh_edit_prediction(true, false, window, cx);
 9911        });
 9912    }
 9913
 9914    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9915        if self.mode.is_single_line() {
 9916            cx.propagate();
 9917            return;
 9918        }
 9919
 9920        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9921        if self.move_to_prev_snippet_tabstop(window, cx) {
 9922            return;
 9923        }
 9924        self.outdent(&Outdent, window, cx);
 9925    }
 9926
 9927    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9928        if self.mode.is_single_line() {
 9929            cx.propagate();
 9930            return;
 9931        }
 9932
 9933        if self.move_to_next_snippet_tabstop(window, cx) {
 9934            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9935            return;
 9936        }
 9937        if self.read_only(cx) {
 9938            return;
 9939        }
 9940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9941        let mut selections = self.selections.all_adjusted(cx);
 9942        let buffer = self.buffer.read(cx);
 9943        let snapshot = buffer.snapshot(cx);
 9944        let rows_iter = selections.iter().map(|s| s.head().row);
 9945        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9946
 9947        let has_some_cursor_in_whitespace = selections
 9948            .iter()
 9949            .filter(|selection| selection.is_empty())
 9950            .any(|selection| {
 9951                let cursor = selection.head();
 9952                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9953                cursor.column < current_indent.len
 9954            });
 9955
 9956        let mut edits = Vec::new();
 9957        let mut prev_edited_row = 0;
 9958        let mut row_delta = 0;
 9959        for selection in &mut selections {
 9960            if selection.start.row != prev_edited_row {
 9961                row_delta = 0;
 9962            }
 9963            prev_edited_row = selection.end.row;
 9964
 9965            // If the selection is non-empty, then increase the indentation of the selected lines.
 9966            if !selection.is_empty() {
 9967                row_delta =
 9968                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9969                continue;
 9970            }
 9971
 9972            let cursor = selection.head();
 9973            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9974            if let Some(suggested_indent) =
 9975                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9976            {
 9977                // Don't do anything if already at suggested indent
 9978                // and there is any other cursor which is not
 9979                if has_some_cursor_in_whitespace
 9980                    && cursor.column == current_indent.len
 9981                    && current_indent.len == suggested_indent.len
 9982                {
 9983                    continue;
 9984                }
 9985
 9986                // Adjust line and move cursor to suggested indent
 9987                // if cursor is not at suggested indent
 9988                if cursor.column < suggested_indent.len
 9989                    && cursor.column <= current_indent.len
 9990                    && current_indent.len <= suggested_indent.len
 9991                {
 9992                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9993                    selection.end = selection.start;
 9994                    if row_delta == 0 {
 9995                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9996                            cursor.row,
 9997                            current_indent,
 9998                            suggested_indent,
 9999                        ));
10000                        row_delta = suggested_indent.len - current_indent.len;
10001                    }
10002                    continue;
10003                }
10004
10005                // If current indent is more than suggested indent
10006                // only move cursor to current indent and skip indent
10007                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10008                    selection.start = Point::new(cursor.row, current_indent.len);
10009                    selection.end = selection.start;
10010                    continue;
10011                }
10012            }
10013
10014            // Otherwise, insert a hard or soft tab.
10015            let settings = buffer.language_settings_at(cursor, cx);
10016            let tab_size = if settings.hard_tabs {
10017                IndentSize::tab()
10018            } else {
10019                let tab_size = settings.tab_size.get();
10020                let indent_remainder = snapshot
10021                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10022                    .flat_map(str::chars)
10023                    .fold(row_delta % tab_size, |counter: u32, c| {
10024                        if c == '\t' {
10025                            0
10026                        } else {
10027                            (counter + 1) % tab_size
10028                        }
10029                    });
10030
10031                let chars_to_next_tab_stop = tab_size - indent_remainder;
10032                IndentSize::spaces(chars_to_next_tab_stop)
10033            };
10034            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10035            selection.end = selection.start;
10036            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10037            row_delta += tab_size.len;
10038        }
10039
10040        self.transact(window, cx, |this, window, cx| {
10041            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10042            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10043            this.refresh_edit_prediction(true, false, window, cx);
10044        });
10045    }
10046
10047    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10048        if self.read_only(cx) {
10049            return;
10050        }
10051        if self.mode.is_single_line() {
10052            cx.propagate();
10053            return;
10054        }
10055
10056        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10057        let mut selections = self.selections.all::<Point>(cx);
10058        let mut prev_edited_row = 0;
10059        let mut row_delta = 0;
10060        let mut edits = Vec::new();
10061        let buffer = self.buffer.read(cx);
10062        let snapshot = buffer.snapshot(cx);
10063        for selection in &mut selections {
10064            if selection.start.row != prev_edited_row {
10065                row_delta = 0;
10066            }
10067            prev_edited_row = selection.end.row;
10068
10069            row_delta =
10070                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10071        }
10072
10073        self.transact(window, cx, |this, window, cx| {
10074            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10075            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10076        });
10077    }
10078
10079    fn indent_selection(
10080        buffer: &MultiBuffer,
10081        snapshot: &MultiBufferSnapshot,
10082        selection: &mut Selection<Point>,
10083        edits: &mut Vec<(Range<Point>, String)>,
10084        delta_for_start_row: u32,
10085        cx: &App,
10086    ) -> u32 {
10087        let settings = buffer.language_settings_at(selection.start, cx);
10088        let tab_size = settings.tab_size.get();
10089        let indent_kind = if settings.hard_tabs {
10090            IndentKind::Tab
10091        } else {
10092            IndentKind::Space
10093        };
10094        let mut start_row = selection.start.row;
10095        let mut end_row = selection.end.row + 1;
10096
10097        // If a selection ends at the beginning of a line, don't indent
10098        // that last line.
10099        if selection.end.column == 0 && selection.end.row > selection.start.row {
10100            end_row -= 1;
10101        }
10102
10103        // Avoid re-indenting a row that has already been indented by a
10104        // previous selection, but still update this selection's column
10105        // to reflect that indentation.
10106        if delta_for_start_row > 0 {
10107            start_row += 1;
10108            selection.start.column += delta_for_start_row;
10109            if selection.end.row == selection.start.row {
10110                selection.end.column += delta_for_start_row;
10111            }
10112        }
10113
10114        let mut delta_for_end_row = 0;
10115        let has_multiple_rows = start_row + 1 != end_row;
10116        for row in start_row..end_row {
10117            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10118            let indent_delta = match (current_indent.kind, indent_kind) {
10119                (IndentKind::Space, IndentKind::Space) => {
10120                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10121                    IndentSize::spaces(columns_to_next_tab_stop)
10122                }
10123                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10124                (_, IndentKind::Tab) => IndentSize::tab(),
10125            };
10126
10127            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10128                0
10129            } else {
10130                selection.start.column
10131            };
10132            let row_start = Point::new(row, start);
10133            edits.push((
10134                row_start..row_start,
10135                indent_delta.chars().collect::<String>(),
10136            ));
10137
10138            // Update this selection's endpoints to reflect the indentation.
10139            if row == selection.start.row {
10140                selection.start.column += indent_delta.len;
10141            }
10142            if row == selection.end.row {
10143                selection.end.column += indent_delta.len;
10144                delta_for_end_row = indent_delta.len;
10145            }
10146        }
10147
10148        if selection.start.row == selection.end.row {
10149            delta_for_start_row + delta_for_end_row
10150        } else {
10151            delta_for_end_row
10152        }
10153    }
10154
10155    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10156        if self.read_only(cx) {
10157            return;
10158        }
10159        if self.mode.is_single_line() {
10160            cx.propagate();
10161            return;
10162        }
10163
10164        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10165        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10166        let selections = self.selections.all::<Point>(cx);
10167        let mut deletion_ranges = Vec::new();
10168        let mut last_outdent = None;
10169        {
10170            let buffer = self.buffer.read(cx);
10171            let snapshot = buffer.snapshot(cx);
10172            for selection in &selections {
10173                let settings = buffer.language_settings_at(selection.start, cx);
10174                let tab_size = settings.tab_size.get();
10175                let mut rows = selection.spanned_rows(false, &display_map);
10176
10177                // Avoid re-outdenting a row that has already been outdented by a
10178                // previous selection.
10179                if let Some(last_row) = last_outdent {
10180                    if last_row == rows.start {
10181                        rows.start = rows.start.next_row();
10182                    }
10183                }
10184                let has_multiple_rows = rows.len() > 1;
10185                for row in rows.iter_rows() {
10186                    let indent_size = snapshot.indent_size_for_line(row);
10187                    if indent_size.len > 0 {
10188                        let deletion_len = match indent_size.kind {
10189                            IndentKind::Space => {
10190                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10191                                if columns_to_prev_tab_stop == 0 {
10192                                    tab_size
10193                                } else {
10194                                    columns_to_prev_tab_stop
10195                                }
10196                            }
10197                            IndentKind::Tab => 1,
10198                        };
10199                        let start = if has_multiple_rows
10200                            || deletion_len > selection.start.column
10201                            || indent_size.len < selection.start.column
10202                        {
10203                            0
10204                        } else {
10205                            selection.start.column - deletion_len
10206                        };
10207                        deletion_ranges.push(
10208                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10209                        );
10210                        last_outdent = Some(row);
10211                    }
10212                }
10213            }
10214        }
10215
10216        self.transact(window, cx, |this, window, cx| {
10217            this.buffer.update(cx, |buffer, cx| {
10218                let empty_str: Arc<str> = Arc::default();
10219                buffer.edit(
10220                    deletion_ranges
10221                        .into_iter()
10222                        .map(|range| (range, empty_str.clone())),
10223                    None,
10224                    cx,
10225                );
10226            });
10227            let selections = this.selections.all::<usize>(cx);
10228            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10229        });
10230    }
10231
10232    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10233        if self.read_only(cx) {
10234            return;
10235        }
10236        if self.mode.is_single_line() {
10237            cx.propagate();
10238            return;
10239        }
10240
10241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10242        let selections = self
10243            .selections
10244            .all::<usize>(cx)
10245            .into_iter()
10246            .map(|s| s.range());
10247
10248        self.transact(window, cx, |this, window, cx| {
10249            this.buffer.update(cx, |buffer, cx| {
10250                buffer.autoindent_ranges(selections, cx);
10251            });
10252            let selections = this.selections.all::<usize>(cx);
10253            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10254        });
10255    }
10256
10257    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10258        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10260        let selections = self.selections.all::<Point>(cx);
10261
10262        let mut new_cursors = Vec::new();
10263        let mut edit_ranges = Vec::new();
10264        let mut selections = selections.iter().peekable();
10265        while let Some(selection) = selections.next() {
10266            let mut rows = selection.spanned_rows(false, &display_map);
10267            let goal_display_column = selection.head().to_display_point(&display_map).column();
10268
10269            // Accumulate contiguous regions of rows that we want to delete.
10270            while let Some(next_selection) = selections.peek() {
10271                let next_rows = next_selection.spanned_rows(false, &display_map);
10272                if next_rows.start <= rows.end {
10273                    rows.end = next_rows.end;
10274                    selections.next().unwrap();
10275                } else {
10276                    break;
10277                }
10278            }
10279
10280            let buffer = &display_map.buffer_snapshot;
10281            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10282            let edit_end;
10283            let cursor_buffer_row;
10284            if buffer.max_point().row >= rows.end.0 {
10285                // If there's a line after the range, delete the \n from the end of the row range
10286                // and position the cursor on the next line.
10287                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10288                cursor_buffer_row = rows.end;
10289            } else {
10290                // If there isn't a line after the range, delete the \n from the line before the
10291                // start of the row range and position the cursor there.
10292                edit_start = edit_start.saturating_sub(1);
10293                edit_end = buffer.len();
10294                cursor_buffer_row = rows.start.previous_row();
10295            }
10296
10297            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10298            *cursor.column_mut() =
10299                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10300
10301            new_cursors.push((
10302                selection.id,
10303                buffer.anchor_after(cursor.to_point(&display_map)),
10304            ));
10305            edit_ranges.push(edit_start..edit_end);
10306        }
10307
10308        self.transact(window, cx, |this, window, cx| {
10309            let buffer = this.buffer.update(cx, |buffer, cx| {
10310                let empty_str: Arc<str> = Arc::default();
10311                buffer.edit(
10312                    edit_ranges
10313                        .into_iter()
10314                        .map(|range| (range, empty_str.clone())),
10315                    None,
10316                    cx,
10317                );
10318                buffer.snapshot(cx)
10319            });
10320            let new_selections = new_cursors
10321                .into_iter()
10322                .map(|(id, cursor)| {
10323                    let cursor = cursor.to_point(&buffer);
10324                    Selection {
10325                        id,
10326                        start: cursor,
10327                        end: cursor,
10328                        reversed: false,
10329                        goal: SelectionGoal::None,
10330                    }
10331                })
10332                .collect();
10333
10334            this.change_selections(Default::default(), window, cx, |s| {
10335                s.select(new_selections);
10336            });
10337        });
10338    }
10339
10340    pub fn join_lines_impl(
10341        &mut self,
10342        insert_whitespace: bool,
10343        window: &mut Window,
10344        cx: &mut Context<Self>,
10345    ) {
10346        if self.read_only(cx) {
10347            return;
10348        }
10349        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10350        for selection in self.selections.all::<Point>(cx) {
10351            let start = MultiBufferRow(selection.start.row);
10352            // Treat single line selections as if they include the next line. Otherwise this action
10353            // would do nothing for single line selections individual cursors.
10354            let end = if selection.start.row == selection.end.row {
10355                MultiBufferRow(selection.start.row + 1)
10356            } else {
10357                MultiBufferRow(selection.end.row)
10358            };
10359
10360            if let Some(last_row_range) = row_ranges.last_mut() {
10361                if start <= last_row_range.end {
10362                    last_row_range.end = end;
10363                    continue;
10364                }
10365            }
10366            row_ranges.push(start..end);
10367        }
10368
10369        let snapshot = self.buffer.read(cx).snapshot(cx);
10370        let mut cursor_positions = Vec::new();
10371        for row_range in &row_ranges {
10372            let anchor = snapshot.anchor_before(Point::new(
10373                row_range.end.previous_row().0,
10374                snapshot.line_len(row_range.end.previous_row()),
10375            ));
10376            cursor_positions.push(anchor..anchor);
10377        }
10378
10379        self.transact(window, cx, |this, window, cx| {
10380            for row_range in row_ranges.into_iter().rev() {
10381                for row in row_range.iter_rows().rev() {
10382                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10383                    let next_line_row = row.next_row();
10384                    let indent = snapshot.indent_size_for_line(next_line_row);
10385                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10386
10387                    let replace =
10388                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10389                            " "
10390                        } else {
10391                            ""
10392                        };
10393
10394                    this.buffer.update(cx, |buffer, cx| {
10395                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10396                    });
10397                }
10398            }
10399
10400            this.change_selections(Default::default(), window, cx, |s| {
10401                s.select_anchor_ranges(cursor_positions)
10402            });
10403        });
10404    }
10405
10406    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10407        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10408        self.join_lines_impl(true, window, cx);
10409    }
10410
10411    pub fn sort_lines_case_sensitive(
10412        &mut self,
10413        _: &SortLinesCaseSensitive,
10414        window: &mut Window,
10415        cx: &mut Context<Self>,
10416    ) {
10417        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10418    }
10419
10420    pub fn sort_lines_by_length(
10421        &mut self,
10422        _: &SortLinesByLength,
10423        window: &mut Window,
10424        cx: &mut Context<Self>,
10425    ) {
10426        self.manipulate_immutable_lines(window, cx, |lines| {
10427            lines.sort_by_key(|&line| line.chars().count())
10428        })
10429    }
10430
10431    pub fn sort_lines_case_insensitive(
10432        &mut self,
10433        _: &SortLinesCaseInsensitive,
10434        window: &mut Window,
10435        cx: &mut Context<Self>,
10436    ) {
10437        self.manipulate_immutable_lines(window, cx, |lines| {
10438            lines.sort_by_key(|line| line.to_lowercase())
10439        })
10440    }
10441
10442    pub fn unique_lines_case_insensitive(
10443        &mut self,
10444        _: &UniqueLinesCaseInsensitive,
10445        window: &mut Window,
10446        cx: &mut Context<Self>,
10447    ) {
10448        self.manipulate_immutable_lines(window, cx, |lines| {
10449            let mut seen = HashSet::default();
10450            lines.retain(|line| seen.insert(line.to_lowercase()));
10451        })
10452    }
10453
10454    pub fn unique_lines_case_sensitive(
10455        &mut self,
10456        _: &UniqueLinesCaseSensitive,
10457        window: &mut Window,
10458        cx: &mut Context<Self>,
10459    ) {
10460        self.manipulate_immutable_lines(window, cx, |lines| {
10461            let mut seen = HashSet::default();
10462            lines.retain(|line| seen.insert(*line));
10463        })
10464    }
10465
10466    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10467        let Some(project) = self.project.clone() else {
10468            return;
10469        };
10470        self.reload(project, window, cx)
10471            .detach_and_notify_err(window, cx);
10472    }
10473
10474    pub fn restore_file(
10475        &mut self,
10476        _: &::git::RestoreFile,
10477        window: &mut Window,
10478        cx: &mut Context<Self>,
10479    ) {
10480        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10481        let mut buffer_ids = HashSet::default();
10482        let snapshot = self.buffer().read(cx).snapshot(cx);
10483        for selection in self.selections.all::<usize>(cx) {
10484            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10485        }
10486
10487        let buffer = self.buffer().read(cx);
10488        let ranges = buffer_ids
10489            .into_iter()
10490            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10491            .collect::<Vec<_>>();
10492
10493        self.restore_hunks_in_ranges(ranges, window, cx);
10494    }
10495
10496    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10497        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10498        let selections = self
10499            .selections
10500            .all(cx)
10501            .into_iter()
10502            .map(|s| s.range())
10503            .collect();
10504        self.restore_hunks_in_ranges(selections, window, cx);
10505    }
10506
10507    pub fn restore_hunks_in_ranges(
10508        &mut self,
10509        ranges: Vec<Range<Point>>,
10510        window: &mut Window,
10511        cx: &mut Context<Editor>,
10512    ) {
10513        let mut revert_changes = HashMap::default();
10514        let chunk_by = self
10515            .snapshot(window, cx)
10516            .hunks_for_ranges(ranges)
10517            .into_iter()
10518            .chunk_by(|hunk| hunk.buffer_id);
10519        for (buffer_id, hunks) in &chunk_by {
10520            let hunks = hunks.collect::<Vec<_>>();
10521            for hunk in &hunks {
10522                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10523            }
10524            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10525        }
10526        drop(chunk_by);
10527        if !revert_changes.is_empty() {
10528            self.transact(window, cx, |editor, window, cx| {
10529                editor.restore(revert_changes, window, cx);
10530            });
10531        }
10532    }
10533
10534    pub fn open_active_item_in_terminal(
10535        &mut self,
10536        _: &OpenInTerminal,
10537        window: &mut Window,
10538        cx: &mut Context<Self>,
10539    ) {
10540        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10541            let project_path = buffer.read(cx).project_path(cx)?;
10542            let project = self.project()?.read(cx);
10543            let entry = project.entry_for_path(&project_path, cx)?;
10544            let parent = match &entry.canonical_path {
10545                Some(canonical_path) => canonical_path.to_path_buf(),
10546                None => project.absolute_path(&project_path, cx)?,
10547            }
10548            .parent()?
10549            .to_path_buf();
10550            Some(parent)
10551        }) {
10552            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10553        }
10554    }
10555
10556    fn set_breakpoint_context_menu(
10557        &mut self,
10558        display_row: DisplayRow,
10559        position: Option<Anchor>,
10560        clicked_point: gpui::Point<Pixels>,
10561        window: &mut Window,
10562        cx: &mut Context<Self>,
10563    ) {
10564        let source = self
10565            .buffer
10566            .read(cx)
10567            .snapshot(cx)
10568            .anchor_before(Point::new(display_row.0, 0u32));
10569
10570        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10571
10572        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10573            self,
10574            source,
10575            clicked_point,
10576            context_menu,
10577            window,
10578            cx,
10579        );
10580    }
10581
10582    fn add_edit_breakpoint_block(
10583        &mut self,
10584        anchor: Anchor,
10585        breakpoint: &Breakpoint,
10586        edit_action: BreakpointPromptEditAction,
10587        window: &mut Window,
10588        cx: &mut Context<Self>,
10589    ) {
10590        let weak_editor = cx.weak_entity();
10591        let bp_prompt = cx.new(|cx| {
10592            BreakpointPromptEditor::new(
10593                weak_editor,
10594                anchor,
10595                breakpoint.clone(),
10596                edit_action,
10597                window,
10598                cx,
10599            )
10600        });
10601
10602        let height = bp_prompt.update(cx, |this, cx| {
10603            this.prompt
10604                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10605        });
10606        let cloned_prompt = bp_prompt.clone();
10607        let blocks = vec![BlockProperties {
10608            style: BlockStyle::Sticky,
10609            placement: BlockPlacement::Above(anchor),
10610            height: Some(height),
10611            render: Arc::new(move |cx| {
10612                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10613                cloned_prompt.clone().into_any_element()
10614            }),
10615            priority: 0,
10616        }];
10617
10618        let focus_handle = bp_prompt.focus_handle(cx);
10619        window.focus(&focus_handle);
10620
10621        let block_ids = self.insert_blocks(blocks, None, cx);
10622        bp_prompt.update(cx, |prompt, _| {
10623            prompt.add_block_ids(block_ids);
10624        });
10625    }
10626
10627    pub(crate) fn breakpoint_at_row(
10628        &self,
10629        row: u32,
10630        window: &mut Window,
10631        cx: &mut Context<Self>,
10632    ) -> Option<(Anchor, Breakpoint)> {
10633        let snapshot = self.snapshot(window, cx);
10634        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10635
10636        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10637    }
10638
10639    pub(crate) fn breakpoint_at_anchor(
10640        &self,
10641        breakpoint_position: Anchor,
10642        snapshot: &EditorSnapshot,
10643        cx: &mut Context<Self>,
10644    ) -> Option<(Anchor, Breakpoint)> {
10645        let project = self.project.clone()?;
10646
10647        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10648            snapshot
10649                .buffer_snapshot
10650                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10651        })?;
10652
10653        let enclosing_excerpt = breakpoint_position.excerpt_id;
10654        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10655        let buffer_snapshot = buffer.read(cx).snapshot();
10656
10657        let row = buffer_snapshot
10658            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10659            .row;
10660
10661        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10662        let anchor_end = snapshot
10663            .buffer_snapshot
10664            .anchor_after(Point::new(row, line_len));
10665
10666        let bp = self
10667            .breakpoint_store
10668            .as_ref()?
10669            .read_with(cx, |breakpoint_store, cx| {
10670                breakpoint_store
10671                    .breakpoints(
10672                        &buffer,
10673                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10674                        &buffer_snapshot,
10675                        cx,
10676                    )
10677                    .next()
10678                    .and_then(|(bp, _)| {
10679                        let breakpoint_row = buffer_snapshot
10680                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10681                            .row;
10682
10683                        if breakpoint_row == row {
10684                            snapshot
10685                                .buffer_snapshot
10686                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10687                                .map(|position| (position, bp.bp.clone()))
10688                        } else {
10689                            None
10690                        }
10691                    })
10692            });
10693        bp
10694    }
10695
10696    pub fn edit_log_breakpoint(
10697        &mut self,
10698        _: &EditLogBreakpoint,
10699        window: &mut Window,
10700        cx: &mut Context<Self>,
10701    ) {
10702        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10703            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10704                message: None,
10705                state: BreakpointState::Enabled,
10706                condition: None,
10707                hit_condition: None,
10708            });
10709
10710            self.add_edit_breakpoint_block(
10711                anchor,
10712                &breakpoint,
10713                BreakpointPromptEditAction::Log,
10714                window,
10715                cx,
10716            );
10717        }
10718    }
10719
10720    fn breakpoints_at_cursors(
10721        &self,
10722        window: &mut Window,
10723        cx: &mut Context<Self>,
10724    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10725        let snapshot = self.snapshot(window, cx);
10726        let cursors = self
10727            .selections
10728            .disjoint_anchors()
10729            .into_iter()
10730            .map(|selection| {
10731                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10732
10733                let breakpoint_position = self
10734                    .breakpoint_at_row(cursor_position.row, window, cx)
10735                    .map(|bp| bp.0)
10736                    .unwrap_or_else(|| {
10737                        snapshot
10738                            .display_snapshot
10739                            .buffer_snapshot
10740                            .anchor_after(Point::new(cursor_position.row, 0))
10741                    });
10742
10743                let breakpoint = self
10744                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10745                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10746
10747                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10748            })
10749            // 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.
10750            .collect::<HashMap<Anchor, _>>();
10751
10752        cursors.into_iter().collect()
10753    }
10754
10755    pub fn enable_breakpoint(
10756        &mut self,
10757        _: &crate::actions::EnableBreakpoint,
10758        window: &mut Window,
10759        cx: &mut Context<Self>,
10760    ) {
10761        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10762            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10763                continue;
10764            };
10765            self.edit_breakpoint_at_anchor(
10766                anchor,
10767                breakpoint,
10768                BreakpointEditAction::InvertState,
10769                cx,
10770            );
10771        }
10772    }
10773
10774    pub fn disable_breakpoint(
10775        &mut self,
10776        _: &crate::actions::DisableBreakpoint,
10777        window: &mut Window,
10778        cx: &mut Context<Self>,
10779    ) {
10780        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10781            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10782                continue;
10783            };
10784            self.edit_breakpoint_at_anchor(
10785                anchor,
10786                breakpoint,
10787                BreakpointEditAction::InvertState,
10788                cx,
10789            );
10790        }
10791    }
10792
10793    pub fn toggle_breakpoint(
10794        &mut self,
10795        _: &crate::actions::ToggleBreakpoint,
10796        window: &mut Window,
10797        cx: &mut Context<Self>,
10798    ) {
10799        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10800            if let Some(breakpoint) = breakpoint {
10801                self.edit_breakpoint_at_anchor(
10802                    anchor,
10803                    breakpoint,
10804                    BreakpointEditAction::Toggle,
10805                    cx,
10806                );
10807            } else {
10808                self.edit_breakpoint_at_anchor(
10809                    anchor,
10810                    Breakpoint::new_standard(),
10811                    BreakpointEditAction::Toggle,
10812                    cx,
10813                );
10814            }
10815        }
10816    }
10817
10818    pub fn edit_breakpoint_at_anchor(
10819        &mut self,
10820        breakpoint_position: Anchor,
10821        breakpoint: Breakpoint,
10822        edit_action: BreakpointEditAction,
10823        cx: &mut Context<Self>,
10824    ) {
10825        let Some(breakpoint_store) = &self.breakpoint_store else {
10826            return;
10827        };
10828
10829        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10830            if breakpoint_position == Anchor::min() {
10831                self.buffer()
10832                    .read(cx)
10833                    .excerpt_buffer_ids()
10834                    .into_iter()
10835                    .next()
10836            } else {
10837                None
10838            }
10839        }) else {
10840            return;
10841        };
10842
10843        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10844            return;
10845        };
10846
10847        breakpoint_store.update(cx, |breakpoint_store, cx| {
10848            breakpoint_store.toggle_breakpoint(
10849                buffer,
10850                BreakpointWithPosition {
10851                    position: breakpoint_position.text_anchor,
10852                    bp: breakpoint,
10853                },
10854                edit_action,
10855                cx,
10856            );
10857        });
10858
10859        cx.notify();
10860    }
10861
10862    #[cfg(any(test, feature = "test-support"))]
10863    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10864        self.breakpoint_store.clone()
10865    }
10866
10867    pub fn prepare_restore_change(
10868        &self,
10869        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10870        hunk: &MultiBufferDiffHunk,
10871        cx: &mut App,
10872    ) -> Option<()> {
10873        if hunk.is_created_file() {
10874            return None;
10875        }
10876        let buffer = self.buffer.read(cx);
10877        let diff = buffer.diff_for(hunk.buffer_id)?;
10878        let buffer = buffer.buffer(hunk.buffer_id)?;
10879        let buffer = buffer.read(cx);
10880        let original_text = diff
10881            .read(cx)
10882            .base_text()
10883            .as_rope()
10884            .slice(hunk.diff_base_byte_range.clone());
10885        let buffer_snapshot = buffer.snapshot();
10886        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10887        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10888            probe
10889                .0
10890                .start
10891                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10892                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10893        }) {
10894            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10895            Some(())
10896        } else {
10897            None
10898        }
10899    }
10900
10901    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10902        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10903    }
10904
10905    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10906        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10907    }
10908
10909    fn manipulate_lines<M>(
10910        &mut self,
10911        window: &mut Window,
10912        cx: &mut Context<Self>,
10913        mut manipulate: M,
10914    ) where
10915        M: FnMut(&str) -> LineManipulationResult,
10916    {
10917        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10918
10919        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10920        let buffer = self.buffer.read(cx).snapshot(cx);
10921
10922        let mut edits = Vec::new();
10923
10924        let selections = self.selections.all::<Point>(cx);
10925        let mut selections = selections.iter().peekable();
10926        let mut contiguous_row_selections = Vec::new();
10927        let mut new_selections = Vec::new();
10928        let mut added_lines = 0;
10929        let mut removed_lines = 0;
10930
10931        while let Some(selection) = selections.next() {
10932            let (start_row, end_row) = consume_contiguous_rows(
10933                &mut contiguous_row_selections,
10934                selection,
10935                &display_map,
10936                &mut selections,
10937            );
10938
10939            let start_point = Point::new(start_row.0, 0);
10940            let end_point = Point::new(
10941                end_row.previous_row().0,
10942                buffer.line_len(end_row.previous_row()),
10943            );
10944            let text = buffer
10945                .text_for_range(start_point..end_point)
10946                .collect::<String>();
10947
10948            let LineManipulationResult {
10949                new_text,
10950                line_count_before,
10951                line_count_after,
10952            } = manipulate(&text);
10953
10954            edits.push((start_point..end_point, new_text));
10955
10956            // Selections must change based on added and removed line count
10957            let start_row =
10958                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10959            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10960            new_selections.push(Selection {
10961                id: selection.id,
10962                start: start_row,
10963                end: end_row,
10964                goal: SelectionGoal::None,
10965                reversed: selection.reversed,
10966            });
10967
10968            if line_count_after > line_count_before {
10969                added_lines += line_count_after - line_count_before;
10970            } else if line_count_before > line_count_after {
10971                removed_lines += line_count_before - line_count_after;
10972            }
10973        }
10974
10975        self.transact(window, cx, |this, window, cx| {
10976            let buffer = this.buffer.update(cx, |buffer, cx| {
10977                buffer.edit(edits, None, cx);
10978                buffer.snapshot(cx)
10979            });
10980
10981            // Recalculate offsets on newly edited buffer
10982            let new_selections = new_selections
10983                .iter()
10984                .map(|s| {
10985                    let start_point = Point::new(s.start.0, 0);
10986                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10987                    Selection {
10988                        id: s.id,
10989                        start: buffer.point_to_offset(start_point),
10990                        end: buffer.point_to_offset(end_point),
10991                        goal: s.goal,
10992                        reversed: s.reversed,
10993                    }
10994                })
10995                .collect();
10996
10997            this.change_selections(Default::default(), window, cx, |s| {
10998                s.select(new_selections);
10999            });
11000
11001            this.request_autoscroll(Autoscroll::fit(), cx);
11002        });
11003    }
11004
11005    fn manipulate_immutable_lines<Fn>(
11006        &mut self,
11007        window: &mut Window,
11008        cx: &mut Context<Self>,
11009        mut callback: Fn,
11010    ) where
11011        Fn: FnMut(&mut Vec<&str>),
11012    {
11013        self.manipulate_lines(window, cx, |text| {
11014            let mut lines: Vec<&str> = text.split('\n').collect();
11015            let line_count_before = lines.len();
11016
11017            callback(&mut lines);
11018
11019            LineManipulationResult {
11020                new_text: lines.join("\n"),
11021                line_count_before,
11022                line_count_after: lines.len(),
11023            }
11024        });
11025    }
11026
11027    fn manipulate_mutable_lines<Fn>(
11028        &mut self,
11029        window: &mut Window,
11030        cx: &mut Context<Self>,
11031        mut callback: Fn,
11032    ) where
11033        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11034    {
11035        self.manipulate_lines(window, cx, |text| {
11036            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11037            let line_count_before = lines.len();
11038
11039            callback(&mut lines);
11040
11041            LineManipulationResult {
11042                new_text: lines.join("\n"),
11043                line_count_before,
11044                line_count_after: lines.len(),
11045            }
11046        });
11047    }
11048
11049    pub fn convert_indentation_to_spaces(
11050        &mut self,
11051        _: &ConvertIndentationToSpaces,
11052        window: &mut Window,
11053        cx: &mut Context<Self>,
11054    ) {
11055        let settings = self.buffer.read(cx).language_settings(cx);
11056        let tab_size = settings.tab_size.get() as usize;
11057
11058        self.manipulate_mutable_lines(window, cx, |lines| {
11059            // Allocates a reasonably sized scratch buffer once for the whole loop
11060            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11061            // Avoids recomputing spaces that could be inserted many times
11062            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11063                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11064                .collect();
11065
11066            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11067                let mut chars = line.as_ref().chars();
11068                let mut col = 0;
11069                let mut changed = false;
11070
11071                while let Some(ch) = chars.next() {
11072                    match ch {
11073                        ' ' => {
11074                            reindented_line.push(' ');
11075                            col += 1;
11076                        }
11077                        '\t' => {
11078                            // \t are converted to spaces depending on the current column
11079                            let spaces_len = tab_size - (col % tab_size);
11080                            reindented_line.extend(&space_cache[spaces_len - 1]);
11081                            col += spaces_len;
11082                            changed = true;
11083                        }
11084                        _ => {
11085                            // If we dont append before break, the character is consumed
11086                            reindented_line.push(ch);
11087                            break;
11088                        }
11089                    }
11090                }
11091
11092                if !changed {
11093                    reindented_line.clear();
11094                    continue;
11095                }
11096                // Append the rest of the line and replace old reference with new one
11097                reindented_line.extend(chars);
11098                *line = Cow::Owned(reindented_line.clone());
11099                reindented_line.clear();
11100            }
11101        });
11102    }
11103
11104    pub fn convert_indentation_to_tabs(
11105        &mut self,
11106        _: &ConvertIndentationToTabs,
11107        window: &mut Window,
11108        cx: &mut Context<Self>,
11109    ) {
11110        let settings = self.buffer.read(cx).language_settings(cx);
11111        let tab_size = settings.tab_size.get() as usize;
11112
11113        self.manipulate_mutable_lines(window, cx, |lines| {
11114            // Allocates a reasonably sized buffer once for the whole loop
11115            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11116            // Avoids recomputing spaces that could be inserted many times
11117            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11118                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11119                .collect();
11120
11121            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11122                let mut chars = line.chars();
11123                let mut spaces_count = 0;
11124                let mut first_non_indent_char = None;
11125                let mut changed = false;
11126
11127                while let Some(ch) = chars.next() {
11128                    match ch {
11129                        ' ' => {
11130                            // Keep track of spaces. Append \t when we reach tab_size
11131                            spaces_count += 1;
11132                            changed = true;
11133                            if spaces_count == tab_size {
11134                                reindented_line.push('\t');
11135                                spaces_count = 0;
11136                            }
11137                        }
11138                        '\t' => {
11139                            reindented_line.push('\t');
11140                            spaces_count = 0;
11141                        }
11142                        _ => {
11143                            // Dont append it yet, we might have remaining spaces
11144                            first_non_indent_char = Some(ch);
11145                            break;
11146                        }
11147                    }
11148                }
11149
11150                if !changed {
11151                    reindented_line.clear();
11152                    continue;
11153                }
11154                // Remaining spaces that didn't make a full tab stop
11155                if spaces_count > 0 {
11156                    reindented_line.extend(&space_cache[spaces_count - 1]);
11157                }
11158                // If we consume an extra character that was not indentation, add it back
11159                if let Some(extra_char) = first_non_indent_char {
11160                    reindented_line.push(extra_char);
11161                }
11162                // Append the rest of the line and replace old reference with new one
11163                reindented_line.extend(chars);
11164                *line = Cow::Owned(reindented_line.clone());
11165                reindented_line.clear();
11166            }
11167        });
11168    }
11169
11170    pub fn convert_to_upper_case(
11171        &mut self,
11172        _: &ConvertToUpperCase,
11173        window: &mut Window,
11174        cx: &mut Context<Self>,
11175    ) {
11176        self.manipulate_text(window, cx, |text| text.to_uppercase())
11177    }
11178
11179    pub fn convert_to_lower_case(
11180        &mut self,
11181        _: &ConvertToLowerCase,
11182        window: &mut Window,
11183        cx: &mut Context<Self>,
11184    ) {
11185        self.manipulate_text(window, cx, |text| text.to_lowercase())
11186    }
11187
11188    pub fn convert_to_title_case(
11189        &mut self,
11190        _: &ConvertToTitleCase,
11191        window: &mut Window,
11192        cx: &mut Context<Self>,
11193    ) {
11194        self.manipulate_text(window, cx, |text| {
11195            text.split('\n')
11196                .map(|line| line.to_case(Case::Title))
11197                .join("\n")
11198        })
11199    }
11200
11201    pub fn convert_to_snake_case(
11202        &mut self,
11203        _: &ConvertToSnakeCase,
11204        window: &mut Window,
11205        cx: &mut Context<Self>,
11206    ) {
11207        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11208    }
11209
11210    pub fn convert_to_kebab_case(
11211        &mut self,
11212        _: &ConvertToKebabCase,
11213        window: &mut Window,
11214        cx: &mut Context<Self>,
11215    ) {
11216        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11217    }
11218
11219    pub fn convert_to_upper_camel_case(
11220        &mut self,
11221        _: &ConvertToUpperCamelCase,
11222        window: &mut Window,
11223        cx: &mut Context<Self>,
11224    ) {
11225        self.manipulate_text(window, cx, |text| {
11226            text.split('\n')
11227                .map(|line| line.to_case(Case::UpperCamel))
11228                .join("\n")
11229        })
11230    }
11231
11232    pub fn convert_to_lower_camel_case(
11233        &mut self,
11234        _: &ConvertToLowerCamelCase,
11235        window: &mut Window,
11236        cx: &mut Context<Self>,
11237    ) {
11238        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11239    }
11240
11241    pub fn convert_to_opposite_case(
11242        &mut self,
11243        _: &ConvertToOppositeCase,
11244        window: &mut Window,
11245        cx: &mut Context<Self>,
11246    ) {
11247        self.manipulate_text(window, cx, |text| {
11248            text.chars()
11249                .fold(String::with_capacity(text.len()), |mut t, c| {
11250                    if c.is_uppercase() {
11251                        t.extend(c.to_lowercase());
11252                    } else {
11253                        t.extend(c.to_uppercase());
11254                    }
11255                    t
11256                })
11257        })
11258    }
11259
11260    pub fn convert_to_sentence_case(
11261        &mut self,
11262        _: &ConvertToSentenceCase,
11263        window: &mut Window,
11264        cx: &mut Context<Self>,
11265    ) {
11266        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11267    }
11268
11269    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11270        self.manipulate_text(window, cx, |text| {
11271            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11272            if has_upper_case_characters {
11273                text.to_lowercase()
11274            } else {
11275                text.to_uppercase()
11276            }
11277        })
11278    }
11279
11280    pub fn convert_to_rot13(
11281        &mut self,
11282        _: &ConvertToRot13,
11283        window: &mut Window,
11284        cx: &mut Context<Self>,
11285    ) {
11286        self.manipulate_text(window, cx, |text| {
11287            text.chars()
11288                .map(|c| match c {
11289                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11290                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11291                    _ => c,
11292                })
11293                .collect()
11294        })
11295    }
11296
11297    pub fn convert_to_rot47(
11298        &mut self,
11299        _: &ConvertToRot47,
11300        window: &mut Window,
11301        cx: &mut Context<Self>,
11302    ) {
11303        self.manipulate_text(window, cx, |text| {
11304            text.chars()
11305                .map(|c| {
11306                    let code_point = c as u32;
11307                    if code_point >= 33 && code_point <= 126 {
11308                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11309                    }
11310                    c
11311                })
11312                .collect()
11313        })
11314    }
11315
11316    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11317    where
11318        Fn: FnMut(&str) -> String,
11319    {
11320        let buffer = self.buffer.read(cx).snapshot(cx);
11321
11322        let mut new_selections = Vec::new();
11323        let mut edits = Vec::new();
11324        let mut selection_adjustment = 0i32;
11325
11326        for selection in self.selections.all::<usize>(cx) {
11327            let selection_is_empty = selection.is_empty();
11328
11329            let (start, end) = if selection_is_empty {
11330                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11331                (word_range.start, word_range.end)
11332            } else {
11333                (selection.start, selection.end)
11334            };
11335
11336            let text = buffer.text_for_range(start..end).collect::<String>();
11337            let old_length = text.len() as i32;
11338            let text = callback(&text);
11339
11340            new_selections.push(Selection {
11341                start: (start as i32 - selection_adjustment) as usize,
11342                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11343                goal: SelectionGoal::None,
11344                ..selection
11345            });
11346
11347            selection_adjustment += old_length - text.len() as i32;
11348
11349            edits.push((start..end, text));
11350        }
11351
11352        self.transact(window, cx, |this, window, cx| {
11353            this.buffer.update(cx, |buffer, cx| {
11354                buffer.edit(edits, None, cx);
11355            });
11356
11357            this.change_selections(Default::default(), window, cx, |s| {
11358                s.select(new_selections);
11359            });
11360
11361            this.request_autoscroll(Autoscroll::fit(), cx);
11362        });
11363    }
11364
11365    pub fn move_selection_on_drop(
11366        &mut self,
11367        selection: &Selection<Anchor>,
11368        target: DisplayPoint,
11369        is_cut: bool,
11370        window: &mut Window,
11371        cx: &mut Context<Self>,
11372    ) {
11373        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11374        let buffer = &display_map.buffer_snapshot;
11375        let mut edits = Vec::new();
11376        let insert_point = display_map
11377            .clip_point(target, Bias::Left)
11378            .to_point(&display_map);
11379        let text = buffer
11380            .text_for_range(selection.start..selection.end)
11381            .collect::<String>();
11382        if is_cut {
11383            edits.push(((selection.start..selection.end), String::new()));
11384        }
11385        let insert_anchor = buffer.anchor_before(insert_point);
11386        edits.push(((insert_anchor..insert_anchor), text));
11387        let last_edit_start = insert_anchor.bias_left(buffer);
11388        let last_edit_end = insert_anchor.bias_right(buffer);
11389        self.transact(window, cx, |this, window, cx| {
11390            this.buffer.update(cx, |buffer, cx| {
11391                buffer.edit(edits, None, cx);
11392            });
11393            this.change_selections(Default::default(), window, cx, |s| {
11394                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11395            });
11396        });
11397    }
11398
11399    pub fn clear_selection_drag_state(&mut self) {
11400        self.selection_drag_state = SelectionDragState::None;
11401    }
11402
11403    pub fn duplicate(
11404        &mut self,
11405        upwards: bool,
11406        whole_lines: bool,
11407        window: &mut Window,
11408        cx: &mut Context<Self>,
11409    ) {
11410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11411
11412        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11413        let buffer = &display_map.buffer_snapshot;
11414        let selections = self.selections.all::<Point>(cx);
11415
11416        let mut edits = Vec::new();
11417        let mut selections_iter = selections.iter().peekable();
11418        while let Some(selection) = selections_iter.next() {
11419            let mut rows = selection.spanned_rows(false, &display_map);
11420            // duplicate line-wise
11421            if whole_lines || selection.start == selection.end {
11422                // Avoid duplicating the same lines twice.
11423                while let Some(next_selection) = selections_iter.peek() {
11424                    let next_rows = next_selection.spanned_rows(false, &display_map);
11425                    if next_rows.start < rows.end {
11426                        rows.end = next_rows.end;
11427                        selections_iter.next().unwrap();
11428                    } else {
11429                        break;
11430                    }
11431                }
11432
11433                // Copy the text from the selected row region and splice it either at the start
11434                // or end of the region.
11435                let start = Point::new(rows.start.0, 0);
11436                let end = Point::new(
11437                    rows.end.previous_row().0,
11438                    buffer.line_len(rows.end.previous_row()),
11439                );
11440                let text = buffer
11441                    .text_for_range(start..end)
11442                    .chain(Some("\n"))
11443                    .collect::<String>();
11444                let insert_location = if upwards {
11445                    Point::new(rows.end.0, 0)
11446                } else {
11447                    start
11448                };
11449                edits.push((insert_location..insert_location, text));
11450            } else {
11451                // duplicate character-wise
11452                let start = selection.start;
11453                let end = selection.end;
11454                let text = buffer.text_for_range(start..end).collect::<String>();
11455                edits.push((selection.end..selection.end, text));
11456            }
11457        }
11458
11459        self.transact(window, cx, |this, _, cx| {
11460            this.buffer.update(cx, |buffer, cx| {
11461                buffer.edit(edits, None, cx);
11462            });
11463
11464            this.request_autoscroll(Autoscroll::fit(), cx);
11465        });
11466    }
11467
11468    pub fn duplicate_line_up(
11469        &mut self,
11470        _: &DuplicateLineUp,
11471        window: &mut Window,
11472        cx: &mut Context<Self>,
11473    ) {
11474        self.duplicate(true, true, window, cx);
11475    }
11476
11477    pub fn duplicate_line_down(
11478        &mut self,
11479        _: &DuplicateLineDown,
11480        window: &mut Window,
11481        cx: &mut Context<Self>,
11482    ) {
11483        self.duplicate(false, true, window, cx);
11484    }
11485
11486    pub fn duplicate_selection(
11487        &mut self,
11488        _: &DuplicateSelection,
11489        window: &mut Window,
11490        cx: &mut Context<Self>,
11491    ) {
11492        self.duplicate(false, false, window, cx);
11493    }
11494
11495    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11496        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11497        if self.mode.is_single_line() {
11498            cx.propagate();
11499            return;
11500        }
11501
11502        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11503        let buffer = self.buffer.read(cx).snapshot(cx);
11504
11505        let mut edits = Vec::new();
11506        let mut unfold_ranges = Vec::new();
11507        let mut refold_creases = Vec::new();
11508
11509        let selections = self.selections.all::<Point>(cx);
11510        let mut selections = selections.iter().peekable();
11511        let mut contiguous_row_selections = Vec::new();
11512        let mut new_selections = Vec::new();
11513
11514        while let Some(selection) = selections.next() {
11515            // Find all the selections that span a contiguous row range
11516            let (start_row, end_row) = consume_contiguous_rows(
11517                &mut contiguous_row_selections,
11518                selection,
11519                &display_map,
11520                &mut selections,
11521            );
11522
11523            // Move the text spanned by the row range to be before the line preceding the row range
11524            if start_row.0 > 0 {
11525                let range_to_move = Point::new(
11526                    start_row.previous_row().0,
11527                    buffer.line_len(start_row.previous_row()),
11528                )
11529                    ..Point::new(
11530                        end_row.previous_row().0,
11531                        buffer.line_len(end_row.previous_row()),
11532                    );
11533                let insertion_point = display_map
11534                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11535                    .0;
11536
11537                // Don't move lines across excerpts
11538                if buffer
11539                    .excerpt_containing(insertion_point..range_to_move.end)
11540                    .is_some()
11541                {
11542                    let text = buffer
11543                        .text_for_range(range_to_move.clone())
11544                        .flat_map(|s| s.chars())
11545                        .skip(1)
11546                        .chain(['\n'])
11547                        .collect::<String>();
11548
11549                    edits.push((
11550                        buffer.anchor_after(range_to_move.start)
11551                            ..buffer.anchor_before(range_to_move.end),
11552                        String::new(),
11553                    ));
11554                    let insertion_anchor = buffer.anchor_after(insertion_point);
11555                    edits.push((insertion_anchor..insertion_anchor, text));
11556
11557                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11558
11559                    // Move selections up
11560                    new_selections.extend(contiguous_row_selections.drain(..).map(
11561                        |mut selection| {
11562                            selection.start.row -= row_delta;
11563                            selection.end.row -= row_delta;
11564                            selection
11565                        },
11566                    ));
11567
11568                    // Move folds up
11569                    unfold_ranges.push(range_to_move.clone());
11570                    for fold in display_map.folds_in_range(
11571                        buffer.anchor_before(range_to_move.start)
11572                            ..buffer.anchor_after(range_to_move.end),
11573                    ) {
11574                        let mut start = fold.range.start.to_point(&buffer);
11575                        let mut end = fold.range.end.to_point(&buffer);
11576                        start.row -= row_delta;
11577                        end.row -= row_delta;
11578                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11579                    }
11580                }
11581            }
11582
11583            // If we didn't move line(s), preserve the existing selections
11584            new_selections.append(&mut contiguous_row_selections);
11585        }
11586
11587        self.transact(window, cx, |this, window, cx| {
11588            this.unfold_ranges(&unfold_ranges, true, true, cx);
11589            this.buffer.update(cx, |buffer, cx| {
11590                for (range, text) in edits {
11591                    buffer.edit([(range, text)], None, cx);
11592                }
11593            });
11594            this.fold_creases(refold_creases, true, window, cx);
11595            this.change_selections(Default::default(), window, cx, |s| {
11596                s.select(new_selections);
11597            })
11598        });
11599    }
11600
11601    pub fn move_line_down(
11602        &mut self,
11603        _: &MoveLineDown,
11604        window: &mut Window,
11605        cx: &mut Context<Self>,
11606    ) {
11607        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11608        if self.mode.is_single_line() {
11609            cx.propagate();
11610            return;
11611        }
11612
11613        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11614        let buffer = self.buffer.read(cx).snapshot(cx);
11615
11616        let mut edits = Vec::new();
11617        let mut unfold_ranges = Vec::new();
11618        let mut refold_creases = Vec::new();
11619
11620        let selections = self.selections.all::<Point>(cx);
11621        let mut selections = selections.iter().peekable();
11622        let mut contiguous_row_selections = Vec::new();
11623        let mut new_selections = Vec::new();
11624
11625        while let Some(selection) = selections.next() {
11626            // Find all the selections that span a contiguous row range
11627            let (start_row, end_row) = consume_contiguous_rows(
11628                &mut contiguous_row_selections,
11629                selection,
11630                &display_map,
11631                &mut selections,
11632            );
11633
11634            // Move the text spanned by the row range to be after the last line of the row range
11635            if end_row.0 <= buffer.max_point().row {
11636                let range_to_move =
11637                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11638                let insertion_point = display_map
11639                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11640                    .0;
11641
11642                // Don't move lines across excerpt boundaries
11643                if buffer
11644                    .excerpt_containing(range_to_move.start..insertion_point)
11645                    .is_some()
11646                {
11647                    let mut text = String::from("\n");
11648                    text.extend(buffer.text_for_range(range_to_move.clone()));
11649                    text.pop(); // Drop trailing newline
11650                    edits.push((
11651                        buffer.anchor_after(range_to_move.start)
11652                            ..buffer.anchor_before(range_to_move.end),
11653                        String::new(),
11654                    ));
11655                    let insertion_anchor = buffer.anchor_after(insertion_point);
11656                    edits.push((insertion_anchor..insertion_anchor, text));
11657
11658                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11659
11660                    // Move selections down
11661                    new_selections.extend(contiguous_row_selections.drain(..).map(
11662                        |mut selection| {
11663                            selection.start.row += row_delta;
11664                            selection.end.row += row_delta;
11665                            selection
11666                        },
11667                    ));
11668
11669                    // Move folds down
11670                    unfold_ranges.push(range_to_move.clone());
11671                    for fold in display_map.folds_in_range(
11672                        buffer.anchor_before(range_to_move.start)
11673                            ..buffer.anchor_after(range_to_move.end),
11674                    ) {
11675                        let mut start = fold.range.start.to_point(&buffer);
11676                        let mut end = fold.range.end.to_point(&buffer);
11677                        start.row += row_delta;
11678                        end.row += row_delta;
11679                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11680                    }
11681                }
11682            }
11683
11684            // If we didn't move line(s), preserve the existing selections
11685            new_selections.append(&mut contiguous_row_selections);
11686        }
11687
11688        self.transact(window, cx, |this, window, cx| {
11689            this.unfold_ranges(&unfold_ranges, true, true, cx);
11690            this.buffer.update(cx, |buffer, cx| {
11691                for (range, text) in edits {
11692                    buffer.edit([(range, text)], None, cx);
11693                }
11694            });
11695            this.fold_creases(refold_creases, true, window, cx);
11696            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11697        });
11698    }
11699
11700    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11701        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11702        let text_layout_details = &self.text_layout_details(window);
11703        self.transact(window, cx, |this, window, cx| {
11704            let edits = this.change_selections(Default::default(), window, cx, |s| {
11705                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11706                s.move_with(|display_map, selection| {
11707                    if !selection.is_empty() {
11708                        return;
11709                    }
11710
11711                    let mut head = selection.head();
11712                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11713                    if head.column() == display_map.line_len(head.row()) {
11714                        transpose_offset = display_map
11715                            .buffer_snapshot
11716                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11717                    }
11718
11719                    if transpose_offset == 0 {
11720                        return;
11721                    }
11722
11723                    *head.column_mut() += 1;
11724                    head = display_map.clip_point(head, Bias::Right);
11725                    let goal = SelectionGoal::HorizontalPosition(
11726                        display_map
11727                            .x_for_display_point(head, text_layout_details)
11728                            .into(),
11729                    );
11730                    selection.collapse_to(head, goal);
11731
11732                    let transpose_start = display_map
11733                        .buffer_snapshot
11734                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11735                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11736                        let transpose_end = display_map
11737                            .buffer_snapshot
11738                            .clip_offset(transpose_offset + 1, Bias::Right);
11739                        if let Some(ch) =
11740                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11741                        {
11742                            edits.push((transpose_start..transpose_offset, String::new()));
11743                            edits.push((transpose_end..transpose_end, ch.to_string()));
11744                        }
11745                    }
11746                });
11747                edits
11748            });
11749            this.buffer
11750                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11751            let selections = this.selections.all::<usize>(cx);
11752            this.change_selections(Default::default(), window, cx, |s| {
11753                s.select(selections);
11754            });
11755        });
11756    }
11757
11758    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11760        if self.mode.is_single_line() {
11761            cx.propagate();
11762            return;
11763        }
11764
11765        self.rewrap_impl(RewrapOptions::default(), cx)
11766    }
11767
11768    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11769        let buffer = self.buffer.read(cx).snapshot(cx);
11770        let selections = self.selections.all::<Point>(cx);
11771
11772        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11773        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11774            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11775                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11776                .peekable();
11777
11778            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11779                row
11780            } else {
11781                return Vec::new();
11782            };
11783
11784            let language_settings = buffer.language_settings_at(selection.head(), cx);
11785            let language_scope = buffer.language_scope_at(selection.head());
11786
11787            let indent_and_prefix_for_row =
11788                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11789                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11790                    let (comment_prefix, rewrap_prefix) =
11791                        if let Some(language_scope) = &language_scope {
11792                            let indent_end = Point::new(row, indent.len);
11793                            let comment_prefix = language_scope
11794                                .line_comment_prefixes()
11795                                .iter()
11796                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11797                                .map(|prefix| prefix.to_string());
11798                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11799                            let line_text_after_indent = buffer
11800                                .text_for_range(indent_end..line_end)
11801                                .collect::<String>();
11802                            let rewrap_prefix = language_scope
11803                                .rewrap_prefixes()
11804                                .iter()
11805                                .find_map(|prefix_regex| {
11806                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11807                                        if mat.start() == 0 {
11808                                            Some(mat.as_str().to_string())
11809                                        } else {
11810                                            None
11811                                        }
11812                                    })
11813                                })
11814                                .flatten();
11815                            (comment_prefix, rewrap_prefix)
11816                        } else {
11817                            (None, None)
11818                        };
11819                    (indent, comment_prefix, rewrap_prefix)
11820                };
11821
11822            let mut ranges = Vec::new();
11823            let from_empty_selection = selection.is_empty();
11824
11825            let mut current_range_start = first_row;
11826            let mut prev_row = first_row;
11827            let (
11828                mut current_range_indent,
11829                mut current_range_comment_prefix,
11830                mut current_range_rewrap_prefix,
11831            ) = indent_and_prefix_for_row(first_row);
11832
11833            for row in non_blank_rows_iter.skip(1) {
11834                let has_paragraph_break = row > prev_row + 1;
11835
11836                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11837                    indent_and_prefix_for_row(row);
11838
11839                let has_indent_change = row_indent != current_range_indent;
11840                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11841
11842                let has_boundary_change = has_comment_change
11843                    || row_rewrap_prefix.is_some()
11844                    || (has_indent_change && current_range_comment_prefix.is_some());
11845
11846                if has_paragraph_break || has_boundary_change {
11847                    ranges.push((
11848                        language_settings.clone(),
11849                        Point::new(current_range_start, 0)
11850                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11851                        current_range_indent,
11852                        current_range_comment_prefix.clone(),
11853                        current_range_rewrap_prefix.clone(),
11854                        from_empty_selection,
11855                    ));
11856                    current_range_start = row;
11857                    current_range_indent = row_indent;
11858                    current_range_comment_prefix = row_comment_prefix;
11859                    current_range_rewrap_prefix = row_rewrap_prefix;
11860                }
11861                prev_row = row;
11862            }
11863
11864            ranges.push((
11865                language_settings.clone(),
11866                Point::new(current_range_start, 0)
11867                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11868                current_range_indent,
11869                current_range_comment_prefix,
11870                current_range_rewrap_prefix,
11871                from_empty_selection,
11872            ));
11873
11874            ranges
11875        });
11876
11877        let mut edits = Vec::new();
11878        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11879
11880        for (
11881            language_settings,
11882            wrap_range,
11883            indent_size,
11884            comment_prefix,
11885            rewrap_prefix,
11886            from_empty_selection,
11887        ) in wrap_ranges
11888        {
11889            let mut start_row = wrap_range.start.row;
11890            let mut end_row = wrap_range.end.row;
11891
11892            // Skip selections that overlap with a range that has already been rewrapped.
11893            let selection_range = start_row..end_row;
11894            if rewrapped_row_ranges
11895                .iter()
11896                .any(|range| range.overlaps(&selection_range))
11897            {
11898                continue;
11899            }
11900
11901            let tab_size = language_settings.tab_size;
11902
11903            let indent_prefix = indent_size.chars().collect::<String>();
11904            let mut line_prefix = indent_prefix.clone();
11905            let mut inside_comment = false;
11906            if let Some(prefix) = &comment_prefix {
11907                line_prefix.push_str(prefix);
11908                inside_comment = true;
11909            }
11910            if let Some(prefix) = &rewrap_prefix {
11911                line_prefix.push_str(prefix);
11912            }
11913
11914            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11915                RewrapBehavior::InComments => inside_comment,
11916                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11917                RewrapBehavior::Anywhere => true,
11918            };
11919
11920            let should_rewrap = options.override_language_settings
11921                || allow_rewrap_based_on_language
11922                || self.hard_wrap.is_some();
11923            if !should_rewrap {
11924                continue;
11925            }
11926
11927            if from_empty_selection {
11928                'expand_upwards: while start_row > 0 {
11929                    let prev_row = start_row - 1;
11930                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11931                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11932                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11933                    {
11934                        start_row = prev_row;
11935                    } else {
11936                        break 'expand_upwards;
11937                    }
11938                }
11939
11940                'expand_downwards: while end_row < buffer.max_point().row {
11941                    let next_row = end_row + 1;
11942                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11943                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11944                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11945                    {
11946                        end_row = next_row;
11947                    } else {
11948                        break 'expand_downwards;
11949                    }
11950                }
11951            }
11952
11953            let start = Point::new(start_row, 0);
11954            let start_offset = start.to_offset(&buffer);
11955            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11956            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11957            let Some(lines_without_prefixes) = selection_text
11958                .lines()
11959                .enumerate()
11960                .map(|(ix, line)| {
11961                    let line_trimmed = line.trim_start();
11962                    if rewrap_prefix.is_some() && ix > 0 {
11963                        Ok(line_trimmed)
11964                    } else {
11965                        line_trimmed
11966                            .strip_prefix(&line_prefix.trim_start())
11967                            .with_context(|| {
11968                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11969                            })
11970                    }
11971                })
11972                .collect::<Result<Vec<_>, _>>()
11973                .log_err()
11974            else {
11975                continue;
11976            };
11977
11978            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11979                buffer
11980                    .language_settings_at(Point::new(start_row, 0), cx)
11981                    .preferred_line_length as usize
11982            });
11983
11984            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11985                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11986            } else {
11987                line_prefix.clone()
11988            };
11989
11990            let wrapped_text = wrap_with_prefix(
11991                line_prefix,
11992                subsequent_lines_prefix,
11993                lines_without_prefixes.join("\n"),
11994                wrap_column,
11995                tab_size,
11996                options.preserve_existing_whitespace,
11997            );
11998
11999            // TODO: should always use char-based diff while still supporting cursor behavior that
12000            // matches vim.
12001            let mut diff_options = DiffOptions::default();
12002            if options.override_language_settings {
12003                diff_options.max_word_diff_len = 0;
12004                diff_options.max_word_diff_line_count = 0;
12005            } else {
12006                diff_options.max_word_diff_len = usize::MAX;
12007                diff_options.max_word_diff_line_count = usize::MAX;
12008            }
12009
12010            for (old_range, new_text) in
12011                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12012            {
12013                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12014                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12015                edits.push((edit_start..edit_end, new_text));
12016            }
12017
12018            rewrapped_row_ranges.push(start_row..=end_row);
12019        }
12020
12021        self.buffer
12022            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12023    }
12024
12025    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12026        let mut text = String::new();
12027        let buffer = self.buffer.read(cx).snapshot(cx);
12028        let mut selections = self.selections.all::<Point>(cx);
12029        let mut clipboard_selections = Vec::with_capacity(selections.len());
12030        {
12031            let max_point = buffer.max_point();
12032            let mut is_first = true;
12033            for selection in &mut selections {
12034                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12035                if is_entire_line {
12036                    selection.start = Point::new(selection.start.row, 0);
12037                    if !selection.is_empty() && selection.end.column == 0 {
12038                        selection.end = cmp::min(max_point, selection.end);
12039                    } else {
12040                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12041                    }
12042                    selection.goal = SelectionGoal::None;
12043                }
12044                if is_first {
12045                    is_first = false;
12046                } else {
12047                    text += "\n";
12048                }
12049                let mut len = 0;
12050                for chunk in buffer.text_for_range(selection.start..selection.end) {
12051                    text.push_str(chunk);
12052                    len += chunk.len();
12053                }
12054                clipboard_selections.push(ClipboardSelection {
12055                    len,
12056                    is_entire_line,
12057                    first_line_indent: buffer
12058                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12059                        .len,
12060                });
12061            }
12062        }
12063
12064        self.transact(window, cx, |this, window, cx| {
12065            this.change_selections(Default::default(), window, cx, |s| {
12066                s.select(selections);
12067            });
12068            this.insert("", window, cx);
12069        });
12070        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12071    }
12072
12073    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12074        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12075        let item = self.cut_common(window, cx);
12076        cx.write_to_clipboard(item);
12077    }
12078
12079    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12080        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12081        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12082            s.move_with(|snapshot, sel| {
12083                if sel.is_empty() {
12084                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12085                }
12086            });
12087        });
12088        let item = self.cut_common(window, cx);
12089        cx.set_global(KillRing(item))
12090    }
12091
12092    pub fn kill_ring_yank(
12093        &mut self,
12094        _: &KillRingYank,
12095        window: &mut Window,
12096        cx: &mut Context<Self>,
12097    ) {
12098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12099        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12100            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12101                (kill_ring.text().to_string(), kill_ring.metadata_json())
12102            } else {
12103                return;
12104            }
12105        } else {
12106            return;
12107        };
12108        self.do_paste(&text, metadata, false, window, cx);
12109    }
12110
12111    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12112        self.do_copy(true, cx);
12113    }
12114
12115    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12116        self.do_copy(false, cx);
12117    }
12118
12119    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12120        let selections = self.selections.all::<Point>(cx);
12121        let buffer = self.buffer.read(cx).read(cx);
12122        let mut text = String::new();
12123
12124        let mut clipboard_selections = Vec::with_capacity(selections.len());
12125        {
12126            let max_point = buffer.max_point();
12127            let mut is_first = true;
12128            for selection in &selections {
12129                let mut start = selection.start;
12130                let mut end = selection.end;
12131                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12132                if is_entire_line {
12133                    start = Point::new(start.row, 0);
12134                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12135                }
12136
12137                let mut trimmed_selections = Vec::new();
12138                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12139                    let row = MultiBufferRow(start.row);
12140                    let first_indent = buffer.indent_size_for_line(row);
12141                    if first_indent.len == 0 || start.column > first_indent.len {
12142                        trimmed_selections.push(start..end);
12143                    } else {
12144                        trimmed_selections.push(
12145                            Point::new(row.0, first_indent.len)
12146                                ..Point::new(row.0, buffer.line_len(row)),
12147                        );
12148                        for row in start.row + 1..=end.row {
12149                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12150                            if row == end.row {
12151                                line_len = end.column;
12152                            }
12153                            if line_len == 0 {
12154                                trimmed_selections
12155                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12156                                continue;
12157                            }
12158                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12159                            if row_indent_size.len >= first_indent.len {
12160                                trimmed_selections.push(
12161                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12162                                );
12163                            } else {
12164                                trimmed_selections.clear();
12165                                trimmed_selections.push(start..end);
12166                                break;
12167                            }
12168                        }
12169                    }
12170                } else {
12171                    trimmed_selections.push(start..end);
12172                }
12173
12174                for trimmed_range in trimmed_selections {
12175                    if is_first {
12176                        is_first = false;
12177                    } else {
12178                        text += "\n";
12179                    }
12180                    let mut len = 0;
12181                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12182                        text.push_str(chunk);
12183                        len += chunk.len();
12184                    }
12185                    clipboard_selections.push(ClipboardSelection {
12186                        len,
12187                        is_entire_line,
12188                        first_line_indent: buffer
12189                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12190                            .len,
12191                    });
12192                }
12193            }
12194        }
12195
12196        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12197            text,
12198            clipboard_selections,
12199        ));
12200    }
12201
12202    pub fn do_paste(
12203        &mut self,
12204        text: &String,
12205        clipboard_selections: Option<Vec<ClipboardSelection>>,
12206        handle_entire_lines: bool,
12207        window: &mut Window,
12208        cx: &mut Context<Self>,
12209    ) {
12210        if self.read_only(cx) {
12211            return;
12212        }
12213
12214        let clipboard_text = Cow::Borrowed(text);
12215
12216        self.transact(window, cx, |this, window, cx| {
12217            let had_active_edit_prediction = this.has_active_edit_prediction();
12218
12219            if let Some(mut clipboard_selections) = clipboard_selections {
12220                let old_selections = this.selections.all::<usize>(cx);
12221                let all_selections_were_entire_line =
12222                    clipboard_selections.iter().all(|s| s.is_entire_line);
12223                let first_selection_indent_column =
12224                    clipboard_selections.first().map(|s| s.first_line_indent);
12225                if clipboard_selections.len() != old_selections.len() {
12226                    clipboard_selections.drain(..);
12227                }
12228                let cursor_offset = this.selections.last::<usize>(cx).head();
12229                let mut auto_indent_on_paste = true;
12230
12231                this.buffer.update(cx, |buffer, cx| {
12232                    let snapshot = buffer.read(cx);
12233                    auto_indent_on_paste = snapshot
12234                        .language_settings_at(cursor_offset, cx)
12235                        .auto_indent_on_paste;
12236
12237                    let mut start_offset = 0;
12238                    let mut edits = Vec::new();
12239                    let mut original_indent_columns = Vec::new();
12240                    for (ix, selection) in old_selections.iter().enumerate() {
12241                        let to_insert;
12242                        let entire_line;
12243                        let original_indent_column;
12244                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12245                            let end_offset = start_offset + clipboard_selection.len;
12246                            to_insert = &clipboard_text[start_offset..end_offset];
12247                            entire_line = clipboard_selection.is_entire_line;
12248                            start_offset = end_offset + 1;
12249                            original_indent_column = Some(clipboard_selection.first_line_indent);
12250                        } else {
12251                            to_insert = clipboard_text.as_str();
12252                            entire_line = all_selections_were_entire_line;
12253                            original_indent_column = first_selection_indent_column
12254                        }
12255
12256                        // If the corresponding selection was empty when this slice of the
12257                        // clipboard text was written, then the entire line containing the
12258                        // selection was copied. If this selection is also currently empty,
12259                        // then paste the line before the current line of the buffer.
12260                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12261                            let column = selection.start.to_point(&snapshot).column as usize;
12262                            let line_start = selection.start - column;
12263                            line_start..line_start
12264                        } else {
12265                            selection.range()
12266                        };
12267
12268                        edits.push((range, to_insert));
12269                        original_indent_columns.push(original_indent_column);
12270                    }
12271                    drop(snapshot);
12272
12273                    buffer.edit(
12274                        edits,
12275                        if auto_indent_on_paste {
12276                            Some(AutoindentMode::Block {
12277                                original_indent_columns,
12278                            })
12279                        } else {
12280                            None
12281                        },
12282                        cx,
12283                    );
12284                });
12285
12286                let selections = this.selections.all::<usize>(cx);
12287                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12288            } else {
12289                this.insert(&clipboard_text, window, cx);
12290            }
12291
12292            let trigger_in_words =
12293                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12294
12295            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12296        });
12297    }
12298
12299    pub fn diff_clipboard_with_selection(
12300        &mut self,
12301        _: &DiffClipboardWithSelection,
12302        window: &mut Window,
12303        cx: &mut Context<Self>,
12304    ) {
12305        let selections = self.selections.all::<usize>(cx);
12306
12307        if selections.is_empty() {
12308            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12309            return;
12310        };
12311
12312        let clipboard_text = match cx.read_from_clipboard() {
12313            Some(item) => match item.entries().first() {
12314                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12315                _ => None,
12316            },
12317            None => None,
12318        };
12319
12320        let Some(clipboard_text) = clipboard_text else {
12321            log::warn!("Clipboard doesn't contain text.");
12322            return;
12323        };
12324
12325        window.dispatch_action(
12326            Box::new(DiffClipboardWithSelectionData {
12327                clipboard_text,
12328                editor: cx.entity(),
12329            }),
12330            cx,
12331        );
12332    }
12333
12334    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12336        if let Some(item) = cx.read_from_clipboard() {
12337            let entries = item.entries();
12338
12339            match entries.first() {
12340                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12341                // of all the pasted entries.
12342                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12343                    .do_paste(
12344                        clipboard_string.text(),
12345                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12346                        true,
12347                        window,
12348                        cx,
12349                    ),
12350                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12351            }
12352        }
12353    }
12354
12355    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12356        if self.read_only(cx) {
12357            return;
12358        }
12359
12360        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12361
12362        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12363            if let Some((selections, _)) =
12364                self.selection_history.transaction(transaction_id).cloned()
12365            {
12366                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12367                    s.select_anchors(selections.to_vec());
12368                });
12369            } else {
12370                log::error!(
12371                    "No entry in selection_history found for undo. \
12372                     This may correspond to a bug where undo does not update the selection. \
12373                     If this is occurring, please add details to \
12374                     https://github.com/zed-industries/zed/issues/22692"
12375                );
12376            }
12377            self.request_autoscroll(Autoscroll::fit(), cx);
12378            self.unmark_text(window, cx);
12379            self.refresh_edit_prediction(true, false, window, cx);
12380            cx.emit(EditorEvent::Edited { transaction_id });
12381            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12382        }
12383    }
12384
12385    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12386        if self.read_only(cx) {
12387            return;
12388        }
12389
12390        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12391
12392        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12393            if let Some((_, Some(selections))) =
12394                self.selection_history.transaction(transaction_id).cloned()
12395            {
12396                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12397                    s.select_anchors(selections.to_vec());
12398                });
12399            } else {
12400                log::error!(
12401                    "No entry in selection_history found for redo. \
12402                     This may correspond to a bug where undo does not update the selection. \
12403                     If this is occurring, please add details to \
12404                     https://github.com/zed-industries/zed/issues/22692"
12405                );
12406            }
12407            self.request_autoscroll(Autoscroll::fit(), cx);
12408            self.unmark_text(window, cx);
12409            self.refresh_edit_prediction(true, false, window, cx);
12410            cx.emit(EditorEvent::Edited { transaction_id });
12411        }
12412    }
12413
12414    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12415        self.buffer
12416            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12417    }
12418
12419    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12420        self.buffer
12421            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12422    }
12423
12424    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12426        self.change_selections(Default::default(), window, cx, |s| {
12427            s.move_with(|map, selection| {
12428                let cursor = if selection.is_empty() {
12429                    movement::left(map, selection.start)
12430                } else {
12431                    selection.start
12432                };
12433                selection.collapse_to(cursor, SelectionGoal::None);
12434            });
12435        })
12436    }
12437
12438    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12440        self.change_selections(Default::default(), window, cx, |s| {
12441            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12442        })
12443    }
12444
12445    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12446        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12447        self.change_selections(Default::default(), window, cx, |s| {
12448            s.move_with(|map, selection| {
12449                let cursor = if selection.is_empty() {
12450                    movement::right(map, selection.end)
12451                } else {
12452                    selection.end
12453                };
12454                selection.collapse_to(cursor, SelectionGoal::None)
12455            });
12456        })
12457    }
12458
12459    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12461        self.change_selections(Default::default(), window, cx, |s| {
12462            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12463        })
12464    }
12465
12466    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12467        if self.take_rename(true, window, cx).is_some() {
12468            return;
12469        }
12470
12471        if self.mode.is_single_line() {
12472            cx.propagate();
12473            return;
12474        }
12475
12476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12477
12478        let text_layout_details = &self.text_layout_details(window);
12479        let selection_count = self.selections.count();
12480        let first_selection = self.selections.first_anchor();
12481
12482        self.change_selections(Default::default(), window, cx, |s| {
12483            s.move_with(|map, selection| {
12484                if !selection.is_empty() {
12485                    selection.goal = SelectionGoal::None;
12486                }
12487                let (cursor, goal) = movement::up(
12488                    map,
12489                    selection.start,
12490                    selection.goal,
12491                    false,
12492                    text_layout_details,
12493                );
12494                selection.collapse_to(cursor, goal);
12495            });
12496        });
12497
12498        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12499        {
12500            cx.propagate();
12501        }
12502    }
12503
12504    pub fn move_up_by_lines(
12505        &mut self,
12506        action: &MoveUpByLines,
12507        window: &mut Window,
12508        cx: &mut Context<Self>,
12509    ) {
12510        if self.take_rename(true, window, cx).is_some() {
12511            return;
12512        }
12513
12514        if self.mode.is_single_line() {
12515            cx.propagate();
12516            return;
12517        }
12518
12519        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12520
12521        let text_layout_details = &self.text_layout_details(window);
12522
12523        self.change_selections(Default::default(), window, cx, |s| {
12524            s.move_with(|map, selection| {
12525                if !selection.is_empty() {
12526                    selection.goal = SelectionGoal::None;
12527                }
12528                let (cursor, goal) = movement::up_by_rows(
12529                    map,
12530                    selection.start,
12531                    action.lines,
12532                    selection.goal,
12533                    false,
12534                    text_layout_details,
12535                );
12536                selection.collapse_to(cursor, goal);
12537            });
12538        })
12539    }
12540
12541    pub fn move_down_by_lines(
12542        &mut self,
12543        action: &MoveDownByLines,
12544        window: &mut Window,
12545        cx: &mut Context<Self>,
12546    ) {
12547        if self.take_rename(true, window, cx).is_some() {
12548            return;
12549        }
12550
12551        if self.mode.is_single_line() {
12552            cx.propagate();
12553            return;
12554        }
12555
12556        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12557
12558        let text_layout_details = &self.text_layout_details(window);
12559
12560        self.change_selections(Default::default(), window, cx, |s| {
12561            s.move_with(|map, selection| {
12562                if !selection.is_empty() {
12563                    selection.goal = SelectionGoal::None;
12564                }
12565                let (cursor, goal) = movement::down_by_rows(
12566                    map,
12567                    selection.start,
12568                    action.lines,
12569                    selection.goal,
12570                    false,
12571                    text_layout_details,
12572                );
12573                selection.collapse_to(cursor, goal);
12574            });
12575        })
12576    }
12577
12578    pub fn select_down_by_lines(
12579        &mut self,
12580        action: &SelectDownByLines,
12581        window: &mut Window,
12582        cx: &mut Context<Self>,
12583    ) {
12584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12585        let text_layout_details = &self.text_layout_details(window);
12586        self.change_selections(Default::default(), window, cx, |s| {
12587            s.move_heads_with(|map, head, goal| {
12588                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12589            })
12590        })
12591    }
12592
12593    pub fn select_up_by_lines(
12594        &mut self,
12595        action: &SelectUpByLines,
12596        window: &mut Window,
12597        cx: &mut Context<Self>,
12598    ) {
12599        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12600        let text_layout_details = &self.text_layout_details(window);
12601        self.change_selections(Default::default(), window, cx, |s| {
12602            s.move_heads_with(|map, head, goal| {
12603                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12604            })
12605        })
12606    }
12607
12608    pub fn select_page_up(
12609        &mut self,
12610        _: &SelectPageUp,
12611        window: &mut Window,
12612        cx: &mut Context<Self>,
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 text_layout_details = &self.text_layout_details(window);
12621
12622        self.change_selections(Default::default(), window, cx, |s| {
12623            s.move_heads_with(|map, head, goal| {
12624                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12625            })
12626        })
12627    }
12628
12629    pub fn move_page_up(
12630        &mut self,
12631        action: &MovePageUp,
12632        window: &mut Window,
12633        cx: &mut Context<Self>,
12634    ) {
12635        if self.take_rename(true, window, cx).is_some() {
12636            return;
12637        }
12638
12639        if self
12640            .context_menu
12641            .borrow_mut()
12642            .as_mut()
12643            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12644            .unwrap_or(false)
12645        {
12646            return;
12647        }
12648
12649        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12650            cx.propagate();
12651            return;
12652        }
12653
12654        let Some(row_count) = self.visible_row_count() else {
12655            return;
12656        };
12657
12658        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12659
12660        let effects = if action.center_cursor {
12661            SelectionEffects::scroll(Autoscroll::center())
12662        } else {
12663            SelectionEffects::default()
12664        };
12665
12666        let text_layout_details = &self.text_layout_details(window);
12667
12668        self.change_selections(effects, window, cx, |s| {
12669            s.move_with(|map, selection| {
12670                if !selection.is_empty() {
12671                    selection.goal = SelectionGoal::None;
12672                }
12673                let (cursor, goal) = movement::up_by_rows(
12674                    map,
12675                    selection.end,
12676                    row_count,
12677                    selection.goal,
12678                    false,
12679                    text_layout_details,
12680                );
12681                selection.collapse_to(cursor, goal);
12682            });
12683        });
12684    }
12685
12686    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12687        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12688        let text_layout_details = &self.text_layout_details(window);
12689        self.change_selections(Default::default(), window, cx, |s| {
12690            s.move_heads_with(|map, head, goal| {
12691                movement::up(map, head, goal, false, text_layout_details)
12692            })
12693        })
12694    }
12695
12696    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12697        self.take_rename(true, window, cx);
12698
12699        if self.mode.is_single_line() {
12700            cx.propagate();
12701            return;
12702        }
12703
12704        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12705
12706        let text_layout_details = &self.text_layout_details(window);
12707        let selection_count = self.selections.count();
12708        let first_selection = self.selections.first_anchor();
12709
12710        self.change_selections(Default::default(), window, cx, |s| {
12711            s.move_with(|map, selection| {
12712                if !selection.is_empty() {
12713                    selection.goal = SelectionGoal::None;
12714                }
12715                let (cursor, goal) = movement::down(
12716                    map,
12717                    selection.end,
12718                    selection.goal,
12719                    false,
12720                    text_layout_details,
12721                );
12722                selection.collapse_to(cursor, goal);
12723            });
12724        });
12725
12726        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12727        {
12728            cx.propagate();
12729        }
12730    }
12731
12732    pub fn select_page_down(
12733        &mut self,
12734        _: &SelectPageDown,
12735        window: &mut Window,
12736        cx: &mut Context<Self>,
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 text_layout_details = &self.text_layout_details(window);
12745
12746        self.change_selections(Default::default(), window, cx, |s| {
12747            s.move_heads_with(|map, head, goal| {
12748                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12749            })
12750        })
12751    }
12752
12753    pub fn move_page_down(
12754        &mut self,
12755        action: &MovePageDown,
12756        window: &mut Window,
12757        cx: &mut Context<Self>,
12758    ) {
12759        if self.take_rename(true, window, cx).is_some() {
12760            return;
12761        }
12762
12763        if self
12764            .context_menu
12765            .borrow_mut()
12766            .as_mut()
12767            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12768            .unwrap_or(false)
12769        {
12770            return;
12771        }
12772
12773        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12774            cx.propagate();
12775            return;
12776        }
12777
12778        let Some(row_count) = self.visible_row_count() else {
12779            return;
12780        };
12781
12782        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12783
12784        let effects = if action.center_cursor {
12785            SelectionEffects::scroll(Autoscroll::center())
12786        } else {
12787            SelectionEffects::default()
12788        };
12789
12790        let text_layout_details = &self.text_layout_details(window);
12791        self.change_selections(effects, window, cx, |s| {
12792            s.move_with(|map, selection| {
12793                if !selection.is_empty() {
12794                    selection.goal = SelectionGoal::None;
12795                }
12796                let (cursor, goal) = movement::down_by_rows(
12797                    map,
12798                    selection.end,
12799                    row_count,
12800                    selection.goal,
12801                    false,
12802                    text_layout_details,
12803                );
12804                selection.collapse_to(cursor, goal);
12805            });
12806        });
12807    }
12808
12809    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12811        let text_layout_details = &self.text_layout_details(window);
12812        self.change_selections(Default::default(), window, cx, |s| {
12813            s.move_heads_with(|map, head, goal| {
12814                movement::down(map, head, goal, false, text_layout_details)
12815            })
12816        });
12817    }
12818
12819    pub fn context_menu_first(
12820        &mut self,
12821        _: &ContextMenuFirst,
12822        window: &mut Window,
12823        cx: &mut Context<Self>,
12824    ) {
12825        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12826            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12827        }
12828    }
12829
12830    pub fn context_menu_prev(
12831        &mut self,
12832        _: &ContextMenuPrevious,
12833        window: &mut Window,
12834        cx: &mut Context<Self>,
12835    ) {
12836        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12837            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12838        }
12839    }
12840
12841    pub fn context_menu_next(
12842        &mut self,
12843        _: &ContextMenuNext,
12844        window: &mut Window,
12845        cx: &mut Context<Self>,
12846    ) {
12847        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12848            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12849        }
12850    }
12851
12852    pub fn context_menu_last(
12853        &mut self,
12854        _: &ContextMenuLast,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) {
12858        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12859            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12860        }
12861    }
12862
12863    pub fn signature_help_prev(
12864        &mut self,
12865        _: &SignatureHelpPrevious,
12866        _: &mut Window,
12867        cx: &mut Context<Self>,
12868    ) {
12869        if let Some(popover) = self.signature_help_state.popover_mut() {
12870            if popover.current_signature == 0 {
12871                popover.current_signature = popover.signatures.len() - 1;
12872            } else {
12873                popover.current_signature -= 1;
12874            }
12875            cx.notify();
12876        }
12877    }
12878
12879    pub fn signature_help_next(
12880        &mut self,
12881        _: &SignatureHelpNext,
12882        _: &mut Window,
12883        cx: &mut Context<Self>,
12884    ) {
12885        if let Some(popover) = self.signature_help_state.popover_mut() {
12886            if popover.current_signature + 1 == popover.signatures.len() {
12887                popover.current_signature = 0;
12888            } else {
12889                popover.current_signature += 1;
12890            }
12891            cx.notify();
12892        }
12893    }
12894
12895    pub fn move_to_previous_word_start(
12896        &mut self,
12897        _: &MoveToPreviousWordStart,
12898        window: &mut Window,
12899        cx: &mut Context<Self>,
12900    ) {
12901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12902        self.change_selections(Default::default(), window, cx, |s| {
12903            s.move_cursors_with(|map, head, _| {
12904                (
12905                    movement::previous_word_start(map, head),
12906                    SelectionGoal::None,
12907                )
12908            });
12909        })
12910    }
12911
12912    pub fn move_to_previous_subword_start(
12913        &mut self,
12914        _: &MoveToPreviousSubwordStart,
12915        window: &mut Window,
12916        cx: &mut Context<Self>,
12917    ) {
12918        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12919        self.change_selections(Default::default(), window, cx, |s| {
12920            s.move_cursors_with(|map, head, _| {
12921                (
12922                    movement::previous_subword_start(map, head),
12923                    SelectionGoal::None,
12924                )
12925            });
12926        })
12927    }
12928
12929    pub fn select_to_previous_word_start(
12930        &mut self,
12931        _: &SelectToPreviousWordStart,
12932        window: &mut Window,
12933        cx: &mut Context<Self>,
12934    ) {
12935        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12936        self.change_selections(Default::default(), window, cx, |s| {
12937            s.move_heads_with(|map, head, _| {
12938                (
12939                    movement::previous_word_start(map, head),
12940                    SelectionGoal::None,
12941                )
12942            });
12943        })
12944    }
12945
12946    pub fn select_to_previous_subword_start(
12947        &mut self,
12948        _: &SelectToPreviousSubwordStart,
12949        window: &mut Window,
12950        cx: &mut Context<Self>,
12951    ) {
12952        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12953        self.change_selections(Default::default(), window, cx, |s| {
12954            s.move_heads_with(|map, head, _| {
12955                (
12956                    movement::previous_subword_start(map, head),
12957                    SelectionGoal::None,
12958                )
12959            });
12960        })
12961    }
12962
12963    pub fn delete_to_previous_word_start(
12964        &mut self,
12965        action: &DeleteToPreviousWordStart,
12966        window: &mut Window,
12967        cx: &mut Context<Self>,
12968    ) {
12969        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12970        self.transact(window, cx, |this, window, cx| {
12971            this.select_autoclose_pair(window, cx);
12972            this.change_selections(Default::default(), window, cx, |s| {
12973                s.move_with(|map, selection| {
12974                    if selection.is_empty() {
12975                        let cursor = if action.ignore_newlines {
12976                            movement::previous_word_start(map, selection.head())
12977                        } else {
12978                            movement::previous_word_start_or_newline(map, selection.head())
12979                        };
12980                        selection.set_head(cursor, SelectionGoal::None);
12981                    }
12982                });
12983            });
12984            this.insert("", window, cx);
12985        });
12986    }
12987
12988    pub fn delete_to_previous_subword_start(
12989        &mut self,
12990        _: &DeleteToPreviousSubwordStart,
12991        window: &mut Window,
12992        cx: &mut Context<Self>,
12993    ) {
12994        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12995        self.transact(window, cx, |this, window, cx| {
12996            this.select_autoclose_pair(window, cx);
12997            this.change_selections(Default::default(), window, cx, |s| {
12998                s.move_with(|map, selection| {
12999                    if selection.is_empty() {
13000                        let cursor = movement::previous_subword_start(map, selection.head());
13001                        selection.set_head(cursor, SelectionGoal::None);
13002                    }
13003                });
13004            });
13005            this.insert("", window, cx);
13006        });
13007    }
13008
13009    pub fn move_to_next_word_end(
13010        &mut self,
13011        _: &MoveToNextWordEnd,
13012        window: &mut Window,
13013        cx: &mut Context<Self>,
13014    ) {
13015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13016        self.change_selections(Default::default(), window, cx, |s| {
13017            s.move_cursors_with(|map, head, _| {
13018                (movement::next_word_end(map, head), SelectionGoal::None)
13019            });
13020        })
13021    }
13022
13023    pub fn move_to_next_subword_end(
13024        &mut self,
13025        _: &MoveToNextSubwordEnd,
13026        window: &mut Window,
13027        cx: &mut Context<Self>,
13028    ) {
13029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13030        self.change_selections(Default::default(), window, cx, |s| {
13031            s.move_cursors_with(|map, head, _| {
13032                (movement::next_subword_end(map, head), SelectionGoal::None)
13033            });
13034        })
13035    }
13036
13037    pub fn select_to_next_word_end(
13038        &mut self,
13039        _: &SelectToNextWordEnd,
13040        window: &mut Window,
13041        cx: &mut Context<Self>,
13042    ) {
13043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13044        self.change_selections(Default::default(), window, cx, |s| {
13045            s.move_heads_with(|map, head, _| {
13046                (movement::next_word_end(map, head), SelectionGoal::None)
13047            });
13048        })
13049    }
13050
13051    pub fn select_to_next_subword_end(
13052        &mut self,
13053        _: &SelectToNextSubwordEnd,
13054        window: &mut Window,
13055        cx: &mut Context<Self>,
13056    ) {
13057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13058        self.change_selections(Default::default(), window, cx, |s| {
13059            s.move_heads_with(|map, head, _| {
13060                (movement::next_subword_end(map, head), SelectionGoal::None)
13061            });
13062        })
13063    }
13064
13065    pub fn delete_to_next_word_end(
13066        &mut self,
13067        action: &DeleteToNextWordEnd,
13068        window: &mut Window,
13069        cx: &mut Context<Self>,
13070    ) {
13071        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13072        self.transact(window, cx, |this, window, cx| {
13073            this.change_selections(Default::default(), window, cx, |s| {
13074                s.move_with(|map, selection| {
13075                    if selection.is_empty() {
13076                        let cursor = if action.ignore_newlines {
13077                            movement::next_word_end(map, selection.head())
13078                        } else {
13079                            movement::next_word_end_or_newline(map, selection.head())
13080                        };
13081                        selection.set_head(cursor, SelectionGoal::None);
13082                    }
13083                });
13084            });
13085            this.insert("", window, cx);
13086        });
13087    }
13088
13089    pub fn delete_to_next_subword_end(
13090        &mut self,
13091        _: &DeleteToNextSubwordEnd,
13092        window: &mut Window,
13093        cx: &mut Context<Self>,
13094    ) {
13095        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13096        self.transact(window, cx, |this, window, cx| {
13097            this.change_selections(Default::default(), window, cx, |s| {
13098                s.move_with(|map, selection| {
13099                    if selection.is_empty() {
13100                        let cursor = movement::next_subword_end(map, selection.head());
13101                        selection.set_head(cursor, SelectionGoal::None);
13102                    }
13103                });
13104            });
13105            this.insert("", window, cx);
13106        });
13107    }
13108
13109    pub fn move_to_beginning_of_line(
13110        &mut self,
13111        action: &MoveToBeginningOfLine,
13112        window: &mut Window,
13113        cx: &mut Context<Self>,
13114    ) {
13115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13116        self.change_selections(Default::default(), window, cx, |s| {
13117            s.move_cursors_with(|map, head, _| {
13118                (
13119                    movement::indented_line_beginning(
13120                        map,
13121                        head,
13122                        action.stop_at_soft_wraps,
13123                        action.stop_at_indent,
13124                    ),
13125                    SelectionGoal::None,
13126                )
13127            });
13128        })
13129    }
13130
13131    pub fn select_to_beginning_of_line(
13132        &mut self,
13133        action: &SelectToBeginningOfLine,
13134        window: &mut Window,
13135        cx: &mut Context<Self>,
13136    ) {
13137        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13138        self.change_selections(Default::default(), window, cx, |s| {
13139            s.move_heads_with(|map, head, _| {
13140                (
13141                    movement::indented_line_beginning(
13142                        map,
13143                        head,
13144                        action.stop_at_soft_wraps,
13145                        action.stop_at_indent,
13146                    ),
13147                    SelectionGoal::None,
13148                )
13149            });
13150        });
13151    }
13152
13153    pub fn delete_to_beginning_of_line(
13154        &mut self,
13155        action: &DeleteToBeginningOfLine,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13160        self.transact(window, cx, |this, window, cx| {
13161            this.change_selections(Default::default(), window, cx, |s| {
13162                s.move_with(|_, selection| {
13163                    selection.reversed = true;
13164                });
13165            });
13166
13167            this.select_to_beginning_of_line(
13168                &SelectToBeginningOfLine {
13169                    stop_at_soft_wraps: false,
13170                    stop_at_indent: action.stop_at_indent,
13171                },
13172                window,
13173                cx,
13174            );
13175            this.backspace(&Backspace, window, cx);
13176        });
13177    }
13178
13179    pub fn move_to_end_of_line(
13180        &mut self,
13181        action: &MoveToEndOfLine,
13182        window: &mut Window,
13183        cx: &mut Context<Self>,
13184    ) {
13185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13186        self.change_selections(Default::default(), window, cx, |s| {
13187            s.move_cursors_with(|map, head, _| {
13188                (
13189                    movement::line_end(map, head, action.stop_at_soft_wraps),
13190                    SelectionGoal::None,
13191                )
13192            });
13193        })
13194    }
13195
13196    pub fn select_to_end_of_line(
13197        &mut self,
13198        action: &SelectToEndOfLine,
13199        window: &mut Window,
13200        cx: &mut Context<Self>,
13201    ) {
13202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13203        self.change_selections(Default::default(), window, cx, |s| {
13204            s.move_heads_with(|map, head, _| {
13205                (
13206                    movement::line_end(map, head, action.stop_at_soft_wraps),
13207                    SelectionGoal::None,
13208                )
13209            });
13210        })
13211    }
13212
13213    pub fn delete_to_end_of_line(
13214        &mut self,
13215        _: &DeleteToEndOfLine,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13220        self.transact(window, cx, |this, window, cx| {
13221            this.select_to_end_of_line(
13222                &SelectToEndOfLine {
13223                    stop_at_soft_wraps: false,
13224                },
13225                window,
13226                cx,
13227            );
13228            this.delete(&Delete, window, cx);
13229        });
13230    }
13231
13232    pub fn cut_to_end_of_line(
13233        &mut self,
13234        _: &CutToEndOfLine,
13235        window: &mut Window,
13236        cx: &mut Context<Self>,
13237    ) {
13238        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13239        self.transact(window, cx, |this, window, cx| {
13240            this.select_to_end_of_line(
13241                &SelectToEndOfLine {
13242                    stop_at_soft_wraps: false,
13243                },
13244                window,
13245                cx,
13246            );
13247            this.cut(&Cut, window, cx);
13248        });
13249    }
13250
13251    pub fn move_to_start_of_paragraph(
13252        &mut self,
13253        _: &MoveToStartOfParagraph,
13254        window: &mut Window,
13255        cx: &mut Context<Self>,
13256    ) {
13257        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13258            cx.propagate();
13259            return;
13260        }
13261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13262        self.change_selections(Default::default(), window, cx, |s| {
13263            s.move_with(|map, selection| {
13264                selection.collapse_to(
13265                    movement::start_of_paragraph(map, selection.head(), 1),
13266                    SelectionGoal::None,
13267                )
13268            });
13269        })
13270    }
13271
13272    pub fn move_to_end_of_paragraph(
13273        &mut self,
13274        _: &MoveToEndOfParagraph,
13275        window: &mut Window,
13276        cx: &mut Context<Self>,
13277    ) {
13278        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13279            cx.propagate();
13280            return;
13281        }
13282        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13283        self.change_selections(Default::default(), window, cx, |s| {
13284            s.move_with(|map, selection| {
13285                selection.collapse_to(
13286                    movement::end_of_paragraph(map, selection.head(), 1),
13287                    SelectionGoal::None,
13288                )
13289            });
13290        })
13291    }
13292
13293    pub fn select_to_start_of_paragraph(
13294        &mut self,
13295        _: &SelectToStartOfParagraph,
13296        window: &mut Window,
13297        cx: &mut Context<Self>,
13298    ) {
13299        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13300            cx.propagate();
13301            return;
13302        }
13303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13304        self.change_selections(Default::default(), window, cx, |s| {
13305            s.move_heads_with(|map, head, _| {
13306                (
13307                    movement::start_of_paragraph(map, head, 1),
13308                    SelectionGoal::None,
13309                )
13310            });
13311        })
13312    }
13313
13314    pub fn select_to_end_of_paragraph(
13315        &mut self,
13316        _: &SelectToEndOfParagraph,
13317        window: &mut Window,
13318        cx: &mut Context<Self>,
13319    ) {
13320        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13321            cx.propagate();
13322            return;
13323        }
13324        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13325        self.change_selections(Default::default(), window, cx, |s| {
13326            s.move_heads_with(|map, head, _| {
13327                (
13328                    movement::end_of_paragraph(map, head, 1),
13329                    SelectionGoal::None,
13330                )
13331            });
13332        })
13333    }
13334
13335    pub fn move_to_start_of_excerpt(
13336        &mut self,
13337        _: &MoveToStartOfExcerpt,
13338        window: &mut Window,
13339        cx: &mut Context<Self>,
13340    ) {
13341        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13342            cx.propagate();
13343            return;
13344        }
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13346        self.change_selections(Default::default(), window, cx, |s| {
13347            s.move_with(|map, selection| {
13348                selection.collapse_to(
13349                    movement::start_of_excerpt(
13350                        map,
13351                        selection.head(),
13352                        workspace::searchable::Direction::Prev,
13353                    ),
13354                    SelectionGoal::None,
13355                )
13356            });
13357        })
13358    }
13359
13360    pub fn move_to_start_of_next_excerpt(
13361        &mut self,
13362        _: &MoveToStartOfNextExcerpt,
13363        window: &mut Window,
13364        cx: &mut Context<Self>,
13365    ) {
13366        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13367            cx.propagate();
13368            return;
13369        }
13370
13371        self.change_selections(Default::default(), window, cx, |s| {
13372            s.move_with(|map, selection| {
13373                selection.collapse_to(
13374                    movement::start_of_excerpt(
13375                        map,
13376                        selection.head(),
13377                        workspace::searchable::Direction::Next,
13378                    ),
13379                    SelectionGoal::None,
13380                )
13381            });
13382        })
13383    }
13384
13385    pub fn move_to_end_of_excerpt(
13386        &mut self,
13387        _: &MoveToEndOfExcerpt,
13388        window: &mut Window,
13389        cx: &mut Context<Self>,
13390    ) {
13391        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13392            cx.propagate();
13393            return;
13394        }
13395        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13396        self.change_selections(Default::default(), window, cx, |s| {
13397            s.move_with(|map, selection| {
13398                selection.collapse_to(
13399                    movement::end_of_excerpt(
13400                        map,
13401                        selection.head(),
13402                        workspace::searchable::Direction::Next,
13403                    ),
13404                    SelectionGoal::None,
13405                )
13406            });
13407        })
13408    }
13409
13410    pub fn move_to_end_of_previous_excerpt(
13411        &mut self,
13412        _: &MoveToEndOfPreviousExcerpt,
13413        window: &mut Window,
13414        cx: &mut Context<Self>,
13415    ) {
13416        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13417            cx.propagate();
13418            return;
13419        }
13420        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13421        self.change_selections(Default::default(), window, cx, |s| {
13422            s.move_with(|map, selection| {
13423                selection.collapse_to(
13424                    movement::end_of_excerpt(
13425                        map,
13426                        selection.head(),
13427                        workspace::searchable::Direction::Prev,
13428                    ),
13429                    SelectionGoal::None,
13430                )
13431            });
13432        })
13433    }
13434
13435    pub fn select_to_start_of_excerpt(
13436        &mut self,
13437        _: &SelectToStartOfExcerpt,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13442            cx.propagate();
13443            return;
13444        }
13445        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13446        self.change_selections(Default::default(), window, cx, |s| {
13447            s.move_heads_with(|map, head, _| {
13448                (
13449                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13450                    SelectionGoal::None,
13451                )
13452            });
13453        })
13454    }
13455
13456    pub fn select_to_start_of_next_excerpt(
13457        &mut self,
13458        _: &SelectToStartOfNextExcerpt,
13459        window: &mut Window,
13460        cx: &mut Context<Self>,
13461    ) {
13462        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13463            cx.propagate();
13464            return;
13465        }
13466        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13467        self.change_selections(Default::default(), window, cx, |s| {
13468            s.move_heads_with(|map, head, _| {
13469                (
13470                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13471                    SelectionGoal::None,
13472                )
13473            });
13474        })
13475    }
13476
13477    pub fn select_to_end_of_excerpt(
13478        &mut self,
13479        _: &SelectToEndOfExcerpt,
13480        window: &mut Window,
13481        cx: &mut Context<Self>,
13482    ) {
13483        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13484            cx.propagate();
13485            return;
13486        }
13487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13488        self.change_selections(Default::default(), window, cx, |s| {
13489            s.move_heads_with(|map, head, _| {
13490                (
13491                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13492                    SelectionGoal::None,
13493                )
13494            });
13495        })
13496    }
13497
13498    pub fn select_to_end_of_previous_excerpt(
13499        &mut self,
13500        _: &SelectToEndOfPreviousExcerpt,
13501        window: &mut Window,
13502        cx: &mut Context<Self>,
13503    ) {
13504        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13505            cx.propagate();
13506            return;
13507        }
13508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13509        self.change_selections(Default::default(), window, cx, |s| {
13510            s.move_heads_with(|map, head, _| {
13511                (
13512                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13513                    SelectionGoal::None,
13514                )
13515            });
13516        })
13517    }
13518
13519    pub fn move_to_beginning(
13520        &mut self,
13521        _: &MoveToBeginning,
13522        window: &mut Window,
13523        cx: &mut Context<Self>,
13524    ) {
13525        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13526            cx.propagate();
13527            return;
13528        }
13529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13530        self.change_selections(Default::default(), window, cx, |s| {
13531            s.select_ranges(vec![0..0]);
13532        });
13533    }
13534
13535    pub fn select_to_beginning(
13536        &mut self,
13537        _: &SelectToBeginning,
13538        window: &mut Window,
13539        cx: &mut Context<Self>,
13540    ) {
13541        let mut selection = self.selections.last::<Point>(cx);
13542        selection.set_head(Point::zero(), SelectionGoal::None);
13543        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13544        self.change_selections(Default::default(), window, cx, |s| {
13545            s.select(vec![selection]);
13546        });
13547    }
13548
13549    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13550        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13551            cx.propagate();
13552            return;
13553        }
13554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13555        let cursor = self.buffer.read(cx).read(cx).len();
13556        self.change_selections(Default::default(), window, cx, |s| {
13557            s.select_ranges(vec![cursor..cursor])
13558        });
13559    }
13560
13561    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13562        self.nav_history = nav_history;
13563    }
13564
13565    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13566        self.nav_history.as_ref()
13567    }
13568
13569    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13570        self.push_to_nav_history(
13571            self.selections.newest_anchor().head(),
13572            None,
13573            false,
13574            true,
13575            cx,
13576        );
13577    }
13578
13579    fn push_to_nav_history(
13580        &mut self,
13581        cursor_anchor: Anchor,
13582        new_position: Option<Point>,
13583        is_deactivate: bool,
13584        always: bool,
13585        cx: &mut Context<Self>,
13586    ) {
13587        if let Some(nav_history) = self.nav_history.as_mut() {
13588            let buffer = self.buffer.read(cx).read(cx);
13589            let cursor_position = cursor_anchor.to_point(&buffer);
13590            let scroll_state = self.scroll_manager.anchor();
13591            let scroll_top_row = scroll_state.top_row(&buffer);
13592            drop(buffer);
13593
13594            if let Some(new_position) = new_position {
13595                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13596                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13597                    return;
13598                }
13599            }
13600
13601            nav_history.push(
13602                Some(NavigationData {
13603                    cursor_anchor,
13604                    cursor_position,
13605                    scroll_anchor: scroll_state,
13606                    scroll_top_row,
13607                }),
13608                cx,
13609            );
13610            cx.emit(EditorEvent::PushedToNavHistory {
13611                anchor: cursor_anchor,
13612                is_deactivate,
13613            })
13614        }
13615    }
13616
13617    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13618        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13619        let buffer = self.buffer.read(cx).snapshot(cx);
13620        let mut selection = self.selections.first::<usize>(cx);
13621        selection.set_head(buffer.len(), SelectionGoal::None);
13622        self.change_selections(Default::default(), window, cx, |s| {
13623            s.select(vec![selection]);
13624        });
13625    }
13626
13627    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13628        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13629        let end = self.buffer.read(cx).read(cx).len();
13630        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13631            s.select_ranges(vec![0..end]);
13632        });
13633    }
13634
13635    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13637        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13638        let mut selections = self.selections.all::<Point>(cx);
13639        let max_point = display_map.buffer_snapshot.max_point();
13640        for selection in &mut selections {
13641            let rows = selection.spanned_rows(true, &display_map);
13642            selection.start = Point::new(rows.start.0, 0);
13643            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13644            selection.reversed = false;
13645        }
13646        self.change_selections(Default::default(), window, cx, |s| {
13647            s.select(selections);
13648        });
13649    }
13650
13651    pub fn split_selection_into_lines(
13652        &mut self,
13653        action: &SplitSelectionIntoLines,
13654        window: &mut Window,
13655        cx: &mut Context<Self>,
13656    ) {
13657        let selections = self
13658            .selections
13659            .all::<Point>(cx)
13660            .into_iter()
13661            .map(|selection| selection.start..selection.end)
13662            .collect::<Vec<_>>();
13663        self.unfold_ranges(&selections, true, true, cx);
13664
13665        let mut new_selection_ranges = Vec::new();
13666        {
13667            let buffer = self.buffer.read(cx).read(cx);
13668            for selection in selections {
13669                for row in selection.start.row..selection.end.row {
13670                    let line_start = Point::new(row, 0);
13671                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13672
13673                    if action.keep_selections {
13674                        // Keep the selection range for each line
13675                        let selection_start = if row == selection.start.row {
13676                            selection.start
13677                        } else {
13678                            line_start
13679                        };
13680                        new_selection_ranges.push(selection_start..line_end);
13681                    } else {
13682                        // Collapse to cursor at end of line
13683                        new_selection_ranges.push(line_end..line_end);
13684                    }
13685                }
13686
13687                let is_multiline_selection = selection.start.row != selection.end.row;
13688                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13689                // so this action feels more ergonomic when paired with other selection operations
13690                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13691                if !should_skip_last {
13692                    if action.keep_selections {
13693                        if is_multiline_selection {
13694                            let line_start = Point::new(selection.end.row, 0);
13695                            new_selection_ranges.push(line_start..selection.end);
13696                        } else {
13697                            new_selection_ranges.push(selection.start..selection.end);
13698                        }
13699                    } else {
13700                        new_selection_ranges.push(selection.end..selection.end);
13701                    }
13702                }
13703            }
13704        }
13705        self.change_selections(Default::default(), window, cx, |s| {
13706            s.select_ranges(new_selection_ranges);
13707        });
13708    }
13709
13710    pub fn add_selection_above(
13711        &mut self,
13712        _: &AddSelectionAbove,
13713        window: &mut Window,
13714        cx: &mut Context<Self>,
13715    ) {
13716        self.add_selection(true, window, cx);
13717    }
13718
13719    pub fn add_selection_below(
13720        &mut self,
13721        _: &AddSelectionBelow,
13722        window: &mut Window,
13723        cx: &mut Context<Self>,
13724    ) {
13725        self.add_selection(false, window, cx);
13726    }
13727
13728    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13729        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13730
13731        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13732        let all_selections = self.selections.all::<Point>(cx);
13733        let text_layout_details = self.text_layout_details(window);
13734
13735        let (mut columnar_selections, new_selections_to_columnarize) = {
13736            if let Some(state) = self.add_selections_state.as_ref() {
13737                let columnar_selection_ids: HashSet<_> = state
13738                    .groups
13739                    .iter()
13740                    .flat_map(|group| group.stack.iter())
13741                    .copied()
13742                    .collect();
13743
13744                all_selections
13745                    .into_iter()
13746                    .partition(|s| columnar_selection_ids.contains(&s.id))
13747            } else {
13748                (Vec::new(), all_selections)
13749            }
13750        };
13751
13752        let mut state = self
13753            .add_selections_state
13754            .take()
13755            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13756
13757        for selection in new_selections_to_columnarize {
13758            let range = selection.display_range(&display_map).sorted();
13759            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13760            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13761            let positions = start_x.min(end_x)..start_x.max(end_x);
13762            let mut stack = Vec::new();
13763            for row in range.start.row().0..=range.end.row().0 {
13764                if let Some(selection) = self.selections.build_columnar_selection(
13765                    &display_map,
13766                    DisplayRow(row),
13767                    &positions,
13768                    selection.reversed,
13769                    &text_layout_details,
13770                ) {
13771                    stack.push(selection.id);
13772                    columnar_selections.push(selection);
13773                }
13774            }
13775            if !stack.is_empty() {
13776                if above {
13777                    stack.reverse();
13778                }
13779                state.groups.push(AddSelectionsGroup { above, stack });
13780            }
13781        }
13782
13783        let mut final_selections = Vec::new();
13784        let end_row = if above {
13785            DisplayRow(0)
13786        } else {
13787            display_map.max_point().row()
13788        };
13789
13790        let mut last_added_item_per_group = HashMap::default();
13791        for group in state.groups.iter_mut() {
13792            if let Some(last_id) = group.stack.last() {
13793                last_added_item_per_group.insert(*last_id, group);
13794            }
13795        }
13796
13797        for selection in columnar_selections {
13798            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13799                if above == group.above {
13800                    let range = selection.display_range(&display_map).sorted();
13801                    debug_assert_eq!(range.start.row(), range.end.row());
13802                    let mut row = range.start.row();
13803                    let positions =
13804                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13805                            px(start)..px(end)
13806                        } else {
13807                            let start_x =
13808                                display_map.x_for_display_point(range.start, &text_layout_details);
13809                            let end_x =
13810                                display_map.x_for_display_point(range.end, &text_layout_details);
13811                            start_x.min(end_x)..start_x.max(end_x)
13812                        };
13813
13814                    let mut maybe_new_selection = None;
13815                    while row != end_row {
13816                        if above {
13817                            row.0 -= 1;
13818                        } else {
13819                            row.0 += 1;
13820                        }
13821                        if let Some(new_selection) = self.selections.build_columnar_selection(
13822                            &display_map,
13823                            row,
13824                            &positions,
13825                            selection.reversed,
13826                            &text_layout_details,
13827                        ) {
13828                            maybe_new_selection = Some(new_selection);
13829                            break;
13830                        }
13831                    }
13832
13833                    if let Some(new_selection) = maybe_new_selection {
13834                        group.stack.push(new_selection.id);
13835                        if above {
13836                            final_selections.push(new_selection);
13837                            final_selections.push(selection);
13838                        } else {
13839                            final_selections.push(selection);
13840                            final_selections.push(new_selection);
13841                        }
13842                    } else {
13843                        final_selections.push(selection);
13844                    }
13845                } else {
13846                    group.stack.pop();
13847                }
13848            } else {
13849                final_selections.push(selection);
13850            }
13851        }
13852
13853        self.change_selections(Default::default(), window, cx, |s| {
13854            s.select(final_selections);
13855        });
13856
13857        let final_selection_ids: HashSet<_> = self
13858            .selections
13859            .all::<Point>(cx)
13860            .iter()
13861            .map(|s| s.id)
13862            .collect();
13863        state.groups.retain_mut(|group| {
13864            // selections might get merged above so we remove invalid items from stacks
13865            group.stack.retain(|id| final_selection_ids.contains(id));
13866
13867            // single selection in stack can be treated as initial state
13868            group.stack.len() > 1
13869        });
13870
13871        if !state.groups.is_empty() {
13872            self.add_selections_state = Some(state);
13873        }
13874    }
13875
13876    fn select_match_ranges(
13877        &mut self,
13878        range: Range<usize>,
13879        reversed: bool,
13880        replace_newest: bool,
13881        auto_scroll: Option<Autoscroll>,
13882        window: &mut Window,
13883        cx: &mut Context<Editor>,
13884    ) {
13885        self.unfold_ranges(
13886            std::slice::from_ref(&range),
13887            false,
13888            auto_scroll.is_some(),
13889            cx,
13890        );
13891        let effects = if let Some(scroll) = auto_scroll {
13892            SelectionEffects::scroll(scroll)
13893        } else {
13894            SelectionEffects::no_scroll()
13895        };
13896        self.change_selections(effects, window, cx, |s| {
13897            if replace_newest {
13898                s.delete(s.newest_anchor().id);
13899            }
13900            if reversed {
13901                s.insert_range(range.end..range.start);
13902            } else {
13903                s.insert_range(range);
13904            }
13905        });
13906    }
13907
13908    pub fn select_next_match_internal(
13909        &mut self,
13910        display_map: &DisplaySnapshot,
13911        replace_newest: bool,
13912        autoscroll: Option<Autoscroll>,
13913        window: &mut Window,
13914        cx: &mut Context<Self>,
13915    ) -> Result<()> {
13916        let buffer = &display_map.buffer_snapshot;
13917        let mut selections = self.selections.all::<usize>(cx);
13918        if let Some(mut select_next_state) = self.select_next_state.take() {
13919            let query = &select_next_state.query;
13920            if !select_next_state.done {
13921                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13922                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13923                let mut next_selected_range = None;
13924
13925                let bytes_after_last_selection =
13926                    buffer.bytes_in_range(last_selection.end..buffer.len());
13927                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13928                let query_matches = query
13929                    .stream_find_iter(bytes_after_last_selection)
13930                    .map(|result| (last_selection.end, result))
13931                    .chain(
13932                        query
13933                            .stream_find_iter(bytes_before_first_selection)
13934                            .map(|result| (0, result)),
13935                    );
13936
13937                for (start_offset, query_match) in query_matches {
13938                    let query_match = query_match.unwrap(); // can only fail due to I/O
13939                    let offset_range =
13940                        start_offset + query_match.start()..start_offset + query_match.end();
13941
13942                    if !select_next_state.wordwise
13943                        || (!buffer.is_inside_word(offset_range.start, false)
13944                            && !buffer.is_inside_word(offset_range.end, false))
13945                    {
13946                        // TODO: This is n^2, because we might check all the selections
13947                        if !selections
13948                            .iter()
13949                            .any(|selection| selection.range().overlaps(&offset_range))
13950                        {
13951                            next_selected_range = Some(offset_range);
13952                            break;
13953                        }
13954                    }
13955                }
13956
13957                if let Some(next_selected_range) = next_selected_range {
13958                    self.select_match_ranges(
13959                        next_selected_range,
13960                        last_selection.reversed,
13961                        replace_newest,
13962                        autoscroll,
13963                        window,
13964                        cx,
13965                    );
13966                } else {
13967                    select_next_state.done = true;
13968                }
13969            }
13970
13971            self.select_next_state = Some(select_next_state);
13972        } else {
13973            let mut only_carets = true;
13974            let mut same_text_selected = true;
13975            let mut selected_text = None;
13976
13977            let mut selections_iter = selections.iter().peekable();
13978            while let Some(selection) = selections_iter.next() {
13979                if selection.start != selection.end {
13980                    only_carets = false;
13981                }
13982
13983                if same_text_selected {
13984                    if selected_text.is_none() {
13985                        selected_text =
13986                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13987                    }
13988
13989                    if let Some(next_selection) = selections_iter.peek() {
13990                        if next_selection.range().len() == selection.range().len() {
13991                            let next_selected_text = buffer
13992                                .text_for_range(next_selection.range())
13993                                .collect::<String>();
13994                            if Some(next_selected_text) != selected_text {
13995                                same_text_selected = false;
13996                                selected_text = None;
13997                            }
13998                        } else {
13999                            same_text_selected = false;
14000                            selected_text = None;
14001                        }
14002                    }
14003                }
14004            }
14005
14006            if only_carets {
14007                for selection in &mut selections {
14008                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14009                    selection.start = word_range.start;
14010                    selection.end = word_range.end;
14011                    selection.goal = SelectionGoal::None;
14012                    selection.reversed = false;
14013                    self.select_match_ranges(
14014                        selection.start..selection.end,
14015                        selection.reversed,
14016                        replace_newest,
14017                        autoscroll,
14018                        window,
14019                        cx,
14020                    );
14021                }
14022
14023                if selections.len() == 1 {
14024                    let selection = selections
14025                        .last()
14026                        .expect("ensured that there's only one selection");
14027                    let query = buffer
14028                        .text_for_range(selection.start..selection.end)
14029                        .collect::<String>();
14030                    let is_empty = query.is_empty();
14031                    let select_state = SelectNextState {
14032                        query: AhoCorasick::new(&[query])?,
14033                        wordwise: true,
14034                        done: is_empty,
14035                    };
14036                    self.select_next_state = Some(select_state);
14037                } else {
14038                    self.select_next_state = None;
14039                }
14040            } else if let Some(selected_text) = selected_text {
14041                self.select_next_state = Some(SelectNextState {
14042                    query: AhoCorasick::new(&[selected_text])?,
14043                    wordwise: false,
14044                    done: false,
14045                });
14046                self.select_next_match_internal(
14047                    display_map,
14048                    replace_newest,
14049                    autoscroll,
14050                    window,
14051                    cx,
14052                )?;
14053            }
14054        }
14055        Ok(())
14056    }
14057
14058    pub fn select_all_matches(
14059        &mut self,
14060        _action: &SelectAllMatches,
14061        window: &mut Window,
14062        cx: &mut Context<Self>,
14063    ) -> Result<()> {
14064        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14065
14066        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14067
14068        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14069        let Some(select_next_state) = self.select_next_state.as_mut() else {
14070            return Ok(());
14071        };
14072        if select_next_state.done {
14073            return Ok(());
14074        }
14075
14076        let mut new_selections = Vec::new();
14077
14078        let reversed = self.selections.oldest::<usize>(cx).reversed;
14079        let buffer = &display_map.buffer_snapshot;
14080        let query_matches = select_next_state
14081            .query
14082            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14083
14084        for query_match in query_matches.into_iter() {
14085            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14086            let offset_range = if reversed {
14087                query_match.end()..query_match.start()
14088            } else {
14089                query_match.start()..query_match.end()
14090            };
14091
14092            if !select_next_state.wordwise
14093                || (!buffer.is_inside_word(offset_range.start, false)
14094                    && !buffer.is_inside_word(offset_range.end, false))
14095            {
14096                new_selections.push(offset_range.start..offset_range.end);
14097            }
14098        }
14099
14100        select_next_state.done = true;
14101
14102        if new_selections.is_empty() {
14103            log::error!("bug: new_selections is empty in select_all_matches");
14104            return Ok(());
14105        }
14106
14107        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14108        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14109            selections.select_ranges(new_selections)
14110        });
14111
14112        Ok(())
14113    }
14114
14115    pub fn select_next(
14116        &mut self,
14117        action: &SelectNext,
14118        window: &mut Window,
14119        cx: &mut Context<Self>,
14120    ) -> Result<()> {
14121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14122        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14123        self.select_next_match_internal(
14124            &display_map,
14125            action.replace_newest,
14126            Some(Autoscroll::newest()),
14127            window,
14128            cx,
14129        )?;
14130        Ok(())
14131    }
14132
14133    pub fn select_previous(
14134        &mut self,
14135        action: &SelectPrevious,
14136        window: &mut Window,
14137        cx: &mut Context<Self>,
14138    ) -> Result<()> {
14139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14140        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14141        let buffer = &display_map.buffer_snapshot;
14142        let mut selections = self.selections.all::<usize>(cx);
14143        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14144            let query = &select_prev_state.query;
14145            if !select_prev_state.done {
14146                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14147                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14148                let mut next_selected_range = None;
14149                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14150                let bytes_before_last_selection =
14151                    buffer.reversed_bytes_in_range(0..last_selection.start);
14152                let bytes_after_first_selection =
14153                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14154                let query_matches = query
14155                    .stream_find_iter(bytes_before_last_selection)
14156                    .map(|result| (last_selection.start, result))
14157                    .chain(
14158                        query
14159                            .stream_find_iter(bytes_after_first_selection)
14160                            .map(|result| (buffer.len(), result)),
14161                    );
14162                for (end_offset, query_match) in query_matches {
14163                    let query_match = query_match.unwrap(); // can only fail due to I/O
14164                    let offset_range =
14165                        end_offset - query_match.end()..end_offset - query_match.start();
14166
14167                    if !select_prev_state.wordwise
14168                        || (!buffer.is_inside_word(offset_range.start, false)
14169                            && !buffer.is_inside_word(offset_range.end, false))
14170                    {
14171                        next_selected_range = Some(offset_range);
14172                        break;
14173                    }
14174                }
14175
14176                if let Some(next_selected_range) = next_selected_range {
14177                    self.select_match_ranges(
14178                        next_selected_range,
14179                        last_selection.reversed,
14180                        action.replace_newest,
14181                        Some(Autoscroll::newest()),
14182                        window,
14183                        cx,
14184                    );
14185                } else {
14186                    select_prev_state.done = true;
14187                }
14188            }
14189
14190            self.select_prev_state = Some(select_prev_state);
14191        } else {
14192            let mut only_carets = true;
14193            let mut same_text_selected = true;
14194            let mut selected_text = None;
14195
14196            let mut selections_iter = selections.iter().peekable();
14197            while let Some(selection) = selections_iter.next() {
14198                if selection.start != selection.end {
14199                    only_carets = false;
14200                }
14201
14202                if same_text_selected {
14203                    if selected_text.is_none() {
14204                        selected_text =
14205                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14206                    }
14207
14208                    if let Some(next_selection) = selections_iter.peek() {
14209                        if next_selection.range().len() == selection.range().len() {
14210                            let next_selected_text = buffer
14211                                .text_for_range(next_selection.range())
14212                                .collect::<String>();
14213                            if Some(next_selected_text) != selected_text {
14214                                same_text_selected = false;
14215                                selected_text = None;
14216                            }
14217                        } else {
14218                            same_text_selected = false;
14219                            selected_text = None;
14220                        }
14221                    }
14222                }
14223            }
14224
14225            if only_carets {
14226                for selection in &mut selections {
14227                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14228                    selection.start = word_range.start;
14229                    selection.end = word_range.end;
14230                    selection.goal = SelectionGoal::None;
14231                    selection.reversed = false;
14232                    self.select_match_ranges(
14233                        selection.start..selection.end,
14234                        selection.reversed,
14235                        action.replace_newest,
14236                        Some(Autoscroll::newest()),
14237                        window,
14238                        cx,
14239                    );
14240                }
14241                if selections.len() == 1 {
14242                    let selection = selections
14243                        .last()
14244                        .expect("ensured that there's only one selection");
14245                    let query = buffer
14246                        .text_for_range(selection.start..selection.end)
14247                        .collect::<String>();
14248                    let is_empty = query.is_empty();
14249                    let select_state = SelectNextState {
14250                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14251                        wordwise: true,
14252                        done: is_empty,
14253                    };
14254                    self.select_prev_state = Some(select_state);
14255                } else {
14256                    self.select_prev_state = None;
14257                }
14258            } else if let Some(selected_text) = selected_text {
14259                self.select_prev_state = Some(SelectNextState {
14260                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14261                    wordwise: false,
14262                    done: false,
14263                });
14264                self.select_previous(action, window, cx)?;
14265            }
14266        }
14267        Ok(())
14268    }
14269
14270    pub fn find_next_match(
14271        &mut self,
14272        _: &FindNextMatch,
14273        window: &mut Window,
14274        cx: &mut Context<Self>,
14275    ) -> Result<()> {
14276        let selections = self.selections.disjoint_anchors();
14277        match selections.first() {
14278            Some(first) if selections.len() >= 2 => {
14279                self.change_selections(Default::default(), window, cx, |s| {
14280                    s.select_ranges([first.range()]);
14281                });
14282            }
14283            _ => self.select_next(
14284                &SelectNext {
14285                    replace_newest: true,
14286                },
14287                window,
14288                cx,
14289            )?,
14290        }
14291        Ok(())
14292    }
14293
14294    pub fn find_previous_match(
14295        &mut self,
14296        _: &FindPreviousMatch,
14297        window: &mut Window,
14298        cx: &mut Context<Self>,
14299    ) -> Result<()> {
14300        let selections = self.selections.disjoint_anchors();
14301        match selections.last() {
14302            Some(last) if selections.len() >= 2 => {
14303                self.change_selections(Default::default(), window, cx, |s| {
14304                    s.select_ranges([last.range()]);
14305                });
14306            }
14307            _ => self.select_previous(
14308                &SelectPrevious {
14309                    replace_newest: true,
14310                },
14311                window,
14312                cx,
14313            )?,
14314        }
14315        Ok(())
14316    }
14317
14318    pub fn toggle_comments(
14319        &mut self,
14320        action: &ToggleComments,
14321        window: &mut Window,
14322        cx: &mut Context<Self>,
14323    ) {
14324        if self.read_only(cx) {
14325            return;
14326        }
14327        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14328        let text_layout_details = &self.text_layout_details(window);
14329        self.transact(window, cx, |this, window, cx| {
14330            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14331            let mut edits = Vec::new();
14332            let mut selection_edit_ranges = Vec::new();
14333            let mut last_toggled_row = None;
14334            let snapshot = this.buffer.read(cx).read(cx);
14335            let empty_str: Arc<str> = Arc::default();
14336            let mut suffixes_inserted = Vec::new();
14337            let ignore_indent = action.ignore_indent;
14338
14339            fn comment_prefix_range(
14340                snapshot: &MultiBufferSnapshot,
14341                row: MultiBufferRow,
14342                comment_prefix: &str,
14343                comment_prefix_whitespace: &str,
14344                ignore_indent: bool,
14345            ) -> Range<Point> {
14346                let indent_size = if ignore_indent {
14347                    0
14348                } else {
14349                    snapshot.indent_size_for_line(row).len
14350                };
14351
14352                let start = Point::new(row.0, indent_size);
14353
14354                let mut line_bytes = snapshot
14355                    .bytes_in_range(start..snapshot.max_point())
14356                    .flatten()
14357                    .copied();
14358
14359                // If this line currently begins with the line comment prefix, then record
14360                // the range containing the prefix.
14361                if line_bytes
14362                    .by_ref()
14363                    .take(comment_prefix.len())
14364                    .eq(comment_prefix.bytes())
14365                {
14366                    // Include any whitespace that matches the comment prefix.
14367                    let matching_whitespace_len = line_bytes
14368                        .zip(comment_prefix_whitespace.bytes())
14369                        .take_while(|(a, b)| a == b)
14370                        .count() as u32;
14371                    let end = Point::new(
14372                        start.row,
14373                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14374                    );
14375                    start..end
14376                } else {
14377                    start..start
14378                }
14379            }
14380
14381            fn comment_suffix_range(
14382                snapshot: &MultiBufferSnapshot,
14383                row: MultiBufferRow,
14384                comment_suffix: &str,
14385                comment_suffix_has_leading_space: bool,
14386            ) -> Range<Point> {
14387                let end = Point::new(row.0, snapshot.line_len(row));
14388                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14389
14390                let mut line_end_bytes = snapshot
14391                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14392                    .flatten()
14393                    .copied();
14394
14395                let leading_space_len = if suffix_start_column > 0
14396                    && line_end_bytes.next() == Some(b' ')
14397                    && comment_suffix_has_leading_space
14398                {
14399                    1
14400                } else {
14401                    0
14402                };
14403
14404                // If this line currently begins with the line comment prefix, then record
14405                // the range containing the prefix.
14406                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14407                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14408                    start..end
14409                } else {
14410                    end..end
14411                }
14412            }
14413
14414            // TODO: Handle selections that cross excerpts
14415            for selection in &mut selections {
14416                let start_column = snapshot
14417                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14418                    .len;
14419                let language = if let Some(language) =
14420                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14421                {
14422                    language
14423                } else {
14424                    continue;
14425                };
14426
14427                selection_edit_ranges.clear();
14428
14429                // If multiple selections contain a given row, avoid processing that
14430                // row more than once.
14431                let mut start_row = MultiBufferRow(selection.start.row);
14432                if last_toggled_row == Some(start_row) {
14433                    start_row = start_row.next_row();
14434                }
14435                let end_row =
14436                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14437                        MultiBufferRow(selection.end.row - 1)
14438                    } else {
14439                        MultiBufferRow(selection.end.row)
14440                    };
14441                last_toggled_row = Some(end_row);
14442
14443                if start_row > end_row {
14444                    continue;
14445                }
14446
14447                // If the language has line comments, toggle those.
14448                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14449
14450                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14451                if ignore_indent {
14452                    full_comment_prefixes = full_comment_prefixes
14453                        .into_iter()
14454                        .map(|s| Arc::from(s.trim_end()))
14455                        .collect();
14456                }
14457
14458                if !full_comment_prefixes.is_empty() {
14459                    let first_prefix = full_comment_prefixes
14460                        .first()
14461                        .expect("prefixes is non-empty");
14462                    let prefix_trimmed_lengths = full_comment_prefixes
14463                        .iter()
14464                        .map(|p| p.trim_end_matches(' ').len())
14465                        .collect::<SmallVec<[usize; 4]>>();
14466
14467                    let mut all_selection_lines_are_comments = true;
14468
14469                    for row in start_row.0..=end_row.0 {
14470                        let row = MultiBufferRow(row);
14471                        if start_row < end_row && snapshot.is_line_blank(row) {
14472                            continue;
14473                        }
14474
14475                        let prefix_range = full_comment_prefixes
14476                            .iter()
14477                            .zip(prefix_trimmed_lengths.iter().copied())
14478                            .map(|(prefix, trimmed_prefix_len)| {
14479                                comment_prefix_range(
14480                                    snapshot.deref(),
14481                                    row,
14482                                    &prefix[..trimmed_prefix_len],
14483                                    &prefix[trimmed_prefix_len..],
14484                                    ignore_indent,
14485                                )
14486                            })
14487                            .max_by_key(|range| range.end.column - range.start.column)
14488                            .expect("prefixes is non-empty");
14489
14490                        if prefix_range.is_empty() {
14491                            all_selection_lines_are_comments = false;
14492                        }
14493
14494                        selection_edit_ranges.push(prefix_range);
14495                    }
14496
14497                    if all_selection_lines_are_comments {
14498                        edits.extend(
14499                            selection_edit_ranges
14500                                .iter()
14501                                .cloned()
14502                                .map(|range| (range, empty_str.clone())),
14503                        );
14504                    } else {
14505                        let min_column = selection_edit_ranges
14506                            .iter()
14507                            .map(|range| range.start.column)
14508                            .min()
14509                            .unwrap_or(0);
14510                        edits.extend(selection_edit_ranges.iter().map(|range| {
14511                            let position = Point::new(range.start.row, min_column);
14512                            (position..position, first_prefix.clone())
14513                        }));
14514                    }
14515                } else if let Some(BlockCommentConfig {
14516                    start: full_comment_prefix,
14517                    end: comment_suffix,
14518                    ..
14519                }) = language.block_comment()
14520                {
14521                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14522                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14523                    let prefix_range = comment_prefix_range(
14524                        snapshot.deref(),
14525                        start_row,
14526                        comment_prefix,
14527                        comment_prefix_whitespace,
14528                        ignore_indent,
14529                    );
14530                    let suffix_range = comment_suffix_range(
14531                        snapshot.deref(),
14532                        end_row,
14533                        comment_suffix.trim_start_matches(' '),
14534                        comment_suffix.starts_with(' '),
14535                    );
14536
14537                    if prefix_range.is_empty() || suffix_range.is_empty() {
14538                        edits.push((
14539                            prefix_range.start..prefix_range.start,
14540                            full_comment_prefix.clone(),
14541                        ));
14542                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14543                        suffixes_inserted.push((end_row, comment_suffix.len()));
14544                    } else {
14545                        edits.push((prefix_range, empty_str.clone()));
14546                        edits.push((suffix_range, empty_str.clone()));
14547                    }
14548                } else {
14549                    continue;
14550                }
14551            }
14552
14553            drop(snapshot);
14554            this.buffer.update(cx, |buffer, cx| {
14555                buffer.edit(edits, None, cx);
14556            });
14557
14558            // Adjust selections so that they end before any comment suffixes that
14559            // were inserted.
14560            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14561            let mut selections = this.selections.all::<Point>(cx);
14562            let snapshot = this.buffer.read(cx).read(cx);
14563            for selection in &mut selections {
14564                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14565                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14566                        Ordering::Less => {
14567                            suffixes_inserted.next();
14568                            continue;
14569                        }
14570                        Ordering::Greater => break,
14571                        Ordering::Equal => {
14572                            if selection.end.column == snapshot.line_len(row) {
14573                                if selection.is_empty() {
14574                                    selection.start.column -= suffix_len as u32;
14575                                }
14576                                selection.end.column -= suffix_len as u32;
14577                            }
14578                            break;
14579                        }
14580                    }
14581                }
14582            }
14583
14584            drop(snapshot);
14585            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14586
14587            let selections = this.selections.all::<Point>(cx);
14588            let selections_on_single_row = selections.windows(2).all(|selections| {
14589                selections[0].start.row == selections[1].start.row
14590                    && selections[0].end.row == selections[1].end.row
14591                    && selections[0].start.row == selections[0].end.row
14592            });
14593            let selections_selecting = selections
14594                .iter()
14595                .any(|selection| selection.start != selection.end);
14596            let advance_downwards = action.advance_downwards
14597                && selections_on_single_row
14598                && !selections_selecting
14599                && !matches!(this.mode, EditorMode::SingleLine { .. });
14600
14601            if advance_downwards {
14602                let snapshot = this.buffer.read(cx).snapshot(cx);
14603
14604                this.change_selections(Default::default(), window, cx, |s| {
14605                    s.move_cursors_with(|display_snapshot, display_point, _| {
14606                        let mut point = display_point.to_point(display_snapshot);
14607                        point.row += 1;
14608                        point = snapshot.clip_point(point, Bias::Left);
14609                        let display_point = point.to_display_point(display_snapshot);
14610                        let goal = SelectionGoal::HorizontalPosition(
14611                            display_snapshot
14612                                .x_for_display_point(display_point, text_layout_details)
14613                                .into(),
14614                        );
14615                        (display_point, goal)
14616                    })
14617                });
14618            }
14619        });
14620    }
14621
14622    pub fn select_enclosing_symbol(
14623        &mut self,
14624        _: &SelectEnclosingSymbol,
14625        window: &mut Window,
14626        cx: &mut Context<Self>,
14627    ) {
14628        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14629
14630        let buffer = self.buffer.read(cx).snapshot(cx);
14631        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14632
14633        fn update_selection(
14634            selection: &Selection<usize>,
14635            buffer_snap: &MultiBufferSnapshot,
14636        ) -> Option<Selection<usize>> {
14637            let cursor = selection.head();
14638            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14639            for symbol in symbols.iter().rev() {
14640                let start = symbol.range.start.to_offset(buffer_snap);
14641                let end = symbol.range.end.to_offset(buffer_snap);
14642                let new_range = start..end;
14643                if start < selection.start || end > selection.end {
14644                    return Some(Selection {
14645                        id: selection.id,
14646                        start: new_range.start,
14647                        end: new_range.end,
14648                        goal: SelectionGoal::None,
14649                        reversed: selection.reversed,
14650                    });
14651                }
14652            }
14653            None
14654        }
14655
14656        let mut selected_larger_symbol = false;
14657        let new_selections = old_selections
14658            .iter()
14659            .map(|selection| match update_selection(selection, &buffer) {
14660                Some(new_selection) => {
14661                    if new_selection.range() != selection.range() {
14662                        selected_larger_symbol = true;
14663                    }
14664                    new_selection
14665                }
14666                None => selection.clone(),
14667            })
14668            .collect::<Vec<_>>();
14669
14670        if selected_larger_symbol {
14671            self.change_selections(Default::default(), window, cx, |s| {
14672                s.select(new_selections);
14673            });
14674        }
14675    }
14676
14677    pub fn select_larger_syntax_node(
14678        &mut self,
14679        _: &SelectLargerSyntaxNode,
14680        window: &mut Window,
14681        cx: &mut Context<Self>,
14682    ) {
14683        let Some(visible_row_count) = self.visible_row_count() else {
14684            return;
14685        };
14686        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14687        if old_selections.is_empty() {
14688            return;
14689        }
14690
14691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14692
14693        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14694        let buffer = self.buffer.read(cx).snapshot(cx);
14695
14696        let mut selected_larger_node = false;
14697        let mut new_selections = old_selections
14698            .iter()
14699            .map(|selection| {
14700                let old_range = selection.start..selection.end;
14701
14702                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14703                    // manually select word at selection
14704                    if ["string_content", "inline"].contains(&node.kind()) {
14705                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14706                        // ignore if word is already selected
14707                        if !word_range.is_empty() && old_range != word_range {
14708                            let (last_word_range, _) =
14709                                buffer.surrounding_word(old_range.end, false);
14710                            // only select word if start and end point belongs to same word
14711                            if word_range == last_word_range {
14712                                selected_larger_node = true;
14713                                return Selection {
14714                                    id: selection.id,
14715                                    start: word_range.start,
14716                                    end: word_range.end,
14717                                    goal: SelectionGoal::None,
14718                                    reversed: selection.reversed,
14719                                };
14720                            }
14721                        }
14722                    }
14723                }
14724
14725                let mut new_range = old_range.clone();
14726                while let Some((_node, containing_range)) =
14727                    buffer.syntax_ancestor(new_range.clone())
14728                {
14729                    new_range = match containing_range {
14730                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14731                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14732                    };
14733                    if !display_map.intersects_fold(new_range.start)
14734                        && !display_map.intersects_fold(new_range.end)
14735                    {
14736                        break;
14737                    }
14738                }
14739
14740                selected_larger_node |= new_range != old_range;
14741                Selection {
14742                    id: selection.id,
14743                    start: new_range.start,
14744                    end: new_range.end,
14745                    goal: SelectionGoal::None,
14746                    reversed: selection.reversed,
14747                }
14748            })
14749            .collect::<Vec<_>>();
14750
14751        if !selected_larger_node {
14752            return; // don't put this call in the history
14753        }
14754
14755        // scroll based on transformation done to the last selection created by the user
14756        let (last_old, last_new) = old_selections
14757            .last()
14758            .zip(new_selections.last().cloned())
14759            .expect("old_selections isn't empty");
14760
14761        // revert selection
14762        let is_selection_reversed = {
14763            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14764            new_selections.last_mut().expect("checked above").reversed =
14765                should_newest_selection_be_reversed;
14766            should_newest_selection_be_reversed
14767        };
14768
14769        if selected_larger_node {
14770            self.select_syntax_node_history.disable_clearing = true;
14771            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14772                s.select(new_selections.clone());
14773            });
14774            self.select_syntax_node_history.disable_clearing = false;
14775        }
14776
14777        let start_row = last_new.start.to_display_point(&display_map).row().0;
14778        let end_row = last_new.end.to_display_point(&display_map).row().0;
14779        let selection_height = end_row - start_row + 1;
14780        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14781
14782        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14783        let scroll_behavior = if fits_on_the_screen {
14784            self.request_autoscroll(Autoscroll::fit(), cx);
14785            SelectSyntaxNodeScrollBehavior::FitSelection
14786        } else if is_selection_reversed {
14787            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14788            SelectSyntaxNodeScrollBehavior::CursorTop
14789        } else {
14790            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14791            SelectSyntaxNodeScrollBehavior::CursorBottom
14792        };
14793
14794        self.select_syntax_node_history.push((
14795            old_selections,
14796            scroll_behavior,
14797            is_selection_reversed,
14798        ));
14799    }
14800
14801    pub fn select_smaller_syntax_node(
14802        &mut self,
14803        _: &SelectSmallerSyntaxNode,
14804        window: &mut Window,
14805        cx: &mut Context<Self>,
14806    ) {
14807        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14808
14809        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14810            self.select_syntax_node_history.pop()
14811        {
14812            if let Some(selection) = selections.last_mut() {
14813                selection.reversed = is_selection_reversed;
14814            }
14815
14816            self.select_syntax_node_history.disable_clearing = true;
14817            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14818                s.select(selections.to_vec());
14819            });
14820            self.select_syntax_node_history.disable_clearing = false;
14821
14822            match scroll_behavior {
14823                SelectSyntaxNodeScrollBehavior::CursorTop => {
14824                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14825                }
14826                SelectSyntaxNodeScrollBehavior::FitSelection => {
14827                    self.request_autoscroll(Autoscroll::fit(), cx);
14828                }
14829                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14830                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14831                }
14832            }
14833        }
14834    }
14835
14836    pub fn unwrap_syntax_node(
14837        &mut self,
14838        _: &UnwrapSyntaxNode,
14839        window: &mut Window,
14840        cx: &mut Context<Self>,
14841    ) {
14842        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14843
14844        let buffer = self.buffer.read(cx).snapshot(cx);
14845        let selections = self
14846            .selections
14847            .all::<usize>(cx)
14848            .into_iter()
14849            // subtracting the offset requires sorting
14850            .sorted_by_key(|i| i.start);
14851
14852        let full_edits = selections
14853            .into_iter()
14854            .filter_map(|selection| {
14855                // Only requires two branches once if-let-chains stabilize (#53667)
14856                let child = if !selection.is_empty() {
14857                    selection.range()
14858                } else if let Some((_, ancestor_range)) =
14859                    buffer.syntax_ancestor(selection.start..selection.end)
14860                {
14861                    match ancestor_range {
14862                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14863                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14864                    }
14865                } else {
14866                    selection.range()
14867                };
14868
14869                let mut parent = child.clone();
14870                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14871                    parent = match ancestor_range {
14872                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14873                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14874                    };
14875                    if parent.start < child.start || parent.end > child.end {
14876                        break;
14877                    }
14878                }
14879
14880                if parent == child {
14881                    return None;
14882                }
14883                let text = buffer.text_for_range(child.clone()).collect::<String>();
14884                Some((selection.id, parent, text))
14885            })
14886            .collect::<Vec<_>>();
14887
14888        self.transact(window, cx, |this, window, cx| {
14889            this.buffer.update(cx, |buffer, cx| {
14890                buffer.edit(
14891                    full_edits
14892                        .iter()
14893                        .map(|(_, p, t)| (p.clone(), t.clone()))
14894                        .collect::<Vec<_>>(),
14895                    None,
14896                    cx,
14897                );
14898            });
14899            this.change_selections(Default::default(), window, cx, |s| {
14900                let mut offset = 0;
14901                let mut selections = vec![];
14902                for (id, parent, text) in full_edits {
14903                    let start = parent.start - offset;
14904                    offset += parent.len() - text.len();
14905                    selections.push(Selection {
14906                        id: id,
14907                        start,
14908                        end: start + text.len(),
14909                        reversed: false,
14910                        goal: Default::default(),
14911                    });
14912                }
14913                s.select(selections);
14914            });
14915        });
14916    }
14917
14918    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14919        if !EditorSettings::get_global(cx).gutter.runnables {
14920            self.clear_tasks();
14921            return Task::ready(());
14922        }
14923        let project = self.project().map(Entity::downgrade);
14924        let task_sources = self.lsp_task_sources(cx);
14925        let multi_buffer = self.buffer.downgrade();
14926        cx.spawn_in(window, async move |editor, cx| {
14927            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14928            let Some(project) = project.and_then(|p| p.upgrade()) else {
14929                return;
14930            };
14931            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14932                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14933            }) else {
14934                return;
14935            };
14936
14937            let hide_runnables = project
14938                .update(cx, |project, cx| {
14939                    // Do not display any test indicators in non-dev server remote projects.
14940                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14941                })
14942                .unwrap_or(true);
14943            if hide_runnables {
14944                return;
14945            }
14946            let new_rows =
14947                cx.background_spawn({
14948                    let snapshot = display_snapshot.clone();
14949                    async move {
14950                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14951                    }
14952                })
14953                    .await;
14954            let Ok(lsp_tasks) =
14955                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14956            else {
14957                return;
14958            };
14959            let lsp_tasks = lsp_tasks.await;
14960
14961            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14962                lsp_tasks
14963                    .into_iter()
14964                    .flat_map(|(kind, tasks)| {
14965                        tasks.into_iter().filter_map(move |(location, task)| {
14966                            Some((kind.clone(), location?, task))
14967                        })
14968                    })
14969                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14970                        let buffer = location.target.buffer;
14971                        let buffer_snapshot = buffer.read(cx).snapshot();
14972                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14973                            |(excerpt_id, snapshot, _)| {
14974                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14975                                    display_snapshot
14976                                        .buffer_snapshot
14977                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14978                                } else {
14979                                    None
14980                                }
14981                            },
14982                        );
14983                        if let Some(offset) = offset {
14984                            let task_buffer_range =
14985                                location.target.range.to_point(&buffer_snapshot);
14986                            let context_buffer_range =
14987                                task_buffer_range.to_offset(&buffer_snapshot);
14988                            let context_range = BufferOffset(context_buffer_range.start)
14989                                ..BufferOffset(context_buffer_range.end);
14990
14991                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14992                                .or_insert_with(|| RunnableTasks {
14993                                    templates: Vec::new(),
14994                                    offset,
14995                                    column: task_buffer_range.start.column,
14996                                    extra_variables: HashMap::default(),
14997                                    context_range,
14998                                })
14999                                .templates
15000                                .push((kind, task.original_task().clone()));
15001                        }
15002
15003                        acc
15004                    })
15005            }) else {
15006                return;
15007            };
15008
15009            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15010                buffer.language_settings(cx).tasks.prefer_lsp
15011            }) else {
15012                return;
15013            };
15014
15015            let rows = Self::runnable_rows(
15016                project,
15017                display_snapshot,
15018                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15019                new_rows,
15020                cx.clone(),
15021            )
15022            .await;
15023            editor
15024                .update(cx, |editor, _| {
15025                    editor.clear_tasks();
15026                    for (key, mut value) in rows {
15027                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15028                            value.templates.extend(lsp_tasks.templates);
15029                        }
15030
15031                        editor.insert_tasks(key, value);
15032                    }
15033                    for (key, value) in lsp_tasks_by_rows {
15034                        editor.insert_tasks(key, value);
15035                    }
15036                })
15037                .ok();
15038        })
15039    }
15040    fn fetch_runnable_ranges(
15041        snapshot: &DisplaySnapshot,
15042        range: Range<Anchor>,
15043    ) -> Vec<language::RunnableRange> {
15044        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15045    }
15046
15047    fn runnable_rows(
15048        project: Entity<Project>,
15049        snapshot: DisplaySnapshot,
15050        prefer_lsp: bool,
15051        runnable_ranges: Vec<RunnableRange>,
15052        cx: AsyncWindowContext,
15053    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15054        cx.spawn(async move |cx| {
15055            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15056            for mut runnable in runnable_ranges {
15057                let Some(tasks) = cx
15058                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15059                    .ok()
15060                else {
15061                    continue;
15062                };
15063                let mut tasks = tasks.await;
15064
15065                if prefer_lsp {
15066                    tasks.retain(|(task_kind, _)| {
15067                        !matches!(task_kind, TaskSourceKind::Language { .. })
15068                    });
15069                }
15070                if tasks.is_empty() {
15071                    continue;
15072                }
15073
15074                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15075                let Some(row) = snapshot
15076                    .buffer_snapshot
15077                    .buffer_line_for_row(MultiBufferRow(point.row))
15078                    .map(|(_, range)| range.start.row)
15079                else {
15080                    continue;
15081                };
15082
15083                let context_range =
15084                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15085                runnable_rows.push((
15086                    (runnable.buffer_id, row),
15087                    RunnableTasks {
15088                        templates: tasks,
15089                        offset: snapshot
15090                            .buffer_snapshot
15091                            .anchor_before(runnable.run_range.start),
15092                        context_range,
15093                        column: point.column,
15094                        extra_variables: runnable.extra_captures,
15095                    },
15096                ));
15097            }
15098            runnable_rows
15099        })
15100    }
15101
15102    fn templates_with_tags(
15103        project: &Entity<Project>,
15104        runnable: &mut Runnable,
15105        cx: &mut App,
15106    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15107        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15108            let (worktree_id, file) = project
15109                .buffer_for_id(runnable.buffer, cx)
15110                .and_then(|buffer| buffer.read(cx).file())
15111                .map(|file| (file.worktree_id(cx), file.clone()))
15112                .unzip();
15113
15114            (
15115                project.task_store().read(cx).task_inventory().cloned(),
15116                worktree_id,
15117                file,
15118            )
15119        });
15120
15121        let tags = mem::take(&mut runnable.tags);
15122        let language = runnable.language.clone();
15123        cx.spawn(async move |cx| {
15124            let mut templates_with_tags = Vec::new();
15125            if let Some(inventory) = inventory {
15126                for RunnableTag(tag) in tags {
15127                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15128                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15129                    }) else {
15130                        return templates_with_tags;
15131                    };
15132                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15133                        move |(_, template)| {
15134                            template.tags.iter().any(|source_tag| source_tag == &tag)
15135                        },
15136                    ));
15137                }
15138            }
15139            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15140
15141            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15142                // Strongest source wins; if we have worktree tag binding, prefer that to
15143                // global and language bindings;
15144                // if we have a global binding, prefer that to language binding.
15145                let first_mismatch = templates_with_tags
15146                    .iter()
15147                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15148                if let Some(index) = first_mismatch {
15149                    templates_with_tags.truncate(index);
15150                }
15151            }
15152
15153            templates_with_tags
15154        })
15155    }
15156
15157    pub fn move_to_enclosing_bracket(
15158        &mut self,
15159        _: &MoveToEnclosingBracket,
15160        window: &mut Window,
15161        cx: &mut Context<Self>,
15162    ) {
15163        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15164        self.change_selections(Default::default(), window, cx, |s| {
15165            s.move_offsets_with(|snapshot, selection| {
15166                let Some(enclosing_bracket_ranges) =
15167                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15168                else {
15169                    return;
15170                };
15171
15172                let mut best_length = usize::MAX;
15173                let mut best_inside = false;
15174                let mut best_in_bracket_range = false;
15175                let mut best_destination = None;
15176                for (open, close) in enclosing_bracket_ranges {
15177                    let close = close.to_inclusive();
15178                    let length = close.end() - open.start;
15179                    let inside = selection.start >= open.end && selection.end <= *close.start();
15180                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15181                        || close.contains(&selection.head());
15182
15183                    // If best is next to a bracket and current isn't, skip
15184                    if !in_bracket_range && best_in_bracket_range {
15185                        continue;
15186                    }
15187
15188                    // Prefer smaller lengths unless best is inside and current isn't
15189                    if length > best_length && (best_inside || !inside) {
15190                        continue;
15191                    }
15192
15193                    best_length = length;
15194                    best_inside = inside;
15195                    best_in_bracket_range = in_bracket_range;
15196                    best_destination = Some(
15197                        if close.contains(&selection.start) && close.contains(&selection.end) {
15198                            if inside { open.end } else { open.start }
15199                        } else if inside {
15200                            *close.start()
15201                        } else {
15202                            *close.end()
15203                        },
15204                    );
15205                }
15206
15207                if let Some(destination) = best_destination {
15208                    selection.collapse_to(destination, SelectionGoal::None);
15209                }
15210            })
15211        });
15212    }
15213
15214    pub fn undo_selection(
15215        &mut self,
15216        _: &UndoSelection,
15217        window: &mut Window,
15218        cx: &mut Context<Self>,
15219    ) {
15220        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15221        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15222            self.selection_history.mode = SelectionHistoryMode::Undoing;
15223            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15224                this.end_selection(window, cx);
15225                this.change_selections(
15226                    SelectionEffects::scroll(Autoscroll::newest()),
15227                    window,
15228                    cx,
15229                    |s| s.select_anchors(entry.selections.to_vec()),
15230                );
15231            });
15232            self.selection_history.mode = SelectionHistoryMode::Normal;
15233
15234            self.select_next_state = entry.select_next_state;
15235            self.select_prev_state = entry.select_prev_state;
15236            self.add_selections_state = entry.add_selections_state;
15237        }
15238    }
15239
15240    pub fn redo_selection(
15241        &mut self,
15242        _: &RedoSelection,
15243        window: &mut Window,
15244        cx: &mut Context<Self>,
15245    ) {
15246        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15247        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15248            self.selection_history.mode = SelectionHistoryMode::Redoing;
15249            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15250                this.end_selection(window, cx);
15251                this.change_selections(
15252                    SelectionEffects::scroll(Autoscroll::newest()),
15253                    window,
15254                    cx,
15255                    |s| s.select_anchors(entry.selections.to_vec()),
15256                );
15257            });
15258            self.selection_history.mode = SelectionHistoryMode::Normal;
15259
15260            self.select_next_state = entry.select_next_state;
15261            self.select_prev_state = entry.select_prev_state;
15262            self.add_selections_state = entry.add_selections_state;
15263        }
15264    }
15265
15266    pub fn expand_excerpts(
15267        &mut self,
15268        action: &ExpandExcerpts,
15269        _: &mut Window,
15270        cx: &mut Context<Self>,
15271    ) {
15272        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15273    }
15274
15275    pub fn expand_excerpts_down(
15276        &mut self,
15277        action: &ExpandExcerptsDown,
15278        _: &mut Window,
15279        cx: &mut Context<Self>,
15280    ) {
15281        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15282    }
15283
15284    pub fn expand_excerpts_up(
15285        &mut self,
15286        action: &ExpandExcerptsUp,
15287        _: &mut Window,
15288        cx: &mut Context<Self>,
15289    ) {
15290        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15291    }
15292
15293    pub fn expand_excerpts_for_direction(
15294        &mut self,
15295        lines: u32,
15296        direction: ExpandExcerptDirection,
15297
15298        cx: &mut Context<Self>,
15299    ) {
15300        let selections = self.selections.disjoint_anchors();
15301
15302        let lines = if lines == 0 {
15303            EditorSettings::get_global(cx).expand_excerpt_lines
15304        } else {
15305            lines
15306        };
15307
15308        self.buffer.update(cx, |buffer, cx| {
15309            let snapshot = buffer.snapshot(cx);
15310            let mut excerpt_ids = selections
15311                .iter()
15312                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15313                .collect::<Vec<_>>();
15314            excerpt_ids.sort();
15315            excerpt_ids.dedup();
15316            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15317        })
15318    }
15319
15320    pub fn expand_excerpt(
15321        &mut self,
15322        excerpt: ExcerptId,
15323        direction: ExpandExcerptDirection,
15324        window: &mut Window,
15325        cx: &mut Context<Self>,
15326    ) {
15327        let current_scroll_position = self.scroll_position(cx);
15328        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15329        let mut should_scroll_up = false;
15330
15331        if direction == ExpandExcerptDirection::Down {
15332            let multi_buffer = self.buffer.read(cx);
15333            let snapshot = multi_buffer.snapshot(cx);
15334            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15335                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15336                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15337                        let buffer_snapshot = buffer.read(cx).snapshot();
15338                        let excerpt_end_row =
15339                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15340                        let last_row = buffer_snapshot.max_point().row;
15341                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15342                        should_scroll_up = lines_below >= lines_to_expand;
15343                    }
15344                }
15345            }
15346        }
15347
15348        self.buffer.update(cx, |buffer, cx| {
15349            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15350        });
15351
15352        if should_scroll_up {
15353            let new_scroll_position =
15354                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15355            self.set_scroll_position(new_scroll_position, window, cx);
15356        }
15357    }
15358
15359    pub fn go_to_singleton_buffer_point(
15360        &mut self,
15361        point: Point,
15362        window: &mut Window,
15363        cx: &mut Context<Self>,
15364    ) {
15365        self.go_to_singleton_buffer_range(point..point, window, cx);
15366    }
15367
15368    pub fn go_to_singleton_buffer_range(
15369        &mut self,
15370        range: Range<Point>,
15371        window: &mut Window,
15372        cx: &mut Context<Self>,
15373    ) {
15374        let multibuffer = self.buffer().read(cx);
15375        let Some(buffer) = multibuffer.as_singleton() else {
15376            return;
15377        };
15378        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15379            return;
15380        };
15381        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15382            return;
15383        };
15384        self.change_selections(
15385            SelectionEffects::default().nav_history(true),
15386            window,
15387            cx,
15388            |s| s.select_anchor_ranges([start..end]),
15389        );
15390    }
15391
15392    pub fn go_to_diagnostic(
15393        &mut self,
15394        action: &GoToDiagnostic,
15395        window: &mut Window,
15396        cx: &mut Context<Self>,
15397    ) {
15398        if !self.diagnostics_enabled() {
15399            return;
15400        }
15401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15402        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15403    }
15404
15405    pub fn go_to_prev_diagnostic(
15406        &mut self,
15407        action: &GoToPreviousDiagnostic,
15408        window: &mut Window,
15409        cx: &mut Context<Self>,
15410    ) {
15411        if !self.diagnostics_enabled() {
15412            return;
15413        }
15414        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15415        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15416    }
15417
15418    pub fn go_to_diagnostic_impl(
15419        &mut self,
15420        direction: Direction,
15421        severity: GoToDiagnosticSeverityFilter,
15422        window: &mut Window,
15423        cx: &mut Context<Self>,
15424    ) {
15425        let buffer = self.buffer.read(cx).snapshot(cx);
15426        let selection = self.selections.newest::<usize>(cx);
15427
15428        let mut active_group_id = None;
15429        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15430            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15431                active_group_id = Some(active_group.group_id);
15432            }
15433        }
15434
15435        fn filtered(
15436            snapshot: EditorSnapshot,
15437            severity: GoToDiagnosticSeverityFilter,
15438            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15439        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15440            diagnostics
15441                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15442                .filter(|entry| entry.range.start != entry.range.end)
15443                .filter(|entry| !entry.diagnostic.is_unnecessary)
15444                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15445        }
15446
15447        let snapshot = self.snapshot(window, cx);
15448        let before = filtered(
15449            snapshot.clone(),
15450            severity,
15451            buffer
15452                .diagnostics_in_range(0..selection.start)
15453                .filter(|entry| entry.range.start <= selection.start),
15454        );
15455        let after = filtered(
15456            snapshot,
15457            severity,
15458            buffer
15459                .diagnostics_in_range(selection.start..buffer.len())
15460                .filter(|entry| entry.range.start >= selection.start),
15461        );
15462
15463        let mut found: Option<DiagnosticEntry<usize>> = None;
15464        if direction == Direction::Prev {
15465            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15466            {
15467                for diagnostic in prev_diagnostics.into_iter().rev() {
15468                    if diagnostic.range.start != selection.start
15469                        || active_group_id
15470                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15471                    {
15472                        found = Some(diagnostic);
15473                        break 'outer;
15474                    }
15475                }
15476            }
15477        } else {
15478            for diagnostic in after.chain(before) {
15479                if diagnostic.range.start != selection.start
15480                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15481                {
15482                    found = Some(diagnostic);
15483                    break;
15484                }
15485            }
15486        }
15487        let Some(next_diagnostic) = found else {
15488            return;
15489        };
15490
15491        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15492            return;
15493        };
15494        self.change_selections(Default::default(), window, cx, |s| {
15495            s.select_ranges(vec![
15496                next_diagnostic.range.start..next_diagnostic.range.start,
15497            ])
15498        });
15499        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15500        self.refresh_edit_prediction(false, true, window, cx);
15501    }
15502
15503    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15504        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15505        let snapshot = self.snapshot(window, cx);
15506        let selection = self.selections.newest::<Point>(cx);
15507        self.go_to_hunk_before_or_after_position(
15508            &snapshot,
15509            selection.head(),
15510            Direction::Next,
15511            window,
15512            cx,
15513        );
15514    }
15515
15516    pub fn go_to_hunk_before_or_after_position(
15517        &mut self,
15518        snapshot: &EditorSnapshot,
15519        position: Point,
15520        direction: Direction,
15521        window: &mut Window,
15522        cx: &mut Context<Editor>,
15523    ) {
15524        let row = if direction == Direction::Next {
15525            self.hunk_after_position(snapshot, position)
15526                .map(|hunk| hunk.row_range.start)
15527        } else {
15528            self.hunk_before_position(snapshot, position)
15529        };
15530
15531        if let Some(row) = row {
15532            let destination = Point::new(row.0, 0);
15533            let autoscroll = Autoscroll::center();
15534
15535            self.unfold_ranges(&[destination..destination], false, false, cx);
15536            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15537                s.select_ranges([destination..destination]);
15538            });
15539        }
15540    }
15541
15542    fn hunk_after_position(
15543        &mut self,
15544        snapshot: &EditorSnapshot,
15545        position: Point,
15546    ) -> Option<MultiBufferDiffHunk> {
15547        snapshot
15548            .buffer_snapshot
15549            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15550            .find(|hunk| hunk.row_range.start.0 > position.row)
15551            .or_else(|| {
15552                snapshot
15553                    .buffer_snapshot
15554                    .diff_hunks_in_range(Point::zero()..position)
15555                    .find(|hunk| hunk.row_range.end.0 < position.row)
15556            })
15557    }
15558
15559    fn go_to_prev_hunk(
15560        &mut self,
15561        _: &GoToPreviousHunk,
15562        window: &mut Window,
15563        cx: &mut Context<Self>,
15564    ) {
15565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15566        let snapshot = self.snapshot(window, cx);
15567        let selection = self.selections.newest::<Point>(cx);
15568        self.go_to_hunk_before_or_after_position(
15569            &snapshot,
15570            selection.head(),
15571            Direction::Prev,
15572            window,
15573            cx,
15574        );
15575    }
15576
15577    fn hunk_before_position(
15578        &mut self,
15579        snapshot: &EditorSnapshot,
15580        position: Point,
15581    ) -> Option<MultiBufferRow> {
15582        snapshot
15583            .buffer_snapshot
15584            .diff_hunk_before(position)
15585            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15586    }
15587
15588    fn go_to_next_change(
15589        &mut self,
15590        _: &GoToNextChange,
15591        window: &mut Window,
15592        cx: &mut Context<Self>,
15593    ) {
15594        if let Some(selections) = self
15595            .change_list
15596            .next_change(1, Direction::Next)
15597            .map(|s| s.to_vec())
15598        {
15599            self.change_selections(Default::default(), window, cx, |s| {
15600                let map = s.display_map();
15601                s.select_display_ranges(selections.iter().map(|a| {
15602                    let point = a.to_display_point(&map);
15603                    point..point
15604                }))
15605            })
15606        }
15607    }
15608
15609    fn go_to_previous_change(
15610        &mut self,
15611        _: &GoToPreviousChange,
15612        window: &mut Window,
15613        cx: &mut Context<Self>,
15614    ) {
15615        if let Some(selections) = self
15616            .change_list
15617            .next_change(1, Direction::Prev)
15618            .map(|s| s.to_vec())
15619        {
15620            self.change_selections(Default::default(), window, cx, |s| {
15621                let map = s.display_map();
15622                s.select_display_ranges(selections.iter().map(|a| {
15623                    let point = a.to_display_point(&map);
15624                    point..point
15625                }))
15626            })
15627        }
15628    }
15629
15630    fn go_to_line<T: 'static>(
15631        &mut self,
15632        position: Anchor,
15633        highlight_color: Option<Hsla>,
15634        window: &mut Window,
15635        cx: &mut Context<Self>,
15636    ) {
15637        let snapshot = self.snapshot(window, cx).display_snapshot;
15638        let position = position.to_point(&snapshot.buffer_snapshot);
15639        let start = snapshot
15640            .buffer_snapshot
15641            .clip_point(Point::new(position.row, 0), Bias::Left);
15642        let end = start + Point::new(1, 0);
15643        let start = snapshot.buffer_snapshot.anchor_before(start);
15644        let end = snapshot.buffer_snapshot.anchor_before(end);
15645
15646        self.highlight_rows::<T>(
15647            start..end,
15648            highlight_color
15649                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15650            Default::default(),
15651            cx,
15652        );
15653
15654        if self.buffer.read(cx).is_singleton() {
15655            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15656        }
15657    }
15658
15659    pub fn go_to_definition(
15660        &mut self,
15661        _: &GoToDefinition,
15662        window: &mut Window,
15663        cx: &mut Context<Self>,
15664    ) -> Task<Result<Navigated>> {
15665        let definition =
15666            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15667        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15668        cx.spawn_in(window, async move |editor, cx| {
15669            if definition.await? == Navigated::Yes {
15670                return Ok(Navigated::Yes);
15671            }
15672            match fallback_strategy {
15673                GoToDefinitionFallback::None => Ok(Navigated::No),
15674                GoToDefinitionFallback::FindAllReferences => {
15675                    match editor.update_in(cx, |editor, window, cx| {
15676                        editor.find_all_references(&FindAllReferences, window, cx)
15677                    })? {
15678                        Some(references) => references.await,
15679                        None => Ok(Navigated::No),
15680                    }
15681                }
15682            }
15683        })
15684    }
15685
15686    pub fn go_to_declaration(
15687        &mut self,
15688        _: &GoToDeclaration,
15689        window: &mut Window,
15690        cx: &mut Context<Self>,
15691    ) -> Task<Result<Navigated>> {
15692        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15693    }
15694
15695    pub fn go_to_declaration_split(
15696        &mut self,
15697        _: &GoToDeclaration,
15698        window: &mut Window,
15699        cx: &mut Context<Self>,
15700    ) -> Task<Result<Navigated>> {
15701        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15702    }
15703
15704    pub fn go_to_implementation(
15705        &mut self,
15706        _: &GoToImplementation,
15707        window: &mut Window,
15708        cx: &mut Context<Self>,
15709    ) -> Task<Result<Navigated>> {
15710        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15711    }
15712
15713    pub fn go_to_implementation_split(
15714        &mut self,
15715        _: &GoToImplementationSplit,
15716        window: &mut Window,
15717        cx: &mut Context<Self>,
15718    ) -> Task<Result<Navigated>> {
15719        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15720    }
15721
15722    pub fn go_to_type_definition(
15723        &mut self,
15724        _: &GoToTypeDefinition,
15725        window: &mut Window,
15726        cx: &mut Context<Self>,
15727    ) -> Task<Result<Navigated>> {
15728        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15729    }
15730
15731    pub fn go_to_definition_split(
15732        &mut self,
15733        _: &GoToDefinitionSplit,
15734        window: &mut Window,
15735        cx: &mut Context<Self>,
15736    ) -> Task<Result<Navigated>> {
15737        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15738    }
15739
15740    pub fn go_to_type_definition_split(
15741        &mut self,
15742        _: &GoToTypeDefinitionSplit,
15743        window: &mut Window,
15744        cx: &mut Context<Self>,
15745    ) -> Task<Result<Navigated>> {
15746        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15747    }
15748
15749    fn go_to_definition_of_kind(
15750        &mut self,
15751        kind: GotoDefinitionKind,
15752        split: bool,
15753        window: &mut Window,
15754        cx: &mut Context<Self>,
15755    ) -> Task<Result<Navigated>> {
15756        let Some(provider) = self.semantics_provider.clone() else {
15757            return Task::ready(Ok(Navigated::No));
15758        };
15759        let head = self.selections.newest::<usize>(cx).head();
15760        let buffer = self.buffer.read(cx);
15761        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15762            return Task::ready(Ok(Navigated::No));
15763        };
15764        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15765            return Task::ready(Ok(Navigated::No));
15766        };
15767
15768        cx.spawn_in(window, async move |editor, cx| {
15769            let definitions = definitions.await?;
15770            let navigated = editor
15771                .update_in(cx, |editor, window, cx| {
15772                    editor.navigate_to_hover_links(
15773                        Some(kind),
15774                        definitions
15775                            .into_iter()
15776                            .filter(|location| {
15777                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15778                            })
15779                            .map(HoverLink::Text)
15780                            .collect::<Vec<_>>(),
15781                        split,
15782                        window,
15783                        cx,
15784                    )
15785                })?
15786                .await?;
15787            anyhow::Ok(navigated)
15788        })
15789    }
15790
15791    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15792        let selection = self.selections.newest_anchor();
15793        let head = selection.head();
15794        let tail = selection.tail();
15795
15796        let Some((buffer, start_position)) =
15797            self.buffer.read(cx).text_anchor_for_position(head, cx)
15798        else {
15799            return;
15800        };
15801
15802        let end_position = if head != tail {
15803            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15804                return;
15805            };
15806            Some(pos)
15807        } else {
15808            None
15809        };
15810
15811        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15812            let url = if let Some(end_pos) = end_position {
15813                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15814            } else {
15815                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15816            };
15817
15818            if let Some(url) = url {
15819                editor.update(cx, |_, cx| {
15820                    cx.open_url(&url);
15821                })
15822            } else {
15823                Ok(())
15824            }
15825        });
15826
15827        url_finder.detach();
15828    }
15829
15830    pub fn open_selected_filename(
15831        &mut self,
15832        _: &OpenSelectedFilename,
15833        window: &mut Window,
15834        cx: &mut Context<Self>,
15835    ) {
15836        let Some(workspace) = self.workspace() else {
15837            return;
15838        };
15839
15840        let position = self.selections.newest_anchor().head();
15841
15842        let Some((buffer, buffer_position)) =
15843            self.buffer.read(cx).text_anchor_for_position(position, cx)
15844        else {
15845            return;
15846        };
15847
15848        let project = self.project.clone();
15849
15850        cx.spawn_in(window, async move |_, cx| {
15851            let result = find_file(&buffer, project, buffer_position, cx).await;
15852
15853            if let Some((_, path)) = result {
15854                workspace
15855                    .update_in(cx, |workspace, window, cx| {
15856                        workspace.open_resolved_path(path, window, cx)
15857                    })?
15858                    .await?;
15859            }
15860            anyhow::Ok(())
15861        })
15862        .detach();
15863    }
15864
15865    pub(crate) fn navigate_to_hover_links(
15866        &mut self,
15867        kind: Option<GotoDefinitionKind>,
15868        definitions: Vec<HoverLink>,
15869        split: bool,
15870        window: &mut Window,
15871        cx: &mut Context<Editor>,
15872    ) -> Task<Result<Navigated>> {
15873        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15874        let mut first_url_or_file = None;
15875        let definitions: Vec<_> = definitions
15876            .into_iter()
15877            .filter_map(|def| match def {
15878                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15879                HoverLink::InlayHint(lsp_location, server_id) => {
15880                    let computation =
15881                        self.compute_target_location(lsp_location, server_id, window, cx);
15882                    Some(cx.background_spawn(computation))
15883                }
15884                HoverLink::Url(url) => {
15885                    first_url_or_file = Some(Either::Left(url));
15886                    None
15887                }
15888                HoverLink::File(path) => {
15889                    first_url_or_file = Some(Either::Right(path));
15890                    None
15891                }
15892            })
15893            .collect();
15894
15895        let workspace = self.workspace();
15896
15897        cx.spawn_in(window, async move |editor, acx| {
15898            let mut locations: Vec<Location> = future::join_all(definitions)
15899                .await
15900                .into_iter()
15901                .filter_map(|location| location.transpose())
15902                .collect::<Result<_>>()
15903                .context("location tasks")?;
15904
15905            if locations.len() > 1 {
15906                let Some(workspace) = workspace else {
15907                    return Ok(Navigated::No);
15908                };
15909
15910                let tab_kind = match kind {
15911                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15912                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15913                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15914                    Some(GotoDefinitionKind::Type) => "Types",
15915                };
15916                let title = editor
15917                    .update_in(acx, |_, _, cx| {
15918                        let target = locations
15919                            .iter()
15920                            .map(|location| {
15921                                location
15922                                    .buffer
15923                                    .read(cx)
15924                                    .text_for_range(location.range.clone())
15925                                    .collect::<String>()
15926                            })
15927                            .filter(|text| !text.contains('\n'))
15928                            .unique()
15929                            .take(3)
15930                            .join(", ");
15931                        if target.is_empty() {
15932                            tab_kind.to_owned()
15933                        } else {
15934                            format!("{tab_kind} for {target}")
15935                        }
15936                    })
15937                    .context("buffer title")?;
15938
15939                let opened = workspace
15940                    .update_in(acx, |workspace, window, cx| {
15941                        Self::open_locations_in_multibuffer(
15942                            workspace,
15943                            locations,
15944                            title,
15945                            split,
15946                            MultibufferSelectionMode::First,
15947                            window,
15948                            cx,
15949                        )
15950                    })
15951                    .is_ok();
15952
15953                anyhow::Ok(Navigated::from_bool(opened))
15954            } else if locations.is_empty() {
15955                // If there is one definition, just open it directly
15956                match first_url_or_file {
15957                    Some(Either::Left(url)) => {
15958                        acx.update(|_, cx| cx.open_url(&url))?;
15959                        Ok(Navigated::Yes)
15960                    }
15961                    Some(Either::Right(path)) => {
15962                        let Some(workspace) = workspace else {
15963                            return Ok(Navigated::No);
15964                        };
15965
15966                        workspace
15967                            .update_in(acx, |workspace, window, cx| {
15968                                workspace.open_resolved_path(path, window, cx)
15969                            })?
15970                            .await?;
15971                        Ok(Navigated::Yes)
15972                    }
15973                    None => Ok(Navigated::No),
15974                }
15975            } else {
15976                let Some(workspace) = workspace else {
15977                    return Ok(Navigated::No);
15978                };
15979
15980                let target = locations.pop().unwrap();
15981                editor.update_in(acx, |editor, window, cx| {
15982                    let pane = workspace.read(cx).active_pane().clone();
15983
15984                    let range = target.range.to_point(target.buffer.read(cx));
15985                    let range = editor.range_for_match(&range);
15986                    let range = collapse_multiline_range(range);
15987
15988                    if !split
15989                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15990                    {
15991                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15992                    } else {
15993                        window.defer(cx, move |window, cx| {
15994                            let target_editor: Entity<Self> =
15995                                workspace.update(cx, |workspace, cx| {
15996                                    let pane = if split {
15997                                        workspace.adjacent_pane(window, cx)
15998                                    } else {
15999                                        workspace.active_pane().clone()
16000                                    };
16001
16002                                    workspace.open_project_item(
16003                                        pane,
16004                                        target.buffer.clone(),
16005                                        true,
16006                                        true,
16007                                        window,
16008                                        cx,
16009                                    )
16010                                });
16011                            target_editor.update(cx, |target_editor, cx| {
16012                                // When selecting a definition in a different buffer, disable the nav history
16013                                // to avoid creating a history entry at the previous cursor location.
16014                                pane.update(cx, |pane, _| pane.disable_history());
16015                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16016                                pane.update(cx, |pane, _| pane.enable_history());
16017                            });
16018                        });
16019                    }
16020                    Navigated::Yes
16021                })
16022            }
16023        })
16024    }
16025
16026    fn compute_target_location(
16027        &self,
16028        lsp_location: lsp::Location,
16029        server_id: LanguageServerId,
16030        window: &mut Window,
16031        cx: &mut Context<Self>,
16032    ) -> Task<anyhow::Result<Option<Location>>> {
16033        let Some(project) = self.project.clone() else {
16034            return Task::ready(Ok(None));
16035        };
16036
16037        cx.spawn_in(window, async move |editor, cx| {
16038            let location_task = editor.update(cx, |_, cx| {
16039                project.update(cx, |project, cx| {
16040                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16041                })
16042            })?;
16043            let location = Some({
16044                let target_buffer_handle = location_task.await.context("open local buffer")?;
16045                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16046                    let target_start = target_buffer
16047                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16048                    let target_end = target_buffer
16049                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16050                    target_buffer.anchor_after(target_start)
16051                        ..target_buffer.anchor_before(target_end)
16052                })?;
16053                Location {
16054                    buffer: target_buffer_handle,
16055                    range,
16056                }
16057            });
16058            Ok(location)
16059        })
16060    }
16061
16062    pub fn find_all_references(
16063        &mut self,
16064        _: &FindAllReferences,
16065        window: &mut Window,
16066        cx: &mut Context<Self>,
16067    ) -> Option<Task<Result<Navigated>>> {
16068        let selection = self.selections.newest::<usize>(cx);
16069        let multi_buffer = self.buffer.read(cx);
16070        let head = selection.head();
16071
16072        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16073        let head_anchor = multi_buffer_snapshot.anchor_at(
16074            head,
16075            if head < selection.tail() {
16076                Bias::Right
16077            } else {
16078                Bias::Left
16079            },
16080        );
16081
16082        match self
16083            .find_all_references_task_sources
16084            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16085        {
16086            Ok(_) => {
16087                log::info!(
16088                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16089                );
16090                return None;
16091            }
16092            Err(i) => {
16093                self.find_all_references_task_sources.insert(i, head_anchor);
16094            }
16095        }
16096
16097        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16098        let workspace = self.workspace()?;
16099        let project = workspace.read(cx).project().clone();
16100        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16101        Some(cx.spawn_in(window, async move |editor, cx| {
16102            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16103                if let Ok(i) = editor
16104                    .find_all_references_task_sources
16105                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16106                {
16107                    editor.find_all_references_task_sources.remove(i);
16108                }
16109            });
16110
16111            let locations = references.await?;
16112            if locations.is_empty() {
16113                return anyhow::Ok(Navigated::No);
16114            }
16115
16116            workspace.update_in(cx, |workspace, window, cx| {
16117                let target = locations
16118                    .iter()
16119                    .map(|location| {
16120                        location
16121                            .buffer
16122                            .read(cx)
16123                            .text_for_range(location.range.clone())
16124                            .collect::<String>()
16125                    })
16126                    .filter(|text| !text.contains('\n'))
16127                    .unique()
16128                    .take(3)
16129                    .join(", ");
16130                let title = if target.is_empty() {
16131                    "References".to_owned()
16132                } else {
16133                    format!("References to {target}")
16134                };
16135                Self::open_locations_in_multibuffer(
16136                    workspace,
16137                    locations,
16138                    title,
16139                    false,
16140                    MultibufferSelectionMode::First,
16141                    window,
16142                    cx,
16143                );
16144                Navigated::Yes
16145            })
16146        }))
16147    }
16148
16149    /// Opens a multibuffer with the given project locations in it
16150    pub fn open_locations_in_multibuffer(
16151        workspace: &mut Workspace,
16152        mut locations: Vec<Location>,
16153        title: String,
16154        split: bool,
16155        multibuffer_selection_mode: MultibufferSelectionMode,
16156        window: &mut Window,
16157        cx: &mut Context<Workspace>,
16158    ) {
16159        if locations.is_empty() {
16160            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16161            return;
16162        }
16163
16164        // If there are multiple definitions, open them in a multibuffer
16165        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16166        let mut locations = locations.into_iter().peekable();
16167        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16168        let capability = workspace.project().read(cx).capability();
16169
16170        let excerpt_buffer = cx.new(|cx| {
16171            let mut multibuffer = MultiBuffer::new(capability);
16172            while let Some(location) = locations.next() {
16173                let buffer = location.buffer.read(cx);
16174                let mut ranges_for_buffer = Vec::new();
16175                let range = location.range.to_point(buffer);
16176                ranges_for_buffer.push(range.clone());
16177
16178                while let Some(next_location) = locations.peek() {
16179                    if next_location.buffer == location.buffer {
16180                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16181                        locations.next();
16182                    } else {
16183                        break;
16184                    }
16185                }
16186
16187                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16188                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16189                    PathKey::for_buffer(&location.buffer, cx),
16190                    location.buffer.clone(),
16191                    ranges_for_buffer,
16192                    DEFAULT_MULTIBUFFER_CONTEXT,
16193                    cx,
16194                );
16195                ranges.extend(new_ranges)
16196            }
16197
16198            multibuffer.with_title(title)
16199        });
16200
16201        let editor = cx.new(|cx| {
16202            Editor::for_multibuffer(
16203                excerpt_buffer,
16204                Some(workspace.project().clone()),
16205                window,
16206                cx,
16207            )
16208        });
16209        editor.update(cx, |editor, cx| {
16210            match multibuffer_selection_mode {
16211                MultibufferSelectionMode::First => {
16212                    if let Some(first_range) = ranges.first() {
16213                        editor.change_selections(
16214                            SelectionEffects::no_scroll(),
16215                            window,
16216                            cx,
16217                            |selections| {
16218                                selections.clear_disjoint();
16219                                selections
16220                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16221                            },
16222                        );
16223                    }
16224                    editor.highlight_background::<Self>(
16225                        &ranges,
16226                        |theme| theme.colors().editor_highlighted_line_background,
16227                        cx,
16228                    );
16229                }
16230                MultibufferSelectionMode::All => {
16231                    editor.change_selections(
16232                        SelectionEffects::no_scroll(),
16233                        window,
16234                        cx,
16235                        |selections| {
16236                            selections.clear_disjoint();
16237                            selections.select_anchor_ranges(ranges);
16238                        },
16239                    );
16240                }
16241            }
16242            editor.register_buffers_with_language_servers(cx);
16243        });
16244
16245        let item = Box::new(editor);
16246        let item_id = item.item_id();
16247
16248        if split {
16249            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16250        } else {
16251            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16252                let (preview_item_id, preview_item_idx) =
16253                    workspace.active_pane().read_with(cx, |pane, _| {
16254                        (pane.preview_item_id(), pane.preview_item_idx())
16255                    });
16256
16257                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16258
16259                if let Some(preview_item_id) = preview_item_id {
16260                    workspace.active_pane().update(cx, |pane, cx| {
16261                        pane.remove_item(preview_item_id, false, false, window, cx);
16262                    });
16263                }
16264            } else {
16265                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16266            }
16267        }
16268        workspace.active_pane().update(cx, |pane, cx| {
16269            pane.set_preview_item_id(Some(item_id), cx);
16270        });
16271    }
16272
16273    pub fn rename(
16274        &mut self,
16275        _: &Rename,
16276        window: &mut Window,
16277        cx: &mut Context<Self>,
16278    ) -> Option<Task<Result<()>>> {
16279        use language::ToOffset as _;
16280
16281        let provider = self.semantics_provider.clone()?;
16282        let selection = self.selections.newest_anchor().clone();
16283        let (cursor_buffer, cursor_buffer_position) = self
16284            .buffer
16285            .read(cx)
16286            .text_anchor_for_position(selection.head(), cx)?;
16287        let (tail_buffer, cursor_buffer_position_end) = self
16288            .buffer
16289            .read(cx)
16290            .text_anchor_for_position(selection.tail(), cx)?;
16291        if tail_buffer != cursor_buffer {
16292            return None;
16293        }
16294
16295        let snapshot = cursor_buffer.read(cx).snapshot();
16296        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16297        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16298        let prepare_rename = provider
16299            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16300            .unwrap_or_else(|| Task::ready(Ok(None)));
16301        drop(snapshot);
16302
16303        Some(cx.spawn_in(window, async move |this, cx| {
16304            let rename_range = if let Some(range) = prepare_rename.await? {
16305                Some(range)
16306            } else {
16307                this.update(cx, |this, cx| {
16308                    let buffer = this.buffer.read(cx).snapshot(cx);
16309                    let mut buffer_highlights = this
16310                        .document_highlights_for_position(selection.head(), &buffer)
16311                        .filter(|highlight| {
16312                            highlight.start.excerpt_id == selection.head().excerpt_id
16313                                && highlight.end.excerpt_id == selection.head().excerpt_id
16314                        });
16315                    buffer_highlights
16316                        .next()
16317                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16318                })?
16319            };
16320            if let Some(rename_range) = rename_range {
16321                this.update_in(cx, |this, window, cx| {
16322                    let snapshot = cursor_buffer.read(cx).snapshot();
16323                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16324                    let cursor_offset_in_rename_range =
16325                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16326                    let cursor_offset_in_rename_range_end =
16327                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16328
16329                    this.take_rename(false, window, cx);
16330                    let buffer = this.buffer.read(cx).read(cx);
16331                    let cursor_offset = selection.head().to_offset(&buffer);
16332                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16333                    let rename_end = rename_start + rename_buffer_range.len();
16334                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16335                    let mut old_highlight_id = None;
16336                    let old_name: Arc<str> = buffer
16337                        .chunks(rename_start..rename_end, true)
16338                        .map(|chunk| {
16339                            if old_highlight_id.is_none() {
16340                                old_highlight_id = chunk.syntax_highlight_id;
16341                            }
16342                            chunk.text
16343                        })
16344                        .collect::<String>()
16345                        .into();
16346
16347                    drop(buffer);
16348
16349                    // Position the selection in the rename editor so that it matches the current selection.
16350                    this.show_local_selections = false;
16351                    let rename_editor = cx.new(|cx| {
16352                        let mut editor = Editor::single_line(window, cx);
16353                        editor.buffer.update(cx, |buffer, cx| {
16354                            buffer.edit([(0..0, old_name.clone())], None, cx)
16355                        });
16356                        let rename_selection_range = match cursor_offset_in_rename_range
16357                            .cmp(&cursor_offset_in_rename_range_end)
16358                        {
16359                            Ordering::Equal => {
16360                                editor.select_all(&SelectAll, window, cx);
16361                                return editor;
16362                            }
16363                            Ordering::Less => {
16364                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16365                            }
16366                            Ordering::Greater => {
16367                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16368                            }
16369                        };
16370                        if rename_selection_range.end > old_name.len() {
16371                            editor.select_all(&SelectAll, window, cx);
16372                        } else {
16373                            editor.change_selections(Default::default(), window, cx, |s| {
16374                                s.select_ranges([rename_selection_range]);
16375                            });
16376                        }
16377                        editor
16378                    });
16379                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16380                        if e == &EditorEvent::Focused {
16381                            cx.emit(EditorEvent::FocusedIn)
16382                        }
16383                    })
16384                    .detach();
16385
16386                    let write_highlights =
16387                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16388                    let read_highlights =
16389                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16390                    let ranges = write_highlights
16391                        .iter()
16392                        .flat_map(|(_, ranges)| ranges.iter())
16393                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16394                        .cloned()
16395                        .collect();
16396
16397                    this.highlight_text::<Rename>(
16398                        ranges,
16399                        HighlightStyle {
16400                            fade_out: Some(0.6),
16401                            ..Default::default()
16402                        },
16403                        cx,
16404                    );
16405                    let rename_focus_handle = rename_editor.focus_handle(cx);
16406                    window.focus(&rename_focus_handle);
16407                    let block_id = this.insert_blocks(
16408                        [BlockProperties {
16409                            style: BlockStyle::Flex,
16410                            placement: BlockPlacement::Below(range.start),
16411                            height: Some(1),
16412                            render: Arc::new({
16413                                let rename_editor = rename_editor.clone();
16414                                move |cx: &mut BlockContext| {
16415                                    let mut text_style = cx.editor_style.text.clone();
16416                                    if let Some(highlight_style) = old_highlight_id
16417                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16418                                    {
16419                                        text_style = text_style.highlight(highlight_style);
16420                                    }
16421                                    div()
16422                                        .block_mouse_except_scroll()
16423                                        .pl(cx.anchor_x)
16424                                        .child(EditorElement::new(
16425                                            &rename_editor,
16426                                            EditorStyle {
16427                                                background: cx.theme().system().transparent,
16428                                                local_player: cx.editor_style.local_player,
16429                                                text: text_style,
16430                                                scrollbar_width: cx.editor_style.scrollbar_width,
16431                                                syntax: cx.editor_style.syntax.clone(),
16432                                                status: cx.editor_style.status.clone(),
16433                                                inlay_hints_style: HighlightStyle {
16434                                                    font_weight: Some(FontWeight::BOLD),
16435                                                    ..make_inlay_hints_style(cx.app)
16436                                                },
16437                                                edit_prediction_styles: make_suggestion_styles(
16438                                                    cx.app,
16439                                                ),
16440                                                ..EditorStyle::default()
16441                                            },
16442                                        ))
16443                                        .into_any_element()
16444                                }
16445                            }),
16446                            priority: 0,
16447                        }],
16448                        Some(Autoscroll::fit()),
16449                        cx,
16450                    )[0];
16451                    this.pending_rename = Some(RenameState {
16452                        range,
16453                        old_name,
16454                        editor: rename_editor,
16455                        block_id,
16456                    });
16457                })?;
16458            }
16459
16460            Ok(())
16461        }))
16462    }
16463
16464    pub fn confirm_rename(
16465        &mut self,
16466        _: &ConfirmRename,
16467        window: &mut Window,
16468        cx: &mut Context<Self>,
16469    ) -> Option<Task<Result<()>>> {
16470        let rename = self.take_rename(false, window, cx)?;
16471        let workspace = self.workspace()?.downgrade();
16472        let (buffer, start) = self
16473            .buffer
16474            .read(cx)
16475            .text_anchor_for_position(rename.range.start, cx)?;
16476        let (end_buffer, _) = self
16477            .buffer
16478            .read(cx)
16479            .text_anchor_for_position(rename.range.end, cx)?;
16480        if buffer != end_buffer {
16481            return None;
16482        }
16483
16484        let old_name = rename.old_name;
16485        let new_name = rename.editor.read(cx).text(cx);
16486
16487        let rename = self.semantics_provider.as_ref()?.perform_rename(
16488            &buffer,
16489            start,
16490            new_name.clone(),
16491            cx,
16492        )?;
16493
16494        Some(cx.spawn_in(window, async move |editor, cx| {
16495            let project_transaction = rename.await?;
16496            Self::open_project_transaction(
16497                &editor,
16498                workspace,
16499                project_transaction,
16500                format!("Rename: {}{}", old_name, new_name),
16501                cx,
16502            )
16503            .await?;
16504
16505            editor.update(cx, |editor, cx| {
16506                editor.refresh_document_highlights(cx);
16507            })?;
16508            Ok(())
16509        }))
16510    }
16511
16512    fn take_rename(
16513        &mut self,
16514        moving_cursor: bool,
16515        window: &mut Window,
16516        cx: &mut Context<Self>,
16517    ) -> Option<RenameState> {
16518        let rename = self.pending_rename.take()?;
16519        if rename.editor.focus_handle(cx).is_focused(window) {
16520            window.focus(&self.focus_handle);
16521        }
16522
16523        self.remove_blocks(
16524            [rename.block_id].into_iter().collect(),
16525            Some(Autoscroll::fit()),
16526            cx,
16527        );
16528        self.clear_highlights::<Rename>(cx);
16529        self.show_local_selections = true;
16530
16531        if moving_cursor {
16532            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16533                editor.selections.newest::<usize>(cx).head()
16534            });
16535
16536            // Update the selection to match the position of the selection inside
16537            // the rename editor.
16538            let snapshot = self.buffer.read(cx).read(cx);
16539            let rename_range = rename.range.to_offset(&snapshot);
16540            let cursor_in_editor = snapshot
16541                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16542                .min(rename_range.end);
16543            drop(snapshot);
16544
16545            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16546                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16547            });
16548        } else {
16549            self.refresh_document_highlights(cx);
16550        }
16551
16552        Some(rename)
16553    }
16554
16555    pub fn pending_rename(&self) -> Option<&RenameState> {
16556        self.pending_rename.as_ref()
16557    }
16558
16559    fn format(
16560        &mut self,
16561        _: &Format,
16562        window: &mut Window,
16563        cx: &mut Context<Self>,
16564    ) -> Option<Task<Result<()>>> {
16565        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16566
16567        let project = match &self.project {
16568            Some(project) => project.clone(),
16569            None => return None,
16570        };
16571
16572        Some(self.perform_format(
16573            project,
16574            FormatTrigger::Manual,
16575            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16576            window,
16577            cx,
16578        ))
16579    }
16580
16581    fn format_selections(
16582        &mut self,
16583        _: &FormatSelections,
16584        window: &mut Window,
16585        cx: &mut Context<Self>,
16586    ) -> Option<Task<Result<()>>> {
16587        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16588
16589        let project = match &self.project {
16590            Some(project) => project.clone(),
16591            None => return None,
16592        };
16593
16594        let ranges = self
16595            .selections
16596            .all_adjusted(cx)
16597            .into_iter()
16598            .map(|selection| selection.range())
16599            .collect_vec();
16600
16601        Some(self.perform_format(
16602            project,
16603            FormatTrigger::Manual,
16604            FormatTarget::Ranges(ranges),
16605            window,
16606            cx,
16607        ))
16608    }
16609
16610    fn perform_format(
16611        &mut self,
16612        project: Entity<Project>,
16613        trigger: FormatTrigger,
16614        target: FormatTarget,
16615        window: &mut Window,
16616        cx: &mut Context<Self>,
16617    ) -> Task<Result<()>> {
16618        let buffer = self.buffer.clone();
16619        let (buffers, target) = match target {
16620            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16621            FormatTarget::Ranges(selection_ranges) => {
16622                let multi_buffer = buffer.read(cx);
16623                let snapshot = multi_buffer.read(cx);
16624                let mut buffers = HashSet::default();
16625                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16626                    BTreeMap::new();
16627                for selection_range in selection_ranges {
16628                    for (buffer, buffer_range, _) in
16629                        snapshot.range_to_buffer_ranges(selection_range)
16630                    {
16631                        let buffer_id = buffer.remote_id();
16632                        let start = buffer.anchor_before(buffer_range.start);
16633                        let end = buffer.anchor_after(buffer_range.end);
16634                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16635                        buffer_id_to_ranges
16636                            .entry(buffer_id)
16637                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16638                            .or_insert_with(|| vec![start..end]);
16639                    }
16640                }
16641                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16642            }
16643        };
16644
16645        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16646        let selections_prev = transaction_id_prev
16647            .and_then(|transaction_id_prev| {
16648                // default to selections as they were after the last edit, if we have them,
16649                // instead of how they are now.
16650                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16651                // will take you back to where you made the last edit, instead of staying where you scrolled
16652                self.selection_history
16653                    .transaction(transaction_id_prev)
16654                    .map(|t| t.0.clone())
16655            })
16656            .unwrap_or_else(|| {
16657                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16658                self.selections.disjoint_anchors()
16659            });
16660
16661        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16662        let format = project.update(cx, |project, cx| {
16663            project.format(buffers, target, true, trigger, cx)
16664        });
16665
16666        cx.spawn_in(window, async move |editor, cx| {
16667            let transaction = futures::select_biased! {
16668                transaction = format.log_err().fuse() => transaction,
16669                () = timeout => {
16670                    log::warn!("timed out waiting for formatting");
16671                    None
16672                }
16673            };
16674
16675            buffer
16676                .update(cx, |buffer, cx| {
16677                    if let Some(transaction) = transaction {
16678                        if !buffer.is_singleton() {
16679                            buffer.push_transaction(&transaction.0, cx);
16680                        }
16681                    }
16682                    cx.notify();
16683                })
16684                .ok();
16685
16686            if let Some(transaction_id_now) =
16687                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16688            {
16689                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16690                if has_new_transaction {
16691                    _ = editor.update(cx, |editor, _| {
16692                        editor
16693                            .selection_history
16694                            .insert_transaction(transaction_id_now, selections_prev);
16695                    });
16696                }
16697            }
16698
16699            Ok(())
16700        })
16701    }
16702
16703    fn organize_imports(
16704        &mut self,
16705        _: &OrganizeImports,
16706        window: &mut Window,
16707        cx: &mut Context<Self>,
16708    ) -> Option<Task<Result<()>>> {
16709        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16710        let project = match &self.project {
16711            Some(project) => project.clone(),
16712            None => return None,
16713        };
16714        Some(self.perform_code_action_kind(
16715            project,
16716            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16717            window,
16718            cx,
16719        ))
16720    }
16721
16722    fn perform_code_action_kind(
16723        &mut self,
16724        project: Entity<Project>,
16725        kind: CodeActionKind,
16726        window: &mut Window,
16727        cx: &mut Context<Self>,
16728    ) -> Task<Result<()>> {
16729        let buffer = self.buffer.clone();
16730        let buffers = buffer.read(cx).all_buffers();
16731        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16732        let apply_action = project.update(cx, |project, cx| {
16733            project.apply_code_action_kind(buffers, kind, true, cx)
16734        });
16735        cx.spawn_in(window, async move |_, cx| {
16736            let transaction = futures::select_biased! {
16737                () = timeout => {
16738                    log::warn!("timed out waiting for executing code action");
16739                    None
16740                }
16741                transaction = apply_action.log_err().fuse() => transaction,
16742            };
16743            buffer
16744                .update(cx, |buffer, cx| {
16745                    // check if we need this
16746                    if let Some(transaction) = transaction {
16747                        if !buffer.is_singleton() {
16748                            buffer.push_transaction(&transaction.0, cx);
16749                        }
16750                    }
16751                    cx.notify();
16752                })
16753                .ok();
16754            Ok(())
16755        })
16756    }
16757
16758    pub fn restart_language_server(
16759        &mut self,
16760        _: &RestartLanguageServer,
16761        _: &mut Window,
16762        cx: &mut Context<Self>,
16763    ) {
16764        if let Some(project) = self.project.clone() {
16765            self.buffer.update(cx, |multi_buffer, cx| {
16766                project.update(cx, |project, cx| {
16767                    project.restart_language_servers_for_buffers(
16768                        multi_buffer.all_buffers().into_iter().collect(),
16769                        HashSet::default(),
16770                        cx,
16771                    );
16772                });
16773            })
16774        }
16775    }
16776
16777    pub fn stop_language_server(
16778        &mut self,
16779        _: &StopLanguageServer,
16780        _: &mut Window,
16781        cx: &mut Context<Self>,
16782    ) {
16783        if let Some(project) = self.project.clone() {
16784            self.buffer.update(cx, |multi_buffer, cx| {
16785                project.update(cx, |project, cx| {
16786                    project.stop_language_servers_for_buffers(
16787                        multi_buffer.all_buffers().into_iter().collect(),
16788                        HashSet::default(),
16789                        cx,
16790                    );
16791                    cx.emit(project::Event::RefreshInlayHints);
16792                });
16793            });
16794        }
16795    }
16796
16797    fn cancel_language_server_work(
16798        workspace: &mut Workspace,
16799        _: &actions::CancelLanguageServerWork,
16800        _: &mut Window,
16801        cx: &mut Context<Workspace>,
16802    ) {
16803        let project = workspace.project();
16804        let buffers = workspace
16805            .active_item(cx)
16806            .and_then(|item| item.act_as::<Editor>(cx))
16807            .map_or(HashSet::default(), |editor| {
16808                editor.read(cx).buffer.read(cx).all_buffers()
16809            });
16810        project.update(cx, |project, cx| {
16811            project.cancel_language_server_work_for_buffers(buffers, cx);
16812        });
16813    }
16814
16815    fn show_character_palette(
16816        &mut self,
16817        _: &ShowCharacterPalette,
16818        window: &mut Window,
16819        _: &mut Context<Self>,
16820    ) {
16821        window.show_character_palette();
16822    }
16823
16824    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16825        if !self.diagnostics_enabled() {
16826            return;
16827        }
16828
16829        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16830            let buffer = self.buffer.read(cx).snapshot(cx);
16831            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16832            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16833            let is_valid = buffer
16834                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16835                .any(|entry| {
16836                    entry.diagnostic.is_primary
16837                        && !entry.range.is_empty()
16838                        && entry.range.start == primary_range_start
16839                        && entry.diagnostic.message == active_diagnostics.active_message
16840                });
16841
16842            if !is_valid {
16843                self.dismiss_diagnostics(cx);
16844            }
16845        }
16846    }
16847
16848    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16849        match &self.active_diagnostics {
16850            ActiveDiagnostic::Group(group) => Some(group),
16851            _ => None,
16852        }
16853    }
16854
16855    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16856        if !self.diagnostics_enabled() {
16857            return;
16858        }
16859        self.dismiss_diagnostics(cx);
16860        self.active_diagnostics = ActiveDiagnostic::All;
16861    }
16862
16863    fn activate_diagnostics(
16864        &mut self,
16865        buffer_id: BufferId,
16866        diagnostic: DiagnosticEntry<usize>,
16867        window: &mut Window,
16868        cx: &mut Context<Self>,
16869    ) {
16870        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16871            return;
16872        }
16873        self.dismiss_diagnostics(cx);
16874        let snapshot = self.snapshot(window, cx);
16875        let buffer = self.buffer.read(cx).snapshot(cx);
16876        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16877            return;
16878        };
16879
16880        let diagnostic_group = buffer
16881            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16882            .collect::<Vec<_>>();
16883
16884        let blocks =
16885            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16886
16887        let blocks = self.display_map.update(cx, |display_map, cx| {
16888            display_map.insert_blocks(blocks, cx).into_iter().collect()
16889        });
16890        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16891            active_range: buffer.anchor_before(diagnostic.range.start)
16892                ..buffer.anchor_after(diagnostic.range.end),
16893            active_message: diagnostic.diagnostic.message.clone(),
16894            group_id: diagnostic.diagnostic.group_id,
16895            blocks,
16896        });
16897        cx.notify();
16898    }
16899
16900    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16901        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16902            return;
16903        };
16904
16905        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16906        if let ActiveDiagnostic::Group(group) = prev {
16907            self.display_map.update(cx, |display_map, cx| {
16908                display_map.remove_blocks(group.blocks, cx);
16909            });
16910            cx.notify();
16911        }
16912    }
16913
16914    /// Disable inline diagnostics rendering for this editor.
16915    pub fn disable_inline_diagnostics(&mut self) {
16916        self.inline_diagnostics_enabled = false;
16917        self.inline_diagnostics_update = Task::ready(());
16918        self.inline_diagnostics.clear();
16919    }
16920
16921    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16922        self.diagnostics_enabled = false;
16923        self.dismiss_diagnostics(cx);
16924        self.inline_diagnostics_update = Task::ready(());
16925        self.inline_diagnostics.clear();
16926    }
16927
16928    pub fn diagnostics_enabled(&self) -> bool {
16929        self.diagnostics_enabled && self.mode.is_full()
16930    }
16931
16932    pub fn inline_diagnostics_enabled(&self) -> bool {
16933        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16934    }
16935
16936    pub fn show_inline_diagnostics(&self) -> bool {
16937        self.show_inline_diagnostics
16938    }
16939
16940    pub fn toggle_inline_diagnostics(
16941        &mut self,
16942        _: &ToggleInlineDiagnostics,
16943        window: &mut Window,
16944        cx: &mut Context<Editor>,
16945    ) {
16946        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16947        self.refresh_inline_diagnostics(false, window, cx);
16948    }
16949
16950    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16951        self.diagnostics_max_severity = severity;
16952        self.display_map.update(cx, |display_map, _| {
16953            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16954        });
16955    }
16956
16957    pub fn toggle_diagnostics(
16958        &mut self,
16959        _: &ToggleDiagnostics,
16960        window: &mut Window,
16961        cx: &mut Context<Editor>,
16962    ) {
16963        if !self.diagnostics_enabled() {
16964            return;
16965        }
16966
16967        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16968            EditorSettings::get_global(cx)
16969                .diagnostics_max_severity
16970                .filter(|severity| severity != &DiagnosticSeverity::Off)
16971                .unwrap_or(DiagnosticSeverity::Hint)
16972        } else {
16973            DiagnosticSeverity::Off
16974        };
16975        self.set_max_diagnostics_severity(new_severity, cx);
16976        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16977            self.active_diagnostics = ActiveDiagnostic::None;
16978            self.inline_diagnostics_update = Task::ready(());
16979            self.inline_diagnostics.clear();
16980        } else {
16981            self.refresh_inline_diagnostics(false, window, cx);
16982        }
16983
16984        cx.notify();
16985    }
16986
16987    pub fn toggle_minimap(
16988        &mut self,
16989        _: &ToggleMinimap,
16990        window: &mut Window,
16991        cx: &mut Context<Editor>,
16992    ) {
16993        if self.supports_minimap(cx) {
16994            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16995        }
16996    }
16997
16998    fn refresh_inline_diagnostics(
16999        &mut self,
17000        debounce: bool,
17001        window: &mut Window,
17002        cx: &mut Context<Self>,
17003    ) {
17004        let max_severity = ProjectSettings::get_global(cx)
17005            .diagnostics
17006            .inline
17007            .max_severity
17008            .unwrap_or(self.diagnostics_max_severity);
17009
17010        if !self.inline_diagnostics_enabled()
17011            || !self.show_inline_diagnostics
17012            || max_severity == DiagnosticSeverity::Off
17013        {
17014            self.inline_diagnostics_update = Task::ready(());
17015            self.inline_diagnostics.clear();
17016            return;
17017        }
17018
17019        let debounce_ms = ProjectSettings::get_global(cx)
17020            .diagnostics
17021            .inline
17022            .update_debounce_ms;
17023        let debounce = if debounce && debounce_ms > 0 {
17024            Some(Duration::from_millis(debounce_ms))
17025        } else {
17026            None
17027        };
17028        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17029            if let Some(debounce) = debounce {
17030                cx.background_executor().timer(debounce).await;
17031            }
17032            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17033                editor
17034                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17035                    .ok()
17036            }) else {
17037                return;
17038            };
17039
17040            let new_inline_diagnostics = cx
17041                .background_spawn(async move {
17042                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17043                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17044                        let message = diagnostic_entry
17045                            .diagnostic
17046                            .message
17047                            .split_once('\n')
17048                            .map(|(line, _)| line)
17049                            .map(SharedString::new)
17050                            .unwrap_or_else(|| {
17051                                SharedString::from(diagnostic_entry.diagnostic.message)
17052                            });
17053                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17054                        let (Ok(i) | Err(i)) = inline_diagnostics
17055                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17056                        inline_diagnostics.insert(
17057                            i,
17058                            (
17059                                start_anchor,
17060                                InlineDiagnostic {
17061                                    message,
17062                                    group_id: diagnostic_entry.diagnostic.group_id,
17063                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17064                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17065                                    severity: diagnostic_entry.diagnostic.severity,
17066                                },
17067                            ),
17068                        );
17069                    }
17070                    inline_diagnostics
17071                })
17072                .await;
17073
17074            editor
17075                .update(cx, |editor, cx| {
17076                    editor.inline_diagnostics = new_inline_diagnostics;
17077                    cx.notify();
17078                })
17079                .ok();
17080        });
17081    }
17082
17083    fn pull_diagnostics(
17084        &mut self,
17085        buffer_id: Option<BufferId>,
17086        window: &Window,
17087        cx: &mut Context<Self>,
17088    ) -> Option<()> {
17089        if !self.mode().is_full() {
17090            return None;
17091        }
17092        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17093            .diagnostics
17094            .lsp_pull_diagnostics;
17095        if !pull_diagnostics_settings.enabled {
17096            return None;
17097        }
17098        let project = self.project()?.downgrade();
17099        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17100        let mut buffers = self.buffer.read(cx).all_buffers();
17101        if let Some(buffer_id) = buffer_id {
17102            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17103        }
17104
17105        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17106            cx.background_executor().timer(debounce).await;
17107
17108            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17109                buffers
17110                    .into_iter()
17111                    .filter_map(|buffer| {
17112                        project
17113                            .update(cx, |project, cx| {
17114                                project.lsp_store().update(cx, |lsp_store, cx| {
17115                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17116                                })
17117                            })
17118                            .ok()
17119                    })
17120                    .collect::<FuturesUnordered<_>>()
17121            }) else {
17122                return;
17123            };
17124
17125            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17126                match pull_task {
17127                    Ok(()) => {
17128                        if editor
17129                            .update_in(cx, |editor, window, cx| {
17130                                editor.update_diagnostics_state(window, cx);
17131                            })
17132                            .is_err()
17133                        {
17134                            return;
17135                        }
17136                    }
17137                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17138                }
17139            }
17140        });
17141
17142        Some(())
17143    }
17144
17145    pub fn set_selections_from_remote(
17146        &mut self,
17147        selections: Vec<Selection<Anchor>>,
17148        pending_selection: Option<Selection<Anchor>>,
17149        window: &mut Window,
17150        cx: &mut Context<Self>,
17151    ) {
17152        let old_cursor_position = self.selections.newest_anchor().head();
17153        self.selections.change_with(cx, |s| {
17154            s.select_anchors(selections);
17155            if let Some(pending_selection) = pending_selection {
17156                s.set_pending(pending_selection, SelectMode::Character);
17157            } else {
17158                s.clear_pending();
17159            }
17160        });
17161        self.selections_did_change(
17162            false,
17163            &old_cursor_position,
17164            SelectionEffects::default(),
17165            window,
17166            cx,
17167        );
17168    }
17169
17170    pub fn transact(
17171        &mut self,
17172        window: &mut Window,
17173        cx: &mut Context<Self>,
17174        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17175    ) -> Option<TransactionId> {
17176        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17177            this.start_transaction_at(Instant::now(), window, cx);
17178            update(this, window, cx);
17179            this.end_transaction_at(Instant::now(), cx)
17180        })
17181    }
17182
17183    pub fn start_transaction_at(
17184        &mut self,
17185        now: Instant,
17186        window: &mut Window,
17187        cx: &mut Context<Self>,
17188    ) -> Option<TransactionId> {
17189        self.end_selection(window, cx);
17190        if let Some(tx_id) = self
17191            .buffer
17192            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17193        {
17194            self.selection_history
17195                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17196            cx.emit(EditorEvent::TransactionBegun {
17197                transaction_id: tx_id,
17198            });
17199            Some(tx_id)
17200        } else {
17201            None
17202        }
17203    }
17204
17205    pub fn end_transaction_at(
17206        &mut self,
17207        now: Instant,
17208        cx: &mut Context<Self>,
17209    ) -> Option<TransactionId> {
17210        if let Some(transaction_id) = self
17211            .buffer
17212            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17213        {
17214            if let Some((_, end_selections)) =
17215                self.selection_history.transaction_mut(transaction_id)
17216            {
17217                *end_selections = Some(self.selections.disjoint_anchors());
17218            } else {
17219                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17220            }
17221
17222            cx.emit(EditorEvent::Edited { transaction_id });
17223            Some(transaction_id)
17224        } else {
17225            None
17226        }
17227    }
17228
17229    pub fn modify_transaction_selection_history(
17230        &mut self,
17231        transaction_id: TransactionId,
17232        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17233    ) -> bool {
17234        self.selection_history
17235            .transaction_mut(transaction_id)
17236            .map(modify)
17237            .is_some()
17238    }
17239
17240    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17241        if self.selection_mark_mode {
17242            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17243                s.move_with(|_, sel| {
17244                    sel.collapse_to(sel.head(), SelectionGoal::None);
17245                });
17246            })
17247        }
17248        self.selection_mark_mode = true;
17249        cx.notify();
17250    }
17251
17252    pub fn swap_selection_ends(
17253        &mut self,
17254        _: &actions::SwapSelectionEnds,
17255        window: &mut Window,
17256        cx: &mut Context<Self>,
17257    ) {
17258        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17259            s.move_with(|_, sel| {
17260                if sel.start != sel.end {
17261                    sel.reversed = !sel.reversed
17262                }
17263            });
17264        });
17265        self.request_autoscroll(Autoscroll::newest(), cx);
17266        cx.notify();
17267    }
17268
17269    pub fn toggle_focus(
17270        workspace: &mut Workspace,
17271        _: &actions::ToggleFocus,
17272        window: &mut Window,
17273        cx: &mut Context<Workspace>,
17274    ) {
17275        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17276            return;
17277        };
17278        workspace.activate_item(&item, true, true, window, cx);
17279    }
17280
17281    pub fn toggle_fold(
17282        &mut self,
17283        _: &actions::ToggleFold,
17284        window: &mut Window,
17285        cx: &mut Context<Self>,
17286    ) {
17287        if self.is_singleton(cx) {
17288            let selection = self.selections.newest::<Point>(cx);
17289
17290            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17291            let range = if selection.is_empty() {
17292                let point = selection.head().to_display_point(&display_map);
17293                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17294                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17295                    .to_point(&display_map);
17296                start..end
17297            } else {
17298                selection.range()
17299            };
17300            if display_map.folds_in_range(range).next().is_some() {
17301                self.unfold_lines(&Default::default(), window, cx)
17302            } else {
17303                self.fold(&Default::default(), window, cx)
17304            }
17305        } else {
17306            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17307            let buffer_ids: HashSet<_> = self
17308                .selections
17309                .disjoint_anchor_ranges()
17310                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17311                .collect();
17312
17313            let should_unfold = buffer_ids
17314                .iter()
17315                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17316
17317            for buffer_id in buffer_ids {
17318                if should_unfold {
17319                    self.unfold_buffer(buffer_id, cx);
17320                } else {
17321                    self.fold_buffer(buffer_id, cx);
17322                }
17323            }
17324        }
17325    }
17326
17327    pub fn toggle_fold_recursive(
17328        &mut self,
17329        _: &actions::ToggleFoldRecursive,
17330        window: &mut Window,
17331        cx: &mut Context<Self>,
17332    ) {
17333        let selection = self.selections.newest::<Point>(cx);
17334
17335        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17336        let range = if selection.is_empty() {
17337            let point = selection.head().to_display_point(&display_map);
17338            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17339            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17340                .to_point(&display_map);
17341            start..end
17342        } else {
17343            selection.range()
17344        };
17345        if display_map.folds_in_range(range).next().is_some() {
17346            self.unfold_recursive(&Default::default(), window, cx)
17347        } else {
17348            self.fold_recursive(&Default::default(), window, cx)
17349        }
17350    }
17351
17352    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17353        if self.is_singleton(cx) {
17354            let mut to_fold = Vec::new();
17355            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17356            let selections = self.selections.all_adjusted(cx);
17357
17358            for selection in selections {
17359                let range = selection.range().sorted();
17360                let buffer_start_row = range.start.row;
17361
17362                if range.start.row != range.end.row {
17363                    let mut found = false;
17364                    let mut row = range.start.row;
17365                    while row <= range.end.row {
17366                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17367                        {
17368                            found = true;
17369                            row = crease.range().end.row + 1;
17370                            to_fold.push(crease);
17371                        } else {
17372                            row += 1
17373                        }
17374                    }
17375                    if found {
17376                        continue;
17377                    }
17378                }
17379
17380                for row in (0..=range.start.row).rev() {
17381                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17382                        if crease.range().end.row >= buffer_start_row {
17383                            to_fold.push(crease);
17384                            if row <= range.start.row {
17385                                break;
17386                            }
17387                        }
17388                    }
17389                }
17390            }
17391
17392            self.fold_creases(to_fold, true, window, cx);
17393        } else {
17394            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17395            let buffer_ids = self
17396                .selections
17397                .disjoint_anchor_ranges()
17398                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17399                .collect::<HashSet<_>>();
17400            for buffer_id in buffer_ids {
17401                self.fold_buffer(buffer_id, cx);
17402            }
17403        }
17404    }
17405
17406    pub fn toggle_fold_all(
17407        &mut self,
17408        _: &actions::ToggleFoldAll,
17409        window: &mut Window,
17410        cx: &mut Context<Self>,
17411    ) {
17412        if self.buffer.read(cx).is_singleton() {
17413            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17414            let has_folds = display_map
17415                .folds_in_range(0..display_map.buffer_snapshot.len())
17416                .next()
17417                .is_some();
17418
17419            if has_folds {
17420                self.unfold_all(&actions::UnfoldAll, window, cx);
17421            } else {
17422                self.fold_all(&actions::FoldAll, window, cx);
17423            }
17424        } else {
17425            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17426            let should_unfold = buffer_ids
17427                .iter()
17428                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17429
17430            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17431                editor
17432                    .update_in(cx, |editor, _, cx| {
17433                        for buffer_id in buffer_ids {
17434                            if should_unfold {
17435                                editor.unfold_buffer(buffer_id, cx);
17436                            } else {
17437                                editor.fold_buffer(buffer_id, cx);
17438                            }
17439                        }
17440                    })
17441                    .ok();
17442            });
17443        }
17444    }
17445
17446    fn fold_at_level(
17447        &mut self,
17448        fold_at: &FoldAtLevel,
17449        window: &mut Window,
17450        cx: &mut Context<Self>,
17451    ) {
17452        if !self.buffer.read(cx).is_singleton() {
17453            return;
17454        }
17455
17456        let fold_at_level = fold_at.0;
17457        let snapshot = self.buffer.read(cx).snapshot(cx);
17458        let mut to_fold = Vec::new();
17459        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17460
17461        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17462            while start_row < end_row {
17463                match self
17464                    .snapshot(window, cx)
17465                    .crease_for_buffer_row(MultiBufferRow(start_row))
17466                {
17467                    Some(crease) => {
17468                        let nested_start_row = crease.range().start.row + 1;
17469                        let nested_end_row = crease.range().end.row;
17470
17471                        if current_level < fold_at_level {
17472                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17473                        } else if current_level == fold_at_level {
17474                            to_fold.push(crease);
17475                        }
17476
17477                        start_row = nested_end_row + 1;
17478                    }
17479                    None => start_row += 1,
17480                }
17481            }
17482        }
17483
17484        self.fold_creases(to_fold, true, window, cx);
17485    }
17486
17487    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17488        if self.buffer.read(cx).is_singleton() {
17489            let mut fold_ranges = Vec::new();
17490            let snapshot = self.buffer.read(cx).snapshot(cx);
17491
17492            for row in 0..snapshot.max_row().0 {
17493                if let Some(foldable_range) = self
17494                    .snapshot(window, cx)
17495                    .crease_for_buffer_row(MultiBufferRow(row))
17496                {
17497                    fold_ranges.push(foldable_range);
17498                }
17499            }
17500
17501            self.fold_creases(fold_ranges, true, window, cx);
17502        } else {
17503            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17504                editor
17505                    .update_in(cx, |editor, _, cx| {
17506                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17507                            editor.fold_buffer(buffer_id, cx);
17508                        }
17509                    })
17510                    .ok();
17511            });
17512        }
17513    }
17514
17515    pub fn fold_function_bodies(
17516        &mut self,
17517        _: &actions::FoldFunctionBodies,
17518        window: &mut Window,
17519        cx: &mut Context<Self>,
17520    ) {
17521        let snapshot = self.buffer.read(cx).snapshot(cx);
17522
17523        let ranges = snapshot
17524            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17525            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17526            .collect::<Vec<_>>();
17527
17528        let creases = ranges
17529            .into_iter()
17530            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17531            .collect();
17532
17533        self.fold_creases(creases, true, window, cx);
17534    }
17535
17536    pub fn fold_recursive(
17537        &mut self,
17538        _: &actions::FoldRecursive,
17539        window: &mut Window,
17540        cx: &mut Context<Self>,
17541    ) {
17542        let mut to_fold = Vec::new();
17543        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17544        let selections = self.selections.all_adjusted(cx);
17545
17546        for selection in selections {
17547            let range = selection.range().sorted();
17548            let buffer_start_row = range.start.row;
17549
17550            if range.start.row != range.end.row {
17551                let mut found = false;
17552                for row in range.start.row..=range.end.row {
17553                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17554                        found = true;
17555                        to_fold.push(crease);
17556                    }
17557                }
17558                if found {
17559                    continue;
17560                }
17561            }
17562
17563            for row in (0..=range.start.row).rev() {
17564                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17565                    if crease.range().end.row >= buffer_start_row {
17566                        to_fold.push(crease);
17567                    } else {
17568                        break;
17569                    }
17570                }
17571            }
17572        }
17573
17574        self.fold_creases(to_fold, true, window, cx);
17575    }
17576
17577    pub fn fold_at(
17578        &mut self,
17579        buffer_row: MultiBufferRow,
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
17585        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17586            let autoscroll = self
17587                .selections
17588                .all::<Point>(cx)
17589                .iter()
17590                .any(|selection| crease.range().overlaps(&selection.range()));
17591
17592            self.fold_creases(vec![crease], autoscroll, window, cx);
17593        }
17594    }
17595
17596    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17597        if self.is_singleton(cx) {
17598            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17599            let buffer = &display_map.buffer_snapshot;
17600            let selections = self.selections.all::<Point>(cx);
17601            let ranges = selections
17602                .iter()
17603                .map(|s| {
17604                    let range = s.display_range(&display_map).sorted();
17605                    let mut start = range.start.to_point(&display_map);
17606                    let mut end = range.end.to_point(&display_map);
17607                    start.column = 0;
17608                    end.column = buffer.line_len(MultiBufferRow(end.row));
17609                    start..end
17610                })
17611                .collect::<Vec<_>>();
17612
17613            self.unfold_ranges(&ranges, true, true, cx);
17614        } else {
17615            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17616            let buffer_ids = self
17617                .selections
17618                .disjoint_anchor_ranges()
17619                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17620                .collect::<HashSet<_>>();
17621            for buffer_id in buffer_ids {
17622                self.unfold_buffer(buffer_id, cx);
17623            }
17624        }
17625    }
17626
17627    pub fn unfold_recursive(
17628        &mut self,
17629        _: &UnfoldRecursive,
17630        _window: &mut Window,
17631        cx: &mut Context<Self>,
17632    ) {
17633        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17634        let selections = self.selections.all::<Point>(cx);
17635        let ranges = selections
17636            .iter()
17637            .map(|s| {
17638                let mut range = s.display_range(&display_map).sorted();
17639                *range.start.column_mut() = 0;
17640                *range.end.column_mut() = display_map.line_len(range.end.row());
17641                let start = range.start.to_point(&display_map);
17642                let end = range.end.to_point(&display_map);
17643                start..end
17644            })
17645            .collect::<Vec<_>>();
17646
17647        self.unfold_ranges(&ranges, true, true, cx);
17648    }
17649
17650    pub fn unfold_at(
17651        &mut self,
17652        buffer_row: MultiBufferRow,
17653        _window: &mut Window,
17654        cx: &mut Context<Self>,
17655    ) {
17656        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17657
17658        let intersection_range = Point::new(buffer_row.0, 0)
17659            ..Point::new(
17660                buffer_row.0,
17661                display_map.buffer_snapshot.line_len(buffer_row),
17662            );
17663
17664        let autoscroll = self
17665            .selections
17666            .all::<Point>(cx)
17667            .iter()
17668            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17669
17670        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17671    }
17672
17673    pub fn unfold_all(
17674        &mut self,
17675        _: &actions::UnfoldAll,
17676        _window: &mut Window,
17677        cx: &mut Context<Self>,
17678    ) {
17679        if self.buffer.read(cx).is_singleton() {
17680            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17681            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17682        } else {
17683            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17684                editor
17685                    .update(cx, |editor, cx| {
17686                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17687                            editor.unfold_buffer(buffer_id, cx);
17688                        }
17689                    })
17690                    .ok();
17691            });
17692        }
17693    }
17694
17695    pub fn fold_selected_ranges(
17696        &mut self,
17697        _: &FoldSelectedRanges,
17698        window: &mut Window,
17699        cx: &mut Context<Self>,
17700    ) {
17701        let selections = self.selections.all_adjusted(cx);
17702        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17703        let ranges = selections
17704            .into_iter()
17705            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17706            .collect::<Vec<_>>();
17707        self.fold_creases(ranges, true, window, cx);
17708    }
17709
17710    pub fn fold_ranges<T: ToOffset + Clone>(
17711        &mut self,
17712        ranges: Vec<Range<T>>,
17713        auto_scroll: bool,
17714        window: &mut Window,
17715        cx: &mut Context<Self>,
17716    ) {
17717        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17718        let ranges = ranges
17719            .into_iter()
17720            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17721            .collect::<Vec<_>>();
17722        self.fold_creases(ranges, auto_scroll, window, cx);
17723    }
17724
17725    pub fn fold_creases<T: ToOffset + Clone>(
17726        &mut self,
17727        creases: Vec<Crease<T>>,
17728        auto_scroll: bool,
17729        _window: &mut Window,
17730        cx: &mut Context<Self>,
17731    ) {
17732        if creases.is_empty() {
17733            return;
17734        }
17735
17736        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17737
17738        if auto_scroll {
17739            self.request_autoscroll(Autoscroll::fit(), cx);
17740        }
17741
17742        cx.notify();
17743
17744        self.scrollbar_marker_state.dirty = true;
17745        self.folds_did_change(cx);
17746    }
17747
17748    /// Removes any folds whose ranges intersect any of the given ranges.
17749    pub fn unfold_ranges<T: ToOffset + Clone>(
17750        &mut self,
17751        ranges: &[Range<T>],
17752        inclusive: bool,
17753        auto_scroll: bool,
17754        cx: &mut Context<Self>,
17755    ) {
17756        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17757            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17758        });
17759        self.folds_did_change(cx);
17760    }
17761
17762    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17763        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17764            return;
17765        }
17766        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17767        self.display_map.update(cx, |display_map, cx| {
17768            display_map.fold_buffers([buffer_id], cx)
17769        });
17770        cx.emit(EditorEvent::BufferFoldToggled {
17771            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17772            folded: true,
17773        });
17774        cx.notify();
17775    }
17776
17777    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17778        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17779            return;
17780        }
17781        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17782        self.display_map.update(cx, |display_map, cx| {
17783            display_map.unfold_buffers([buffer_id], cx);
17784        });
17785        cx.emit(EditorEvent::BufferFoldToggled {
17786            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17787            folded: false,
17788        });
17789        cx.notify();
17790    }
17791
17792    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17793        self.display_map.read(cx).is_buffer_folded(buffer)
17794    }
17795
17796    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17797        self.display_map.read(cx).folded_buffers()
17798    }
17799
17800    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17801        self.display_map.update(cx, |display_map, cx| {
17802            display_map.disable_header_for_buffer(buffer_id, cx);
17803        });
17804        cx.notify();
17805    }
17806
17807    /// Removes any folds with the given ranges.
17808    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17809        &mut self,
17810        ranges: &[Range<T>],
17811        type_id: TypeId,
17812        auto_scroll: bool,
17813        cx: &mut Context<Self>,
17814    ) {
17815        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17816            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17817        });
17818        self.folds_did_change(cx);
17819    }
17820
17821    fn remove_folds_with<T: ToOffset + Clone>(
17822        &mut self,
17823        ranges: &[Range<T>],
17824        auto_scroll: bool,
17825        cx: &mut Context<Self>,
17826        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17827    ) {
17828        if ranges.is_empty() {
17829            return;
17830        }
17831
17832        let mut buffers_affected = HashSet::default();
17833        let multi_buffer = self.buffer().read(cx);
17834        for range in ranges {
17835            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17836                buffers_affected.insert(buffer.read(cx).remote_id());
17837            };
17838        }
17839
17840        self.display_map.update(cx, update);
17841
17842        if auto_scroll {
17843            self.request_autoscroll(Autoscroll::fit(), cx);
17844        }
17845
17846        cx.notify();
17847        self.scrollbar_marker_state.dirty = true;
17848        self.active_indent_guides_state.dirty = true;
17849    }
17850
17851    pub fn update_renderer_widths(
17852        &mut self,
17853        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17854        cx: &mut Context<Self>,
17855    ) -> bool {
17856        self.display_map
17857            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17858    }
17859
17860    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17861        self.display_map.read(cx).fold_placeholder.clone()
17862    }
17863
17864    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17865        self.buffer.update(cx, |buffer, cx| {
17866            buffer.set_all_diff_hunks_expanded(cx);
17867        });
17868    }
17869
17870    pub fn expand_all_diff_hunks(
17871        &mut self,
17872        _: &ExpandAllDiffHunks,
17873        _window: &mut Window,
17874        cx: &mut Context<Self>,
17875    ) {
17876        self.buffer.update(cx, |buffer, cx| {
17877            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17878        });
17879    }
17880
17881    pub fn toggle_selected_diff_hunks(
17882        &mut self,
17883        _: &ToggleSelectedDiffHunks,
17884        _window: &mut Window,
17885        cx: &mut Context<Self>,
17886    ) {
17887        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17888        self.toggle_diff_hunks_in_ranges(ranges, cx);
17889    }
17890
17891    pub fn diff_hunks_in_ranges<'a>(
17892        &'a self,
17893        ranges: &'a [Range<Anchor>],
17894        buffer: &'a MultiBufferSnapshot,
17895    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17896        ranges.iter().flat_map(move |range| {
17897            let end_excerpt_id = range.end.excerpt_id;
17898            let range = range.to_point(buffer);
17899            let mut peek_end = range.end;
17900            if range.end.row < buffer.max_row().0 {
17901                peek_end = Point::new(range.end.row + 1, 0);
17902            }
17903            buffer
17904                .diff_hunks_in_range(range.start..peek_end)
17905                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17906        })
17907    }
17908
17909    pub fn has_stageable_diff_hunks_in_ranges(
17910        &self,
17911        ranges: &[Range<Anchor>],
17912        snapshot: &MultiBufferSnapshot,
17913    ) -> bool {
17914        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17915        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17916    }
17917
17918    pub fn toggle_staged_selected_diff_hunks(
17919        &mut self,
17920        _: &::git::ToggleStaged,
17921        _: &mut Window,
17922        cx: &mut Context<Self>,
17923    ) {
17924        let snapshot = self.buffer.read(cx).snapshot(cx);
17925        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17926        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17927        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17928    }
17929
17930    pub fn set_render_diff_hunk_controls(
17931        &mut self,
17932        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17933        cx: &mut Context<Self>,
17934    ) {
17935        self.render_diff_hunk_controls = render_diff_hunk_controls;
17936        cx.notify();
17937    }
17938
17939    pub fn stage_and_next(
17940        &mut self,
17941        _: &::git::StageAndNext,
17942        window: &mut Window,
17943        cx: &mut Context<Self>,
17944    ) {
17945        self.do_stage_or_unstage_and_next(true, window, cx);
17946    }
17947
17948    pub fn unstage_and_next(
17949        &mut self,
17950        _: &::git::UnstageAndNext,
17951        window: &mut Window,
17952        cx: &mut Context<Self>,
17953    ) {
17954        self.do_stage_or_unstage_and_next(false, window, cx);
17955    }
17956
17957    pub fn stage_or_unstage_diff_hunks(
17958        &mut self,
17959        stage: bool,
17960        ranges: Vec<Range<Anchor>>,
17961        cx: &mut Context<Self>,
17962    ) {
17963        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17964        cx.spawn(async move |this, cx| {
17965            task.await?;
17966            this.update(cx, |this, cx| {
17967                let snapshot = this.buffer.read(cx).snapshot(cx);
17968                let chunk_by = this
17969                    .diff_hunks_in_ranges(&ranges, &snapshot)
17970                    .chunk_by(|hunk| hunk.buffer_id);
17971                for (buffer_id, hunks) in &chunk_by {
17972                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17973                }
17974            })
17975        })
17976        .detach_and_log_err(cx);
17977    }
17978
17979    fn save_buffers_for_ranges_if_needed(
17980        &mut self,
17981        ranges: &[Range<Anchor>],
17982        cx: &mut Context<Editor>,
17983    ) -> Task<Result<()>> {
17984        let multibuffer = self.buffer.read(cx);
17985        let snapshot = multibuffer.read(cx);
17986        let buffer_ids: HashSet<_> = ranges
17987            .iter()
17988            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17989            .collect();
17990        drop(snapshot);
17991
17992        let mut buffers = HashSet::default();
17993        for buffer_id in buffer_ids {
17994            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17995                let buffer = buffer_entity.read(cx);
17996                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17997                {
17998                    buffers.insert(buffer_entity);
17999                }
18000            }
18001        }
18002
18003        if let Some(project) = &self.project {
18004            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18005        } else {
18006            Task::ready(Ok(()))
18007        }
18008    }
18009
18010    fn do_stage_or_unstage_and_next(
18011        &mut self,
18012        stage: bool,
18013        window: &mut Window,
18014        cx: &mut Context<Self>,
18015    ) {
18016        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18017
18018        if ranges.iter().any(|range| range.start != range.end) {
18019            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18020            return;
18021        }
18022
18023        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18024        let snapshot = self.snapshot(window, cx);
18025        let position = self.selections.newest::<Point>(cx).head();
18026        let mut row = snapshot
18027            .buffer_snapshot
18028            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18029            .find(|hunk| hunk.row_range.start.0 > position.row)
18030            .map(|hunk| hunk.row_range.start);
18031
18032        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18033        // Outside of the project diff editor, wrap around to the beginning.
18034        if !all_diff_hunks_expanded {
18035            row = row.or_else(|| {
18036                snapshot
18037                    .buffer_snapshot
18038                    .diff_hunks_in_range(Point::zero()..position)
18039                    .find(|hunk| hunk.row_range.end.0 < position.row)
18040                    .map(|hunk| hunk.row_range.start)
18041            });
18042        }
18043
18044        if let Some(row) = row {
18045            let destination = Point::new(row.0, 0);
18046            let autoscroll = Autoscroll::center();
18047
18048            self.unfold_ranges(&[destination..destination], false, false, cx);
18049            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18050                s.select_ranges([destination..destination]);
18051            });
18052        }
18053    }
18054
18055    fn do_stage_or_unstage(
18056        &self,
18057        stage: bool,
18058        buffer_id: BufferId,
18059        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18060        cx: &mut App,
18061    ) -> Option<()> {
18062        let project = self.project()?;
18063        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18064        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18065        let buffer_snapshot = buffer.read(cx).snapshot();
18066        let file_exists = buffer_snapshot
18067            .file()
18068            .is_some_and(|file| file.disk_state().exists());
18069        diff.update(cx, |diff, cx| {
18070            diff.stage_or_unstage_hunks(
18071                stage,
18072                &hunks
18073                    .map(|hunk| buffer_diff::DiffHunk {
18074                        buffer_range: hunk.buffer_range,
18075                        diff_base_byte_range: hunk.diff_base_byte_range,
18076                        secondary_status: hunk.secondary_status,
18077                        range: Point::zero()..Point::zero(), // unused
18078                    })
18079                    .collect::<Vec<_>>(),
18080                &buffer_snapshot,
18081                file_exists,
18082                cx,
18083            )
18084        });
18085        None
18086    }
18087
18088    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18089        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18090        self.buffer
18091            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18092    }
18093
18094    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18095        self.buffer.update(cx, |buffer, cx| {
18096            let ranges = vec![Anchor::min()..Anchor::max()];
18097            if !buffer.all_diff_hunks_expanded()
18098                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18099            {
18100                buffer.collapse_diff_hunks(ranges, cx);
18101                true
18102            } else {
18103                false
18104            }
18105        })
18106    }
18107
18108    fn toggle_diff_hunks_in_ranges(
18109        &mut self,
18110        ranges: Vec<Range<Anchor>>,
18111        cx: &mut Context<Editor>,
18112    ) {
18113        self.buffer.update(cx, |buffer, cx| {
18114            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18115            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18116        })
18117    }
18118
18119    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18120        self.buffer.update(cx, |buffer, cx| {
18121            let snapshot = buffer.snapshot(cx);
18122            let excerpt_id = range.end.excerpt_id;
18123            let point_range = range.to_point(&snapshot);
18124            let expand = !buffer.single_hunk_is_expanded(range, cx);
18125            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18126        })
18127    }
18128
18129    pub(crate) fn apply_all_diff_hunks(
18130        &mut self,
18131        _: &ApplyAllDiffHunks,
18132        window: &mut Window,
18133        cx: &mut Context<Self>,
18134    ) {
18135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18136
18137        let buffers = self.buffer.read(cx).all_buffers();
18138        for branch_buffer in buffers {
18139            branch_buffer.update(cx, |branch_buffer, cx| {
18140                branch_buffer.merge_into_base(Vec::new(), cx);
18141            });
18142        }
18143
18144        if let Some(project) = self.project.clone() {
18145            self.save(
18146                SaveOptions {
18147                    format: true,
18148                    autosave: false,
18149                },
18150                project,
18151                window,
18152                cx,
18153            )
18154            .detach_and_log_err(cx);
18155        }
18156    }
18157
18158    pub(crate) fn apply_selected_diff_hunks(
18159        &mut self,
18160        _: &ApplyDiffHunk,
18161        window: &mut Window,
18162        cx: &mut Context<Self>,
18163    ) {
18164        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18165        let snapshot = self.snapshot(window, cx);
18166        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18167        let mut ranges_by_buffer = HashMap::default();
18168        self.transact(window, cx, |editor, _window, cx| {
18169            for hunk in hunks {
18170                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18171                    ranges_by_buffer
18172                        .entry(buffer.clone())
18173                        .or_insert_with(Vec::new)
18174                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18175                }
18176            }
18177
18178            for (buffer, ranges) in ranges_by_buffer {
18179                buffer.update(cx, |buffer, cx| {
18180                    buffer.merge_into_base(ranges, cx);
18181                });
18182            }
18183        });
18184
18185        if let Some(project) = self.project.clone() {
18186            self.save(
18187                SaveOptions {
18188                    format: true,
18189                    autosave: false,
18190                },
18191                project,
18192                window,
18193                cx,
18194            )
18195            .detach_and_log_err(cx);
18196        }
18197    }
18198
18199    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18200        if hovered != self.gutter_hovered {
18201            self.gutter_hovered = hovered;
18202            cx.notify();
18203        }
18204    }
18205
18206    pub fn insert_blocks(
18207        &mut self,
18208        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18209        autoscroll: Option<Autoscroll>,
18210        cx: &mut Context<Self>,
18211    ) -> Vec<CustomBlockId> {
18212        let blocks = self
18213            .display_map
18214            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18215        if let Some(autoscroll) = autoscroll {
18216            self.request_autoscroll(autoscroll, cx);
18217        }
18218        cx.notify();
18219        blocks
18220    }
18221
18222    pub fn resize_blocks(
18223        &mut self,
18224        heights: HashMap<CustomBlockId, u32>,
18225        autoscroll: Option<Autoscroll>,
18226        cx: &mut Context<Self>,
18227    ) {
18228        self.display_map
18229            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18230        if let Some(autoscroll) = autoscroll {
18231            self.request_autoscroll(autoscroll, cx);
18232        }
18233        cx.notify();
18234    }
18235
18236    pub fn replace_blocks(
18237        &mut self,
18238        renderers: HashMap<CustomBlockId, RenderBlock>,
18239        autoscroll: Option<Autoscroll>,
18240        cx: &mut Context<Self>,
18241    ) {
18242        self.display_map
18243            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18244        if let Some(autoscroll) = autoscroll {
18245            self.request_autoscroll(autoscroll, cx);
18246        }
18247        cx.notify();
18248    }
18249
18250    pub fn remove_blocks(
18251        &mut self,
18252        block_ids: HashSet<CustomBlockId>,
18253        autoscroll: Option<Autoscroll>,
18254        cx: &mut Context<Self>,
18255    ) {
18256        self.display_map.update(cx, |display_map, cx| {
18257            display_map.remove_blocks(block_ids, cx)
18258        });
18259        if let Some(autoscroll) = autoscroll {
18260            self.request_autoscroll(autoscroll, cx);
18261        }
18262        cx.notify();
18263    }
18264
18265    pub fn row_for_block(
18266        &self,
18267        block_id: CustomBlockId,
18268        cx: &mut Context<Self>,
18269    ) -> Option<DisplayRow> {
18270        self.display_map
18271            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18272    }
18273
18274    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18275        self.focused_block = Some(focused_block);
18276    }
18277
18278    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18279        self.focused_block.take()
18280    }
18281
18282    pub fn insert_creases(
18283        &mut self,
18284        creases: impl IntoIterator<Item = Crease<Anchor>>,
18285        cx: &mut Context<Self>,
18286    ) -> Vec<CreaseId> {
18287        self.display_map
18288            .update(cx, |map, cx| map.insert_creases(creases, cx))
18289    }
18290
18291    pub fn remove_creases(
18292        &mut self,
18293        ids: impl IntoIterator<Item = CreaseId>,
18294        cx: &mut Context<Self>,
18295    ) -> Vec<(CreaseId, Range<Anchor>)> {
18296        self.display_map
18297            .update(cx, |map, cx| map.remove_creases(ids, cx))
18298    }
18299
18300    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18301        self.display_map
18302            .update(cx, |map, cx| map.snapshot(cx))
18303            .longest_row()
18304    }
18305
18306    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18307        self.display_map
18308            .update(cx, |map, cx| map.snapshot(cx))
18309            .max_point()
18310    }
18311
18312    pub fn text(&self, cx: &App) -> String {
18313        self.buffer.read(cx).read(cx).text()
18314    }
18315
18316    pub fn is_empty(&self, cx: &App) -> bool {
18317        self.buffer.read(cx).read(cx).is_empty()
18318    }
18319
18320    pub fn text_option(&self, cx: &App) -> Option<String> {
18321        let text = self.text(cx);
18322        let text = text.trim();
18323
18324        if text.is_empty() {
18325            return None;
18326        }
18327
18328        Some(text.to_string())
18329    }
18330
18331    pub fn set_text(
18332        &mut self,
18333        text: impl Into<Arc<str>>,
18334        window: &mut Window,
18335        cx: &mut Context<Self>,
18336    ) {
18337        self.transact(window, cx, |this, _, cx| {
18338            this.buffer
18339                .read(cx)
18340                .as_singleton()
18341                .expect("you can only call set_text on editors for singleton buffers")
18342                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18343        });
18344    }
18345
18346    pub fn display_text(&self, cx: &mut App) -> String {
18347        self.display_map
18348            .update(cx, |map, cx| map.snapshot(cx))
18349            .text()
18350    }
18351
18352    fn create_minimap(
18353        &self,
18354        minimap_settings: MinimapSettings,
18355        window: &mut Window,
18356        cx: &mut Context<Self>,
18357    ) -> Option<Entity<Self>> {
18358        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18359            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18360    }
18361
18362    fn initialize_new_minimap(
18363        &self,
18364        minimap_settings: MinimapSettings,
18365        window: &mut Window,
18366        cx: &mut Context<Self>,
18367    ) -> Entity<Self> {
18368        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18369
18370        let mut minimap = Editor::new_internal(
18371            EditorMode::Minimap {
18372                parent: cx.weak_entity(),
18373            },
18374            self.buffer.clone(),
18375            None,
18376            Some(self.display_map.clone()),
18377            window,
18378            cx,
18379        );
18380        minimap.scroll_manager.clone_state(&self.scroll_manager);
18381        minimap.set_text_style_refinement(TextStyleRefinement {
18382            font_size: Some(MINIMAP_FONT_SIZE),
18383            font_weight: Some(MINIMAP_FONT_WEIGHT),
18384            ..Default::default()
18385        });
18386        minimap.update_minimap_configuration(minimap_settings, cx);
18387        cx.new(|_| minimap)
18388    }
18389
18390    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18391        let current_line_highlight = minimap_settings
18392            .current_line_highlight
18393            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18394        self.set_current_line_highlight(Some(current_line_highlight));
18395    }
18396
18397    pub fn minimap(&self) -> Option<&Entity<Self>> {
18398        self.minimap
18399            .as_ref()
18400            .filter(|_| self.minimap_visibility.visible())
18401    }
18402
18403    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18404        let mut wrap_guides = smallvec![];
18405
18406        if self.show_wrap_guides == Some(false) {
18407            return wrap_guides;
18408        }
18409
18410        let settings = self.buffer.read(cx).language_settings(cx);
18411        if settings.show_wrap_guides {
18412            match self.soft_wrap_mode(cx) {
18413                SoftWrap::Column(soft_wrap) => {
18414                    wrap_guides.push((soft_wrap as usize, true));
18415                }
18416                SoftWrap::Bounded(soft_wrap) => {
18417                    wrap_guides.push((soft_wrap as usize, true));
18418                }
18419                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18420            }
18421            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18422        }
18423
18424        wrap_guides
18425    }
18426
18427    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18428        let settings = self.buffer.read(cx).language_settings(cx);
18429        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18430        match mode {
18431            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18432                SoftWrap::None
18433            }
18434            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18435            language_settings::SoftWrap::PreferredLineLength => {
18436                SoftWrap::Column(settings.preferred_line_length)
18437            }
18438            language_settings::SoftWrap::Bounded => {
18439                SoftWrap::Bounded(settings.preferred_line_length)
18440            }
18441        }
18442    }
18443
18444    pub fn set_soft_wrap_mode(
18445        &mut self,
18446        mode: language_settings::SoftWrap,
18447
18448        cx: &mut Context<Self>,
18449    ) {
18450        self.soft_wrap_mode_override = Some(mode);
18451        cx.notify();
18452    }
18453
18454    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18455        self.hard_wrap = hard_wrap;
18456        cx.notify();
18457    }
18458
18459    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18460        self.text_style_refinement = Some(style);
18461    }
18462
18463    /// called by the Element so we know what style we were most recently rendered with.
18464    pub(crate) fn set_style(
18465        &mut self,
18466        style: EditorStyle,
18467        window: &mut Window,
18468        cx: &mut Context<Self>,
18469    ) {
18470        // We intentionally do not inform the display map about the minimap style
18471        // so that wrapping is not recalculated and stays consistent for the editor
18472        // and its linked minimap.
18473        if !self.mode.is_minimap() {
18474            let rem_size = window.rem_size();
18475            self.display_map.update(cx, |map, cx| {
18476                map.set_font(
18477                    style.text.font(),
18478                    style.text.font_size.to_pixels(rem_size),
18479                    cx,
18480                )
18481            });
18482        }
18483        self.style = Some(style);
18484    }
18485
18486    pub fn style(&self) -> Option<&EditorStyle> {
18487        self.style.as_ref()
18488    }
18489
18490    // Called by the element. This method is not designed to be called outside of the editor
18491    // element's layout code because it does not notify when rewrapping is computed synchronously.
18492    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18493        self.display_map
18494            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18495    }
18496
18497    pub fn set_soft_wrap(&mut self) {
18498        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18499    }
18500
18501    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18502        if self.soft_wrap_mode_override.is_some() {
18503            self.soft_wrap_mode_override.take();
18504        } else {
18505            let soft_wrap = match self.soft_wrap_mode(cx) {
18506                SoftWrap::GitDiff => return,
18507                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18508                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18509                    language_settings::SoftWrap::None
18510                }
18511            };
18512            self.soft_wrap_mode_override = Some(soft_wrap);
18513        }
18514        cx.notify();
18515    }
18516
18517    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18518        let Some(workspace) = self.workspace() else {
18519            return;
18520        };
18521        let fs = workspace.read(cx).app_state().fs.clone();
18522        let current_show = TabBarSettings::get_global(cx).show;
18523        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18524            setting.show = Some(!current_show);
18525        });
18526    }
18527
18528    pub fn toggle_indent_guides(
18529        &mut self,
18530        _: &ToggleIndentGuides,
18531        _: &mut Window,
18532        cx: &mut Context<Self>,
18533    ) {
18534        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18535            self.buffer
18536                .read(cx)
18537                .language_settings(cx)
18538                .indent_guides
18539                .enabled
18540        });
18541        self.show_indent_guides = Some(!currently_enabled);
18542        cx.notify();
18543    }
18544
18545    fn should_show_indent_guides(&self) -> Option<bool> {
18546        self.show_indent_guides
18547    }
18548
18549    pub fn toggle_line_numbers(
18550        &mut self,
18551        _: &ToggleLineNumbers,
18552        _: &mut Window,
18553        cx: &mut Context<Self>,
18554    ) {
18555        let mut editor_settings = EditorSettings::get_global(cx).clone();
18556        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18557        EditorSettings::override_global(editor_settings, cx);
18558    }
18559
18560    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18561        if let Some(show_line_numbers) = self.show_line_numbers {
18562            return show_line_numbers;
18563        }
18564        EditorSettings::get_global(cx).gutter.line_numbers
18565    }
18566
18567    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18568        self.use_relative_line_numbers
18569            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18570    }
18571
18572    pub fn toggle_relative_line_numbers(
18573        &mut self,
18574        _: &ToggleRelativeLineNumbers,
18575        _: &mut Window,
18576        cx: &mut Context<Self>,
18577    ) {
18578        let is_relative = self.should_use_relative_line_numbers(cx);
18579        self.set_relative_line_number(Some(!is_relative), cx)
18580    }
18581
18582    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18583        self.use_relative_line_numbers = is_relative;
18584        cx.notify();
18585    }
18586
18587    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18588        self.show_gutter = show_gutter;
18589        cx.notify();
18590    }
18591
18592    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18593        self.show_scrollbars = ScrollbarAxes {
18594            horizontal: show,
18595            vertical: show,
18596        };
18597        cx.notify();
18598    }
18599
18600    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18601        self.show_scrollbars.vertical = show;
18602        cx.notify();
18603    }
18604
18605    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18606        self.show_scrollbars.horizontal = show;
18607        cx.notify();
18608    }
18609
18610    pub fn set_minimap_visibility(
18611        &mut self,
18612        minimap_visibility: MinimapVisibility,
18613        window: &mut Window,
18614        cx: &mut Context<Self>,
18615    ) {
18616        if self.minimap_visibility != minimap_visibility {
18617            if minimap_visibility.visible() && self.minimap.is_none() {
18618                let minimap_settings = EditorSettings::get_global(cx).minimap;
18619                self.minimap =
18620                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18621            }
18622            self.minimap_visibility = minimap_visibility;
18623            cx.notify();
18624        }
18625    }
18626
18627    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18628        self.set_show_scrollbars(false, cx);
18629        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18630    }
18631
18632    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18633        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18634    }
18635
18636    /// Normally the text in full mode and auto height editors is padded on the
18637    /// left side by roughly half a character width for improved hit testing.
18638    ///
18639    /// Use this method to disable this for cases where this is not wanted (e.g.
18640    /// if you want to align the editor text with some other text above or below)
18641    /// or if you want to add this padding to single-line editors.
18642    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18643        self.offset_content = offset_content;
18644        cx.notify();
18645    }
18646
18647    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18648        self.show_line_numbers = Some(show_line_numbers);
18649        cx.notify();
18650    }
18651
18652    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18653        self.disable_expand_excerpt_buttons = true;
18654        cx.notify();
18655    }
18656
18657    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18658        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18659        cx.notify();
18660    }
18661
18662    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18663        self.show_code_actions = Some(show_code_actions);
18664        cx.notify();
18665    }
18666
18667    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18668        self.show_runnables = Some(show_runnables);
18669        cx.notify();
18670    }
18671
18672    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18673        self.show_breakpoints = Some(show_breakpoints);
18674        cx.notify();
18675    }
18676
18677    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18678        if self.display_map.read(cx).masked != masked {
18679            self.display_map.update(cx, |map, _| map.masked = masked);
18680        }
18681        cx.notify()
18682    }
18683
18684    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18685        self.show_wrap_guides = Some(show_wrap_guides);
18686        cx.notify();
18687    }
18688
18689    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18690        self.show_indent_guides = Some(show_indent_guides);
18691        cx.notify();
18692    }
18693
18694    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18695        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18696            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18697                if let Some(dir) = file.abs_path(cx).parent() {
18698                    return Some(dir.to_owned());
18699                }
18700            }
18701
18702            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18703                return Some(project_path.path.to_path_buf());
18704            }
18705        }
18706
18707        None
18708    }
18709
18710    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18711        self.active_excerpt(cx)?
18712            .1
18713            .read(cx)
18714            .file()
18715            .and_then(|f| f.as_local())
18716    }
18717
18718    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18719        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18720            let buffer = buffer.read(cx);
18721            if let Some(project_path) = buffer.project_path(cx) {
18722                let project = self.project()?.read(cx);
18723                project.absolute_path(&project_path, cx)
18724            } else {
18725                buffer
18726                    .file()
18727                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18728            }
18729        })
18730    }
18731
18732    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18733        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18734            let project_path = buffer.read(cx).project_path(cx)?;
18735            let project = self.project()?.read(cx);
18736            let entry = project.entry_for_path(&project_path, cx)?;
18737            let path = entry.path.to_path_buf();
18738            Some(path)
18739        })
18740    }
18741
18742    pub fn reveal_in_finder(
18743        &mut self,
18744        _: &RevealInFileManager,
18745        _window: &mut Window,
18746        cx: &mut Context<Self>,
18747    ) {
18748        if let Some(target) = self.target_file(cx) {
18749            cx.reveal_path(&target.abs_path(cx));
18750        }
18751    }
18752
18753    pub fn copy_path(
18754        &mut self,
18755        _: &zed_actions::workspace::CopyPath,
18756        _window: &mut Window,
18757        cx: &mut Context<Self>,
18758    ) {
18759        if let Some(path) = self.target_file_abs_path(cx) {
18760            if let Some(path) = path.to_str() {
18761                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18762            }
18763        }
18764    }
18765
18766    pub fn copy_relative_path(
18767        &mut self,
18768        _: &zed_actions::workspace::CopyRelativePath,
18769        _window: &mut Window,
18770        cx: &mut Context<Self>,
18771    ) {
18772        if let Some(path) = self.target_file_path(cx) {
18773            if let Some(path) = path.to_str() {
18774                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18775            }
18776        }
18777    }
18778
18779    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18780        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18781            buffer.read(cx).project_path(cx)
18782        } else {
18783            None
18784        }
18785    }
18786
18787    // Returns true if the editor handled a go-to-line request
18788    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18789        maybe!({
18790            let breakpoint_store = self.breakpoint_store.as_ref()?;
18791
18792            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18793            else {
18794                self.clear_row_highlights::<ActiveDebugLine>();
18795                return None;
18796            };
18797
18798            let position = active_stack_frame.position;
18799            let buffer_id = position.buffer_id?;
18800            let snapshot = self
18801                .project
18802                .as_ref()?
18803                .read(cx)
18804                .buffer_for_id(buffer_id, cx)?
18805                .read(cx)
18806                .snapshot();
18807
18808            let mut handled = false;
18809            for (id, ExcerptRange { context, .. }) in
18810                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18811            {
18812                if context.start.cmp(&position, &snapshot).is_ge()
18813                    || context.end.cmp(&position, &snapshot).is_lt()
18814                {
18815                    continue;
18816                }
18817                let snapshot = self.buffer.read(cx).snapshot(cx);
18818                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18819
18820                handled = true;
18821                self.clear_row_highlights::<ActiveDebugLine>();
18822
18823                self.go_to_line::<ActiveDebugLine>(
18824                    multibuffer_anchor,
18825                    Some(cx.theme().colors().editor_debugger_active_line_background),
18826                    window,
18827                    cx,
18828                );
18829
18830                cx.notify();
18831            }
18832
18833            handled.then_some(())
18834        })
18835        .is_some()
18836    }
18837
18838    pub fn copy_file_name_without_extension(
18839        &mut self,
18840        _: &CopyFileNameWithoutExtension,
18841        _: &mut Window,
18842        cx: &mut Context<Self>,
18843    ) {
18844        if let Some(file) = self.target_file(cx) {
18845            if let Some(file_stem) = file.path().file_stem() {
18846                if let Some(name) = file_stem.to_str() {
18847                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18848                }
18849            }
18850        }
18851    }
18852
18853    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18854        if let Some(file) = self.target_file(cx) {
18855            if let Some(file_name) = file.path().file_name() {
18856                if let Some(name) = file_name.to_str() {
18857                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18858                }
18859            }
18860        }
18861    }
18862
18863    pub fn toggle_git_blame(
18864        &mut self,
18865        _: &::git::Blame,
18866        window: &mut Window,
18867        cx: &mut Context<Self>,
18868    ) {
18869        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18870
18871        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18872            self.start_git_blame(true, window, cx);
18873        }
18874
18875        cx.notify();
18876    }
18877
18878    pub fn toggle_git_blame_inline(
18879        &mut self,
18880        _: &ToggleGitBlameInline,
18881        window: &mut Window,
18882        cx: &mut Context<Self>,
18883    ) {
18884        self.toggle_git_blame_inline_internal(true, window, cx);
18885        cx.notify();
18886    }
18887
18888    pub fn open_git_blame_commit(
18889        &mut self,
18890        _: &OpenGitBlameCommit,
18891        window: &mut Window,
18892        cx: &mut Context<Self>,
18893    ) {
18894        self.open_git_blame_commit_internal(window, cx);
18895    }
18896
18897    fn open_git_blame_commit_internal(
18898        &mut self,
18899        window: &mut Window,
18900        cx: &mut Context<Self>,
18901    ) -> Option<()> {
18902        let blame = self.blame.as_ref()?;
18903        let snapshot = self.snapshot(window, cx);
18904        let cursor = self.selections.newest::<Point>(cx).head();
18905        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18906        let blame_entry = blame
18907            .update(cx, |blame, cx| {
18908                blame
18909                    .blame_for_rows(
18910                        &[RowInfo {
18911                            buffer_id: Some(buffer.remote_id()),
18912                            buffer_row: Some(point.row),
18913                            ..Default::default()
18914                        }],
18915                        cx,
18916                    )
18917                    .next()
18918            })
18919            .flatten()?;
18920        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18921        let repo = blame.read(cx).repository(cx)?;
18922        let workspace = self.workspace()?.downgrade();
18923        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18924        None
18925    }
18926
18927    pub fn git_blame_inline_enabled(&self) -> bool {
18928        self.git_blame_inline_enabled
18929    }
18930
18931    pub fn toggle_selection_menu(
18932        &mut self,
18933        _: &ToggleSelectionMenu,
18934        _: &mut Window,
18935        cx: &mut Context<Self>,
18936    ) {
18937        self.show_selection_menu = self
18938            .show_selection_menu
18939            .map(|show_selections_menu| !show_selections_menu)
18940            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18941
18942        cx.notify();
18943    }
18944
18945    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18946        self.show_selection_menu
18947            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18948    }
18949
18950    fn start_git_blame(
18951        &mut self,
18952        user_triggered: bool,
18953        window: &mut Window,
18954        cx: &mut Context<Self>,
18955    ) {
18956        if let Some(project) = self.project() {
18957            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18958                return;
18959            };
18960
18961            if buffer.read(cx).file().is_none() {
18962                return;
18963            }
18964
18965            let focused = self.focus_handle(cx).contains_focused(window, cx);
18966
18967            let project = project.clone();
18968            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18969            self.blame_subscription =
18970                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18971            self.blame = Some(blame);
18972        }
18973    }
18974
18975    fn toggle_git_blame_inline_internal(
18976        &mut self,
18977        user_triggered: bool,
18978        window: &mut Window,
18979        cx: &mut Context<Self>,
18980    ) {
18981        if self.git_blame_inline_enabled {
18982            self.git_blame_inline_enabled = false;
18983            self.show_git_blame_inline = false;
18984            self.show_git_blame_inline_delay_task.take();
18985        } else {
18986            self.git_blame_inline_enabled = true;
18987            self.start_git_blame_inline(user_triggered, window, cx);
18988        }
18989
18990        cx.notify();
18991    }
18992
18993    fn start_git_blame_inline(
18994        &mut self,
18995        user_triggered: bool,
18996        window: &mut Window,
18997        cx: &mut Context<Self>,
18998    ) {
18999        self.start_git_blame(user_triggered, window, cx);
19000
19001        if ProjectSettings::get_global(cx)
19002            .git
19003            .inline_blame_delay()
19004            .is_some()
19005        {
19006            self.start_inline_blame_timer(window, cx);
19007        } else {
19008            self.show_git_blame_inline = true
19009        }
19010    }
19011
19012    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19013        self.blame.as_ref()
19014    }
19015
19016    pub fn show_git_blame_gutter(&self) -> bool {
19017        self.show_git_blame_gutter
19018    }
19019
19020    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19021        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19022    }
19023
19024    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19025        self.show_git_blame_inline
19026            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19027            && !self.newest_selection_head_on_empty_line(cx)
19028            && self.has_blame_entries(cx)
19029    }
19030
19031    fn has_blame_entries(&self, cx: &App) -> bool {
19032        self.blame()
19033            .map_or(false, |blame| blame.read(cx).has_generated_entries())
19034    }
19035
19036    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19037        let cursor_anchor = self.selections.newest_anchor().head();
19038
19039        let snapshot = self.buffer.read(cx).snapshot(cx);
19040        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19041
19042        snapshot.line_len(buffer_row) == 0
19043    }
19044
19045    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19046        let buffer_and_selection = maybe!({
19047            let selection = self.selections.newest::<Point>(cx);
19048            let selection_range = selection.range();
19049
19050            let multi_buffer = self.buffer().read(cx);
19051            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19052            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19053
19054            let (buffer, range, _) = if selection.reversed {
19055                buffer_ranges.first()
19056            } else {
19057                buffer_ranges.last()
19058            }?;
19059
19060            let selection = text::ToPoint::to_point(&range.start, buffer).row
19061                ..text::ToPoint::to_point(&range.end, buffer).row;
19062            Some((
19063                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
19064                selection,
19065            ))
19066        });
19067
19068        let Some((buffer, selection)) = buffer_and_selection else {
19069            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19070        };
19071
19072        let Some(project) = self.project() else {
19073            return Task::ready(Err(anyhow!("editor does not have project")));
19074        };
19075
19076        project.update(cx, |project, cx| {
19077            project.get_permalink_to_line(&buffer, selection, cx)
19078        })
19079    }
19080
19081    pub fn copy_permalink_to_line(
19082        &mut self,
19083        _: &CopyPermalinkToLine,
19084        window: &mut Window,
19085        cx: &mut Context<Self>,
19086    ) {
19087        let permalink_task = self.get_permalink_to_line(cx);
19088        let workspace = self.workspace();
19089
19090        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19091            Ok(permalink) => {
19092                cx.update(|_, cx| {
19093                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19094                })
19095                .ok();
19096            }
19097            Err(err) => {
19098                let message = format!("Failed to copy permalink: {err}");
19099
19100                anyhow::Result::<()>::Err(err).log_err();
19101
19102                if let Some(workspace) = workspace {
19103                    workspace
19104                        .update_in(cx, |workspace, _, cx| {
19105                            struct CopyPermalinkToLine;
19106
19107                            workspace.show_toast(
19108                                Toast::new(
19109                                    NotificationId::unique::<CopyPermalinkToLine>(),
19110                                    message,
19111                                ),
19112                                cx,
19113                            )
19114                        })
19115                        .ok();
19116                }
19117            }
19118        })
19119        .detach();
19120    }
19121
19122    pub fn copy_file_location(
19123        &mut self,
19124        _: &CopyFileLocation,
19125        _: &mut Window,
19126        cx: &mut Context<Self>,
19127    ) {
19128        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19129        if let Some(file) = self.target_file(cx) {
19130            if let Some(path) = file.path().to_str() {
19131                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19132            }
19133        }
19134    }
19135
19136    pub fn open_permalink_to_line(
19137        &mut self,
19138        _: &OpenPermalinkToLine,
19139        window: &mut Window,
19140        cx: &mut Context<Self>,
19141    ) {
19142        let permalink_task = self.get_permalink_to_line(cx);
19143        let workspace = self.workspace();
19144
19145        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19146            Ok(permalink) => {
19147                cx.update(|_, cx| {
19148                    cx.open_url(permalink.as_ref());
19149                })
19150                .ok();
19151            }
19152            Err(err) => {
19153                let message = format!("Failed to open permalink: {err}");
19154
19155                anyhow::Result::<()>::Err(err).log_err();
19156
19157                if let Some(workspace) = workspace {
19158                    workspace
19159                        .update(cx, |workspace, cx| {
19160                            struct OpenPermalinkToLine;
19161
19162                            workspace.show_toast(
19163                                Toast::new(
19164                                    NotificationId::unique::<OpenPermalinkToLine>(),
19165                                    message,
19166                                ),
19167                                cx,
19168                            )
19169                        })
19170                        .ok();
19171                }
19172            }
19173        })
19174        .detach();
19175    }
19176
19177    pub fn insert_uuid_v4(
19178        &mut self,
19179        _: &InsertUuidV4,
19180        window: &mut Window,
19181        cx: &mut Context<Self>,
19182    ) {
19183        self.insert_uuid(UuidVersion::V4, window, cx);
19184    }
19185
19186    pub fn insert_uuid_v7(
19187        &mut self,
19188        _: &InsertUuidV7,
19189        window: &mut Window,
19190        cx: &mut Context<Self>,
19191    ) {
19192        self.insert_uuid(UuidVersion::V7, window, cx);
19193    }
19194
19195    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19196        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19197        self.transact(window, cx, |this, window, cx| {
19198            let edits = this
19199                .selections
19200                .all::<Point>(cx)
19201                .into_iter()
19202                .map(|selection| {
19203                    let uuid = match version {
19204                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19205                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19206                    };
19207
19208                    (selection.range(), uuid.to_string())
19209                });
19210            this.edit(edits, cx);
19211            this.refresh_edit_prediction(true, false, window, cx);
19212        });
19213    }
19214
19215    pub fn open_selections_in_multibuffer(
19216        &mut self,
19217        _: &OpenSelectionsInMultibuffer,
19218        window: &mut Window,
19219        cx: &mut Context<Self>,
19220    ) {
19221        let multibuffer = self.buffer.read(cx);
19222
19223        let Some(buffer) = multibuffer.as_singleton() else {
19224            return;
19225        };
19226
19227        let Some(workspace) = self.workspace() else {
19228            return;
19229        };
19230
19231        let title = multibuffer.title(cx).to_string();
19232
19233        let locations = self
19234            .selections
19235            .all_anchors(cx)
19236            .into_iter()
19237            .map(|selection| Location {
19238                buffer: buffer.clone(),
19239                range: selection.start.text_anchor..selection.end.text_anchor,
19240            })
19241            .collect::<Vec<_>>();
19242
19243        cx.spawn_in(window, async move |_, cx| {
19244            workspace.update_in(cx, |workspace, window, cx| {
19245                Self::open_locations_in_multibuffer(
19246                    workspace,
19247                    locations,
19248                    format!("Selections for '{title}'"),
19249                    false,
19250                    MultibufferSelectionMode::All,
19251                    window,
19252                    cx,
19253                );
19254            })
19255        })
19256        .detach();
19257    }
19258
19259    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19260    /// last highlight added will be used.
19261    ///
19262    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19263    pub fn highlight_rows<T: 'static>(
19264        &mut self,
19265        range: Range<Anchor>,
19266        color: Hsla,
19267        options: RowHighlightOptions,
19268        cx: &mut Context<Self>,
19269    ) {
19270        let snapshot = self.buffer().read(cx).snapshot(cx);
19271        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19272        let ix = row_highlights.binary_search_by(|highlight| {
19273            Ordering::Equal
19274                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19275                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19276        });
19277
19278        if let Err(mut ix) = ix {
19279            let index = post_inc(&mut self.highlight_order);
19280
19281            // If this range intersects with the preceding highlight, then merge it with
19282            // the preceding highlight. Otherwise insert a new highlight.
19283            let mut merged = false;
19284            if ix > 0 {
19285                let prev_highlight = &mut row_highlights[ix - 1];
19286                if prev_highlight
19287                    .range
19288                    .end
19289                    .cmp(&range.start, &snapshot)
19290                    .is_ge()
19291                {
19292                    ix -= 1;
19293                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19294                        prev_highlight.range.end = range.end;
19295                    }
19296                    merged = true;
19297                    prev_highlight.index = index;
19298                    prev_highlight.color = color;
19299                    prev_highlight.options = options;
19300                }
19301            }
19302
19303            if !merged {
19304                row_highlights.insert(
19305                    ix,
19306                    RowHighlight {
19307                        range: range.clone(),
19308                        index,
19309                        color,
19310                        options,
19311                        type_id: TypeId::of::<T>(),
19312                    },
19313                );
19314            }
19315
19316            // If any of the following highlights intersect with this one, merge them.
19317            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19318                let highlight = &row_highlights[ix];
19319                if next_highlight
19320                    .range
19321                    .start
19322                    .cmp(&highlight.range.end, &snapshot)
19323                    .is_le()
19324                {
19325                    if next_highlight
19326                        .range
19327                        .end
19328                        .cmp(&highlight.range.end, &snapshot)
19329                        .is_gt()
19330                    {
19331                        row_highlights[ix].range.end = next_highlight.range.end;
19332                    }
19333                    row_highlights.remove(ix + 1);
19334                } else {
19335                    break;
19336                }
19337            }
19338        }
19339    }
19340
19341    /// Remove any highlighted row ranges of the given type that intersect the
19342    /// given ranges.
19343    pub fn remove_highlighted_rows<T: 'static>(
19344        &mut self,
19345        ranges_to_remove: Vec<Range<Anchor>>,
19346        cx: &mut Context<Self>,
19347    ) {
19348        let snapshot = self.buffer().read(cx).snapshot(cx);
19349        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19350        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19351        row_highlights.retain(|highlight| {
19352            while let Some(range_to_remove) = ranges_to_remove.peek() {
19353                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19354                    Ordering::Less | Ordering::Equal => {
19355                        ranges_to_remove.next();
19356                    }
19357                    Ordering::Greater => {
19358                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19359                            Ordering::Less | Ordering::Equal => {
19360                                return false;
19361                            }
19362                            Ordering::Greater => break,
19363                        }
19364                    }
19365                }
19366            }
19367
19368            true
19369        })
19370    }
19371
19372    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19373    pub fn clear_row_highlights<T: 'static>(&mut self) {
19374        self.highlighted_rows.remove(&TypeId::of::<T>());
19375    }
19376
19377    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19378    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19379        self.highlighted_rows
19380            .get(&TypeId::of::<T>())
19381            .map_or(&[] as &[_], |vec| vec.as_slice())
19382            .iter()
19383            .map(|highlight| (highlight.range.clone(), highlight.color))
19384    }
19385
19386    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19387    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19388    /// Allows to ignore certain kinds of highlights.
19389    pub fn highlighted_display_rows(
19390        &self,
19391        window: &mut Window,
19392        cx: &mut App,
19393    ) -> BTreeMap<DisplayRow, LineHighlight> {
19394        let snapshot = self.snapshot(window, cx);
19395        let mut used_highlight_orders = HashMap::default();
19396        self.highlighted_rows
19397            .iter()
19398            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19399            .fold(
19400                BTreeMap::<DisplayRow, LineHighlight>::new(),
19401                |mut unique_rows, highlight| {
19402                    let start = highlight.range.start.to_display_point(&snapshot);
19403                    let end = highlight.range.end.to_display_point(&snapshot);
19404                    let start_row = start.row().0;
19405                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19406                        && end.column() == 0
19407                    {
19408                        end.row().0.saturating_sub(1)
19409                    } else {
19410                        end.row().0
19411                    };
19412                    for row in start_row..=end_row {
19413                        let used_index =
19414                            used_highlight_orders.entry(row).or_insert(highlight.index);
19415                        if highlight.index >= *used_index {
19416                            *used_index = highlight.index;
19417                            unique_rows.insert(
19418                                DisplayRow(row),
19419                                LineHighlight {
19420                                    include_gutter: highlight.options.include_gutter,
19421                                    border: None,
19422                                    background: highlight.color.into(),
19423                                    type_id: Some(highlight.type_id),
19424                                },
19425                            );
19426                        }
19427                    }
19428                    unique_rows
19429                },
19430            )
19431    }
19432
19433    pub fn highlighted_display_row_for_autoscroll(
19434        &self,
19435        snapshot: &DisplaySnapshot,
19436    ) -> Option<DisplayRow> {
19437        self.highlighted_rows
19438            .values()
19439            .flat_map(|highlighted_rows| highlighted_rows.iter())
19440            .filter_map(|highlight| {
19441                if highlight.options.autoscroll {
19442                    Some(highlight.range.start.to_display_point(snapshot).row())
19443                } else {
19444                    None
19445                }
19446            })
19447            .min()
19448    }
19449
19450    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19451        self.highlight_background::<SearchWithinRange>(
19452            ranges,
19453            |colors| colors.colors().editor_document_highlight_read_background,
19454            cx,
19455        )
19456    }
19457
19458    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19459        self.breadcrumb_header = Some(new_header);
19460    }
19461
19462    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19463        self.clear_background_highlights::<SearchWithinRange>(cx);
19464    }
19465
19466    pub fn highlight_background<T: 'static>(
19467        &mut self,
19468        ranges: &[Range<Anchor>],
19469        color_fetcher: fn(&Theme) -> Hsla,
19470        cx: &mut Context<Self>,
19471    ) {
19472        self.background_highlights.insert(
19473            HighlightKey::Type(TypeId::of::<T>()),
19474            (color_fetcher, Arc::from(ranges)),
19475        );
19476        self.scrollbar_marker_state.dirty = true;
19477        cx.notify();
19478    }
19479
19480    pub fn highlight_background_key<T: 'static>(
19481        &mut self,
19482        key: usize,
19483        ranges: &[Range<Anchor>],
19484        color_fetcher: fn(&Theme) -> Hsla,
19485        cx: &mut Context<Self>,
19486    ) {
19487        self.background_highlights.insert(
19488            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19489            (color_fetcher, Arc::from(ranges)),
19490        );
19491        self.scrollbar_marker_state.dirty = true;
19492        cx.notify();
19493    }
19494
19495    pub fn clear_background_highlights<T: 'static>(
19496        &mut self,
19497        cx: &mut Context<Self>,
19498    ) -> Option<BackgroundHighlight> {
19499        let text_highlights = self
19500            .background_highlights
19501            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19502        if !text_highlights.1.is_empty() {
19503            self.scrollbar_marker_state.dirty = true;
19504            cx.notify();
19505        }
19506        Some(text_highlights)
19507    }
19508
19509    pub fn highlight_gutter<T: 'static>(
19510        &mut self,
19511        ranges: impl Into<Vec<Range<Anchor>>>,
19512        color_fetcher: fn(&App) -> Hsla,
19513        cx: &mut Context<Self>,
19514    ) {
19515        self.gutter_highlights
19516            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19517        cx.notify();
19518    }
19519
19520    pub fn clear_gutter_highlights<T: 'static>(
19521        &mut self,
19522        cx: &mut Context<Self>,
19523    ) -> Option<GutterHighlight> {
19524        cx.notify();
19525        self.gutter_highlights.remove(&TypeId::of::<T>())
19526    }
19527
19528    pub fn insert_gutter_highlight<T: 'static>(
19529        &mut self,
19530        range: Range<Anchor>,
19531        color_fetcher: fn(&App) -> Hsla,
19532        cx: &mut Context<Self>,
19533    ) {
19534        let snapshot = self.buffer().read(cx).snapshot(cx);
19535        let mut highlights = self
19536            .gutter_highlights
19537            .remove(&TypeId::of::<T>())
19538            .map(|(_, highlights)| highlights)
19539            .unwrap_or_default();
19540        let ix = highlights.binary_search_by(|highlight| {
19541            Ordering::Equal
19542                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19543                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19544        });
19545        if let Err(ix) = ix {
19546            highlights.insert(ix, range);
19547        }
19548        self.gutter_highlights
19549            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19550    }
19551
19552    pub fn remove_gutter_highlights<T: 'static>(
19553        &mut self,
19554        ranges_to_remove: Vec<Range<Anchor>>,
19555        cx: &mut Context<Self>,
19556    ) {
19557        let snapshot = self.buffer().read(cx).snapshot(cx);
19558        let Some((color_fetcher, mut gutter_highlights)) =
19559            self.gutter_highlights.remove(&TypeId::of::<T>())
19560        else {
19561            return;
19562        };
19563        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19564        gutter_highlights.retain(|highlight| {
19565            while let Some(range_to_remove) = ranges_to_remove.peek() {
19566                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19567                    Ordering::Less | Ordering::Equal => {
19568                        ranges_to_remove.next();
19569                    }
19570                    Ordering::Greater => {
19571                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19572                            Ordering::Less | Ordering::Equal => {
19573                                return false;
19574                            }
19575                            Ordering::Greater => break,
19576                        }
19577                    }
19578                }
19579            }
19580
19581            true
19582        });
19583        self.gutter_highlights
19584            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19585    }
19586
19587    #[cfg(feature = "test-support")]
19588    pub fn all_text_highlights(
19589        &self,
19590        window: &mut Window,
19591        cx: &mut Context<Self>,
19592    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19593        let snapshot = self.snapshot(window, cx);
19594        self.display_map.update(cx, |display_map, _| {
19595            display_map
19596                .all_text_highlights()
19597                .map(|highlight| {
19598                    let (style, ranges) = highlight.as_ref();
19599                    (
19600                        *style,
19601                        ranges
19602                            .iter()
19603                            .map(|range| range.clone().to_display_points(&snapshot))
19604                            .collect(),
19605                    )
19606                })
19607                .collect()
19608        })
19609    }
19610
19611    #[cfg(feature = "test-support")]
19612    pub fn all_text_background_highlights(
19613        &self,
19614        window: &mut Window,
19615        cx: &mut Context<Self>,
19616    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19617        let snapshot = self.snapshot(window, cx);
19618        let buffer = &snapshot.buffer_snapshot;
19619        let start = buffer.anchor_before(0);
19620        let end = buffer.anchor_after(buffer.len());
19621        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19622    }
19623
19624    #[cfg(feature = "test-support")]
19625    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19626        let snapshot = self.buffer().read(cx).snapshot(cx);
19627
19628        let highlights = self
19629            .background_highlights
19630            .get(&HighlightKey::Type(TypeId::of::<
19631                items::BufferSearchHighlights,
19632            >()));
19633
19634        if let Some((_color, ranges)) = highlights {
19635            ranges
19636                .iter()
19637                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19638                .collect_vec()
19639        } else {
19640            vec![]
19641        }
19642    }
19643
19644    fn document_highlights_for_position<'a>(
19645        &'a self,
19646        position: Anchor,
19647        buffer: &'a MultiBufferSnapshot,
19648    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19649        let read_highlights = self
19650            .background_highlights
19651            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19652            .map(|h| &h.1);
19653        let write_highlights = self
19654            .background_highlights
19655            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19656            .map(|h| &h.1);
19657        let left_position = position.bias_left(buffer);
19658        let right_position = position.bias_right(buffer);
19659        read_highlights
19660            .into_iter()
19661            .chain(write_highlights)
19662            .flat_map(move |ranges| {
19663                let start_ix = match ranges.binary_search_by(|probe| {
19664                    let cmp = probe.end.cmp(&left_position, buffer);
19665                    if cmp.is_ge() {
19666                        Ordering::Greater
19667                    } else {
19668                        Ordering::Less
19669                    }
19670                }) {
19671                    Ok(i) | Err(i) => i,
19672                };
19673
19674                ranges[start_ix..]
19675                    .iter()
19676                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19677            })
19678    }
19679
19680    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19681        self.background_highlights
19682            .get(&HighlightKey::Type(TypeId::of::<T>()))
19683            .map_or(false, |(_, highlights)| !highlights.is_empty())
19684    }
19685
19686    pub fn background_highlights_in_range(
19687        &self,
19688        search_range: Range<Anchor>,
19689        display_snapshot: &DisplaySnapshot,
19690        theme: &Theme,
19691    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19692        let mut results = Vec::new();
19693        for (color_fetcher, ranges) in self.background_highlights.values() {
19694            let color = color_fetcher(theme);
19695            let start_ix = match ranges.binary_search_by(|probe| {
19696                let cmp = probe
19697                    .end
19698                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19699                if cmp.is_gt() {
19700                    Ordering::Greater
19701                } else {
19702                    Ordering::Less
19703                }
19704            }) {
19705                Ok(i) | Err(i) => i,
19706            };
19707            for range in &ranges[start_ix..] {
19708                if range
19709                    .start
19710                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19711                    .is_ge()
19712                {
19713                    break;
19714                }
19715
19716                let start = range.start.to_display_point(display_snapshot);
19717                let end = range.end.to_display_point(display_snapshot);
19718                results.push((start..end, color))
19719            }
19720        }
19721        results
19722    }
19723
19724    pub fn background_highlight_row_ranges<T: 'static>(
19725        &self,
19726        search_range: Range<Anchor>,
19727        display_snapshot: &DisplaySnapshot,
19728        count: usize,
19729    ) -> Vec<RangeInclusive<DisplayPoint>> {
19730        let mut results = Vec::new();
19731        let Some((_, ranges)) = self
19732            .background_highlights
19733            .get(&HighlightKey::Type(TypeId::of::<T>()))
19734        else {
19735            return vec![];
19736        };
19737
19738        let start_ix = match ranges.binary_search_by(|probe| {
19739            let cmp = probe
19740                .end
19741                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19742            if cmp.is_gt() {
19743                Ordering::Greater
19744            } else {
19745                Ordering::Less
19746            }
19747        }) {
19748            Ok(i) | Err(i) => i,
19749        };
19750        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19751            if let (Some(start_display), Some(end_display)) = (start, end) {
19752                results.push(
19753                    start_display.to_display_point(display_snapshot)
19754                        ..=end_display.to_display_point(display_snapshot),
19755                );
19756            }
19757        };
19758        let mut start_row: Option<Point> = None;
19759        let mut end_row: Option<Point> = None;
19760        if ranges.len() > count {
19761            return Vec::new();
19762        }
19763        for range in &ranges[start_ix..] {
19764            if range
19765                .start
19766                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19767                .is_ge()
19768            {
19769                break;
19770            }
19771            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19772            if let Some(current_row) = &end_row {
19773                if end.row == current_row.row {
19774                    continue;
19775                }
19776            }
19777            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19778            if start_row.is_none() {
19779                assert_eq!(end_row, None);
19780                start_row = Some(start);
19781                end_row = Some(end);
19782                continue;
19783            }
19784            if let Some(current_end) = end_row.as_mut() {
19785                if start.row > current_end.row + 1 {
19786                    push_region(start_row, end_row);
19787                    start_row = Some(start);
19788                    end_row = Some(end);
19789                } else {
19790                    // Merge two hunks.
19791                    *current_end = end;
19792                }
19793            } else {
19794                unreachable!();
19795            }
19796        }
19797        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19798        push_region(start_row, end_row);
19799        results
19800    }
19801
19802    pub fn gutter_highlights_in_range(
19803        &self,
19804        search_range: Range<Anchor>,
19805        display_snapshot: &DisplaySnapshot,
19806        cx: &App,
19807    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19808        let mut results = Vec::new();
19809        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19810            let color = color_fetcher(cx);
19811            let start_ix = match ranges.binary_search_by(|probe| {
19812                let cmp = probe
19813                    .end
19814                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19815                if cmp.is_gt() {
19816                    Ordering::Greater
19817                } else {
19818                    Ordering::Less
19819                }
19820            }) {
19821                Ok(i) | Err(i) => i,
19822            };
19823            for range in &ranges[start_ix..] {
19824                if range
19825                    .start
19826                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19827                    .is_ge()
19828                {
19829                    break;
19830                }
19831
19832                let start = range.start.to_display_point(display_snapshot);
19833                let end = range.end.to_display_point(display_snapshot);
19834                results.push((start..end, color))
19835            }
19836        }
19837        results
19838    }
19839
19840    /// Get the text ranges corresponding to the redaction query
19841    pub fn redacted_ranges(
19842        &self,
19843        search_range: Range<Anchor>,
19844        display_snapshot: &DisplaySnapshot,
19845        cx: &App,
19846    ) -> Vec<Range<DisplayPoint>> {
19847        display_snapshot
19848            .buffer_snapshot
19849            .redacted_ranges(search_range, |file| {
19850                if let Some(file) = file {
19851                    file.is_private()
19852                        && EditorSettings::get(
19853                            Some(SettingsLocation {
19854                                worktree_id: file.worktree_id(cx),
19855                                path: file.path().as_ref(),
19856                            }),
19857                            cx,
19858                        )
19859                        .redact_private_values
19860                } else {
19861                    false
19862                }
19863            })
19864            .map(|range| {
19865                range.start.to_display_point(display_snapshot)
19866                    ..range.end.to_display_point(display_snapshot)
19867            })
19868            .collect()
19869    }
19870
19871    pub fn highlight_text_key<T: 'static>(
19872        &mut self,
19873        key: usize,
19874        ranges: Vec<Range<Anchor>>,
19875        style: HighlightStyle,
19876        cx: &mut Context<Self>,
19877    ) {
19878        self.display_map.update(cx, |map, _| {
19879            map.highlight_text(
19880                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19881                ranges,
19882                style,
19883            );
19884        });
19885        cx.notify();
19886    }
19887
19888    pub fn highlight_text<T: 'static>(
19889        &mut self,
19890        ranges: Vec<Range<Anchor>>,
19891        style: HighlightStyle,
19892        cx: &mut Context<Self>,
19893    ) {
19894        self.display_map.update(cx, |map, _| {
19895            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19896        });
19897        cx.notify();
19898    }
19899
19900    pub(crate) fn highlight_inlays<T: 'static>(
19901        &mut self,
19902        highlights: Vec<InlayHighlight>,
19903        style: HighlightStyle,
19904        cx: &mut Context<Self>,
19905    ) {
19906        self.display_map.update(cx, |map, _| {
19907            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19908        });
19909        cx.notify();
19910    }
19911
19912    pub fn text_highlights<'a, T: 'static>(
19913        &'a self,
19914        cx: &'a App,
19915    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19916        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19917    }
19918
19919    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19920        let cleared = self
19921            .display_map
19922            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19923        if cleared {
19924            cx.notify();
19925        }
19926    }
19927
19928    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19929        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19930            && self.focus_handle.is_focused(window)
19931    }
19932
19933    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19934        self.show_cursor_when_unfocused = is_enabled;
19935        cx.notify();
19936    }
19937
19938    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19939        cx.notify();
19940    }
19941
19942    fn on_debug_session_event(
19943        &mut self,
19944        _session: Entity<Session>,
19945        event: &SessionEvent,
19946        cx: &mut Context<Self>,
19947    ) {
19948        match event {
19949            SessionEvent::InvalidateInlineValue => {
19950                self.refresh_inline_values(cx);
19951            }
19952            _ => {}
19953        }
19954    }
19955
19956    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19957        let Some(project) = self.project.clone() else {
19958            return;
19959        };
19960
19961        if !self.inline_value_cache.enabled {
19962            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19963            self.splice_inlays(&inlays, Vec::new(), cx);
19964            return;
19965        }
19966
19967        let current_execution_position = self
19968            .highlighted_rows
19969            .get(&TypeId::of::<ActiveDebugLine>())
19970            .and_then(|lines| lines.last().map(|line| line.range.end));
19971
19972        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19973            let inline_values = editor
19974                .update(cx, |editor, cx| {
19975                    let Some(current_execution_position) = current_execution_position else {
19976                        return Some(Task::ready(Ok(Vec::new())));
19977                    };
19978
19979                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19980                        let snapshot = buffer.snapshot(cx);
19981
19982                        let excerpt = snapshot.excerpt_containing(
19983                            current_execution_position..current_execution_position,
19984                        )?;
19985
19986                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19987                    })?;
19988
19989                    let range =
19990                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19991
19992                    project.inline_values(buffer, range, cx)
19993                })
19994                .ok()
19995                .flatten()?
19996                .await
19997                .context("refreshing debugger inlays")
19998                .log_err()?;
19999
20000            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20001
20002            for (buffer_id, inline_value) in inline_values
20003                .into_iter()
20004                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20005            {
20006                buffer_inline_values
20007                    .entry(buffer_id)
20008                    .or_default()
20009                    .push(inline_value);
20010            }
20011
20012            editor
20013                .update(cx, |editor, cx| {
20014                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20015                    let mut new_inlays = Vec::default();
20016
20017                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20018                        let buffer_id = buffer_snapshot.remote_id();
20019                        buffer_inline_values
20020                            .get(&buffer_id)
20021                            .into_iter()
20022                            .flatten()
20023                            .for_each(|hint| {
20024                                let inlay = Inlay::debugger(
20025                                    post_inc(&mut editor.next_inlay_id),
20026                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20027                                    hint.text(),
20028                                );
20029                                if !inlay.text.chars().contains(&'\n') {
20030                                    new_inlays.push(inlay);
20031                                }
20032                            });
20033                    }
20034
20035                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20036                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20037
20038                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20039                })
20040                .ok()?;
20041            Some(())
20042        });
20043    }
20044
20045    fn on_buffer_event(
20046        &mut self,
20047        multibuffer: &Entity<MultiBuffer>,
20048        event: &multi_buffer::Event,
20049        window: &mut Window,
20050        cx: &mut Context<Self>,
20051    ) {
20052        match event {
20053            multi_buffer::Event::Edited {
20054                singleton_buffer_edited,
20055                edited_buffer,
20056            } => {
20057                self.scrollbar_marker_state.dirty = true;
20058                self.active_indent_guides_state.dirty = true;
20059                self.refresh_active_diagnostics(cx);
20060                self.refresh_code_actions(window, cx);
20061                self.refresh_selected_text_highlights(true, window, cx);
20062                self.refresh_single_line_folds(window, cx);
20063                refresh_matching_bracket_highlights(self, window, cx);
20064                if self.has_active_edit_prediction() {
20065                    self.update_visible_edit_prediction(window, cx);
20066                }
20067                if let Some(project) = self.project.as_ref() {
20068                    if let Some(edited_buffer) = edited_buffer {
20069                        project.update(cx, |project, cx| {
20070                            self.registered_buffers
20071                                .entry(edited_buffer.read(cx).remote_id())
20072                                .or_insert_with(|| {
20073                                    project.register_buffer_with_language_servers(edited_buffer, cx)
20074                                });
20075                        });
20076                    }
20077                }
20078                cx.emit(EditorEvent::BufferEdited);
20079                cx.emit(SearchEvent::MatchesInvalidated);
20080
20081                if let Some(buffer) = edited_buffer {
20082                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20083                }
20084
20085                if *singleton_buffer_edited {
20086                    if let Some(buffer) = edited_buffer {
20087                        if buffer.read(cx).file().is_none() {
20088                            cx.emit(EditorEvent::TitleChanged);
20089                        }
20090                    }
20091                    if let Some(project) = &self.project {
20092                        #[allow(clippy::mutable_key_type)]
20093                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20094                            multibuffer
20095                                .all_buffers()
20096                                .into_iter()
20097                                .filter_map(|buffer| {
20098                                    buffer.update(cx, |buffer, cx| {
20099                                        let language = buffer.language()?;
20100                                        let should_discard = project.update(cx, |project, cx| {
20101                                            project.is_local()
20102                                                && !project.has_language_servers_for(buffer, cx)
20103                                        });
20104                                        should_discard.not().then_some(language.clone())
20105                                    })
20106                                })
20107                                .collect::<HashSet<_>>()
20108                        });
20109                        if !languages_affected.is_empty() {
20110                            self.refresh_inlay_hints(
20111                                InlayHintRefreshReason::BufferEdited(languages_affected),
20112                                cx,
20113                            );
20114                        }
20115                    }
20116                }
20117
20118                let Some(project) = &self.project else { return };
20119                let (telemetry, is_via_ssh) = {
20120                    let project = project.read(cx);
20121                    let telemetry = project.client().telemetry().clone();
20122                    let is_via_ssh = project.is_via_ssh();
20123                    (telemetry, is_via_ssh)
20124                };
20125                refresh_linked_ranges(self, window, cx);
20126                telemetry.log_edit_event("editor", is_via_ssh);
20127            }
20128            multi_buffer::Event::ExcerptsAdded {
20129                buffer,
20130                predecessor,
20131                excerpts,
20132            } => {
20133                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20134                let buffer_id = buffer.read(cx).remote_id();
20135                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
20136                    if let Some(project) = &self.project {
20137                        update_uncommitted_diff_for_buffer(
20138                            cx.entity(),
20139                            project,
20140                            [buffer.clone()],
20141                            self.buffer.clone(),
20142                            cx,
20143                        )
20144                        .detach();
20145                    }
20146                }
20147                self.update_lsp_data(false, Some(buffer_id), window, cx);
20148                cx.emit(EditorEvent::ExcerptsAdded {
20149                    buffer: buffer.clone(),
20150                    predecessor: *predecessor,
20151                    excerpts: excerpts.clone(),
20152                });
20153                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20154            }
20155            multi_buffer::Event::ExcerptsRemoved {
20156                ids,
20157                removed_buffer_ids,
20158            } => {
20159                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20160                let buffer = self.buffer.read(cx);
20161                self.registered_buffers
20162                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20163                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20164                cx.emit(EditorEvent::ExcerptsRemoved {
20165                    ids: ids.clone(),
20166                    removed_buffer_ids: removed_buffer_ids.clone(),
20167                });
20168            }
20169            multi_buffer::Event::ExcerptsEdited {
20170                excerpt_ids,
20171                buffer_ids,
20172            } => {
20173                self.display_map.update(cx, |map, cx| {
20174                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20175                });
20176                cx.emit(EditorEvent::ExcerptsEdited {
20177                    ids: excerpt_ids.clone(),
20178                });
20179            }
20180            multi_buffer::Event::ExcerptsExpanded { ids } => {
20181                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20182                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20183            }
20184            multi_buffer::Event::Reparsed(buffer_id) => {
20185                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20186                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20187
20188                cx.emit(EditorEvent::Reparsed(*buffer_id));
20189            }
20190            multi_buffer::Event::DiffHunksToggled => {
20191                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20192            }
20193            multi_buffer::Event::LanguageChanged(buffer_id) => {
20194                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20195                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20196                cx.emit(EditorEvent::Reparsed(*buffer_id));
20197                cx.notify();
20198            }
20199            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20200            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20201            multi_buffer::Event::FileHandleChanged
20202            | multi_buffer::Event::Reloaded
20203            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20204            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20205            multi_buffer::Event::DiagnosticsUpdated => {
20206                self.update_diagnostics_state(window, cx);
20207            }
20208            _ => {}
20209        };
20210    }
20211
20212    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20213        if !self.diagnostics_enabled() {
20214            return;
20215        }
20216        self.refresh_active_diagnostics(cx);
20217        self.refresh_inline_diagnostics(true, window, cx);
20218        self.scrollbar_marker_state.dirty = true;
20219        cx.notify();
20220    }
20221
20222    pub fn start_temporary_diff_override(&mut self) {
20223        self.load_diff_task.take();
20224        self.temporary_diff_override = true;
20225    }
20226
20227    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20228        self.temporary_diff_override = false;
20229        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20230        self.buffer.update(cx, |buffer, cx| {
20231            buffer.set_all_diff_hunks_collapsed(cx);
20232        });
20233
20234        if let Some(project) = self.project.clone() {
20235            self.load_diff_task = Some(
20236                update_uncommitted_diff_for_buffer(
20237                    cx.entity(),
20238                    &project,
20239                    self.buffer.read(cx).all_buffers(),
20240                    self.buffer.clone(),
20241                    cx,
20242                )
20243                .shared(),
20244            );
20245        }
20246    }
20247
20248    fn on_display_map_changed(
20249        &mut self,
20250        _: Entity<DisplayMap>,
20251        _: &mut Window,
20252        cx: &mut Context<Self>,
20253    ) {
20254        cx.notify();
20255    }
20256
20257    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20258        if self.diagnostics_enabled() {
20259            let new_severity = EditorSettings::get_global(cx)
20260                .diagnostics_max_severity
20261                .unwrap_or(DiagnosticSeverity::Hint);
20262            self.set_max_diagnostics_severity(new_severity, cx);
20263        }
20264        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20265        self.update_edit_prediction_settings(cx);
20266        self.refresh_edit_prediction(true, false, window, cx);
20267        self.refresh_inline_values(cx);
20268        self.refresh_inlay_hints(
20269            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20270                self.selections.newest_anchor().head(),
20271                &self.buffer.read(cx).snapshot(cx),
20272                cx,
20273            )),
20274            cx,
20275        );
20276
20277        let old_cursor_shape = self.cursor_shape;
20278        let old_show_breadcrumbs = self.show_breadcrumbs;
20279
20280        {
20281            let editor_settings = EditorSettings::get_global(cx);
20282            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20283            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20284            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20285            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20286        }
20287
20288        if old_cursor_shape != self.cursor_shape {
20289            cx.emit(EditorEvent::CursorShapeChanged);
20290        }
20291
20292        if old_show_breadcrumbs != self.show_breadcrumbs {
20293            cx.emit(EditorEvent::BreadcrumbsChanged);
20294        }
20295
20296        let project_settings = ProjectSettings::get_global(cx);
20297        self.serialize_dirty_buffers =
20298            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20299
20300        if self.mode.is_full() {
20301            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20302            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20303            if self.show_inline_diagnostics != show_inline_diagnostics {
20304                self.show_inline_diagnostics = show_inline_diagnostics;
20305                self.refresh_inline_diagnostics(false, window, cx);
20306            }
20307
20308            if self.git_blame_inline_enabled != inline_blame_enabled {
20309                self.toggle_git_blame_inline_internal(false, window, cx);
20310            }
20311
20312            let minimap_settings = EditorSettings::get_global(cx).minimap;
20313            if self.minimap_visibility != MinimapVisibility::Disabled {
20314                if self.minimap_visibility.settings_visibility()
20315                    != minimap_settings.minimap_enabled()
20316                {
20317                    self.set_minimap_visibility(
20318                        MinimapVisibility::for_mode(self.mode(), cx),
20319                        window,
20320                        cx,
20321                    );
20322                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20323                    minimap_entity.update(cx, |minimap_editor, cx| {
20324                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20325                    })
20326                }
20327            }
20328        }
20329
20330        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20331            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20332        }) {
20333            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20334                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20335            }
20336            self.refresh_colors(false, None, window, cx);
20337        }
20338
20339        cx.notify();
20340    }
20341
20342    pub fn set_searchable(&mut self, searchable: bool) {
20343        self.searchable = searchable;
20344    }
20345
20346    pub fn searchable(&self) -> bool {
20347        self.searchable
20348    }
20349
20350    fn open_proposed_changes_editor(
20351        &mut self,
20352        _: &OpenProposedChangesEditor,
20353        window: &mut Window,
20354        cx: &mut Context<Self>,
20355    ) {
20356        let Some(workspace) = self.workspace() else {
20357            cx.propagate();
20358            return;
20359        };
20360
20361        let selections = self.selections.all::<usize>(cx);
20362        let multi_buffer = self.buffer.read(cx);
20363        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20364        let mut new_selections_by_buffer = HashMap::default();
20365        for selection in selections {
20366            for (buffer, range, _) in
20367                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20368            {
20369                let mut range = range.to_point(buffer);
20370                range.start.column = 0;
20371                range.end.column = buffer.line_len(range.end.row);
20372                new_selections_by_buffer
20373                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20374                    .or_insert(Vec::new())
20375                    .push(range)
20376            }
20377        }
20378
20379        let proposed_changes_buffers = new_selections_by_buffer
20380            .into_iter()
20381            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20382            .collect::<Vec<_>>();
20383        let proposed_changes_editor = cx.new(|cx| {
20384            ProposedChangesEditor::new(
20385                "Proposed changes",
20386                proposed_changes_buffers,
20387                self.project.clone(),
20388                window,
20389                cx,
20390            )
20391        });
20392
20393        window.defer(cx, move |window, cx| {
20394            workspace.update(cx, |workspace, cx| {
20395                workspace.active_pane().update(cx, |pane, cx| {
20396                    pane.add_item(
20397                        Box::new(proposed_changes_editor),
20398                        true,
20399                        true,
20400                        None,
20401                        window,
20402                        cx,
20403                    );
20404                });
20405            });
20406        });
20407    }
20408
20409    pub fn open_excerpts_in_split(
20410        &mut self,
20411        _: &OpenExcerptsSplit,
20412        window: &mut Window,
20413        cx: &mut Context<Self>,
20414    ) {
20415        self.open_excerpts_common(None, true, window, cx)
20416    }
20417
20418    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20419        self.open_excerpts_common(None, false, window, cx)
20420    }
20421
20422    fn open_excerpts_common(
20423        &mut self,
20424        jump_data: Option<JumpData>,
20425        split: bool,
20426        window: &mut Window,
20427        cx: &mut Context<Self>,
20428    ) {
20429        let Some(workspace) = self.workspace() else {
20430            cx.propagate();
20431            return;
20432        };
20433
20434        if self.buffer.read(cx).is_singleton() {
20435            cx.propagate();
20436            return;
20437        }
20438
20439        let mut new_selections_by_buffer = HashMap::default();
20440        match &jump_data {
20441            Some(JumpData::MultiBufferPoint {
20442                excerpt_id,
20443                position,
20444                anchor,
20445                line_offset_from_top,
20446            }) => {
20447                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20448                if let Some(buffer) = multi_buffer_snapshot
20449                    .buffer_id_for_excerpt(*excerpt_id)
20450                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20451                {
20452                    let buffer_snapshot = buffer.read(cx).snapshot();
20453                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20454                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20455                    } else {
20456                        buffer_snapshot.clip_point(*position, Bias::Left)
20457                    };
20458                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20459                    new_selections_by_buffer.insert(
20460                        buffer,
20461                        (
20462                            vec![jump_to_offset..jump_to_offset],
20463                            Some(*line_offset_from_top),
20464                        ),
20465                    );
20466                }
20467            }
20468            Some(JumpData::MultiBufferRow {
20469                row,
20470                line_offset_from_top,
20471            }) => {
20472                let point = MultiBufferPoint::new(row.0, 0);
20473                if let Some((buffer, buffer_point, _)) =
20474                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20475                {
20476                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20477                    new_selections_by_buffer
20478                        .entry(buffer)
20479                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20480                        .0
20481                        .push(buffer_offset..buffer_offset)
20482                }
20483            }
20484            None => {
20485                let selections = self.selections.all::<usize>(cx);
20486                let multi_buffer = self.buffer.read(cx);
20487                for selection in selections {
20488                    for (snapshot, range, _, anchor) in multi_buffer
20489                        .snapshot(cx)
20490                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20491                    {
20492                        if let Some(anchor) = anchor {
20493                            // selection is in a deleted hunk
20494                            let Some(buffer_id) = anchor.buffer_id else {
20495                                continue;
20496                            };
20497                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20498                                continue;
20499                            };
20500                            let offset = text::ToOffset::to_offset(
20501                                &anchor.text_anchor,
20502                                &buffer_handle.read(cx).snapshot(),
20503                            );
20504                            let range = offset..offset;
20505                            new_selections_by_buffer
20506                                .entry(buffer_handle)
20507                                .or_insert((Vec::new(), None))
20508                                .0
20509                                .push(range)
20510                        } else {
20511                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20512                            else {
20513                                continue;
20514                            };
20515                            new_selections_by_buffer
20516                                .entry(buffer_handle)
20517                                .or_insert((Vec::new(), None))
20518                                .0
20519                                .push(range)
20520                        }
20521                    }
20522                }
20523            }
20524        }
20525
20526        new_selections_by_buffer
20527            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20528
20529        if new_selections_by_buffer.is_empty() {
20530            return;
20531        }
20532
20533        // We defer the pane interaction because we ourselves are a workspace item
20534        // and activating a new item causes the pane to call a method on us reentrantly,
20535        // which panics if we're on the stack.
20536        window.defer(cx, move |window, cx| {
20537            workspace.update(cx, |workspace, cx| {
20538                let pane = if split {
20539                    workspace.adjacent_pane(window, cx)
20540                } else {
20541                    workspace.active_pane().clone()
20542                };
20543
20544                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20545                    let editor = buffer
20546                        .read(cx)
20547                        .file()
20548                        .is_none()
20549                        .then(|| {
20550                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20551                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20552                            // Instead, we try to activate the existing editor in the pane first.
20553                            let (editor, pane_item_index) =
20554                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20555                                    let editor = item.downcast::<Editor>()?;
20556                                    let singleton_buffer =
20557                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20558                                    if singleton_buffer == buffer {
20559                                        Some((editor, i))
20560                                    } else {
20561                                        None
20562                                    }
20563                                })?;
20564                            pane.update(cx, |pane, cx| {
20565                                pane.activate_item(pane_item_index, true, true, window, cx)
20566                            });
20567                            Some(editor)
20568                        })
20569                        .flatten()
20570                        .unwrap_or_else(|| {
20571                            workspace.open_project_item::<Self>(
20572                                pane.clone(),
20573                                buffer,
20574                                true,
20575                                true,
20576                                window,
20577                                cx,
20578                            )
20579                        });
20580
20581                    editor.update(cx, |editor, cx| {
20582                        let autoscroll = match scroll_offset {
20583                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20584                            None => Autoscroll::newest(),
20585                        };
20586                        let nav_history = editor.nav_history.take();
20587                        editor.change_selections(
20588                            SelectionEffects::scroll(autoscroll),
20589                            window,
20590                            cx,
20591                            |s| {
20592                                s.select_ranges(ranges);
20593                            },
20594                        );
20595                        editor.nav_history = nav_history;
20596                    });
20597                }
20598            })
20599        });
20600    }
20601
20602    // For now, don't allow opening excerpts in buffers that aren't backed by
20603    // regular project files.
20604    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20605        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20606    }
20607
20608    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20609        let snapshot = self.buffer.read(cx).read(cx);
20610        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20611        Some(
20612            ranges
20613                .iter()
20614                .map(move |range| {
20615                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20616                })
20617                .collect(),
20618        )
20619    }
20620
20621    fn selection_replacement_ranges(
20622        &self,
20623        range: Range<OffsetUtf16>,
20624        cx: &mut App,
20625    ) -> Vec<Range<OffsetUtf16>> {
20626        let selections = self.selections.all::<OffsetUtf16>(cx);
20627        let newest_selection = selections
20628            .iter()
20629            .max_by_key(|selection| selection.id)
20630            .unwrap();
20631        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20632        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20633        let snapshot = self.buffer.read(cx).read(cx);
20634        selections
20635            .into_iter()
20636            .map(|mut selection| {
20637                selection.start.0 =
20638                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20639                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20640                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20641                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20642            })
20643            .collect()
20644    }
20645
20646    fn report_editor_event(
20647        &self,
20648        reported_event: ReportEditorEvent,
20649        file_extension: Option<String>,
20650        cx: &App,
20651    ) {
20652        if cfg!(any(test, feature = "test-support")) {
20653            return;
20654        }
20655
20656        let Some(project) = &self.project else { return };
20657
20658        // If None, we are in a file without an extension
20659        let file = self
20660            .buffer
20661            .read(cx)
20662            .as_singleton()
20663            .and_then(|b| b.read(cx).file());
20664        let file_extension = file_extension.or(file
20665            .as_ref()
20666            .and_then(|file| Path::new(file.file_name(cx)).extension())
20667            .and_then(|e| e.to_str())
20668            .map(|a| a.to_string()));
20669
20670        let vim_mode = vim_enabled(cx);
20671
20672        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20673        let copilot_enabled = edit_predictions_provider
20674            == language::language_settings::EditPredictionProvider::Copilot;
20675        let copilot_enabled_for_language = self
20676            .buffer
20677            .read(cx)
20678            .language_settings(cx)
20679            .show_edit_predictions;
20680
20681        let project = project.read(cx);
20682        let event_type = reported_event.event_type();
20683
20684        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20685            telemetry::event!(
20686                event_type,
20687                type = if auto_saved {"autosave"} else {"manual"},
20688                file_extension,
20689                vim_mode,
20690                copilot_enabled,
20691                copilot_enabled_for_language,
20692                edit_predictions_provider,
20693                is_via_ssh = project.is_via_ssh(),
20694            );
20695        } else {
20696            telemetry::event!(
20697                event_type,
20698                file_extension,
20699                vim_mode,
20700                copilot_enabled,
20701                copilot_enabled_for_language,
20702                edit_predictions_provider,
20703                is_via_ssh = project.is_via_ssh(),
20704            );
20705        };
20706    }
20707
20708    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20709    /// with each line being an array of {text, highlight} objects.
20710    fn copy_highlight_json(
20711        &mut self,
20712        _: &CopyHighlightJson,
20713        window: &mut Window,
20714        cx: &mut Context<Self>,
20715    ) {
20716        #[derive(Serialize)]
20717        struct Chunk<'a> {
20718            text: String,
20719            highlight: Option<&'a str>,
20720        }
20721
20722        let snapshot = self.buffer.read(cx).snapshot(cx);
20723        let range = self
20724            .selected_text_range(false, window, cx)
20725            .and_then(|selection| {
20726                if selection.range.is_empty() {
20727                    None
20728                } else {
20729                    Some(selection.range)
20730                }
20731            })
20732            .unwrap_or_else(|| 0..snapshot.len());
20733
20734        let chunks = snapshot.chunks(range, true);
20735        let mut lines = Vec::new();
20736        let mut line: VecDeque<Chunk> = VecDeque::new();
20737
20738        let Some(style) = self.style.as_ref() else {
20739            return;
20740        };
20741
20742        for chunk in chunks {
20743            let highlight = chunk
20744                .syntax_highlight_id
20745                .and_then(|id| id.name(&style.syntax));
20746            let mut chunk_lines = chunk.text.split('\n').peekable();
20747            while let Some(text) = chunk_lines.next() {
20748                let mut merged_with_last_token = false;
20749                if let Some(last_token) = line.back_mut() {
20750                    if last_token.highlight == highlight {
20751                        last_token.text.push_str(text);
20752                        merged_with_last_token = true;
20753                    }
20754                }
20755
20756                if !merged_with_last_token {
20757                    line.push_back(Chunk {
20758                        text: text.into(),
20759                        highlight,
20760                    });
20761                }
20762
20763                if chunk_lines.peek().is_some() {
20764                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20765                        line.pop_front();
20766                    }
20767                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20768                        line.pop_back();
20769                    }
20770
20771                    lines.push(mem::take(&mut line));
20772                }
20773            }
20774        }
20775
20776        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20777            return;
20778        };
20779        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20780    }
20781
20782    pub fn open_context_menu(
20783        &mut self,
20784        _: &OpenContextMenu,
20785        window: &mut Window,
20786        cx: &mut Context<Self>,
20787    ) {
20788        self.request_autoscroll(Autoscroll::newest(), cx);
20789        let position = self.selections.newest_display(cx).start;
20790        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20791    }
20792
20793    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20794        &self.inlay_hint_cache
20795    }
20796
20797    pub fn replay_insert_event(
20798        &mut self,
20799        text: &str,
20800        relative_utf16_range: Option<Range<isize>>,
20801        window: &mut Window,
20802        cx: &mut Context<Self>,
20803    ) {
20804        if !self.input_enabled {
20805            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20806            return;
20807        }
20808        if let Some(relative_utf16_range) = relative_utf16_range {
20809            let selections = self.selections.all::<OffsetUtf16>(cx);
20810            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20811                let new_ranges = selections.into_iter().map(|range| {
20812                    let start = OffsetUtf16(
20813                        range
20814                            .head()
20815                            .0
20816                            .saturating_add_signed(relative_utf16_range.start),
20817                    );
20818                    let end = OffsetUtf16(
20819                        range
20820                            .head()
20821                            .0
20822                            .saturating_add_signed(relative_utf16_range.end),
20823                    );
20824                    start..end
20825                });
20826                s.select_ranges(new_ranges);
20827            });
20828        }
20829
20830        self.handle_input(text, window, cx);
20831    }
20832
20833    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20834        let Some(provider) = self.semantics_provider.as_ref() else {
20835            return false;
20836        };
20837
20838        let mut supports = false;
20839        self.buffer().update(cx, |this, cx| {
20840            this.for_each_buffer(|buffer| {
20841                supports |= provider.supports_inlay_hints(buffer, cx);
20842            });
20843        });
20844
20845        supports
20846    }
20847
20848    pub fn is_focused(&self, window: &Window) -> bool {
20849        self.focus_handle.is_focused(window)
20850    }
20851
20852    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20853        cx.emit(EditorEvent::Focused);
20854
20855        if let Some(descendant) = self
20856            .last_focused_descendant
20857            .take()
20858            .and_then(|descendant| descendant.upgrade())
20859        {
20860            window.focus(&descendant);
20861        } else {
20862            if let Some(blame) = self.blame.as_ref() {
20863                blame.update(cx, GitBlame::focus)
20864            }
20865
20866            self.blink_manager.update(cx, BlinkManager::enable);
20867            self.show_cursor_names(window, cx);
20868            self.buffer.update(cx, |buffer, cx| {
20869                buffer.finalize_last_transaction(cx);
20870                if self.leader_id.is_none() {
20871                    buffer.set_active_selections(
20872                        &self.selections.disjoint_anchors(),
20873                        self.selections.line_mode,
20874                        self.cursor_shape,
20875                        cx,
20876                    );
20877                }
20878            });
20879        }
20880    }
20881
20882    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20883        cx.emit(EditorEvent::FocusedIn)
20884    }
20885
20886    fn handle_focus_out(
20887        &mut self,
20888        event: FocusOutEvent,
20889        _window: &mut Window,
20890        cx: &mut Context<Self>,
20891    ) {
20892        if event.blurred != self.focus_handle {
20893            self.last_focused_descendant = Some(event.blurred);
20894        }
20895        self.selection_drag_state = SelectionDragState::None;
20896        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20897    }
20898
20899    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20900        self.blink_manager.update(cx, BlinkManager::disable);
20901        self.buffer
20902            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20903
20904        if let Some(blame) = self.blame.as_ref() {
20905            blame.update(cx, GitBlame::blur)
20906        }
20907        if !self.hover_state.focused(window, cx) {
20908            hide_hover(self, cx);
20909        }
20910        if !self
20911            .context_menu
20912            .borrow()
20913            .as_ref()
20914            .is_some_and(|context_menu| context_menu.focused(window, cx))
20915        {
20916            self.hide_context_menu(window, cx);
20917        }
20918        self.discard_edit_prediction(false, cx);
20919        cx.emit(EditorEvent::Blurred);
20920        cx.notify();
20921    }
20922
20923    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20924        let mut pending: String = window
20925            .pending_input_keystrokes()
20926            .into_iter()
20927            .flatten()
20928            .filter_map(|keystroke| {
20929                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20930                    keystroke.key_char.clone()
20931                } else {
20932                    None
20933                }
20934            })
20935            .collect();
20936
20937        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20938            pending = "".to_string();
20939        }
20940
20941        let existing_pending = self
20942            .text_highlights::<PendingInput>(cx)
20943            .map(|(_, ranges)| ranges.to_vec());
20944        if existing_pending.is_none() && pending.is_empty() {
20945            return;
20946        }
20947        let transaction =
20948            self.transact(window, cx, |this, window, cx| {
20949                let selections = this.selections.all::<usize>(cx);
20950                let edits = selections
20951                    .iter()
20952                    .map(|selection| (selection.end..selection.end, pending.clone()));
20953                this.edit(edits, cx);
20954                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20955                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20956                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20957                    }));
20958                });
20959                if let Some(existing_ranges) = existing_pending {
20960                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20961                    this.edit(edits, cx);
20962                }
20963            });
20964
20965        let snapshot = self.snapshot(window, cx);
20966        let ranges = self
20967            .selections
20968            .all::<usize>(cx)
20969            .into_iter()
20970            .map(|selection| {
20971                snapshot.buffer_snapshot.anchor_after(selection.end)
20972                    ..snapshot
20973                        .buffer_snapshot
20974                        .anchor_before(selection.end + pending.len())
20975            })
20976            .collect();
20977
20978        if pending.is_empty() {
20979            self.clear_highlights::<PendingInput>(cx);
20980        } else {
20981            self.highlight_text::<PendingInput>(
20982                ranges,
20983                HighlightStyle {
20984                    underline: Some(UnderlineStyle {
20985                        thickness: px(1.),
20986                        color: None,
20987                        wavy: false,
20988                    }),
20989                    ..Default::default()
20990                },
20991                cx,
20992            );
20993        }
20994
20995        self.ime_transaction = self.ime_transaction.or(transaction);
20996        if let Some(transaction) = self.ime_transaction {
20997            self.buffer.update(cx, |buffer, cx| {
20998                buffer.group_until_transaction(transaction, cx);
20999            });
21000        }
21001
21002        if self.text_highlights::<PendingInput>(cx).is_none() {
21003            self.ime_transaction.take();
21004        }
21005    }
21006
21007    pub fn register_action_renderer(
21008        &mut self,
21009        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21010    ) -> Subscription {
21011        let id = self.next_editor_action_id.post_inc();
21012        self.editor_actions
21013            .borrow_mut()
21014            .insert(id, Box::new(listener));
21015
21016        let editor_actions = self.editor_actions.clone();
21017        Subscription::new(move || {
21018            editor_actions.borrow_mut().remove(&id);
21019        })
21020    }
21021
21022    pub fn register_action<A: Action>(
21023        &mut self,
21024        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21025    ) -> Subscription {
21026        let id = self.next_editor_action_id.post_inc();
21027        let listener = Arc::new(listener);
21028        self.editor_actions.borrow_mut().insert(
21029            id,
21030            Box::new(move |_, window, _| {
21031                let listener = listener.clone();
21032                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21033                    let action = action.downcast_ref().unwrap();
21034                    if phase == DispatchPhase::Bubble {
21035                        listener(action, window, cx)
21036                    }
21037                })
21038            }),
21039        );
21040
21041        let editor_actions = self.editor_actions.clone();
21042        Subscription::new(move || {
21043            editor_actions.borrow_mut().remove(&id);
21044        })
21045    }
21046
21047    pub fn file_header_size(&self) -> u32 {
21048        FILE_HEADER_HEIGHT
21049    }
21050
21051    pub fn restore(
21052        &mut self,
21053        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21054        window: &mut Window,
21055        cx: &mut Context<Self>,
21056    ) {
21057        let workspace = self.workspace();
21058        let project = self.project();
21059        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21060            let mut tasks = Vec::new();
21061            for (buffer_id, changes) in revert_changes {
21062                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21063                    buffer.update(cx, |buffer, cx| {
21064                        buffer.edit(
21065                            changes
21066                                .into_iter()
21067                                .map(|(range, text)| (range, text.to_string())),
21068                            None,
21069                            cx,
21070                        );
21071                    });
21072
21073                    if let Some(project) =
21074                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21075                    {
21076                        project.update(cx, |project, cx| {
21077                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21078                        })
21079                    }
21080                }
21081            }
21082            tasks
21083        });
21084        cx.spawn_in(window, async move |_, cx| {
21085            for (buffer, task) in save_tasks {
21086                let result = task.await;
21087                if result.is_err() {
21088                    let Some(path) = buffer
21089                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21090                        .ok()
21091                    else {
21092                        continue;
21093                    };
21094                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21095                        let Some(task) = cx
21096                            .update_window_entity(workspace, |workspace, window, cx| {
21097                                workspace
21098                                    .open_path_preview(path, None, false, false, false, window, cx)
21099                            })
21100                            .ok()
21101                        else {
21102                            continue;
21103                        };
21104                        task.await.log_err();
21105                    }
21106                }
21107            }
21108        })
21109        .detach();
21110        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21111            selections.refresh()
21112        });
21113    }
21114
21115    pub fn to_pixel_point(
21116        &self,
21117        source: multi_buffer::Anchor,
21118        editor_snapshot: &EditorSnapshot,
21119        window: &mut Window,
21120    ) -> Option<gpui::Point<Pixels>> {
21121        let source_point = source.to_display_point(editor_snapshot);
21122        self.display_to_pixel_point(source_point, editor_snapshot, window)
21123    }
21124
21125    pub fn display_to_pixel_point(
21126        &self,
21127        source: DisplayPoint,
21128        editor_snapshot: &EditorSnapshot,
21129        window: &mut Window,
21130    ) -> Option<gpui::Point<Pixels>> {
21131        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21132        let text_layout_details = self.text_layout_details(window);
21133        let scroll_top = text_layout_details
21134            .scroll_anchor
21135            .scroll_position(editor_snapshot)
21136            .y;
21137
21138        if source.row().as_f32() < scroll_top.floor() {
21139            return None;
21140        }
21141        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21142        let source_y = line_height * (source.row().as_f32() - scroll_top);
21143        Some(gpui::Point::new(source_x, source_y))
21144    }
21145
21146    pub fn has_visible_completions_menu(&self) -> bool {
21147        !self.edit_prediction_preview_is_active()
21148            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
21149                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21150            })
21151    }
21152
21153    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21154        if self.mode.is_minimap() {
21155            return;
21156        }
21157        self.addons
21158            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21159    }
21160
21161    pub fn unregister_addon<T: Addon>(&mut self) {
21162        self.addons.remove(&std::any::TypeId::of::<T>());
21163    }
21164
21165    pub fn addon<T: Addon>(&self) -> Option<&T> {
21166        let type_id = std::any::TypeId::of::<T>();
21167        self.addons
21168            .get(&type_id)
21169            .and_then(|item| item.to_any().downcast_ref::<T>())
21170    }
21171
21172    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21173        let type_id = std::any::TypeId::of::<T>();
21174        self.addons
21175            .get_mut(&type_id)
21176            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21177    }
21178
21179    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21180        let text_layout_details = self.text_layout_details(window);
21181        let style = &text_layout_details.editor_style;
21182        let font_id = window.text_system().resolve_font(&style.text.font());
21183        let font_size = style.text.font_size.to_pixels(window.rem_size());
21184        let line_height = style.text.line_height_in_pixels(window.rem_size());
21185        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21186        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21187
21188        CharacterDimensions {
21189            em_width,
21190            em_advance,
21191            line_height,
21192        }
21193    }
21194
21195    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21196        self.load_diff_task.clone()
21197    }
21198
21199    fn read_metadata_from_db(
21200        &mut self,
21201        item_id: u64,
21202        workspace_id: WorkspaceId,
21203        window: &mut Window,
21204        cx: &mut Context<Editor>,
21205    ) {
21206        if self.is_singleton(cx)
21207            && !self.mode.is_minimap()
21208            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21209        {
21210            let buffer_snapshot = OnceCell::new();
21211
21212            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21213                if !folds.is_empty() {
21214                    let snapshot =
21215                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21216                    self.fold_ranges(
21217                        folds
21218                            .into_iter()
21219                            .map(|(start, end)| {
21220                                snapshot.clip_offset(start, Bias::Left)
21221                                    ..snapshot.clip_offset(end, Bias::Right)
21222                            })
21223                            .collect(),
21224                        false,
21225                        window,
21226                        cx,
21227                    );
21228                }
21229            }
21230
21231            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21232                if !selections.is_empty() {
21233                    let snapshot =
21234                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21235                    // skip adding the initial selection to selection history
21236                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21237                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21238                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21239                            snapshot.clip_offset(start, Bias::Left)
21240                                ..snapshot.clip_offset(end, Bias::Right)
21241                        }));
21242                    });
21243                    self.selection_history.mode = SelectionHistoryMode::Normal;
21244                }
21245            };
21246        }
21247
21248        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21249    }
21250
21251    fn update_lsp_data(
21252        &mut self,
21253        ignore_cache: bool,
21254        for_buffer: Option<BufferId>,
21255        window: &mut Window,
21256        cx: &mut Context<'_, Self>,
21257    ) {
21258        self.pull_diagnostics(for_buffer, window, cx);
21259        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21260    }
21261}
21262
21263fn vim_enabled(cx: &App) -> bool {
21264    cx.global::<SettingsStore>()
21265        .raw_user_settings()
21266        .get("vim_mode")
21267        == Some(&serde_json::Value::Bool(true))
21268}
21269
21270fn process_completion_for_edit(
21271    completion: &Completion,
21272    intent: CompletionIntent,
21273    buffer: &Entity<Buffer>,
21274    cursor_position: &text::Anchor,
21275    cx: &mut Context<Editor>,
21276) -> CompletionEdit {
21277    let buffer = buffer.read(cx);
21278    let buffer_snapshot = buffer.snapshot();
21279    let (snippet, new_text) = if completion.is_snippet() {
21280        // Workaround for typescript language server issues so that methods don't expand within
21281        // strings and functions with type expressions. The previous point is used because the query
21282        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21283        let mut snippet_source = completion.new_text.clone();
21284        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21285        previous_point.column = previous_point.column.saturating_sub(1);
21286        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21287            if scope.prefers_label_for_snippet_in_completion() {
21288                if let Some(label) = completion.label() {
21289                    if matches!(
21290                        completion.kind(),
21291                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21292                    ) {
21293                        snippet_source = label;
21294                    }
21295                }
21296            }
21297        }
21298        match Snippet::parse(&snippet_source).log_err() {
21299            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21300            None => (None, completion.new_text.clone()),
21301        }
21302    } else {
21303        (None, completion.new_text.clone())
21304    };
21305
21306    let mut range_to_replace = {
21307        let replace_range = &completion.replace_range;
21308        if let CompletionSource::Lsp {
21309            insert_range: Some(insert_range),
21310            ..
21311        } = &completion.source
21312        {
21313            debug_assert_eq!(
21314                insert_range.start, replace_range.start,
21315                "insert_range and replace_range should start at the same position"
21316            );
21317            debug_assert!(
21318                insert_range
21319                    .start
21320                    .cmp(cursor_position, &buffer_snapshot)
21321                    .is_le(),
21322                "insert_range should start before or at cursor position"
21323            );
21324            debug_assert!(
21325                replace_range
21326                    .start
21327                    .cmp(cursor_position, &buffer_snapshot)
21328                    .is_le(),
21329                "replace_range should start before or at cursor position"
21330            );
21331
21332            let should_replace = match intent {
21333                CompletionIntent::CompleteWithInsert => false,
21334                CompletionIntent::CompleteWithReplace => true,
21335                CompletionIntent::Complete | CompletionIntent::Compose => {
21336                    let insert_mode =
21337                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21338                            .completions
21339                            .lsp_insert_mode;
21340                    match insert_mode {
21341                        LspInsertMode::Insert => false,
21342                        LspInsertMode::Replace => true,
21343                        LspInsertMode::ReplaceSubsequence => {
21344                            let mut text_to_replace = buffer.chars_for_range(
21345                                buffer.anchor_before(replace_range.start)
21346                                    ..buffer.anchor_after(replace_range.end),
21347                            );
21348                            let mut current_needle = text_to_replace.next();
21349                            for haystack_ch in completion.label.text.chars() {
21350                                if let Some(needle_ch) = current_needle {
21351                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21352                                        current_needle = text_to_replace.next();
21353                                    }
21354                                }
21355                            }
21356                            current_needle.is_none()
21357                        }
21358                        LspInsertMode::ReplaceSuffix => {
21359                            if replace_range
21360                                .end
21361                                .cmp(cursor_position, &buffer_snapshot)
21362                                .is_gt()
21363                            {
21364                                let range_after_cursor = *cursor_position..replace_range.end;
21365                                let text_after_cursor = buffer
21366                                    .text_for_range(
21367                                        buffer.anchor_before(range_after_cursor.start)
21368                                            ..buffer.anchor_after(range_after_cursor.end),
21369                                    )
21370                                    .collect::<String>()
21371                                    .to_ascii_lowercase();
21372                                completion
21373                                    .label
21374                                    .text
21375                                    .to_ascii_lowercase()
21376                                    .ends_with(&text_after_cursor)
21377                            } else {
21378                                true
21379                            }
21380                        }
21381                    }
21382                }
21383            };
21384
21385            if should_replace {
21386                replace_range.clone()
21387            } else {
21388                insert_range.clone()
21389            }
21390        } else {
21391            replace_range.clone()
21392        }
21393    };
21394
21395    if range_to_replace
21396        .end
21397        .cmp(cursor_position, &buffer_snapshot)
21398        .is_lt()
21399    {
21400        range_to_replace.end = *cursor_position;
21401    }
21402
21403    CompletionEdit {
21404        new_text,
21405        replace_range: range_to_replace.to_offset(buffer),
21406        snippet,
21407    }
21408}
21409
21410struct CompletionEdit {
21411    new_text: String,
21412    replace_range: Range<usize>,
21413    snippet: Option<Snippet>,
21414}
21415
21416fn insert_extra_newline_brackets(
21417    buffer: &MultiBufferSnapshot,
21418    range: Range<usize>,
21419    language: &language::LanguageScope,
21420) -> bool {
21421    let leading_whitespace_len = buffer
21422        .reversed_chars_at(range.start)
21423        .take_while(|c| c.is_whitespace() && *c != '\n')
21424        .map(|c| c.len_utf8())
21425        .sum::<usize>();
21426    let trailing_whitespace_len = buffer
21427        .chars_at(range.end)
21428        .take_while(|c| c.is_whitespace() && *c != '\n')
21429        .map(|c| c.len_utf8())
21430        .sum::<usize>();
21431    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21432
21433    language.brackets().any(|(pair, enabled)| {
21434        let pair_start = pair.start.trim_end();
21435        let pair_end = pair.end.trim_start();
21436
21437        enabled
21438            && pair.newline
21439            && buffer.contains_str_at(range.end, pair_end)
21440            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21441    })
21442}
21443
21444fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21445    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21446        [(buffer, range, _)] => (*buffer, range.clone()),
21447        _ => return false,
21448    };
21449    let pair = {
21450        let mut result: Option<BracketMatch> = None;
21451
21452        for pair in buffer
21453            .all_bracket_ranges(range.clone())
21454            .filter(move |pair| {
21455                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21456            })
21457        {
21458            let len = pair.close_range.end - pair.open_range.start;
21459
21460            if let Some(existing) = &result {
21461                let existing_len = existing.close_range.end - existing.open_range.start;
21462                if len > existing_len {
21463                    continue;
21464                }
21465            }
21466
21467            result = Some(pair);
21468        }
21469
21470        result
21471    };
21472    let Some(pair) = pair else {
21473        return false;
21474    };
21475    pair.newline_only
21476        && buffer
21477            .chars_for_range(pair.open_range.end..range.start)
21478            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21479            .all(|c| c.is_whitespace() && c != '\n')
21480}
21481
21482fn update_uncommitted_diff_for_buffer(
21483    editor: Entity<Editor>,
21484    project: &Entity<Project>,
21485    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21486    buffer: Entity<MultiBuffer>,
21487    cx: &mut App,
21488) -> Task<()> {
21489    let mut tasks = Vec::new();
21490    project.update(cx, |project, cx| {
21491        for buffer in buffers {
21492            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21493                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21494            }
21495        }
21496    });
21497    cx.spawn(async move |cx| {
21498        let diffs = future::join_all(tasks).await;
21499        if editor
21500            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21501            .unwrap_or(false)
21502        {
21503            return;
21504        }
21505
21506        buffer
21507            .update(cx, |buffer, cx| {
21508                for diff in diffs.into_iter().flatten() {
21509                    buffer.add_diff(diff, cx);
21510                }
21511            })
21512            .ok();
21513    })
21514}
21515
21516fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21517    let tab_size = tab_size.get() as usize;
21518    let mut width = offset;
21519
21520    for ch in text.chars() {
21521        width += if ch == '\t' {
21522            tab_size - (width % tab_size)
21523        } else {
21524            1
21525        };
21526    }
21527
21528    width - offset
21529}
21530
21531#[cfg(test)]
21532mod tests {
21533    use super::*;
21534
21535    #[test]
21536    fn test_string_size_with_expanded_tabs() {
21537        let nz = |val| NonZeroU32::new(val).unwrap();
21538        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21539        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21540        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21541        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21542        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21543        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21544        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21545        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21546    }
21547}
21548
21549/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21550struct WordBreakingTokenizer<'a> {
21551    input: &'a str,
21552}
21553
21554impl<'a> WordBreakingTokenizer<'a> {
21555    fn new(input: &'a str) -> Self {
21556        Self { input }
21557    }
21558}
21559
21560fn is_char_ideographic(ch: char) -> bool {
21561    use unicode_script::Script::*;
21562    use unicode_script::UnicodeScript;
21563    matches!(ch.script(), Han | Tangut | Yi)
21564}
21565
21566fn is_grapheme_ideographic(text: &str) -> bool {
21567    text.chars().any(is_char_ideographic)
21568}
21569
21570fn is_grapheme_whitespace(text: &str) -> bool {
21571    text.chars().any(|x| x.is_whitespace())
21572}
21573
21574fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21575    text.chars().next().map_or(false, |ch| {
21576        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21577    })
21578}
21579
21580#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21581enum WordBreakToken<'a> {
21582    Word { token: &'a str, grapheme_len: usize },
21583    InlineWhitespace { token: &'a str, grapheme_len: usize },
21584    Newline,
21585}
21586
21587impl<'a> Iterator for WordBreakingTokenizer<'a> {
21588    /// Yields a span, the count of graphemes in the token, and whether it was
21589    /// whitespace. Note that it also breaks at word boundaries.
21590    type Item = WordBreakToken<'a>;
21591
21592    fn next(&mut self) -> Option<Self::Item> {
21593        use unicode_segmentation::UnicodeSegmentation;
21594        if self.input.is_empty() {
21595            return None;
21596        }
21597
21598        let mut iter = self.input.graphemes(true).peekable();
21599        let mut offset = 0;
21600        let mut grapheme_len = 0;
21601        if let Some(first_grapheme) = iter.next() {
21602            let is_newline = first_grapheme == "\n";
21603            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21604            offset += first_grapheme.len();
21605            grapheme_len += 1;
21606            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21607                if let Some(grapheme) = iter.peek().copied() {
21608                    if should_stay_with_preceding_ideograph(grapheme) {
21609                        offset += grapheme.len();
21610                        grapheme_len += 1;
21611                    }
21612                }
21613            } else {
21614                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21615                let mut next_word_bound = words.peek().copied();
21616                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21617                    next_word_bound = words.next();
21618                }
21619                while let Some(grapheme) = iter.peek().copied() {
21620                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21621                        break;
21622                    };
21623                    if is_grapheme_whitespace(grapheme) != is_whitespace
21624                        || (grapheme == "\n") != is_newline
21625                    {
21626                        break;
21627                    };
21628                    offset += grapheme.len();
21629                    grapheme_len += 1;
21630                    iter.next();
21631                }
21632            }
21633            let token = &self.input[..offset];
21634            self.input = &self.input[offset..];
21635            if token == "\n" {
21636                Some(WordBreakToken::Newline)
21637            } else if is_whitespace {
21638                Some(WordBreakToken::InlineWhitespace {
21639                    token,
21640                    grapheme_len,
21641                })
21642            } else {
21643                Some(WordBreakToken::Word {
21644                    token,
21645                    grapheme_len,
21646                })
21647            }
21648        } else {
21649            None
21650        }
21651    }
21652}
21653
21654#[test]
21655fn test_word_breaking_tokenizer() {
21656    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21657        ("", &[]),
21658        ("  ", &[whitespace("  ", 2)]),
21659        ("Ʒ", &[word("Ʒ", 1)]),
21660        ("Ǽ", &[word("Ǽ", 1)]),
21661        ("", &[word("", 1)]),
21662        ("⋑⋑", &[word("⋑⋑", 2)]),
21663        (
21664            "原理,进而",
21665            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21666        ),
21667        (
21668            "hello world",
21669            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21670        ),
21671        (
21672            "hello, world",
21673            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21674        ),
21675        (
21676            "  hello world",
21677            &[
21678                whitespace("  ", 2),
21679                word("hello", 5),
21680                whitespace(" ", 1),
21681                word("world", 5),
21682            ],
21683        ),
21684        (
21685            "这是什么 \n 钢笔",
21686            &[
21687                word("", 1),
21688                word("", 1),
21689                word("", 1),
21690                word("", 1),
21691                whitespace(" ", 1),
21692                newline(),
21693                whitespace(" ", 1),
21694                word("", 1),
21695                word("", 1),
21696            ],
21697        ),
21698        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21699    ];
21700
21701    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21702        WordBreakToken::Word {
21703            token,
21704            grapheme_len,
21705        }
21706    }
21707
21708    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21709        WordBreakToken::InlineWhitespace {
21710            token,
21711            grapheme_len,
21712        }
21713    }
21714
21715    fn newline() -> WordBreakToken<'static> {
21716        WordBreakToken::Newline
21717    }
21718
21719    for (input, result) in tests {
21720        assert_eq!(
21721            WordBreakingTokenizer::new(input)
21722                .collect::<Vec<_>>()
21723                .as_slice(),
21724            *result,
21725        );
21726    }
21727}
21728
21729fn wrap_with_prefix(
21730    first_line_prefix: String,
21731    subsequent_lines_prefix: String,
21732    unwrapped_text: String,
21733    wrap_column: usize,
21734    tab_size: NonZeroU32,
21735    preserve_existing_whitespace: bool,
21736) -> String {
21737    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21738    let subsequent_lines_prefix_len =
21739        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21740    let mut wrapped_text = String::new();
21741    let mut current_line = first_line_prefix.clone();
21742    let mut is_first_line = true;
21743
21744    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21745    let mut current_line_len = first_line_prefix_len;
21746    let mut in_whitespace = false;
21747    for token in tokenizer {
21748        let have_preceding_whitespace = in_whitespace;
21749        match token {
21750            WordBreakToken::Word {
21751                token,
21752                grapheme_len,
21753            } => {
21754                in_whitespace = false;
21755                let current_prefix_len = if is_first_line {
21756                    first_line_prefix_len
21757                } else {
21758                    subsequent_lines_prefix_len
21759                };
21760                if current_line_len + grapheme_len > wrap_column
21761                    && current_line_len != current_prefix_len
21762                {
21763                    wrapped_text.push_str(current_line.trim_end());
21764                    wrapped_text.push('\n');
21765                    is_first_line = false;
21766                    current_line = subsequent_lines_prefix.clone();
21767                    current_line_len = subsequent_lines_prefix_len;
21768                }
21769                current_line.push_str(token);
21770                current_line_len += grapheme_len;
21771            }
21772            WordBreakToken::InlineWhitespace {
21773                mut token,
21774                mut grapheme_len,
21775            } => {
21776                in_whitespace = true;
21777                if have_preceding_whitespace && !preserve_existing_whitespace {
21778                    continue;
21779                }
21780                if !preserve_existing_whitespace {
21781                    token = " ";
21782                    grapheme_len = 1;
21783                }
21784                let current_prefix_len = if is_first_line {
21785                    first_line_prefix_len
21786                } else {
21787                    subsequent_lines_prefix_len
21788                };
21789                if current_line_len + grapheme_len > wrap_column {
21790                    wrapped_text.push_str(current_line.trim_end());
21791                    wrapped_text.push('\n');
21792                    is_first_line = false;
21793                    current_line = subsequent_lines_prefix.clone();
21794                    current_line_len = subsequent_lines_prefix_len;
21795                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21796                    current_line.push_str(token);
21797                    current_line_len += grapheme_len;
21798                }
21799            }
21800            WordBreakToken::Newline => {
21801                in_whitespace = true;
21802                let current_prefix_len = if is_first_line {
21803                    first_line_prefix_len
21804                } else {
21805                    subsequent_lines_prefix_len
21806                };
21807                if preserve_existing_whitespace {
21808                    wrapped_text.push_str(current_line.trim_end());
21809                    wrapped_text.push('\n');
21810                    is_first_line = false;
21811                    current_line = subsequent_lines_prefix.clone();
21812                    current_line_len = subsequent_lines_prefix_len;
21813                } else if have_preceding_whitespace {
21814                    continue;
21815                } else if current_line_len + 1 > wrap_column
21816                    && current_line_len != current_prefix_len
21817                {
21818                    wrapped_text.push_str(current_line.trim_end());
21819                    wrapped_text.push('\n');
21820                    is_first_line = false;
21821                    current_line = subsequent_lines_prefix.clone();
21822                    current_line_len = subsequent_lines_prefix_len;
21823                } else if current_line_len != current_prefix_len {
21824                    current_line.push(' ');
21825                    current_line_len += 1;
21826                }
21827            }
21828        }
21829    }
21830
21831    if !current_line.is_empty() {
21832        wrapped_text.push_str(&current_line);
21833    }
21834    wrapped_text
21835}
21836
21837#[test]
21838fn test_wrap_with_prefix() {
21839    assert_eq!(
21840        wrap_with_prefix(
21841            "# ".to_string(),
21842            "# ".to_string(),
21843            "abcdefg".to_string(),
21844            4,
21845            NonZeroU32::new(4).unwrap(),
21846            false,
21847        ),
21848        "# abcdefg"
21849    );
21850    assert_eq!(
21851        wrap_with_prefix(
21852            "".to_string(),
21853            "".to_string(),
21854            "\thello world".to_string(),
21855            8,
21856            NonZeroU32::new(4).unwrap(),
21857            false,
21858        ),
21859        "hello\nworld"
21860    );
21861    assert_eq!(
21862        wrap_with_prefix(
21863            "// ".to_string(),
21864            "// ".to_string(),
21865            "xx \nyy zz aa bb cc".to_string(),
21866            12,
21867            NonZeroU32::new(4).unwrap(),
21868            false,
21869        ),
21870        "// xx yy zz\n// aa bb cc"
21871    );
21872    assert_eq!(
21873        wrap_with_prefix(
21874            String::new(),
21875            String::new(),
21876            "这是什么 \n 钢笔".to_string(),
21877            3,
21878            NonZeroU32::new(4).unwrap(),
21879            false,
21880        ),
21881        "这是什\n么 钢\n"
21882    );
21883}
21884
21885pub trait CollaborationHub {
21886    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21887    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21888    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21889}
21890
21891impl CollaborationHub for Entity<Project> {
21892    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21893        self.read(cx).collaborators()
21894    }
21895
21896    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21897        self.read(cx).user_store().read(cx).participant_indices()
21898    }
21899
21900    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21901        let this = self.read(cx);
21902        let user_ids = this.collaborators().values().map(|c| c.user_id);
21903        this.user_store().read(cx).participant_names(user_ids, cx)
21904    }
21905}
21906
21907pub trait SemanticsProvider {
21908    fn hover(
21909        &self,
21910        buffer: &Entity<Buffer>,
21911        position: text::Anchor,
21912        cx: &mut App,
21913    ) -> Option<Task<Vec<project::Hover>>>;
21914
21915    fn inline_values(
21916        &self,
21917        buffer_handle: Entity<Buffer>,
21918        range: Range<text::Anchor>,
21919        cx: &mut App,
21920    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21921
21922    fn inlay_hints(
21923        &self,
21924        buffer_handle: Entity<Buffer>,
21925        range: Range<text::Anchor>,
21926        cx: &mut App,
21927    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21928
21929    fn resolve_inlay_hint(
21930        &self,
21931        hint: InlayHint,
21932        buffer_handle: Entity<Buffer>,
21933        server_id: LanguageServerId,
21934        cx: &mut App,
21935    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21936
21937    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21938
21939    fn document_highlights(
21940        &self,
21941        buffer: &Entity<Buffer>,
21942        position: text::Anchor,
21943        cx: &mut App,
21944    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21945
21946    fn definitions(
21947        &self,
21948        buffer: &Entity<Buffer>,
21949        position: text::Anchor,
21950        kind: GotoDefinitionKind,
21951        cx: &mut App,
21952    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21953
21954    fn range_for_rename(
21955        &self,
21956        buffer: &Entity<Buffer>,
21957        position: text::Anchor,
21958        cx: &mut App,
21959    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21960
21961    fn perform_rename(
21962        &self,
21963        buffer: &Entity<Buffer>,
21964        position: text::Anchor,
21965        new_name: String,
21966        cx: &mut App,
21967    ) -> Option<Task<Result<ProjectTransaction>>>;
21968}
21969
21970pub trait CompletionProvider {
21971    fn completions(
21972        &self,
21973        excerpt_id: ExcerptId,
21974        buffer: &Entity<Buffer>,
21975        buffer_position: text::Anchor,
21976        trigger: CompletionContext,
21977        window: &mut Window,
21978        cx: &mut Context<Editor>,
21979    ) -> Task<Result<Vec<CompletionResponse>>>;
21980
21981    fn resolve_completions(
21982        &self,
21983        _buffer: Entity<Buffer>,
21984        _completion_indices: Vec<usize>,
21985        _completions: Rc<RefCell<Box<[Completion]>>>,
21986        _cx: &mut Context<Editor>,
21987    ) -> Task<Result<bool>> {
21988        Task::ready(Ok(false))
21989    }
21990
21991    fn apply_additional_edits_for_completion(
21992        &self,
21993        _buffer: Entity<Buffer>,
21994        _completions: Rc<RefCell<Box<[Completion]>>>,
21995        _completion_index: usize,
21996        _push_to_history: bool,
21997        _cx: &mut Context<Editor>,
21998    ) -> Task<Result<Option<language::Transaction>>> {
21999        Task::ready(Ok(None))
22000    }
22001
22002    fn is_completion_trigger(
22003        &self,
22004        buffer: &Entity<Buffer>,
22005        position: language::Anchor,
22006        text: &str,
22007        trigger_in_words: bool,
22008        menu_is_open: bool,
22009        cx: &mut Context<Editor>,
22010    ) -> bool;
22011
22012    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22013
22014    fn sort_completions(&self) -> bool {
22015        true
22016    }
22017
22018    fn filter_completions(&self) -> bool {
22019        true
22020    }
22021}
22022
22023pub trait CodeActionProvider {
22024    fn id(&self) -> Arc<str>;
22025
22026    fn code_actions(
22027        &self,
22028        buffer: &Entity<Buffer>,
22029        range: Range<text::Anchor>,
22030        window: &mut Window,
22031        cx: &mut App,
22032    ) -> Task<Result<Vec<CodeAction>>>;
22033
22034    fn apply_code_action(
22035        &self,
22036        buffer_handle: Entity<Buffer>,
22037        action: CodeAction,
22038        excerpt_id: ExcerptId,
22039        push_to_history: bool,
22040        window: &mut Window,
22041        cx: &mut App,
22042    ) -> Task<Result<ProjectTransaction>>;
22043}
22044
22045impl CodeActionProvider for Entity<Project> {
22046    fn id(&self) -> Arc<str> {
22047        "project".into()
22048    }
22049
22050    fn code_actions(
22051        &self,
22052        buffer: &Entity<Buffer>,
22053        range: Range<text::Anchor>,
22054        _window: &mut Window,
22055        cx: &mut App,
22056    ) -> Task<Result<Vec<CodeAction>>> {
22057        self.update(cx, |project, cx| {
22058            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22059            let code_actions = project.code_actions(buffer, range, None, cx);
22060            cx.background_spawn(async move {
22061                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22062                Ok(code_lens_actions
22063                    .context("code lens fetch")?
22064                    .into_iter()
22065                    .chain(code_actions.context("code action fetch")?)
22066                    .collect())
22067            })
22068        })
22069    }
22070
22071    fn apply_code_action(
22072        &self,
22073        buffer_handle: Entity<Buffer>,
22074        action: CodeAction,
22075        _excerpt_id: ExcerptId,
22076        push_to_history: bool,
22077        _window: &mut Window,
22078        cx: &mut App,
22079    ) -> Task<Result<ProjectTransaction>> {
22080        self.update(cx, |project, cx| {
22081            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22082        })
22083    }
22084}
22085
22086fn snippet_completions(
22087    project: &Project,
22088    buffer: &Entity<Buffer>,
22089    buffer_position: text::Anchor,
22090    cx: &mut App,
22091) -> Task<Result<CompletionResponse>> {
22092    let languages = buffer.read(cx).languages_at(buffer_position);
22093    let snippet_store = project.snippets().read(cx);
22094
22095    let scopes: Vec<_> = languages
22096        .iter()
22097        .filter_map(|language| {
22098            let language_name = language.lsp_id();
22099            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22100
22101            if snippets.is_empty() {
22102                None
22103            } else {
22104                Some((language.default_scope(), snippets))
22105            }
22106        })
22107        .collect();
22108
22109    if scopes.is_empty() {
22110        return Task::ready(Ok(CompletionResponse {
22111            completions: vec![],
22112            is_incomplete: false,
22113        }));
22114    }
22115
22116    let snapshot = buffer.read(cx).text_snapshot();
22117    let chars: String = snapshot
22118        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22119        .collect();
22120    let executor = cx.background_executor().clone();
22121
22122    cx.background_spawn(async move {
22123        let mut is_incomplete = false;
22124        let mut completions: Vec<Completion> = Vec::new();
22125        for (scope, snippets) in scopes.into_iter() {
22126            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22127            let mut last_word = chars
22128                .chars()
22129                .take_while(|c| classifier.is_word(*c))
22130                .collect::<String>();
22131            last_word = last_word.chars().rev().collect();
22132
22133            if last_word.is_empty() {
22134                return Ok(CompletionResponse {
22135                    completions: vec![],
22136                    is_incomplete: true,
22137                });
22138            }
22139
22140            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22141            let to_lsp = |point: &text::Anchor| {
22142                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22143                point_to_lsp(end)
22144            };
22145            let lsp_end = to_lsp(&buffer_position);
22146
22147            let candidates = snippets
22148                .iter()
22149                .enumerate()
22150                .flat_map(|(ix, snippet)| {
22151                    snippet
22152                        .prefix
22153                        .iter()
22154                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22155                })
22156                .collect::<Vec<StringMatchCandidate>>();
22157
22158            const MAX_RESULTS: usize = 100;
22159            let mut matches = fuzzy::match_strings(
22160                &candidates,
22161                &last_word,
22162                last_word.chars().any(|c| c.is_uppercase()),
22163                true,
22164                MAX_RESULTS,
22165                &Default::default(),
22166                executor.clone(),
22167            )
22168            .await;
22169
22170            if matches.len() >= MAX_RESULTS {
22171                is_incomplete = true;
22172            }
22173
22174            // Remove all candidates where the query's start does not match the start of any word in the candidate
22175            if let Some(query_start) = last_word.chars().next() {
22176                matches.retain(|string_match| {
22177                    split_words(&string_match.string).any(|word| {
22178                        // Check that the first codepoint of the word as lowercase matches the first
22179                        // codepoint of the query as lowercase
22180                        word.chars()
22181                            .flat_map(|codepoint| codepoint.to_lowercase())
22182                            .zip(query_start.to_lowercase())
22183                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22184                    })
22185                });
22186            }
22187
22188            let matched_strings = matches
22189                .into_iter()
22190                .map(|m| m.string)
22191                .collect::<HashSet<_>>();
22192
22193            completions.extend(snippets.iter().filter_map(|snippet| {
22194                let matching_prefix = snippet
22195                    .prefix
22196                    .iter()
22197                    .find(|prefix| matched_strings.contains(*prefix))?;
22198                let start = as_offset - last_word.len();
22199                let start = snapshot.anchor_before(start);
22200                let range = start..buffer_position;
22201                let lsp_start = to_lsp(&start);
22202                let lsp_range = lsp::Range {
22203                    start: lsp_start,
22204                    end: lsp_end,
22205                };
22206                Some(Completion {
22207                    replace_range: range,
22208                    new_text: snippet.body.clone(),
22209                    source: CompletionSource::Lsp {
22210                        insert_range: None,
22211                        server_id: LanguageServerId(usize::MAX),
22212                        resolved: true,
22213                        lsp_completion: Box::new(lsp::CompletionItem {
22214                            label: snippet.prefix.first().unwrap().clone(),
22215                            kind: Some(CompletionItemKind::SNIPPET),
22216                            label_details: snippet.description.as_ref().map(|description| {
22217                                lsp::CompletionItemLabelDetails {
22218                                    detail: Some(description.clone()),
22219                                    description: None,
22220                                }
22221                            }),
22222                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22223                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22224                                lsp::InsertReplaceEdit {
22225                                    new_text: snippet.body.clone(),
22226                                    insert: lsp_range,
22227                                    replace: lsp_range,
22228                                },
22229                            )),
22230                            filter_text: Some(snippet.body.clone()),
22231                            sort_text: Some(char::MAX.to_string()),
22232                            ..lsp::CompletionItem::default()
22233                        }),
22234                        lsp_defaults: None,
22235                    },
22236                    label: CodeLabel {
22237                        text: matching_prefix.clone(),
22238                        runs: Vec::new(),
22239                        filter_range: 0..matching_prefix.len(),
22240                    },
22241                    icon_path: None,
22242                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22243                        single_line: snippet.name.clone().into(),
22244                        plain_text: snippet
22245                            .description
22246                            .clone()
22247                            .map(|description| description.into()),
22248                    }),
22249                    insert_text_mode: None,
22250                    confirm: None,
22251                })
22252            }))
22253        }
22254
22255        Ok(CompletionResponse {
22256            completions,
22257            is_incomplete,
22258        })
22259    })
22260}
22261
22262impl CompletionProvider for Entity<Project> {
22263    fn completions(
22264        &self,
22265        _excerpt_id: ExcerptId,
22266        buffer: &Entity<Buffer>,
22267        buffer_position: text::Anchor,
22268        options: CompletionContext,
22269        _window: &mut Window,
22270        cx: &mut Context<Editor>,
22271    ) -> Task<Result<Vec<CompletionResponse>>> {
22272        self.update(cx, |project, cx| {
22273            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22274            let project_completions = project.completions(buffer, buffer_position, options, cx);
22275            cx.background_spawn(async move {
22276                let mut responses = project_completions.await?;
22277                let snippets = snippets.await?;
22278                if !snippets.completions.is_empty() {
22279                    responses.push(snippets);
22280                }
22281                Ok(responses)
22282            })
22283        })
22284    }
22285
22286    fn resolve_completions(
22287        &self,
22288        buffer: Entity<Buffer>,
22289        completion_indices: Vec<usize>,
22290        completions: Rc<RefCell<Box<[Completion]>>>,
22291        cx: &mut Context<Editor>,
22292    ) -> Task<Result<bool>> {
22293        self.update(cx, |project, cx| {
22294            project.lsp_store().update(cx, |lsp_store, cx| {
22295                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22296            })
22297        })
22298    }
22299
22300    fn apply_additional_edits_for_completion(
22301        &self,
22302        buffer: Entity<Buffer>,
22303        completions: Rc<RefCell<Box<[Completion]>>>,
22304        completion_index: usize,
22305        push_to_history: bool,
22306        cx: &mut Context<Editor>,
22307    ) -> Task<Result<Option<language::Transaction>>> {
22308        self.update(cx, |project, cx| {
22309            project.lsp_store().update(cx, |lsp_store, cx| {
22310                lsp_store.apply_additional_edits_for_completion(
22311                    buffer,
22312                    completions,
22313                    completion_index,
22314                    push_to_history,
22315                    cx,
22316                )
22317            })
22318        })
22319    }
22320
22321    fn is_completion_trigger(
22322        &self,
22323        buffer: &Entity<Buffer>,
22324        position: language::Anchor,
22325        text: &str,
22326        trigger_in_words: bool,
22327        menu_is_open: bool,
22328        cx: &mut Context<Editor>,
22329    ) -> bool {
22330        let mut chars = text.chars();
22331        let char = if let Some(char) = chars.next() {
22332            char
22333        } else {
22334            return false;
22335        };
22336        if chars.next().is_some() {
22337            return false;
22338        }
22339
22340        let buffer = buffer.read(cx);
22341        let snapshot = buffer.snapshot();
22342        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22343            return false;
22344        }
22345        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22346        if trigger_in_words && classifier.is_word(char) {
22347            return true;
22348        }
22349
22350        buffer.completion_triggers().contains(text)
22351    }
22352}
22353
22354impl SemanticsProvider for Entity<Project> {
22355    fn hover(
22356        &self,
22357        buffer: &Entity<Buffer>,
22358        position: text::Anchor,
22359        cx: &mut App,
22360    ) -> Option<Task<Vec<project::Hover>>> {
22361        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22362    }
22363
22364    fn document_highlights(
22365        &self,
22366        buffer: &Entity<Buffer>,
22367        position: text::Anchor,
22368        cx: &mut App,
22369    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22370        Some(self.update(cx, |project, cx| {
22371            project.document_highlights(buffer, position, cx)
22372        }))
22373    }
22374
22375    fn definitions(
22376        &self,
22377        buffer: &Entity<Buffer>,
22378        position: text::Anchor,
22379        kind: GotoDefinitionKind,
22380        cx: &mut App,
22381    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22382        Some(self.update(cx, |project, cx| match kind {
22383            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22384            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22385            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22386            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22387        }))
22388    }
22389
22390    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22391        self.update(cx, |project, cx| {
22392            if project
22393                .active_debug_session(cx)
22394                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22395            {
22396                return true;
22397            }
22398
22399            buffer.update(cx, |buffer, cx| {
22400                project.any_language_server_supports_inlay_hints(buffer, cx)
22401            })
22402        })
22403    }
22404
22405    fn inline_values(
22406        &self,
22407        buffer_handle: Entity<Buffer>,
22408        range: Range<text::Anchor>,
22409        cx: &mut App,
22410    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22411        self.update(cx, |project, cx| {
22412            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22413
22414            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22415        })
22416    }
22417
22418    fn inlay_hints(
22419        &self,
22420        buffer_handle: Entity<Buffer>,
22421        range: Range<text::Anchor>,
22422        cx: &mut App,
22423    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22424        Some(self.update(cx, |project, cx| {
22425            project.inlay_hints(buffer_handle, range, cx)
22426        }))
22427    }
22428
22429    fn resolve_inlay_hint(
22430        &self,
22431        hint: InlayHint,
22432        buffer_handle: Entity<Buffer>,
22433        server_id: LanguageServerId,
22434        cx: &mut App,
22435    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22436        Some(self.update(cx, |project, cx| {
22437            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22438        }))
22439    }
22440
22441    fn range_for_rename(
22442        &self,
22443        buffer: &Entity<Buffer>,
22444        position: text::Anchor,
22445        cx: &mut App,
22446    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22447        Some(self.update(cx, |project, cx| {
22448            let buffer = buffer.clone();
22449            let task = project.prepare_rename(buffer.clone(), position, cx);
22450            cx.spawn(async move |_, cx| {
22451                Ok(match task.await? {
22452                    PrepareRenameResponse::Success(range) => Some(range),
22453                    PrepareRenameResponse::InvalidPosition => None,
22454                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22455                        // Fallback on using TreeSitter info to determine identifier range
22456                        buffer.read_with(cx, |buffer, _| {
22457                            let snapshot = buffer.snapshot();
22458                            let (range, kind) = snapshot.surrounding_word(position, false);
22459                            if kind != Some(CharKind::Word) {
22460                                return None;
22461                            }
22462                            Some(
22463                                snapshot.anchor_before(range.start)
22464                                    ..snapshot.anchor_after(range.end),
22465                            )
22466                        })?
22467                    }
22468                })
22469            })
22470        }))
22471    }
22472
22473    fn perform_rename(
22474        &self,
22475        buffer: &Entity<Buffer>,
22476        position: text::Anchor,
22477        new_name: String,
22478        cx: &mut App,
22479    ) -> Option<Task<Result<ProjectTransaction>>> {
22480        Some(self.update(cx, |project, cx| {
22481            project.perform_rename(buffer.clone(), position, new_name, cx)
22482        }))
22483    }
22484}
22485
22486fn inlay_hint_settings(
22487    location: Anchor,
22488    snapshot: &MultiBufferSnapshot,
22489    cx: &mut Context<Editor>,
22490) -> InlayHintSettings {
22491    let file = snapshot.file_at(location);
22492    let language = snapshot.language_at(location).map(|l| l.name());
22493    language_settings(language, file, cx).inlay_hints
22494}
22495
22496fn consume_contiguous_rows(
22497    contiguous_row_selections: &mut Vec<Selection<Point>>,
22498    selection: &Selection<Point>,
22499    display_map: &DisplaySnapshot,
22500    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22501) -> (MultiBufferRow, MultiBufferRow) {
22502    contiguous_row_selections.push(selection.clone());
22503    let start_row = starting_row(selection, display_map);
22504    let mut end_row = ending_row(selection, display_map);
22505
22506    while let Some(next_selection) = selections.peek() {
22507        if next_selection.start.row <= end_row.0 {
22508            end_row = ending_row(next_selection, display_map);
22509            contiguous_row_selections.push(selections.next().unwrap().clone());
22510        } else {
22511            break;
22512        }
22513    }
22514    (start_row, end_row)
22515}
22516
22517fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22518    if selection.start.column > 0 {
22519        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22520    } else {
22521        MultiBufferRow(selection.start.row)
22522    }
22523}
22524
22525fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22526    if next_selection.end.column > 0 || next_selection.is_empty() {
22527        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22528    } else {
22529        MultiBufferRow(next_selection.end.row)
22530    }
22531}
22532
22533impl EditorSnapshot {
22534    pub fn remote_selections_in_range<'a>(
22535        &'a self,
22536        range: &'a Range<Anchor>,
22537        collaboration_hub: &dyn CollaborationHub,
22538        cx: &'a App,
22539    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22540        let participant_names = collaboration_hub.user_names(cx);
22541        let participant_indices = collaboration_hub.user_participant_indices(cx);
22542        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22543        let collaborators_by_replica_id = collaborators_by_peer_id
22544            .values()
22545            .map(|collaborator| (collaborator.replica_id, collaborator))
22546            .collect::<HashMap<_, _>>();
22547        self.buffer_snapshot
22548            .selections_in_range(range, false)
22549            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22550                if replica_id == AGENT_REPLICA_ID {
22551                    Some(RemoteSelection {
22552                        replica_id,
22553                        selection,
22554                        cursor_shape,
22555                        line_mode,
22556                        collaborator_id: CollaboratorId::Agent,
22557                        user_name: Some("Agent".into()),
22558                        color: cx.theme().players().agent(),
22559                    })
22560                } else {
22561                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22562                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22563                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22564                    Some(RemoteSelection {
22565                        replica_id,
22566                        selection,
22567                        cursor_shape,
22568                        line_mode,
22569                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22570                        user_name,
22571                        color: if let Some(index) = participant_index {
22572                            cx.theme().players().color_for_participant(index.0)
22573                        } else {
22574                            cx.theme().players().absent()
22575                        },
22576                    })
22577                }
22578            })
22579    }
22580
22581    pub fn hunks_for_ranges(
22582        &self,
22583        ranges: impl IntoIterator<Item = Range<Point>>,
22584    ) -> Vec<MultiBufferDiffHunk> {
22585        let mut hunks = Vec::new();
22586        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22587            HashMap::default();
22588        for query_range in ranges {
22589            let query_rows =
22590                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22591            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22592                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22593            ) {
22594                // Include deleted hunks that are adjacent to the query range, because
22595                // otherwise they would be missed.
22596                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22597                if hunk.status().is_deleted() {
22598                    intersects_range |= hunk.row_range.start == query_rows.end;
22599                    intersects_range |= hunk.row_range.end == query_rows.start;
22600                }
22601                if intersects_range {
22602                    if !processed_buffer_rows
22603                        .entry(hunk.buffer_id)
22604                        .or_default()
22605                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22606                    {
22607                        continue;
22608                    }
22609                    hunks.push(hunk);
22610                }
22611            }
22612        }
22613
22614        hunks
22615    }
22616
22617    fn display_diff_hunks_for_rows<'a>(
22618        &'a self,
22619        display_rows: Range<DisplayRow>,
22620        folded_buffers: &'a HashSet<BufferId>,
22621    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22622        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22623        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22624
22625        self.buffer_snapshot
22626            .diff_hunks_in_range(buffer_start..buffer_end)
22627            .filter_map(|hunk| {
22628                if folded_buffers.contains(&hunk.buffer_id) {
22629                    return None;
22630                }
22631
22632                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22633                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22634
22635                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22636                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22637
22638                let display_hunk = if hunk_display_start.column() != 0 {
22639                    DisplayDiffHunk::Folded {
22640                        display_row: hunk_display_start.row(),
22641                    }
22642                } else {
22643                    let mut end_row = hunk_display_end.row();
22644                    if hunk_display_end.column() > 0 {
22645                        end_row.0 += 1;
22646                    }
22647                    let is_created_file = hunk.is_created_file();
22648                    DisplayDiffHunk::Unfolded {
22649                        status: hunk.status(),
22650                        diff_base_byte_range: hunk.diff_base_byte_range,
22651                        display_row_range: hunk_display_start.row()..end_row,
22652                        multi_buffer_range: Anchor::range_in_buffer(
22653                            hunk.excerpt_id,
22654                            hunk.buffer_id,
22655                            hunk.buffer_range,
22656                        ),
22657                        is_created_file,
22658                    }
22659                };
22660
22661                Some(display_hunk)
22662            })
22663    }
22664
22665    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22666        self.display_snapshot.buffer_snapshot.language_at(position)
22667    }
22668
22669    pub fn is_focused(&self) -> bool {
22670        self.is_focused
22671    }
22672
22673    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22674        self.placeholder_text.as_ref()
22675    }
22676
22677    pub fn scroll_position(&self) -> gpui::Point<f32> {
22678        self.scroll_anchor.scroll_position(&self.display_snapshot)
22679    }
22680
22681    fn gutter_dimensions(
22682        &self,
22683        font_id: FontId,
22684        font_size: Pixels,
22685        max_line_number_width: Pixels,
22686        cx: &App,
22687    ) -> Option<GutterDimensions> {
22688        if !self.show_gutter {
22689            return None;
22690        }
22691
22692        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22693        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22694
22695        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22696            matches!(
22697                ProjectSettings::get_global(cx).git.git_gutter,
22698                Some(GitGutterSetting::TrackedFiles)
22699            )
22700        });
22701        let gutter_settings = EditorSettings::get_global(cx).gutter;
22702        let show_line_numbers = self
22703            .show_line_numbers
22704            .unwrap_or(gutter_settings.line_numbers);
22705        let line_gutter_width = if show_line_numbers {
22706            // Avoid flicker-like gutter resizes when the line number gains another digit by
22707            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22708            let min_width_for_number_on_gutter =
22709                ch_advance * gutter_settings.min_line_number_digits as f32;
22710            max_line_number_width.max(min_width_for_number_on_gutter)
22711        } else {
22712            0.0.into()
22713        };
22714
22715        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22716        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22717
22718        let git_blame_entries_width =
22719            self.git_blame_gutter_max_author_length
22720                .map(|max_author_length| {
22721                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22722                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22723
22724                    /// The number of characters to dedicate to gaps and margins.
22725                    const SPACING_WIDTH: usize = 4;
22726
22727                    let max_char_count = max_author_length.min(renderer.max_author_length())
22728                        + ::git::SHORT_SHA_LENGTH
22729                        + MAX_RELATIVE_TIMESTAMP.len()
22730                        + SPACING_WIDTH;
22731
22732                    ch_advance * max_char_count
22733                });
22734
22735        let is_singleton = self.buffer_snapshot.is_singleton();
22736
22737        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22738        left_padding += if !is_singleton {
22739            ch_width * 4.0
22740        } else if show_runnables || show_breakpoints {
22741            ch_width * 3.0
22742        } else if show_git_gutter && show_line_numbers {
22743            ch_width * 2.0
22744        } else if show_git_gutter || show_line_numbers {
22745            ch_width
22746        } else {
22747            px(0.)
22748        };
22749
22750        let shows_folds = is_singleton && gutter_settings.folds;
22751
22752        let right_padding = if shows_folds && show_line_numbers {
22753            ch_width * 4.0
22754        } else if shows_folds || (!is_singleton && show_line_numbers) {
22755            ch_width * 3.0
22756        } else if show_line_numbers {
22757            ch_width
22758        } else {
22759            px(0.)
22760        };
22761
22762        Some(GutterDimensions {
22763            left_padding,
22764            right_padding,
22765            width: line_gutter_width + left_padding + right_padding,
22766            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22767            git_blame_entries_width,
22768        })
22769    }
22770
22771    pub fn render_crease_toggle(
22772        &self,
22773        buffer_row: MultiBufferRow,
22774        row_contains_cursor: bool,
22775        editor: Entity<Editor>,
22776        window: &mut Window,
22777        cx: &mut App,
22778    ) -> Option<AnyElement> {
22779        let folded = self.is_line_folded(buffer_row);
22780        let mut is_foldable = false;
22781
22782        if let Some(crease) = self
22783            .crease_snapshot
22784            .query_row(buffer_row, &self.buffer_snapshot)
22785        {
22786            is_foldable = true;
22787            match crease {
22788                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22789                    if let Some(render_toggle) = render_toggle {
22790                        let toggle_callback =
22791                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22792                                if folded {
22793                                    editor.update(cx, |editor, cx| {
22794                                        editor.fold_at(buffer_row, window, cx)
22795                                    });
22796                                } else {
22797                                    editor.update(cx, |editor, cx| {
22798                                        editor.unfold_at(buffer_row, window, cx)
22799                                    });
22800                                }
22801                            });
22802                        return Some((render_toggle)(
22803                            buffer_row,
22804                            folded,
22805                            toggle_callback,
22806                            window,
22807                            cx,
22808                        ));
22809                    }
22810                }
22811            }
22812        }
22813
22814        is_foldable |= self.starts_indent(buffer_row);
22815
22816        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22817            Some(
22818                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22819                    .toggle_state(folded)
22820                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22821                        if folded {
22822                            this.unfold_at(buffer_row, window, cx);
22823                        } else {
22824                            this.fold_at(buffer_row, window, cx);
22825                        }
22826                    }))
22827                    .into_any_element(),
22828            )
22829        } else {
22830            None
22831        }
22832    }
22833
22834    pub fn render_crease_trailer(
22835        &self,
22836        buffer_row: MultiBufferRow,
22837        window: &mut Window,
22838        cx: &mut App,
22839    ) -> Option<AnyElement> {
22840        let folded = self.is_line_folded(buffer_row);
22841        if let Crease::Inline { render_trailer, .. } = self
22842            .crease_snapshot
22843            .query_row(buffer_row, &self.buffer_snapshot)?
22844        {
22845            let render_trailer = render_trailer.as_ref()?;
22846            Some(render_trailer(buffer_row, folded, window, cx))
22847        } else {
22848            None
22849        }
22850    }
22851}
22852
22853impl Deref for EditorSnapshot {
22854    type Target = DisplaySnapshot;
22855
22856    fn deref(&self) -> &Self::Target {
22857        &self.display_snapshot
22858    }
22859}
22860
22861#[derive(Clone, Debug, PartialEq, Eq)]
22862pub enum EditorEvent {
22863    InputIgnored {
22864        text: Arc<str>,
22865    },
22866    InputHandled {
22867        utf16_range_to_replace: Option<Range<isize>>,
22868        text: Arc<str>,
22869    },
22870    ExcerptsAdded {
22871        buffer: Entity<Buffer>,
22872        predecessor: ExcerptId,
22873        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22874    },
22875    ExcerptsRemoved {
22876        ids: Vec<ExcerptId>,
22877        removed_buffer_ids: Vec<BufferId>,
22878    },
22879    BufferFoldToggled {
22880        ids: Vec<ExcerptId>,
22881        folded: bool,
22882    },
22883    ExcerptsEdited {
22884        ids: Vec<ExcerptId>,
22885    },
22886    ExcerptsExpanded {
22887        ids: Vec<ExcerptId>,
22888    },
22889    BufferEdited,
22890    Edited {
22891        transaction_id: clock::Lamport,
22892    },
22893    Reparsed(BufferId),
22894    Focused,
22895    FocusedIn,
22896    Blurred,
22897    DirtyChanged,
22898    Saved,
22899    TitleChanged,
22900    DiffBaseChanged,
22901    SelectionsChanged {
22902        local: bool,
22903    },
22904    ScrollPositionChanged {
22905        local: bool,
22906        autoscroll: bool,
22907    },
22908    Closed,
22909    TransactionUndone {
22910        transaction_id: clock::Lamport,
22911    },
22912    TransactionBegun {
22913        transaction_id: clock::Lamport,
22914    },
22915    Reloaded,
22916    CursorShapeChanged,
22917    BreadcrumbsChanged,
22918    PushedToNavHistory {
22919        anchor: Anchor,
22920        is_deactivate: bool,
22921    },
22922}
22923
22924impl EventEmitter<EditorEvent> for Editor {}
22925
22926impl Focusable for Editor {
22927    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22928        self.focus_handle.clone()
22929    }
22930}
22931
22932impl Render for Editor {
22933    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22934        let settings = ThemeSettings::get_global(cx);
22935
22936        let mut text_style = match self.mode {
22937            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22938                color: cx.theme().colors().editor_foreground,
22939                font_family: settings.ui_font.family.clone(),
22940                font_features: settings.ui_font.features.clone(),
22941                font_fallbacks: settings.ui_font.fallbacks.clone(),
22942                font_size: rems(0.875).into(),
22943                font_weight: settings.ui_font.weight,
22944                line_height: relative(settings.buffer_line_height.value()),
22945                ..Default::default()
22946            },
22947            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22948                color: cx.theme().colors().editor_foreground,
22949                font_family: settings.buffer_font.family.clone(),
22950                font_features: settings.buffer_font.features.clone(),
22951                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22952                font_size: settings.buffer_font_size(cx).into(),
22953                font_weight: settings.buffer_font.weight,
22954                line_height: relative(settings.buffer_line_height.value()),
22955                ..Default::default()
22956            },
22957        };
22958        if let Some(text_style_refinement) = &self.text_style_refinement {
22959            text_style.refine(text_style_refinement)
22960        }
22961
22962        let background = match self.mode {
22963            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22964            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22965            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22966            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22967        };
22968
22969        EditorElement::new(
22970            &cx.entity(),
22971            EditorStyle {
22972                background,
22973                border: cx.theme().colors().border,
22974                local_player: cx.theme().players().local(),
22975                text: text_style,
22976                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22977                syntax: cx.theme().syntax().clone(),
22978                status: cx.theme().status().clone(),
22979                inlay_hints_style: make_inlay_hints_style(cx),
22980                edit_prediction_styles: make_suggestion_styles(cx),
22981                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22982                show_underlines: self.diagnostics_enabled(),
22983            },
22984        )
22985    }
22986}
22987
22988impl EntityInputHandler for Editor {
22989    fn text_for_range(
22990        &mut self,
22991        range_utf16: Range<usize>,
22992        adjusted_range: &mut Option<Range<usize>>,
22993        _: &mut Window,
22994        cx: &mut Context<Self>,
22995    ) -> Option<String> {
22996        let snapshot = self.buffer.read(cx).read(cx);
22997        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22998        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22999        if (start.0..end.0) != range_utf16 {
23000            adjusted_range.replace(start.0..end.0);
23001        }
23002        Some(snapshot.text_for_range(start..end).collect())
23003    }
23004
23005    fn selected_text_range(
23006        &mut self,
23007        ignore_disabled_input: bool,
23008        _: &mut Window,
23009        cx: &mut Context<Self>,
23010    ) -> Option<UTF16Selection> {
23011        // Prevent the IME menu from appearing when holding down an alphabetic key
23012        // while input is disabled.
23013        if !ignore_disabled_input && !self.input_enabled {
23014            return None;
23015        }
23016
23017        let selection = self.selections.newest::<OffsetUtf16>(cx);
23018        let range = selection.range();
23019
23020        Some(UTF16Selection {
23021            range: range.start.0..range.end.0,
23022            reversed: selection.reversed,
23023        })
23024    }
23025
23026    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23027        let snapshot = self.buffer.read(cx).read(cx);
23028        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23029        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23030    }
23031
23032    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23033        self.clear_highlights::<InputComposition>(cx);
23034        self.ime_transaction.take();
23035    }
23036
23037    fn replace_text_in_range(
23038        &mut self,
23039        range_utf16: Option<Range<usize>>,
23040        text: &str,
23041        window: &mut Window,
23042        cx: &mut Context<Self>,
23043    ) {
23044        if !self.input_enabled {
23045            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23046            return;
23047        }
23048
23049        self.transact(window, cx, |this, window, cx| {
23050            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23051                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23052                Some(this.selection_replacement_ranges(range_utf16, cx))
23053            } else {
23054                this.marked_text_ranges(cx)
23055            };
23056
23057            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23058                let newest_selection_id = this.selections.newest_anchor().id;
23059                this.selections
23060                    .all::<OffsetUtf16>(cx)
23061                    .iter()
23062                    .zip(ranges_to_replace.iter())
23063                    .find_map(|(selection, range)| {
23064                        if selection.id == newest_selection_id {
23065                            Some(
23066                                (range.start.0 as isize - selection.head().0 as isize)
23067                                    ..(range.end.0 as isize - selection.head().0 as isize),
23068                            )
23069                        } else {
23070                            None
23071                        }
23072                    })
23073            });
23074
23075            cx.emit(EditorEvent::InputHandled {
23076                utf16_range_to_replace: range_to_replace,
23077                text: text.into(),
23078            });
23079
23080            if let Some(new_selected_ranges) = new_selected_ranges {
23081                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23082                    selections.select_ranges(new_selected_ranges)
23083                });
23084                this.backspace(&Default::default(), window, cx);
23085            }
23086
23087            this.handle_input(text, window, cx);
23088        });
23089
23090        if let Some(transaction) = self.ime_transaction {
23091            self.buffer.update(cx, |buffer, cx| {
23092                buffer.group_until_transaction(transaction, cx);
23093            });
23094        }
23095
23096        self.unmark_text(window, cx);
23097    }
23098
23099    fn replace_and_mark_text_in_range(
23100        &mut self,
23101        range_utf16: Option<Range<usize>>,
23102        text: &str,
23103        new_selected_range_utf16: Option<Range<usize>>,
23104        window: &mut Window,
23105        cx: &mut Context<Self>,
23106    ) {
23107        if !self.input_enabled {
23108            return;
23109        }
23110
23111        let transaction = self.transact(window, cx, |this, window, cx| {
23112            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23113                let snapshot = this.buffer.read(cx).read(cx);
23114                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23115                    for marked_range in &mut marked_ranges {
23116                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23117                        marked_range.start.0 += relative_range_utf16.start;
23118                        marked_range.start =
23119                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23120                        marked_range.end =
23121                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23122                    }
23123                }
23124                Some(marked_ranges)
23125            } else if let Some(range_utf16) = range_utf16 {
23126                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23127                Some(this.selection_replacement_ranges(range_utf16, cx))
23128            } else {
23129                None
23130            };
23131
23132            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23133                let newest_selection_id = this.selections.newest_anchor().id;
23134                this.selections
23135                    .all::<OffsetUtf16>(cx)
23136                    .iter()
23137                    .zip(ranges_to_replace.iter())
23138                    .find_map(|(selection, range)| {
23139                        if selection.id == newest_selection_id {
23140                            Some(
23141                                (range.start.0 as isize - selection.head().0 as isize)
23142                                    ..(range.end.0 as isize - selection.head().0 as isize),
23143                            )
23144                        } else {
23145                            None
23146                        }
23147                    })
23148            });
23149
23150            cx.emit(EditorEvent::InputHandled {
23151                utf16_range_to_replace: range_to_replace,
23152                text: text.into(),
23153            });
23154
23155            if let Some(ranges) = ranges_to_replace {
23156                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23157                    s.select_ranges(ranges)
23158                });
23159            }
23160
23161            let marked_ranges = {
23162                let snapshot = this.buffer.read(cx).read(cx);
23163                this.selections
23164                    .disjoint_anchors()
23165                    .iter()
23166                    .map(|selection| {
23167                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23168                    })
23169                    .collect::<Vec<_>>()
23170            };
23171
23172            if text.is_empty() {
23173                this.unmark_text(window, cx);
23174            } else {
23175                this.highlight_text::<InputComposition>(
23176                    marked_ranges.clone(),
23177                    HighlightStyle {
23178                        underline: Some(UnderlineStyle {
23179                            thickness: px(1.),
23180                            color: None,
23181                            wavy: false,
23182                        }),
23183                        ..Default::default()
23184                    },
23185                    cx,
23186                );
23187            }
23188
23189            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23190            let use_autoclose = this.use_autoclose;
23191            let use_auto_surround = this.use_auto_surround;
23192            this.set_use_autoclose(false);
23193            this.set_use_auto_surround(false);
23194            this.handle_input(text, window, cx);
23195            this.set_use_autoclose(use_autoclose);
23196            this.set_use_auto_surround(use_auto_surround);
23197
23198            if let Some(new_selected_range) = new_selected_range_utf16 {
23199                let snapshot = this.buffer.read(cx).read(cx);
23200                let new_selected_ranges = marked_ranges
23201                    .into_iter()
23202                    .map(|marked_range| {
23203                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23204                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23205                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23206                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23207                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23208                    })
23209                    .collect::<Vec<_>>();
23210
23211                drop(snapshot);
23212                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23213                    selections.select_ranges(new_selected_ranges)
23214                });
23215            }
23216        });
23217
23218        self.ime_transaction = self.ime_transaction.or(transaction);
23219        if let Some(transaction) = self.ime_transaction {
23220            self.buffer.update(cx, |buffer, cx| {
23221                buffer.group_until_transaction(transaction, cx);
23222            });
23223        }
23224
23225        if self.text_highlights::<InputComposition>(cx).is_none() {
23226            self.ime_transaction.take();
23227        }
23228    }
23229
23230    fn bounds_for_range(
23231        &mut self,
23232        range_utf16: Range<usize>,
23233        element_bounds: gpui::Bounds<Pixels>,
23234        window: &mut Window,
23235        cx: &mut Context<Self>,
23236    ) -> Option<gpui::Bounds<Pixels>> {
23237        let text_layout_details = self.text_layout_details(window);
23238        let CharacterDimensions {
23239            em_width,
23240            em_advance,
23241            line_height,
23242        } = self.character_dimensions(window);
23243
23244        let snapshot = self.snapshot(window, cx);
23245        let scroll_position = snapshot.scroll_position();
23246        let scroll_left = scroll_position.x * em_advance;
23247
23248        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23249        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23250            + self.gutter_dimensions.full_width();
23251        let y = line_height * (start.row().as_f32() - scroll_position.y);
23252
23253        Some(Bounds {
23254            origin: element_bounds.origin + point(x, y),
23255            size: size(em_width, line_height),
23256        })
23257    }
23258
23259    fn character_index_for_point(
23260        &mut self,
23261        point: gpui::Point<Pixels>,
23262        _window: &mut Window,
23263        _cx: &mut Context<Self>,
23264    ) -> Option<usize> {
23265        let position_map = self.last_position_map.as_ref()?;
23266        if !position_map.text_hitbox.contains(&point) {
23267            return None;
23268        }
23269        let display_point = position_map.point_for_position(point).previous_valid;
23270        let anchor = position_map
23271            .snapshot
23272            .display_point_to_anchor(display_point, Bias::Left);
23273        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23274        Some(utf16_offset.0)
23275    }
23276}
23277
23278trait SelectionExt {
23279    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23280    fn spanned_rows(
23281        &self,
23282        include_end_if_at_line_start: bool,
23283        map: &DisplaySnapshot,
23284    ) -> Range<MultiBufferRow>;
23285}
23286
23287impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23288    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23289        let start = self
23290            .start
23291            .to_point(&map.buffer_snapshot)
23292            .to_display_point(map);
23293        let end = self
23294            .end
23295            .to_point(&map.buffer_snapshot)
23296            .to_display_point(map);
23297        if self.reversed {
23298            end..start
23299        } else {
23300            start..end
23301        }
23302    }
23303
23304    fn spanned_rows(
23305        &self,
23306        include_end_if_at_line_start: bool,
23307        map: &DisplaySnapshot,
23308    ) -> Range<MultiBufferRow> {
23309        let start = self.start.to_point(&map.buffer_snapshot);
23310        let mut end = self.end.to_point(&map.buffer_snapshot);
23311        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23312            end.row -= 1;
23313        }
23314
23315        let buffer_start = map.prev_line_boundary(start).0;
23316        let buffer_end = map.next_line_boundary(end).0;
23317        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23318    }
23319}
23320
23321impl<T: InvalidationRegion> InvalidationStack<T> {
23322    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23323    where
23324        S: Clone + ToOffset,
23325    {
23326        while let Some(region) = self.last() {
23327            let all_selections_inside_invalidation_ranges =
23328                if selections.len() == region.ranges().len() {
23329                    selections
23330                        .iter()
23331                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23332                        .all(|(selection, invalidation_range)| {
23333                            let head = selection.head().to_offset(buffer);
23334                            invalidation_range.start <= head && invalidation_range.end >= head
23335                        })
23336                } else {
23337                    false
23338                };
23339
23340            if all_selections_inside_invalidation_ranges {
23341                break;
23342            } else {
23343                self.pop();
23344            }
23345        }
23346    }
23347}
23348
23349impl<T> Default for InvalidationStack<T> {
23350    fn default() -> Self {
23351        Self(Default::default())
23352    }
23353}
23354
23355impl<T> Deref for InvalidationStack<T> {
23356    type Target = Vec<T>;
23357
23358    fn deref(&self) -> &Self::Target {
23359        &self.0
23360    }
23361}
23362
23363impl<T> DerefMut for InvalidationStack<T> {
23364    fn deref_mut(&mut self) -> &mut Self::Target {
23365        &mut self.0
23366    }
23367}
23368
23369impl InvalidationRegion for SnippetState {
23370    fn ranges(&self) -> &[Range<Anchor>] {
23371        &self.ranges[self.active_index]
23372    }
23373}
23374
23375fn edit_prediction_edit_text(
23376    current_snapshot: &BufferSnapshot,
23377    edits: &[(Range<Anchor>, String)],
23378    edit_preview: &EditPreview,
23379    include_deletions: bool,
23380    cx: &App,
23381) -> HighlightedText {
23382    let edits = edits
23383        .iter()
23384        .map(|(anchor, text)| {
23385            (
23386                anchor.start.text_anchor..anchor.end.text_anchor,
23387                text.clone(),
23388            )
23389        })
23390        .collect::<Vec<_>>();
23391
23392    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23393}
23394
23395fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23396    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23397    // Just show the raw edit text with basic styling
23398    let mut text = String::new();
23399    let mut highlights = Vec::new();
23400
23401    let insertion_highlight_style = HighlightStyle {
23402        color: Some(cx.theme().colors().text),
23403        ..Default::default()
23404    };
23405
23406    for (_, edit_text) in edits {
23407        let start_offset = text.len();
23408        text.push_str(edit_text);
23409        let end_offset = text.len();
23410
23411        if start_offset < end_offset {
23412            highlights.push((start_offset..end_offset, insertion_highlight_style));
23413        }
23414    }
23415
23416    HighlightedText {
23417        text: text.into(),
23418        highlights,
23419    }
23420}
23421
23422pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23423    match severity {
23424        lsp::DiagnosticSeverity::ERROR => colors.error,
23425        lsp::DiagnosticSeverity::WARNING => colors.warning,
23426        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23427        lsp::DiagnosticSeverity::HINT => colors.info,
23428        _ => colors.ignored,
23429    }
23430}
23431
23432pub fn styled_runs_for_code_label<'a>(
23433    label: &'a CodeLabel,
23434    syntax_theme: &'a theme::SyntaxTheme,
23435) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23436    let fade_out = HighlightStyle {
23437        fade_out: Some(0.35),
23438        ..Default::default()
23439    };
23440
23441    let mut prev_end = label.filter_range.end;
23442    label
23443        .runs
23444        .iter()
23445        .enumerate()
23446        .flat_map(move |(ix, (range, highlight_id))| {
23447            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23448                style
23449            } else {
23450                return Default::default();
23451            };
23452            let mut muted_style = style;
23453            muted_style.highlight(fade_out);
23454
23455            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23456            if range.start >= label.filter_range.end {
23457                if range.start > prev_end {
23458                    runs.push((prev_end..range.start, fade_out));
23459                }
23460                runs.push((range.clone(), muted_style));
23461            } else if range.end <= label.filter_range.end {
23462                runs.push((range.clone(), style));
23463            } else {
23464                runs.push((range.start..label.filter_range.end, style));
23465                runs.push((label.filter_range.end..range.end, muted_style));
23466            }
23467            prev_end = cmp::max(prev_end, range.end);
23468
23469            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23470                runs.push((prev_end..label.text.len(), fade_out));
23471            }
23472
23473            runs
23474        })
23475}
23476
23477pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23478    let mut prev_index = 0;
23479    let mut prev_codepoint: Option<char> = None;
23480    text.char_indices()
23481        .chain([(text.len(), '\0')])
23482        .filter_map(move |(index, codepoint)| {
23483            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23484            let is_boundary = index == text.len()
23485                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23486                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23487            if is_boundary {
23488                let chunk = &text[prev_index..index];
23489                prev_index = index;
23490                Some(chunk)
23491            } else {
23492                None
23493            }
23494        })
23495}
23496
23497pub trait RangeToAnchorExt: Sized {
23498    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23499
23500    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23501        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23502        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23503    }
23504}
23505
23506impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23507    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23508        let start_offset = self.start.to_offset(snapshot);
23509        let end_offset = self.end.to_offset(snapshot);
23510        if start_offset == end_offset {
23511            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23512        } else {
23513            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23514        }
23515    }
23516}
23517
23518pub trait RowExt {
23519    fn as_f32(&self) -> f32;
23520
23521    fn next_row(&self) -> Self;
23522
23523    fn previous_row(&self) -> Self;
23524
23525    fn minus(&self, other: Self) -> u32;
23526}
23527
23528impl RowExt for DisplayRow {
23529    fn as_f32(&self) -> f32 {
23530        self.0 as f32
23531    }
23532
23533    fn next_row(&self) -> Self {
23534        Self(self.0 + 1)
23535    }
23536
23537    fn previous_row(&self) -> Self {
23538        Self(self.0.saturating_sub(1))
23539    }
23540
23541    fn minus(&self, other: Self) -> u32 {
23542        self.0 - other.0
23543    }
23544}
23545
23546impl RowExt for MultiBufferRow {
23547    fn as_f32(&self) -> f32 {
23548        self.0 as f32
23549    }
23550
23551    fn next_row(&self) -> Self {
23552        Self(self.0 + 1)
23553    }
23554
23555    fn previous_row(&self) -> Self {
23556        Self(self.0.saturating_sub(1))
23557    }
23558
23559    fn minus(&self, other: Self) -> u32 {
23560        self.0 - other.0
23561    }
23562}
23563
23564trait RowRangeExt {
23565    type Row;
23566
23567    fn len(&self) -> usize;
23568
23569    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23570}
23571
23572impl RowRangeExt for Range<MultiBufferRow> {
23573    type Row = MultiBufferRow;
23574
23575    fn len(&self) -> usize {
23576        (self.end.0 - self.start.0) as usize
23577    }
23578
23579    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23580        (self.start.0..self.end.0).map(MultiBufferRow)
23581    }
23582}
23583
23584impl RowRangeExt for Range<DisplayRow> {
23585    type Row = DisplayRow;
23586
23587    fn len(&self) -> usize {
23588        (self.end.0 - self.start.0) as usize
23589    }
23590
23591    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23592        (self.start.0..self.end.0).map(DisplayRow)
23593    }
23594}
23595
23596/// If select range has more than one line, we
23597/// just point the cursor to range.start.
23598fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23599    if range.start.row == range.end.row {
23600        range
23601    } else {
23602        range.start..range.start
23603    }
23604}
23605pub struct KillRing(ClipboardItem);
23606impl Global for KillRing {}
23607
23608const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23609
23610enum BreakpointPromptEditAction {
23611    Log,
23612    Condition,
23613    HitCondition,
23614}
23615
23616struct BreakpointPromptEditor {
23617    pub(crate) prompt: Entity<Editor>,
23618    editor: WeakEntity<Editor>,
23619    breakpoint_anchor: Anchor,
23620    breakpoint: Breakpoint,
23621    edit_action: BreakpointPromptEditAction,
23622    block_ids: HashSet<CustomBlockId>,
23623    editor_margins: Arc<Mutex<EditorMargins>>,
23624    _subscriptions: Vec<Subscription>,
23625}
23626
23627impl BreakpointPromptEditor {
23628    const MAX_LINES: u8 = 4;
23629
23630    fn new(
23631        editor: WeakEntity<Editor>,
23632        breakpoint_anchor: Anchor,
23633        breakpoint: Breakpoint,
23634        edit_action: BreakpointPromptEditAction,
23635        window: &mut Window,
23636        cx: &mut Context<Self>,
23637    ) -> Self {
23638        let base_text = match edit_action {
23639            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23640            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23641            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23642        }
23643        .map(|msg| msg.to_string())
23644        .unwrap_or_default();
23645
23646        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23647        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23648
23649        let prompt = cx.new(|cx| {
23650            let mut prompt = Editor::new(
23651                EditorMode::AutoHeight {
23652                    min_lines: 1,
23653                    max_lines: Some(Self::MAX_LINES as usize),
23654                },
23655                buffer,
23656                None,
23657                window,
23658                cx,
23659            );
23660            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23661            prompt.set_show_cursor_when_unfocused(false, cx);
23662            prompt.set_placeholder_text(
23663                match edit_action {
23664                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23665                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23666                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23667                },
23668                cx,
23669            );
23670
23671            prompt
23672        });
23673
23674        Self {
23675            prompt,
23676            editor,
23677            breakpoint_anchor,
23678            breakpoint,
23679            edit_action,
23680            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23681            block_ids: Default::default(),
23682            _subscriptions: vec![],
23683        }
23684    }
23685
23686    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23687        self.block_ids.extend(block_ids)
23688    }
23689
23690    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23691        if let Some(editor) = self.editor.upgrade() {
23692            let message = self
23693                .prompt
23694                .read(cx)
23695                .buffer
23696                .read(cx)
23697                .as_singleton()
23698                .expect("A multi buffer in breakpoint prompt isn't possible")
23699                .read(cx)
23700                .as_rope()
23701                .to_string();
23702
23703            editor.update(cx, |editor, cx| {
23704                editor.edit_breakpoint_at_anchor(
23705                    self.breakpoint_anchor,
23706                    self.breakpoint.clone(),
23707                    match self.edit_action {
23708                        BreakpointPromptEditAction::Log => {
23709                            BreakpointEditAction::EditLogMessage(message.into())
23710                        }
23711                        BreakpointPromptEditAction::Condition => {
23712                            BreakpointEditAction::EditCondition(message.into())
23713                        }
23714                        BreakpointPromptEditAction::HitCondition => {
23715                            BreakpointEditAction::EditHitCondition(message.into())
23716                        }
23717                    },
23718                    cx,
23719                );
23720
23721                editor.remove_blocks(self.block_ids.clone(), None, cx);
23722                cx.focus_self(window);
23723            });
23724        }
23725    }
23726
23727    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23728        self.editor
23729            .update(cx, |editor, cx| {
23730                editor.remove_blocks(self.block_ids.clone(), None, cx);
23731                window.focus(&editor.focus_handle);
23732            })
23733            .log_err();
23734    }
23735
23736    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23737        let settings = ThemeSettings::get_global(cx);
23738        let text_style = TextStyle {
23739            color: if self.prompt.read(cx).read_only(cx) {
23740                cx.theme().colors().text_disabled
23741            } else {
23742                cx.theme().colors().text
23743            },
23744            font_family: settings.buffer_font.family.clone(),
23745            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23746            font_size: settings.buffer_font_size(cx).into(),
23747            font_weight: settings.buffer_font.weight,
23748            line_height: relative(settings.buffer_line_height.value()),
23749            ..Default::default()
23750        };
23751        EditorElement::new(
23752            &self.prompt,
23753            EditorStyle {
23754                background: cx.theme().colors().editor_background,
23755                local_player: cx.theme().players().local(),
23756                text: text_style,
23757                ..Default::default()
23758            },
23759        )
23760    }
23761}
23762
23763impl Render for BreakpointPromptEditor {
23764    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23765        let editor_margins = *self.editor_margins.lock();
23766        let gutter_dimensions = editor_margins.gutter;
23767        h_flex()
23768            .key_context("Editor")
23769            .bg(cx.theme().colors().editor_background)
23770            .border_y_1()
23771            .border_color(cx.theme().status().info_border)
23772            .size_full()
23773            .py(window.line_height() / 2.5)
23774            .on_action(cx.listener(Self::confirm))
23775            .on_action(cx.listener(Self::cancel))
23776            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23777            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23778    }
23779}
23780
23781impl Focusable for BreakpointPromptEditor {
23782    fn focus_handle(&self, cx: &App) -> FocusHandle {
23783        self.prompt.focus_handle(cx)
23784    }
23785}
23786
23787fn all_edits_insertions_or_deletions(
23788    edits: &Vec<(Range<Anchor>, String)>,
23789    snapshot: &MultiBufferSnapshot,
23790) -> bool {
23791    let mut all_insertions = true;
23792    let mut all_deletions = true;
23793
23794    for (range, new_text) in edits.iter() {
23795        let range_is_empty = range.to_offset(snapshot).is_empty();
23796        let text_is_empty = new_text.is_empty();
23797
23798        if range_is_empty != text_is_empty {
23799            if range_is_empty {
23800                all_deletions = false;
23801            } else {
23802                all_insertions = false;
23803            }
23804        } else {
23805            return false;
23806        }
23807
23808        if !all_insertions && !all_deletions {
23809            return false;
23810        }
23811    }
23812    all_insertions || all_deletions
23813}
23814
23815struct MissingEditPredictionKeybindingTooltip;
23816
23817impl Render for MissingEditPredictionKeybindingTooltip {
23818    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23819        ui::tooltip_container(window, cx, |container, _, cx| {
23820            container
23821                .flex_shrink_0()
23822                .max_w_80()
23823                .min_h(rems_from_px(124.))
23824                .justify_between()
23825                .child(
23826                    v_flex()
23827                        .flex_1()
23828                        .text_ui_sm(cx)
23829                        .child(Label::new("Conflict with Accept Keybinding"))
23830                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23831                )
23832                .child(
23833                    h_flex()
23834                        .pb_1()
23835                        .gap_1()
23836                        .items_end()
23837                        .w_full()
23838                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23839                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23840                        }))
23841                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23842                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23843                        })),
23844                )
23845        })
23846    }
23847}
23848
23849#[derive(Debug, Clone, Copy, PartialEq)]
23850pub struct LineHighlight {
23851    pub background: Background,
23852    pub border: Option<gpui::Hsla>,
23853    pub include_gutter: bool,
23854    pub type_id: Option<TypeId>,
23855}
23856
23857struct LineManipulationResult {
23858    pub new_text: String,
23859    pub line_count_before: usize,
23860    pub line_count_after: usize,
23861}
23862
23863fn render_diff_hunk_controls(
23864    row: u32,
23865    status: &DiffHunkStatus,
23866    hunk_range: Range<Anchor>,
23867    is_created_file: bool,
23868    line_height: Pixels,
23869    editor: &Entity<Editor>,
23870    _window: &mut Window,
23871    cx: &mut App,
23872) -> AnyElement {
23873    h_flex()
23874        .h(line_height)
23875        .mr_1()
23876        .gap_1()
23877        .px_0p5()
23878        .pb_1()
23879        .border_x_1()
23880        .border_b_1()
23881        .border_color(cx.theme().colors().border_variant)
23882        .rounded_b_lg()
23883        .bg(cx.theme().colors().editor_background)
23884        .gap_1()
23885        .block_mouse_except_scroll()
23886        .shadow_md()
23887        .child(if status.has_secondary_hunk() {
23888            Button::new(("stage", row as u64), "Stage")
23889                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23890                .tooltip({
23891                    let focus_handle = editor.focus_handle(cx);
23892                    move |window, cx| {
23893                        Tooltip::for_action_in(
23894                            "Stage Hunk",
23895                            &::git::ToggleStaged,
23896                            &focus_handle,
23897                            window,
23898                            cx,
23899                        )
23900                    }
23901                })
23902                .on_click({
23903                    let editor = editor.clone();
23904                    move |_event, _window, cx| {
23905                        editor.update(cx, |editor, cx| {
23906                            editor.stage_or_unstage_diff_hunks(
23907                                true,
23908                                vec![hunk_range.start..hunk_range.start],
23909                                cx,
23910                            );
23911                        });
23912                    }
23913                })
23914        } else {
23915            Button::new(("unstage", row as u64), "Unstage")
23916                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23917                .tooltip({
23918                    let focus_handle = editor.focus_handle(cx);
23919                    move |window, cx| {
23920                        Tooltip::for_action_in(
23921                            "Unstage Hunk",
23922                            &::git::ToggleStaged,
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                            editor.stage_or_unstage_diff_hunks(
23934                                false,
23935                                vec![hunk_range.start..hunk_range.start],
23936                                cx,
23937                            );
23938                        });
23939                    }
23940                })
23941        })
23942        .child(
23943            Button::new(("restore", row as u64), "Restore")
23944                .tooltip({
23945                    let focus_handle = editor.focus_handle(cx);
23946                    move |window, cx| {
23947                        Tooltip::for_action_in(
23948                            "Restore Hunk",
23949                            &::git::Restore,
23950                            &focus_handle,
23951                            window,
23952                            cx,
23953                        )
23954                    }
23955                })
23956                .on_click({
23957                    let editor = editor.clone();
23958                    move |_event, window, cx| {
23959                        editor.update(cx, |editor, cx| {
23960                            let snapshot = editor.snapshot(window, cx);
23961                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23962                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23963                        });
23964                    }
23965                })
23966                .disabled(is_created_file),
23967        )
23968        .when(
23969            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23970            |el| {
23971                el.child(
23972                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23973                        .shape(IconButtonShape::Square)
23974                        .icon_size(IconSize::Small)
23975                        // .disabled(!has_multiple_hunks)
23976                        .tooltip({
23977                            let focus_handle = editor.focus_handle(cx);
23978                            move |window, cx| {
23979                                Tooltip::for_action_in(
23980                                    "Next Hunk",
23981                                    &GoToHunk,
23982                                    &focus_handle,
23983                                    window,
23984                                    cx,
23985                                )
23986                            }
23987                        })
23988                        .on_click({
23989                            let editor = editor.clone();
23990                            move |_event, window, cx| {
23991                                editor.update(cx, |editor, cx| {
23992                                    let snapshot = editor.snapshot(window, cx);
23993                                    let position =
23994                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23995                                    editor.go_to_hunk_before_or_after_position(
23996                                        &snapshot,
23997                                        position,
23998                                        Direction::Next,
23999                                        window,
24000                                        cx,
24001                                    );
24002                                    editor.expand_selected_diff_hunks(cx);
24003                                });
24004                            }
24005                        }),
24006                )
24007                .child(
24008                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24009                        .shape(IconButtonShape::Square)
24010                        .icon_size(IconSize::Small)
24011                        // .disabled(!has_multiple_hunks)
24012                        .tooltip({
24013                            let focus_handle = editor.focus_handle(cx);
24014                            move |window, cx| {
24015                                Tooltip::for_action_in(
24016                                    "Previous Hunk",
24017                                    &GoToPreviousHunk,
24018                                    &focus_handle,
24019                                    window,
24020                                    cx,
24021                                )
24022                            }
24023                        })
24024                        .on_click({
24025                            let editor = editor.clone();
24026                            move |_event, window, cx| {
24027                                editor.update(cx, |editor, cx| {
24028                                    let snapshot = editor.snapshot(window, cx);
24029                                    let point =
24030                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24031                                    editor.go_to_hunk_before_or_after_position(
24032                                        &snapshot,
24033                                        point,
24034                                        Direction::Prev,
24035                                        window,
24036                                        cx,
24037                                    );
24038                                    editor.expand_selected_diff_hunks(cx);
24039                                });
24040                            }
24041                        }),
24042                )
24043            },
24044        )
24045        .into_any_element()
24046}