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        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7768
 7769        if self.edit_prediction_indent_conflict {
 7770            let cursor_point = cursor.to_point(&multibuffer);
 7771
 7772            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7773
 7774            if let Some((_, indent)) = indents.iter().next() {
 7775                if indent.len == cursor_point.column {
 7776                    self.edit_prediction_indent_conflict = false;
 7777                }
 7778            }
 7779        }
 7780
 7781        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7782        let edits = edit_prediction
 7783            .edits
 7784            .into_iter()
 7785            .flat_map(|(range, new_text)| {
 7786                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7787                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7788                Some((start..end, new_text))
 7789            })
 7790            .collect::<Vec<_>>();
 7791        if edits.is_empty() {
 7792            return None;
 7793        }
 7794
 7795        let first_edit_start = edits.first().unwrap().0.start;
 7796        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7797        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7798
 7799        let last_edit_end = edits.last().unwrap().0.end;
 7800        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7801        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7802
 7803        let cursor_row = cursor.to_point(&multibuffer).row;
 7804
 7805        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7806
 7807        let mut inlay_ids = Vec::new();
 7808        let invalidation_row_range;
 7809        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7810            Some(cursor_row..edit_end_row)
 7811        } else if cursor_row > edit_end_row {
 7812            Some(edit_start_row..cursor_row)
 7813        } else {
 7814            None
 7815        };
 7816        let supports_jump = self
 7817            .edit_prediction_provider
 7818            .as_ref()
 7819            .map(|provider| provider.provider.supports_jump_to_edit())
 7820            .unwrap_or(true);
 7821
 7822        let is_move = supports_jump
 7823            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7824        let completion = if is_move {
 7825            invalidation_row_range =
 7826                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7827            let target = first_edit_start;
 7828            EditPrediction::Move { target, snapshot }
 7829        } else {
 7830            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7831                && !self.edit_predictions_hidden_for_vim_mode;
 7832
 7833            if show_completions_in_buffer {
 7834                if edits
 7835                    .iter()
 7836                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7837                {
 7838                    let mut inlays = Vec::new();
 7839                    for (range, new_text) in &edits {
 7840                        let inlay = Inlay::edit_prediction(
 7841                            post_inc(&mut self.next_inlay_id),
 7842                            range.start,
 7843                            new_text.as_str(),
 7844                        );
 7845                        inlay_ids.push(inlay.id);
 7846                        inlays.push(inlay);
 7847                    }
 7848
 7849                    self.splice_inlays(&[], inlays, cx);
 7850                } else {
 7851                    let background_color = cx.theme().status().deleted_background;
 7852                    self.highlight_text::<EditPredictionHighlight>(
 7853                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7854                        HighlightStyle {
 7855                            background_color: Some(background_color),
 7856                            ..Default::default()
 7857                        },
 7858                        cx,
 7859                    );
 7860                }
 7861            }
 7862
 7863            invalidation_row_range = edit_start_row..edit_end_row;
 7864
 7865            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7866                if provider.show_tab_accept_marker() {
 7867                    EditDisplayMode::TabAccept
 7868                } else {
 7869                    EditDisplayMode::Inline
 7870                }
 7871            } else {
 7872                EditDisplayMode::DiffPopover
 7873            };
 7874
 7875            EditPrediction::Edit {
 7876                edits,
 7877                edit_preview: edit_prediction.edit_preview,
 7878                display_mode,
 7879                snapshot,
 7880            }
 7881        };
 7882
 7883        let invalidation_range = multibuffer
 7884            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7885            ..multibuffer.anchor_after(Point::new(
 7886                invalidation_row_range.end,
 7887                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7888            ));
 7889
 7890        self.stale_edit_prediction_in_menu = None;
 7891        self.active_edit_prediction = Some(EditPredictionState {
 7892            inlay_ids,
 7893            completion,
 7894            completion_id: edit_prediction.id,
 7895            invalidation_range,
 7896        });
 7897
 7898        cx.notify();
 7899
 7900        Some(())
 7901    }
 7902
 7903    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7904        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7905    }
 7906
 7907    fn clear_tasks(&mut self) {
 7908        self.tasks.clear()
 7909    }
 7910
 7911    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7912        if self.tasks.insert(key, value).is_some() {
 7913            // This case should hopefully be rare, but just in case...
 7914            log::error!(
 7915                "multiple different run targets found on a single line, only the last target will be rendered"
 7916            )
 7917        }
 7918    }
 7919
 7920    /// Get all display points of breakpoints that will be rendered within editor
 7921    ///
 7922    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7923    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7924    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7925    fn active_breakpoints(
 7926        &self,
 7927        range: Range<DisplayRow>,
 7928        window: &mut Window,
 7929        cx: &mut Context<Self>,
 7930    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7931        let mut breakpoint_display_points = HashMap::default();
 7932
 7933        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7934            return breakpoint_display_points;
 7935        };
 7936
 7937        let snapshot = self.snapshot(window, cx);
 7938
 7939        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7940        let Some(project) = self.project() else {
 7941            return breakpoint_display_points;
 7942        };
 7943
 7944        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7945            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7946
 7947        for (buffer_snapshot, range, excerpt_id) in
 7948            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7949        {
 7950            let Some(buffer) = project
 7951                .read(cx)
 7952                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7953            else {
 7954                continue;
 7955            };
 7956            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7957                &buffer,
 7958                Some(
 7959                    buffer_snapshot.anchor_before(range.start)
 7960                        ..buffer_snapshot.anchor_after(range.end),
 7961                ),
 7962                buffer_snapshot,
 7963                cx,
 7964            );
 7965            for (breakpoint, state) in breakpoints {
 7966                let multi_buffer_anchor =
 7967                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7968                let position = multi_buffer_anchor
 7969                    .to_point(multi_buffer_snapshot)
 7970                    .to_display_point(&snapshot);
 7971
 7972                breakpoint_display_points.insert(
 7973                    position.row(),
 7974                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7975                );
 7976            }
 7977        }
 7978
 7979        breakpoint_display_points
 7980    }
 7981
 7982    fn breakpoint_context_menu(
 7983        &self,
 7984        anchor: Anchor,
 7985        window: &mut Window,
 7986        cx: &mut Context<Self>,
 7987    ) -> Entity<ui::ContextMenu> {
 7988        let weak_editor = cx.weak_entity();
 7989        let focus_handle = self.focus_handle(cx);
 7990
 7991        let row = self
 7992            .buffer
 7993            .read(cx)
 7994            .snapshot(cx)
 7995            .summary_for_anchor::<Point>(&anchor)
 7996            .row;
 7997
 7998        let breakpoint = self
 7999            .breakpoint_at_row(row, window, cx)
 8000            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8001
 8002        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8003            "Edit Log Breakpoint"
 8004        } else {
 8005            "Set Log Breakpoint"
 8006        };
 8007
 8008        let condition_breakpoint_msg = if breakpoint
 8009            .as_ref()
 8010            .is_some_and(|bp| bp.1.condition.is_some())
 8011        {
 8012            "Edit Condition Breakpoint"
 8013        } else {
 8014            "Set Condition Breakpoint"
 8015        };
 8016
 8017        let hit_condition_breakpoint_msg = if breakpoint
 8018            .as_ref()
 8019            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8020        {
 8021            "Edit Hit Condition Breakpoint"
 8022        } else {
 8023            "Set Hit Condition Breakpoint"
 8024        };
 8025
 8026        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8027            "Unset Breakpoint"
 8028        } else {
 8029            "Set Breakpoint"
 8030        };
 8031
 8032        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8033
 8034        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8035            BreakpointState::Enabled => Some("Disable"),
 8036            BreakpointState::Disabled => Some("Enable"),
 8037        });
 8038
 8039        let (anchor, breakpoint) =
 8040            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8041
 8042        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8043            menu.on_blur_subscription(Subscription::new(|| {}))
 8044                .context(focus_handle)
 8045                .when(run_to_cursor, |this| {
 8046                    let weak_editor = weak_editor.clone();
 8047                    this.entry("Run to cursor", None, move |window, cx| {
 8048                        weak_editor
 8049                            .update(cx, |editor, cx| {
 8050                                editor.change_selections(
 8051                                    SelectionEffects::no_scroll(),
 8052                                    window,
 8053                                    cx,
 8054                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8055                                );
 8056                            })
 8057                            .ok();
 8058
 8059                        window.dispatch_action(Box::new(RunToCursor), cx);
 8060                    })
 8061                    .separator()
 8062                })
 8063                .when_some(toggle_state_msg, |this, msg| {
 8064                    this.entry(msg, None, {
 8065                        let weak_editor = weak_editor.clone();
 8066                        let breakpoint = breakpoint.clone();
 8067                        move |_window, cx| {
 8068                            weak_editor
 8069                                .update(cx, |this, cx| {
 8070                                    this.edit_breakpoint_at_anchor(
 8071                                        anchor,
 8072                                        breakpoint.as_ref().clone(),
 8073                                        BreakpointEditAction::InvertState,
 8074                                        cx,
 8075                                    );
 8076                                })
 8077                                .log_err();
 8078                        }
 8079                    })
 8080                })
 8081                .entry(set_breakpoint_msg, None, {
 8082                    let weak_editor = weak_editor.clone();
 8083                    let breakpoint = breakpoint.clone();
 8084                    move |_window, cx| {
 8085                        weak_editor
 8086                            .update(cx, |this, cx| {
 8087                                this.edit_breakpoint_at_anchor(
 8088                                    anchor,
 8089                                    breakpoint.as_ref().clone(),
 8090                                    BreakpointEditAction::Toggle,
 8091                                    cx,
 8092                                );
 8093                            })
 8094                            .log_err();
 8095                    }
 8096                })
 8097                .entry(log_breakpoint_msg, None, {
 8098                    let breakpoint = breakpoint.clone();
 8099                    let weak_editor = weak_editor.clone();
 8100                    move |window, cx| {
 8101                        weak_editor
 8102                            .update(cx, |this, cx| {
 8103                                this.add_edit_breakpoint_block(
 8104                                    anchor,
 8105                                    breakpoint.as_ref(),
 8106                                    BreakpointPromptEditAction::Log,
 8107                                    window,
 8108                                    cx,
 8109                                );
 8110                            })
 8111                            .log_err();
 8112                    }
 8113                })
 8114                .entry(condition_breakpoint_msg, None, {
 8115                    let breakpoint = breakpoint.clone();
 8116                    let weak_editor = weak_editor.clone();
 8117                    move |window, cx| {
 8118                        weak_editor
 8119                            .update(cx, |this, cx| {
 8120                                this.add_edit_breakpoint_block(
 8121                                    anchor,
 8122                                    breakpoint.as_ref(),
 8123                                    BreakpointPromptEditAction::Condition,
 8124                                    window,
 8125                                    cx,
 8126                                );
 8127                            })
 8128                            .log_err();
 8129                    }
 8130                })
 8131                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8132                    weak_editor
 8133                        .update(cx, |this, cx| {
 8134                            this.add_edit_breakpoint_block(
 8135                                anchor,
 8136                                breakpoint.as_ref(),
 8137                                BreakpointPromptEditAction::HitCondition,
 8138                                window,
 8139                                cx,
 8140                            );
 8141                        })
 8142                        .log_err();
 8143                })
 8144        })
 8145    }
 8146
 8147    fn render_breakpoint(
 8148        &self,
 8149        position: Anchor,
 8150        row: DisplayRow,
 8151        breakpoint: &Breakpoint,
 8152        state: Option<BreakpointSessionState>,
 8153        cx: &mut Context<Self>,
 8154    ) -> IconButton {
 8155        let is_rejected = state.is_some_and(|s| !s.verified);
 8156        // Is it a breakpoint that shows up when hovering over gutter?
 8157        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8158            (false, false),
 8159            |PhantomBreakpointIndicator {
 8160                 is_active,
 8161                 display_row,
 8162                 collides_with_existing_breakpoint,
 8163             }| {
 8164                (
 8165                    is_active && display_row == row,
 8166                    collides_with_existing_breakpoint,
 8167                )
 8168            },
 8169        );
 8170
 8171        let (color, icon) = {
 8172            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8173                (false, false) => ui::IconName::DebugBreakpoint,
 8174                (true, false) => ui::IconName::DebugLogBreakpoint,
 8175                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8176                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8177            };
 8178
 8179            let color = if is_phantom {
 8180                Color::Hint
 8181            } else if is_rejected {
 8182                Color::Disabled
 8183            } else {
 8184                Color::Debugger
 8185            };
 8186
 8187            (color, icon)
 8188        };
 8189
 8190        let breakpoint = Arc::from(breakpoint.clone());
 8191
 8192        let alt_as_text = gpui::Keystroke {
 8193            modifiers: Modifiers::secondary_key(),
 8194            ..Default::default()
 8195        };
 8196        let primary_action_text = if breakpoint.is_disabled() {
 8197            "Enable breakpoint"
 8198        } else if is_phantom && !collides_with_existing {
 8199            "Set breakpoint"
 8200        } else {
 8201            "Unset breakpoint"
 8202        };
 8203        let focus_handle = self.focus_handle.clone();
 8204
 8205        let meta = if is_rejected {
 8206            SharedString::from("No executable code is associated with this line.")
 8207        } else if collides_with_existing && !breakpoint.is_disabled() {
 8208            SharedString::from(format!(
 8209                "{alt_as_text}-click to disable,\nright-click for more options."
 8210            ))
 8211        } else {
 8212            SharedString::from("Right-click for more options.")
 8213        };
 8214        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8215            .icon_size(IconSize::XSmall)
 8216            .size(ui::ButtonSize::None)
 8217            .when(is_rejected, |this| {
 8218                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8219            })
 8220            .icon_color(color)
 8221            .style(ButtonStyle::Transparent)
 8222            .on_click(cx.listener({
 8223                let breakpoint = breakpoint.clone();
 8224
 8225                move |editor, event: &ClickEvent, window, cx| {
 8226                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8227                        BreakpointEditAction::InvertState
 8228                    } else {
 8229                        BreakpointEditAction::Toggle
 8230                    };
 8231
 8232                    window.focus(&editor.focus_handle(cx));
 8233                    editor.edit_breakpoint_at_anchor(
 8234                        position,
 8235                        breakpoint.as_ref().clone(),
 8236                        edit_action,
 8237                        cx,
 8238                    );
 8239                }
 8240            }))
 8241            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8242                editor.set_breakpoint_context_menu(
 8243                    row,
 8244                    Some(position),
 8245                    event.position(),
 8246                    window,
 8247                    cx,
 8248                );
 8249            }))
 8250            .tooltip(move |window, cx| {
 8251                Tooltip::with_meta_in(
 8252                    primary_action_text,
 8253                    Some(&ToggleBreakpoint),
 8254                    meta.clone(),
 8255                    &focus_handle,
 8256                    window,
 8257                    cx,
 8258                )
 8259            })
 8260    }
 8261
 8262    fn build_tasks_context(
 8263        project: &Entity<Project>,
 8264        buffer: &Entity<Buffer>,
 8265        buffer_row: u32,
 8266        tasks: &Arc<RunnableTasks>,
 8267        cx: &mut Context<Self>,
 8268    ) -> Task<Option<task::TaskContext>> {
 8269        let position = Point::new(buffer_row, tasks.column);
 8270        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8271        let location = Location {
 8272            buffer: buffer.clone(),
 8273            range: range_start..range_start,
 8274        };
 8275        // Fill in the environmental variables from the tree-sitter captures
 8276        let mut captured_task_variables = TaskVariables::default();
 8277        for (capture_name, value) in tasks.extra_variables.clone() {
 8278            captured_task_variables.insert(
 8279                task::VariableName::Custom(capture_name.into()),
 8280                value.clone(),
 8281            );
 8282        }
 8283        project.update(cx, |project, cx| {
 8284            project.task_store().update(cx, |task_store, cx| {
 8285                task_store.task_context_for_location(captured_task_variables, location, cx)
 8286            })
 8287        })
 8288    }
 8289
 8290    pub fn spawn_nearest_task(
 8291        &mut self,
 8292        action: &SpawnNearestTask,
 8293        window: &mut Window,
 8294        cx: &mut Context<Self>,
 8295    ) {
 8296        let Some((workspace, _)) = self.workspace.clone() else {
 8297            return;
 8298        };
 8299        let Some(project) = self.project.clone() else {
 8300            return;
 8301        };
 8302
 8303        // Try to find a closest, enclosing node using tree-sitter that has a task
 8304        let Some((buffer, buffer_row, tasks)) = self
 8305            .find_enclosing_node_task(cx)
 8306            // Or find the task that's closest in row-distance.
 8307            .or_else(|| self.find_closest_task(cx))
 8308        else {
 8309            return;
 8310        };
 8311
 8312        let reveal_strategy = action.reveal;
 8313        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8314        cx.spawn_in(window, async move |_, cx| {
 8315            let context = task_context.await?;
 8316            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8317
 8318            let resolved = &mut resolved_task.resolved;
 8319            resolved.reveal = reveal_strategy;
 8320
 8321            workspace
 8322                .update_in(cx, |workspace, window, cx| {
 8323                    workspace.schedule_resolved_task(
 8324                        task_source_kind,
 8325                        resolved_task,
 8326                        false,
 8327                        window,
 8328                        cx,
 8329                    );
 8330                })
 8331                .ok()
 8332        })
 8333        .detach();
 8334    }
 8335
 8336    fn find_closest_task(
 8337        &mut self,
 8338        cx: &mut Context<Self>,
 8339    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8340        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8341
 8342        let ((buffer_id, row), tasks) = self
 8343            .tasks
 8344            .iter()
 8345            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8346
 8347        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8348        let tasks = Arc::new(tasks.to_owned());
 8349        Some((buffer, *row, tasks))
 8350    }
 8351
 8352    fn find_enclosing_node_task(
 8353        &mut self,
 8354        cx: &mut Context<Self>,
 8355    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8356        let snapshot = self.buffer.read(cx).snapshot(cx);
 8357        let offset = self.selections.newest::<usize>(cx).head();
 8358        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8359        let buffer_id = excerpt.buffer().remote_id();
 8360
 8361        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8362        let mut cursor = layer.node().walk();
 8363
 8364        while cursor.goto_first_child_for_byte(offset).is_some() {
 8365            if cursor.node().end_byte() == offset {
 8366                cursor.goto_next_sibling();
 8367            }
 8368        }
 8369
 8370        // Ascend to the smallest ancestor that contains the range and has a task.
 8371        loop {
 8372            let node = cursor.node();
 8373            let node_range = node.byte_range();
 8374            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8375
 8376            // Check if this node contains our offset
 8377            if node_range.start <= offset && node_range.end >= offset {
 8378                // If it contains offset, check for task
 8379                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8380                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8381                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8382                }
 8383            }
 8384
 8385            if !cursor.goto_parent() {
 8386                break;
 8387            }
 8388        }
 8389        None
 8390    }
 8391
 8392    fn render_run_indicator(
 8393        &self,
 8394        _style: &EditorStyle,
 8395        is_active: bool,
 8396        row: DisplayRow,
 8397        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8398        cx: &mut Context<Self>,
 8399    ) -> IconButton {
 8400        let color = Color::Muted;
 8401        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8402
 8403        IconButton::new(
 8404            ("run_indicator", row.0 as usize),
 8405            ui::IconName::PlayOutlined,
 8406        )
 8407        .shape(ui::IconButtonShape::Square)
 8408        .icon_size(IconSize::XSmall)
 8409        .icon_color(color)
 8410        .toggle_state(is_active)
 8411        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8412            let quick_launch = match e {
 8413                ClickEvent::Keyboard(_) => true,
 8414                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8415            };
 8416
 8417            window.focus(&editor.focus_handle(cx));
 8418            editor.toggle_code_actions(
 8419                &ToggleCodeActions {
 8420                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8421                    quick_launch,
 8422                },
 8423                window,
 8424                cx,
 8425            );
 8426        }))
 8427        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8428            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8429        }))
 8430    }
 8431
 8432    pub fn context_menu_visible(&self) -> bool {
 8433        !self.edit_prediction_preview_is_active()
 8434            && self
 8435                .context_menu
 8436                .borrow()
 8437                .as_ref()
 8438                .map_or(false, |menu| menu.visible())
 8439    }
 8440
 8441    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8442        self.context_menu
 8443            .borrow()
 8444            .as_ref()
 8445            .map(|menu| menu.origin())
 8446    }
 8447
 8448    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8449        self.context_menu_options = Some(options);
 8450    }
 8451
 8452    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8453    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8454
 8455    fn render_edit_prediction_popover(
 8456        &mut self,
 8457        text_bounds: &Bounds<Pixels>,
 8458        content_origin: gpui::Point<Pixels>,
 8459        right_margin: Pixels,
 8460        editor_snapshot: &EditorSnapshot,
 8461        visible_row_range: Range<DisplayRow>,
 8462        scroll_top: f32,
 8463        scroll_bottom: f32,
 8464        line_layouts: &[LineWithInvisibles],
 8465        line_height: Pixels,
 8466        scroll_pixel_position: gpui::Point<Pixels>,
 8467        newest_selection_head: Option<DisplayPoint>,
 8468        editor_width: Pixels,
 8469        style: &EditorStyle,
 8470        window: &mut Window,
 8471        cx: &mut App,
 8472    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8473        if self.mode().is_minimap() {
 8474            return None;
 8475        }
 8476        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8477
 8478        if self.edit_prediction_visible_in_cursor_popover(true) {
 8479            return None;
 8480        }
 8481
 8482        match &active_edit_prediction.completion {
 8483            EditPrediction::Move { target, .. } => {
 8484                let target_display_point = target.to_display_point(editor_snapshot);
 8485
 8486                if self.edit_prediction_requires_modifier() {
 8487                    if !self.edit_prediction_preview_is_active() {
 8488                        return None;
 8489                    }
 8490
 8491                    self.render_edit_prediction_modifier_jump_popover(
 8492                        text_bounds,
 8493                        content_origin,
 8494                        visible_row_range,
 8495                        line_layouts,
 8496                        line_height,
 8497                        scroll_pixel_position,
 8498                        newest_selection_head,
 8499                        target_display_point,
 8500                        window,
 8501                        cx,
 8502                    )
 8503                } else {
 8504                    self.render_edit_prediction_eager_jump_popover(
 8505                        text_bounds,
 8506                        content_origin,
 8507                        editor_snapshot,
 8508                        visible_row_range,
 8509                        scroll_top,
 8510                        scroll_bottom,
 8511                        line_height,
 8512                        scroll_pixel_position,
 8513                        target_display_point,
 8514                        editor_width,
 8515                        window,
 8516                        cx,
 8517                    )
 8518                }
 8519            }
 8520            EditPrediction::Edit {
 8521                display_mode: EditDisplayMode::Inline,
 8522                ..
 8523            } => None,
 8524            EditPrediction::Edit {
 8525                display_mode: EditDisplayMode::TabAccept,
 8526                edits,
 8527                ..
 8528            } => {
 8529                let range = &edits.first()?.0;
 8530                let target_display_point = range.end.to_display_point(editor_snapshot);
 8531
 8532                self.render_edit_prediction_end_of_line_popover(
 8533                    "Accept",
 8534                    editor_snapshot,
 8535                    visible_row_range,
 8536                    target_display_point,
 8537                    line_height,
 8538                    scroll_pixel_position,
 8539                    content_origin,
 8540                    editor_width,
 8541                    window,
 8542                    cx,
 8543                )
 8544            }
 8545            EditPrediction::Edit {
 8546                edits,
 8547                edit_preview,
 8548                display_mode: EditDisplayMode::DiffPopover,
 8549                snapshot,
 8550            } => self.render_edit_prediction_diff_popover(
 8551                text_bounds,
 8552                content_origin,
 8553                right_margin,
 8554                editor_snapshot,
 8555                visible_row_range,
 8556                line_layouts,
 8557                line_height,
 8558                scroll_pixel_position,
 8559                newest_selection_head,
 8560                editor_width,
 8561                style,
 8562                edits,
 8563                edit_preview,
 8564                snapshot,
 8565                window,
 8566                cx,
 8567            ),
 8568        }
 8569    }
 8570
 8571    fn render_edit_prediction_modifier_jump_popover(
 8572        &mut self,
 8573        text_bounds: &Bounds<Pixels>,
 8574        content_origin: gpui::Point<Pixels>,
 8575        visible_row_range: Range<DisplayRow>,
 8576        line_layouts: &[LineWithInvisibles],
 8577        line_height: Pixels,
 8578        scroll_pixel_position: gpui::Point<Pixels>,
 8579        newest_selection_head: Option<DisplayPoint>,
 8580        target_display_point: DisplayPoint,
 8581        window: &mut Window,
 8582        cx: &mut App,
 8583    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8584        let scrolled_content_origin =
 8585            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8586
 8587        const SCROLL_PADDING_Y: Pixels = px(12.);
 8588
 8589        if target_display_point.row() < visible_row_range.start {
 8590            return self.render_edit_prediction_scroll_popover(
 8591                |_| SCROLL_PADDING_Y,
 8592                IconName::ArrowUp,
 8593                visible_row_range,
 8594                line_layouts,
 8595                newest_selection_head,
 8596                scrolled_content_origin,
 8597                window,
 8598                cx,
 8599            );
 8600        } else if target_display_point.row() >= visible_row_range.end {
 8601            return self.render_edit_prediction_scroll_popover(
 8602                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8603                IconName::ArrowDown,
 8604                visible_row_range,
 8605                line_layouts,
 8606                newest_selection_head,
 8607                scrolled_content_origin,
 8608                window,
 8609                cx,
 8610            );
 8611        }
 8612
 8613        const POLE_WIDTH: Pixels = px(2.);
 8614
 8615        let line_layout =
 8616            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8617        let target_column = target_display_point.column() as usize;
 8618
 8619        let target_x = line_layout.x_for_index(target_column);
 8620        let target_y =
 8621            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8622
 8623        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8624
 8625        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8626        border_color.l += 0.001;
 8627
 8628        let mut element = v_flex()
 8629            .items_end()
 8630            .when(flag_on_right, |el| el.items_start())
 8631            .child(if flag_on_right {
 8632                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8633                    .rounded_bl(px(0.))
 8634                    .rounded_tl(px(0.))
 8635                    .border_l_2()
 8636                    .border_color(border_color)
 8637            } else {
 8638                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8639                    .rounded_br(px(0.))
 8640                    .rounded_tr(px(0.))
 8641                    .border_r_2()
 8642                    .border_color(border_color)
 8643            })
 8644            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8645            .into_any();
 8646
 8647        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8648
 8649        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8650            - point(
 8651                if flag_on_right {
 8652                    POLE_WIDTH
 8653                } else {
 8654                    size.width - POLE_WIDTH
 8655                },
 8656                size.height - line_height,
 8657            );
 8658
 8659        origin.x = origin.x.max(content_origin.x);
 8660
 8661        element.prepaint_at(origin, window, cx);
 8662
 8663        Some((element, origin))
 8664    }
 8665
 8666    fn render_edit_prediction_scroll_popover(
 8667        &mut self,
 8668        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8669        scroll_icon: IconName,
 8670        visible_row_range: Range<DisplayRow>,
 8671        line_layouts: &[LineWithInvisibles],
 8672        newest_selection_head: Option<DisplayPoint>,
 8673        scrolled_content_origin: gpui::Point<Pixels>,
 8674        window: &mut Window,
 8675        cx: &mut App,
 8676    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8677        let mut element = self
 8678            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8679            .into_any();
 8680
 8681        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8682
 8683        let cursor = newest_selection_head?;
 8684        let cursor_row_layout =
 8685            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8686        let cursor_column = cursor.column() as usize;
 8687
 8688        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8689
 8690        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8691
 8692        element.prepaint_at(origin, window, cx);
 8693        Some((element, origin))
 8694    }
 8695
 8696    fn render_edit_prediction_eager_jump_popover(
 8697        &mut self,
 8698        text_bounds: &Bounds<Pixels>,
 8699        content_origin: gpui::Point<Pixels>,
 8700        editor_snapshot: &EditorSnapshot,
 8701        visible_row_range: Range<DisplayRow>,
 8702        scroll_top: f32,
 8703        scroll_bottom: f32,
 8704        line_height: Pixels,
 8705        scroll_pixel_position: gpui::Point<Pixels>,
 8706        target_display_point: DisplayPoint,
 8707        editor_width: Pixels,
 8708        window: &mut Window,
 8709        cx: &mut App,
 8710    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8711        if target_display_point.row().as_f32() < scroll_top {
 8712            let mut element = self
 8713                .render_edit_prediction_line_popover(
 8714                    "Jump to Edit",
 8715                    Some(IconName::ArrowUp),
 8716                    window,
 8717                    cx,
 8718                )?
 8719                .into_any();
 8720
 8721            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8722            let offset = point(
 8723                (text_bounds.size.width - size.width) / 2.,
 8724                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8725            );
 8726
 8727            let origin = text_bounds.origin + offset;
 8728            element.prepaint_at(origin, window, cx);
 8729            Some((element, origin))
 8730        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8731            let mut element = self
 8732                .render_edit_prediction_line_popover(
 8733                    "Jump to Edit",
 8734                    Some(IconName::ArrowDown),
 8735                    window,
 8736                    cx,
 8737                )?
 8738                .into_any();
 8739
 8740            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8741            let offset = point(
 8742                (text_bounds.size.width - size.width) / 2.,
 8743                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8744            );
 8745
 8746            let origin = text_bounds.origin + offset;
 8747            element.prepaint_at(origin, window, cx);
 8748            Some((element, origin))
 8749        } else {
 8750            self.render_edit_prediction_end_of_line_popover(
 8751                "Jump to Edit",
 8752                editor_snapshot,
 8753                visible_row_range,
 8754                target_display_point,
 8755                line_height,
 8756                scroll_pixel_position,
 8757                content_origin,
 8758                editor_width,
 8759                window,
 8760                cx,
 8761            )
 8762        }
 8763    }
 8764
 8765    fn render_edit_prediction_end_of_line_popover(
 8766        self: &mut Editor,
 8767        label: &'static str,
 8768        editor_snapshot: &EditorSnapshot,
 8769        visible_row_range: Range<DisplayRow>,
 8770        target_display_point: DisplayPoint,
 8771        line_height: Pixels,
 8772        scroll_pixel_position: gpui::Point<Pixels>,
 8773        content_origin: gpui::Point<Pixels>,
 8774        editor_width: Pixels,
 8775        window: &mut Window,
 8776        cx: &mut App,
 8777    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8778        let target_line_end = DisplayPoint::new(
 8779            target_display_point.row(),
 8780            editor_snapshot.line_len(target_display_point.row()),
 8781        );
 8782
 8783        let mut element = self
 8784            .render_edit_prediction_line_popover(label, None, window, cx)?
 8785            .into_any();
 8786
 8787        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8788
 8789        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8790
 8791        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8792        let mut origin = start_point
 8793            + line_origin
 8794            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8795        origin.x = origin.x.max(content_origin.x);
 8796
 8797        let max_x = content_origin.x + editor_width - size.width;
 8798
 8799        if origin.x > max_x {
 8800            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8801
 8802            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8803                origin.y += offset;
 8804                IconName::ArrowUp
 8805            } else {
 8806                origin.y -= offset;
 8807                IconName::ArrowDown
 8808            };
 8809
 8810            element = self
 8811                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8812                .into_any();
 8813
 8814            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8815
 8816            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8817        }
 8818
 8819        element.prepaint_at(origin, window, cx);
 8820        Some((element, origin))
 8821    }
 8822
 8823    fn render_edit_prediction_diff_popover(
 8824        self: &Editor,
 8825        text_bounds: &Bounds<Pixels>,
 8826        content_origin: gpui::Point<Pixels>,
 8827        right_margin: Pixels,
 8828        editor_snapshot: &EditorSnapshot,
 8829        visible_row_range: Range<DisplayRow>,
 8830        line_layouts: &[LineWithInvisibles],
 8831        line_height: Pixels,
 8832        scroll_pixel_position: gpui::Point<Pixels>,
 8833        newest_selection_head: Option<DisplayPoint>,
 8834        editor_width: Pixels,
 8835        style: &EditorStyle,
 8836        edits: &Vec<(Range<Anchor>, String)>,
 8837        edit_preview: &Option<language::EditPreview>,
 8838        snapshot: &language::BufferSnapshot,
 8839        window: &mut Window,
 8840        cx: &mut App,
 8841    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8842        let edit_start = edits
 8843            .first()
 8844            .unwrap()
 8845            .0
 8846            .start
 8847            .to_display_point(editor_snapshot);
 8848        let edit_end = edits
 8849            .last()
 8850            .unwrap()
 8851            .0
 8852            .end
 8853            .to_display_point(editor_snapshot);
 8854
 8855        let is_visible = visible_row_range.contains(&edit_start.row())
 8856            || visible_row_range.contains(&edit_end.row());
 8857        if !is_visible {
 8858            return None;
 8859        }
 8860
 8861        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8862            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8863        } else {
 8864            // Fallback for providers without edit_preview
 8865            crate::edit_prediction_fallback_text(edits, cx)
 8866        };
 8867
 8868        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8869        let line_count = highlighted_edits.text.lines().count();
 8870
 8871        const BORDER_WIDTH: Pixels = px(1.);
 8872
 8873        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8874        let has_keybind = keybind.is_some();
 8875
 8876        let mut element = h_flex()
 8877            .items_start()
 8878            .child(
 8879                h_flex()
 8880                    .bg(cx.theme().colors().editor_background)
 8881                    .border(BORDER_WIDTH)
 8882                    .shadow_xs()
 8883                    .border_color(cx.theme().colors().border)
 8884                    .rounded_l_lg()
 8885                    .when(line_count > 1, |el| el.rounded_br_lg())
 8886                    .pr_1()
 8887                    .child(styled_text),
 8888            )
 8889            .child(
 8890                h_flex()
 8891                    .h(line_height + BORDER_WIDTH * 2.)
 8892                    .px_1p5()
 8893                    .gap_1()
 8894                    // Workaround: For some reason, there's a gap if we don't do this
 8895                    .ml(-BORDER_WIDTH)
 8896                    .shadow(vec![gpui::BoxShadow {
 8897                        color: gpui::black().opacity(0.05),
 8898                        offset: point(px(1.), px(1.)),
 8899                        blur_radius: px(2.),
 8900                        spread_radius: px(0.),
 8901                    }])
 8902                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8903                    .border(BORDER_WIDTH)
 8904                    .border_color(cx.theme().colors().border)
 8905                    .rounded_r_lg()
 8906                    .id("edit_prediction_diff_popover_keybind")
 8907                    .when(!has_keybind, |el| {
 8908                        let status_colors = cx.theme().status();
 8909
 8910                        el.bg(status_colors.error_background)
 8911                            .border_color(status_colors.error.opacity(0.6))
 8912                            .child(Icon::new(IconName::Info).color(Color::Error))
 8913                            .cursor_default()
 8914                            .hoverable_tooltip(move |_window, cx| {
 8915                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8916                            })
 8917                    })
 8918                    .children(keybind),
 8919            )
 8920            .into_any();
 8921
 8922        let longest_row =
 8923            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8924        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8925            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8926        } else {
 8927            layout_line(
 8928                longest_row,
 8929                editor_snapshot,
 8930                style,
 8931                editor_width,
 8932                |_| false,
 8933                window,
 8934                cx,
 8935            )
 8936            .width
 8937        };
 8938
 8939        let viewport_bounds =
 8940            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8941                right: -right_margin,
 8942                ..Default::default()
 8943            });
 8944
 8945        let x_after_longest =
 8946            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8947                - scroll_pixel_position.x;
 8948
 8949        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8950
 8951        // Fully visible if it can be displayed within the window (allow overlapping other
 8952        // panes). However, this is only allowed if the popover starts within text_bounds.
 8953        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8954            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8955
 8956        let mut origin = if can_position_to_the_right {
 8957            point(
 8958                x_after_longest,
 8959                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8960                    - scroll_pixel_position.y,
 8961            )
 8962        } else {
 8963            let cursor_row = newest_selection_head.map(|head| head.row());
 8964            let above_edit = edit_start
 8965                .row()
 8966                .0
 8967                .checked_sub(line_count as u32)
 8968                .map(DisplayRow);
 8969            let below_edit = Some(edit_end.row() + 1);
 8970            let above_cursor =
 8971                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8972            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8973
 8974            // Place the edit popover adjacent to the edit if there is a location
 8975            // available that is onscreen and does not obscure the cursor. Otherwise,
 8976            // place it adjacent to the cursor.
 8977            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8978                .into_iter()
 8979                .flatten()
 8980                .find(|&start_row| {
 8981                    let end_row = start_row + line_count as u32;
 8982                    visible_row_range.contains(&start_row)
 8983                        && visible_row_range.contains(&end_row)
 8984                        && cursor_row.map_or(true, |cursor_row| {
 8985                            !((start_row..end_row).contains(&cursor_row))
 8986                        })
 8987                })?;
 8988
 8989            content_origin
 8990                + point(
 8991                    -scroll_pixel_position.x,
 8992                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8993                )
 8994        };
 8995
 8996        origin.x -= BORDER_WIDTH;
 8997
 8998        window.defer_draw(element, origin, 1);
 8999
 9000        // Do not return an element, since it will already be drawn due to defer_draw.
 9001        None
 9002    }
 9003
 9004    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9005        px(30.)
 9006    }
 9007
 9008    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9009        if self.read_only(cx) {
 9010            cx.theme().players().read_only()
 9011        } else {
 9012            self.style.as_ref().unwrap().local_player
 9013        }
 9014    }
 9015
 9016    fn render_edit_prediction_accept_keybind(
 9017        &self,
 9018        window: &mut Window,
 9019        cx: &App,
 9020    ) -> Option<AnyElement> {
 9021        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9022        let accept_keystroke = accept_binding.keystroke()?;
 9023
 9024        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9025
 9026        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 9027            Color::Accent
 9028        } else {
 9029            Color::Muted
 9030        };
 9031
 9032        h_flex()
 9033            .px_0p5()
 9034            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9035            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9036            .text_size(TextSize::XSmall.rems(cx))
 9037            .child(h_flex().children(ui::render_modifiers(
 9038                &accept_keystroke.modifiers,
 9039                PlatformStyle::platform(),
 9040                Some(modifiers_color),
 9041                Some(IconSize::XSmall.rems().into()),
 9042                true,
 9043            )))
 9044            .when(is_platform_style_mac, |parent| {
 9045                parent.child(accept_keystroke.key.clone())
 9046            })
 9047            .when(!is_platform_style_mac, |parent| {
 9048                parent.child(
 9049                    Key::new(
 9050                        util::capitalize(&accept_keystroke.key),
 9051                        Some(Color::Default),
 9052                    )
 9053                    .size(Some(IconSize::XSmall.rems().into())),
 9054                )
 9055            })
 9056            .into_any()
 9057            .into()
 9058    }
 9059
 9060    fn render_edit_prediction_line_popover(
 9061        &self,
 9062        label: impl Into<SharedString>,
 9063        icon: Option<IconName>,
 9064        window: &mut Window,
 9065        cx: &App,
 9066    ) -> Option<Stateful<Div>> {
 9067        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9068
 9069        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9070        let has_keybind = keybind.is_some();
 9071
 9072        let result = h_flex()
 9073            .id("ep-line-popover")
 9074            .py_0p5()
 9075            .pl_1()
 9076            .pr(padding_right)
 9077            .gap_1()
 9078            .rounded_md()
 9079            .border_1()
 9080            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9081            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9082            .shadow_xs()
 9083            .when(!has_keybind, |el| {
 9084                let status_colors = cx.theme().status();
 9085
 9086                el.bg(status_colors.error_background)
 9087                    .border_color(status_colors.error.opacity(0.6))
 9088                    .pl_2()
 9089                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9090                    .cursor_default()
 9091                    .hoverable_tooltip(move |_window, cx| {
 9092                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9093                    })
 9094            })
 9095            .children(keybind)
 9096            .child(
 9097                Label::new(label)
 9098                    .size(LabelSize::Small)
 9099                    .when(!has_keybind, |el| {
 9100                        el.color(cx.theme().status().error.into()).strikethrough()
 9101                    }),
 9102            )
 9103            .when(!has_keybind, |el| {
 9104                el.child(
 9105                    h_flex().ml_1().child(
 9106                        Icon::new(IconName::Info)
 9107                            .size(IconSize::Small)
 9108                            .color(cx.theme().status().error.into()),
 9109                    ),
 9110                )
 9111            })
 9112            .when_some(icon, |element, icon| {
 9113                element.child(
 9114                    div()
 9115                        .mt(px(1.5))
 9116                        .child(Icon::new(icon).size(IconSize::Small)),
 9117                )
 9118            });
 9119
 9120        Some(result)
 9121    }
 9122
 9123    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9124        let accent_color = cx.theme().colors().text_accent;
 9125        let editor_bg_color = cx.theme().colors().editor_background;
 9126        editor_bg_color.blend(accent_color.opacity(0.1))
 9127    }
 9128
 9129    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9130        let accent_color = cx.theme().colors().text_accent;
 9131        let editor_bg_color = cx.theme().colors().editor_background;
 9132        editor_bg_color.blend(accent_color.opacity(0.6))
 9133    }
 9134    fn get_prediction_provider_icon_name(
 9135        provider: &Option<RegisteredEditPredictionProvider>,
 9136    ) -> IconName {
 9137        match provider {
 9138            Some(provider) => match provider.provider.name() {
 9139                "copilot" => IconName::Copilot,
 9140                "supermaven" => IconName::Supermaven,
 9141                _ => IconName::ZedPredict,
 9142            },
 9143            None => IconName::ZedPredict,
 9144        }
 9145    }
 9146
 9147    fn render_edit_prediction_cursor_popover(
 9148        &self,
 9149        min_width: Pixels,
 9150        max_width: Pixels,
 9151        cursor_point: Point,
 9152        style: &EditorStyle,
 9153        accept_keystroke: Option<&gpui::Keystroke>,
 9154        _window: &Window,
 9155        cx: &mut Context<Editor>,
 9156    ) -> Option<AnyElement> {
 9157        let provider = self.edit_prediction_provider.as_ref()?;
 9158        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9159
 9160        if provider.provider.needs_terms_acceptance(cx) {
 9161            return Some(
 9162                h_flex()
 9163                    .min_w(min_width)
 9164                    .flex_1()
 9165                    .px_2()
 9166                    .py_1()
 9167                    .gap_3()
 9168                    .elevation_2(cx)
 9169                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9170                    .id("accept-terms")
 9171                    .cursor_pointer()
 9172                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9173                    .on_click(cx.listener(|this, _event, window, cx| {
 9174                        cx.stop_propagation();
 9175                        this.report_editor_event(ReportEditorEvent::ZetaTosClicked, None, cx);
 9176                        window.dispatch_action(
 9177                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9178                            cx,
 9179                        );
 9180                    }))
 9181                    .child(
 9182                        h_flex()
 9183                            .flex_1()
 9184                            .gap_2()
 9185                            .child(Icon::new(provider_icon))
 9186                            .child(Label::new("Accept Terms of Service"))
 9187                            .child(div().w_full())
 9188                            .child(
 9189                                Icon::new(IconName::ArrowUpRight)
 9190                                    .color(Color::Muted)
 9191                                    .size(IconSize::Small),
 9192                            )
 9193                            .into_any_element(),
 9194                    )
 9195                    .into_any(),
 9196            );
 9197        }
 9198
 9199        let is_refreshing = provider.provider.is_refreshing(cx);
 9200
 9201        fn pending_completion_container(icon: IconName) -> Div {
 9202            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9203        }
 9204
 9205        let completion = match &self.active_edit_prediction {
 9206            Some(prediction) => {
 9207                if !self.has_visible_completions_menu() {
 9208                    const RADIUS: Pixels = px(6.);
 9209                    const BORDER_WIDTH: Pixels = px(1.);
 9210
 9211                    return Some(
 9212                        h_flex()
 9213                            .elevation_2(cx)
 9214                            .border(BORDER_WIDTH)
 9215                            .border_color(cx.theme().colors().border)
 9216                            .when(accept_keystroke.is_none(), |el| {
 9217                                el.border_color(cx.theme().status().error)
 9218                            })
 9219                            .rounded(RADIUS)
 9220                            .rounded_tl(px(0.))
 9221                            .overflow_hidden()
 9222                            .child(div().px_1p5().child(match &prediction.completion {
 9223                                EditPrediction::Move { target, snapshot } => {
 9224                                    use text::ToPoint as _;
 9225                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9226                                    {
 9227                                        Icon::new(IconName::ZedPredictDown)
 9228                                    } else {
 9229                                        Icon::new(IconName::ZedPredictUp)
 9230                                    }
 9231                                }
 9232                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9233                            }))
 9234                            .child(
 9235                                h_flex()
 9236                                    .gap_1()
 9237                                    .py_1()
 9238                                    .px_2()
 9239                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9240                                    .border_l_1()
 9241                                    .border_color(cx.theme().colors().border)
 9242                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9243                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9244                                        el.child(
 9245                                            Label::new("Hold")
 9246                                                .size(LabelSize::Small)
 9247                                                .when(accept_keystroke.is_none(), |el| {
 9248                                                    el.strikethrough()
 9249                                                })
 9250                                                .line_height_style(LineHeightStyle::UiLabel),
 9251                                        )
 9252                                    })
 9253                                    .id("edit_prediction_cursor_popover_keybind")
 9254                                    .when(accept_keystroke.is_none(), |el| {
 9255                                        let status_colors = cx.theme().status();
 9256
 9257                                        el.bg(status_colors.error_background)
 9258                                            .border_color(status_colors.error.opacity(0.6))
 9259                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9260                                            .cursor_default()
 9261                                            .hoverable_tooltip(move |_window, cx| {
 9262                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9263                                                    .into()
 9264                                            })
 9265                                    })
 9266                                    .when_some(
 9267                                        accept_keystroke.as_ref(),
 9268                                        |el, accept_keystroke| {
 9269                                            el.child(h_flex().children(ui::render_modifiers(
 9270                                                &accept_keystroke.modifiers,
 9271                                                PlatformStyle::platform(),
 9272                                                Some(Color::Default),
 9273                                                Some(IconSize::XSmall.rems().into()),
 9274                                                false,
 9275                                            )))
 9276                                        },
 9277                                    ),
 9278                            )
 9279                            .into_any(),
 9280                    );
 9281                }
 9282
 9283                self.render_edit_prediction_cursor_popover_preview(
 9284                    prediction,
 9285                    cursor_point,
 9286                    style,
 9287                    cx,
 9288                )?
 9289            }
 9290
 9291            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9292                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9293                    stale_completion,
 9294                    cursor_point,
 9295                    style,
 9296                    cx,
 9297                )?,
 9298
 9299                None => pending_completion_container(provider_icon)
 9300                    .child(Label::new("...").size(LabelSize::Small)),
 9301            },
 9302
 9303            None => pending_completion_container(provider_icon)
 9304                .child(Label::new("...").size(LabelSize::Small)),
 9305        };
 9306
 9307        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9308            completion
 9309                .with_animation(
 9310                    "loading-completion",
 9311                    Animation::new(Duration::from_secs(2))
 9312                        .repeat()
 9313                        .with_easing(pulsating_between(0.4, 0.8)),
 9314                    |label, delta| label.opacity(delta),
 9315                )
 9316                .into_any_element()
 9317        } else {
 9318            completion.into_any_element()
 9319        };
 9320
 9321        let has_completion = self.active_edit_prediction.is_some();
 9322
 9323        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9324        Some(
 9325            h_flex()
 9326                .min_w(min_width)
 9327                .max_w(max_width)
 9328                .flex_1()
 9329                .elevation_2(cx)
 9330                .border_color(cx.theme().colors().border)
 9331                .child(
 9332                    div()
 9333                        .flex_1()
 9334                        .py_1()
 9335                        .px_2()
 9336                        .overflow_hidden()
 9337                        .child(completion),
 9338                )
 9339                .when_some(accept_keystroke, |el, accept_keystroke| {
 9340                    if !accept_keystroke.modifiers.modified() {
 9341                        return el;
 9342                    }
 9343
 9344                    el.child(
 9345                        h_flex()
 9346                            .h_full()
 9347                            .border_l_1()
 9348                            .rounded_r_lg()
 9349                            .border_color(cx.theme().colors().border)
 9350                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9351                            .gap_1()
 9352                            .py_1()
 9353                            .px_2()
 9354                            .child(
 9355                                h_flex()
 9356                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9357                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9358                                    .child(h_flex().children(ui::render_modifiers(
 9359                                        &accept_keystroke.modifiers,
 9360                                        PlatformStyle::platform(),
 9361                                        Some(if !has_completion {
 9362                                            Color::Muted
 9363                                        } else {
 9364                                            Color::Default
 9365                                        }),
 9366                                        None,
 9367                                        false,
 9368                                    ))),
 9369                            )
 9370                            .child(Label::new("Preview").into_any_element())
 9371                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9372                    )
 9373                })
 9374                .into_any(),
 9375        )
 9376    }
 9377
 9378    fn render_edit_prediction_cursor_popover_preview(
 9379        &self,
 9380        completion: &EditPredictionState,
 9381        cursor_point: Point,
 9382        style: &EditorStyle,
 9383        cx: &mut Context<Editor>,
 9384    ) -> Option<Div> {
 9385        use text::ToPoint as _;
 9386
 9387        fn render_relative_row_jump(
 9388            prefix: impl Into<String>,
 9389            current_row: u32,
 9390            target_row: u32,
 9391        ) -> Div {
 9392            let (row_diff, arrow) = if target_row < current_row {
 9393                (current_row - target_row, IconName::ArrowUp)
 9394            } else {
 9395                (target_row - current_row, IconName::ArrowDown)
 9396            };
 9397
 9398            h_flex()
 9399                .child(
 9400                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9401                        .color(Color::Muted)
 9402                        .size(LabelSize::Small),
 9403                )
 9404                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9405        }
 9406
 9407        let supports_jump = self
 9408            .edit_prediction_provider
 9409            .as_ref()
 9410            .map(|provider| provider.provider.supports_jump_to_edit())
 9411            .unwrap_or(true);
 9412
 9413        match &completion.completion {
 9414            EditPrediction::Move {
 9415                target, snapshot, ..
 9416            } => {
 9417                if !supports_jump {
 9418                    return None;
 9419                }
 9420
 9421                Some(
 9422                    h_flex()
 9423                        .px_2()
 9424                        .gap_2()
 9425                        .flex_1()
 9426                        .child(
 9427                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9428                                Icon::new(IconName::ZedPredictDown)
 9429                            } else {
 9430                                Icon::new(IconName::ZedPredictUp)
 9431                            },
 9432                        )
 9433                        .child(Label::new("Jump to Edit")),
 9434                )
 9435            }
 9436
 9437            EditPrediction::Edit {
 9438                edits,
 9439                edit_preview,
 9440                snapshot,
 9441                display_mode: _,
 9442            } => {
 9443                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9444
 9445                let (highlighted_edits, has_more_lines) =
 9446                    if let Some(edit_preview) = edit_preview.as_ref() {
 9447                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9448                            .first_line_preview()
 9449                    } else {
 9450                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9451                    };
 9452
 9453                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9454                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9455
 9456                let preview = h_flex()
 9457                    .gap_1()
 9458                    .min_w_16()
 9459                    .child(styled_text)
 9460                    .when(has_more_lines, |parent| parent.child(""));
 9461
 9462                let left = if supports_jump && first_edit_row != cursor_point.row {
 9463                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9464                        .into_any_element()
 9465                } else {
 9466                    let icon_name =
 9467                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9468                    Icon::new(icon_name).into_any_element()
 9469                };
 9470
 9471                Some(
 9472                    h_flex()
 9473                        .h_full()
 9474                        .flex_1()
 9475                        .gap_2()
 9476                        .pr_1()
 9477                        .overflow_x_hidden()
 9478                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9479                        .child(left)
 9480                        .child(preview),
 9481                )
 9482            }
 9483        }
 9484    }
 9485
 9486    pub fn render_context_menu(
 9487        &self,
 9488        style: &EditorStyle,
 9489        max_height_in_lines: u32,
 9490        window: &mut Window,
 9491        cx: &mut Context<Editor>,
 9492    ) -> Option<AnyElement> {
 9493        let menu = self.context_menu.borrow();
 9494        let menu = menu.as_ref()?;
 9495        if !menu.visible() {
 9496            return None;
 9497        };
 9498        Some(menu.render(style, max_height_in_lines, window, cx))
 9499    }
 9500
 9501    fn render_context_menu_aside(
 9502        &mut self,
 9503        max_size: Size<Pixels>,
 9504        window: &mut Window,
 9505        cx: &mut Context<Editor>,
 9506    ) -> Option<AnyElement> {
 9507        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9508            if menu.visible() {
 9509                menu.render_aside(max_size, window, cx)
 9510            } else {
 9511                None
 9512            }
 9513        })
 9514    }
 9515
 9516    fn hide_context_menu(
 9517        &mut self,
 9518        window: &mut Window,
 9519        cx: &mut Context<Self>,
 9520    ) -> Option<CodeContextMenu> {
 9521        cx.notify();
 9522        self.completion_tasks.clear();
 9523        let context_menu = self.context_menu.borrow_mut().take();
 9524        self.stale_edit_prediction_in_menu.take();
 9525        self.update_visible_edit_prediction(window, cx);
 9526        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9527            if let Some(completion_provider) = &self.completion_provider {
 9528                completion_provider.selection_changed(None, window, cx);
 9529            }
 9530        }
 9531        context_menu
 9532    }
 9533
 9534    fn show_snippet_choices(
 9535        &mut self,
 9536        choices: &Vec<String>,
 9537        selection: Range<Anchor>,
 9538        cx: &mut Context<Self>,
 9539    ) {
 9540        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9541            (Some(a), Some(b)) if a == b => a,
 9542            _ => {
 9543                log::error!("expected anchor range to have matching buffer IDs");
 9544                return;
 9545            }
 9546        };
 9547        let multi_buffer = self.buffer().read(cx);
 9548        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9549            return;
 9550        };
 9551
 9552        let id = post_inc(&mut self.next_completion_id);
 9553        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9554        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9555            CompletionsMenu::new_snippet_choices(
 9556                id,
 9557                true,
 9558                choices,
 9559                selection,
 9560                buffer,
 9561                snippet_sort_order,
 9562            ),
 9563        ));
 9564    }
 9565
 9566    pub fn insert_snippet(
 9567        &mut self,
 9568        insertion_ranges: &[Range<usize>],
 9569        snippet: Snippet,
 9570        window: &mut Window,
 9571        cx: &mut Context<Self>,
 9572    ) -> Result<()> {
 9573        struct Tabstop<T> {
 9574            is_end_tabstop: bool,
 9575            ranges: Vec<Range<T>>,
 9576            choices: Option<Vec<String>>,
 9577        }
 9578
 9579        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9580            let snippet_text: Arc<str> = snippet.text.clone().into();
 9581            let edits = insertion_ranges
 9582                .iter()
 9583                .cloned()
 9584                .map(|range| (range, snippet_text.clone()));
 9585            let autoindent_mode = AutoindentMode::Block {
 9586                original_indent_columns: Vec::new(),
 9587            };
 9588            buffer.edit(edits, Some(autoindent_mode), cx);
 9589
 9590            let snapshot = &*buffer.read(cx);
 9591            let snippet = &snippet;
 9592            snippet
 9593                .tabstops
 9594                .iter()
 9595                .map(|tabstop| {
 9596                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9597                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9598                    });
 9599                    let mut tabstop_ranges = tabstop
 9600                        .ranges
 9601                        .iter()
 9602                        .flat_map(|tabstop_range| {
 9603                            let mut delta = 0_isize;
 9604                            insertion_ranges.iter().map(move |insertion_range| {
 9605                                let insertion_start = insertion_range.start as isize + delta;
 9606                                delta +=
 9607                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9608
 9609                                let start = ((insertion_start + tabstop_range.start) as usize)
 9610                                    .min(snapshot.len());
 9611                                let end = ((insertion_start + tabstop_range.end) as usize)
 9612                                    .min(snapshot.len());
 9613                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9614                            })
 9615                        })
 9616                        .collect::<Vec<_>>();
 9617                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9618
 9619                    Tabstop {
 9620                        is_end_tabstop,
 9621                        ranges: tabstop_ranges,
 9622                        choices: tabstop.choices.clone(),
 9623                    }
 9624                })
 9625                .collect::<Vec<_>>()
 9626        });
 9627        if let Some(tabstop) = tabstops.first() {
 9628            self.change_selections(Default::default(), window, cx, |s| {
 9629                // Reverse order so that the first range is the newest created selection.
 9630                // Completions will use it and autoscroll will prioritize it.
 9631                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9632            });
 9633
 9634            if let Some(choices) = &tabstop.choices {
 9635                if let Some(selection) = tabstop.ranges.first() {
 9636                    self.show_snippet_choices(choices, selection.clone(), cx)
 9637                }
 9638            }
 9639
 9640            // If we're already at the last tabstop and it's at the end of the snippet,
 9641            // we're done, we don't need to keep the state around.
 9642            if !tabstop.is_end_tabstop {
 9643                let choices = tabstops
 9644                    .iter()
 9645                    .map(|tabstop| tabstop.choices.clone())
 9646                    .collect();
 9647
 9648                let ranges = tabstops
 9649                    .into_iter()
 9650                    .map(|tabstop| tabstop.ranges)
 9651                    .collect::<Vec<_>>();
 9652
 9653                self.snippet_stack.push(SnippetState {
 9654                    active_index: 0,
 9655                    ranges,
 9656                    choices,
 9657                });
 9658            }
 9659
 9660            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9661            if self.autoclose_regions.is_empty() {
 9662                let snapshot = self.buffer.read(cx).snapshot(cx);
 9663                let mut all_selections = self.selections.all::<Point>(cx);
 9664                for selection in &mut all_selections {
 9665                    let selection_head = selection.head();
 9666                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9667                        continue;
 9668                    };
 9669
 9670                    let mut bracket_pair = None;
 9671                    let max_lookup_length = scope
 9672                        .brackets()
 9673                        .map(|(pair, _)| {
 9674                            pair.start
 9675                                .as_str()
 9676                                .chars()
 9677                                .count()
 9678                                .max(pair.end.as_str().chars().count())
 9679                        })
 9680                        .max();
 9681                    if let Some(max_lookup_length) = max_lookup_length {
 9682                        let next_text = snapshot
 9683                            .chars_at(selection_head)
 9684                            .take(max_lookup_length)
 9685                            .collect::<String>();
 9686                        let prev_text = snapshot
 9687                            .reversed_chars_at(selection_head)
 9688                            .take(max_lookup_length)
 9689                            .collect::<String>();
 9690
 9691                        for (pair, enabled) in scope.brackets() {
 9692                            if enabled
 9693                                && pair.close
 9694                                && prev_text.starts_with(pair.start.as_str())
 9695                                && next_text.starts_with(pair.end.as_str())
 9696                            {
 9697                                bracket_pair = Some(pair.clone());
 9698                                break;
 9699                            }
 9700                        }
 9701                    }
 9702
 9703                    if let Some(pair) = bracket_pair {
 9704                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9705                        let autoclose_enabled =
 9706                            self.use_autoclose && snapshot_settings.use_autoclose;
 9707                        if autoclose_enabled {
 9708                            let start = snapshot.anchor_after(selection_head);
 9709                            let end = snapshot.anchor_after(selection_head);
 9710                            self.autoclose_regions.push(AutocloseRegion {
 9711                                selection_id: selection.id,
 9712                                range: start..end,
 9713                                pair,
 9714                            });
 9715                        }
 9716                    }
 9717                }
 9718            }
 9719        }
 9720        Ok(())
 9721    }
 9722
 9723    pub fn move_to_next_snippet_tabstop(
 9724        &mut self,
 9725        window: &mut Window,
 9726        cx: &mut Context<Self>,
 9727    ) -> bool {
 9728        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9729    }
 9730
 9731    pub fn move_to_prev_snippet_tabstop(
 9732        &mut self,
 9733        window: &mut Window,
 9734        cx: &mut Context<Self>,
 9735    ) -> bool {
 9736        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9737    }
 9738
 9739    pub fn move_to_snippet_tabstop(
 9740        &mut self,
 9741        bias: Bias,
 9742        window: &mut Window,
 9743        cx: &mut Context<Self>,
 9744    ) -> bool {
 9745        if let Some(mut snippet) = self.snippet_stack.pop() {
 9746            match bias {
 9747                Bias::Left => {
 9748                    if snippet.active_index > 0 {
 9749                        snippet.active_index -= 1;
 9750                    } else {
 9751                        self.snippet_stack.push(snippet);
 9752                        return false;
 9753                    }
 9754                }
 9755                Bias::Right => {
 9756                    if snippet.active_index + 1 < snippet.ranges.len() {
 9757                        snippet.active_index += 1;
 9758                    } else {
 9759                        self.snippet_stack.push(snippet);
 9760                        return false;
 9761                    }
 9762                }
 9763            }
 9764            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9765                self.change_selections(Default::default(), window, cx, |s| {
 9766                    // Reverse order so that the first range is the newest created selection.
 9767                    // Completions will use it and autoscroll will prioritize it.
 9768                    s.select_ranges(current_ranges.iter().rev().cloned())
 9769                });
 9770
 9771                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9772                    if let Some(selection) = current_ranges.first() {
 9773                        self.show_snippet_choices(choices, selection.clone(), cx);
 9774                    }
 9775                }
 9776
 9777                // If snippet state is not at the last tabstop, push it back on the stack
 9778                if snippet.active_index + 1 < snippet.ranges.len() {
 9779                    self.snippet_stack.push(snippet);
 9780                }
 9781                return true;
 9782            }
 9783        }
 9784
 9785        false
 9786    }
 9787
 9788    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9789        self.transact(window, cx, |this, window, cx| {
 9790            this.select_all(&SelectAll, window, cx);
 9791            this.insert("", window, cx);
 9792        });
 9793    }
 9794
 9795    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9797        self.transact(window, cx, |this, window, cx| {
 9798            this.select_autoclose_pair(window, cx);
 9799            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9800            if !this.linked_edit_ranges.is_empty() {
 9801                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9802                let snapshot = this.buffer.read(cx).snapshot(cx);
 9803
 9804                for selection in selections.iter() {
 9805                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9806                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9807                    if selection_start.buffer_id != selection_end.buffer_id {
 9808                        continue;
 9809                    }
 9810                    if let Some(ranges) =
 9811                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9812                    {
 9813                        for (buffer, entries) in ranges {
 9814                            linked_ranges.entry(buffer).or_default().extend(entries);
 9815                        }
 9816                    }
 9817                }
 9818            }
 9819
 9820            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9821            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9822            for selection in &mut selections {
 9823                if selection.is_empty() {
 9824                    let old_head = selection.head();
 9825                    let mut new_head =
 9826                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9827                            .to_point(&display_map);
 9828                    if let Some((buffer, line_buffer_range)) = display_map
 9829                        .buffer_snapshot
 9830                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9831                    {
 9832                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9833                        let indent_len = match indent_size.kind {
 9834                            IndentKind::Space => {
 9835                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9836                            }
 9837                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9838                        };
 9839                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9840                            let indent_len = indent_len.get();
 9841                            new_head = cmp::min(
 9842                                new_head,
 9843                                MultiBufferPoint::new(
 9844                                    old_head.row,
 9845                                    ((old_head.column - 1) / indent_len) * indent_len,
 9846                                ),
 9847                            );
 9848                        }
 9849                    }
 9850
 9851                    selection.set_head(new_head, SelectionGoal::None);
 9852                }
 9853            }
 9854
 9855            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9856            this.insert("", window, cx);
 9857            let empty_str: Arc<str> = Arc::from("");
 9858            for (buffer, edits) in linked_ranges {
 9859                let snapshot = buffer.read(cx).snapshot();
 9860                use text::ToPoint as TP;
 9861
 9862                let edits = edits
 9863                    .into_iter()
 9864                    .map(|range| {
 9865                        let end_point = TP::to_point(&range.end, &snapshot);
 9866                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9867
 9868                        if end_point == start_point {
 9869                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9870                                .saturating_sub(1);
 9871                            start_point =
 9872                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9873                        };
 9874
 9875                        (start_point..end_point, empty_str.clone())
 9876                    })
 9877                    .sorted_by_key(|(range, _)| range.start)
 9878                    .collect::<Vec<_>>();
 9879                buffer.update(cx, |this, cx| {
 9880                    this.edit(edits, None, cx);
 9881                })
 9882            }
 9883            this.refresh_edit_prediction(true, false, window, cx);
 9884            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9885        });
 9886    }
 9887
 9888    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9889        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9890        self.transact(window, cx, |this, window, cx| {
 9891            this.change_selections(Default::default(), window, cx, |s| {
 9892                s.move_with(|map, selection| {
 9893                    if selection.is_empty() {
 9894                        let cursor = movement::right(map, selection.head());
 9895                        selection.end = cursor;
 9896                        selection.reversed = true;
 9897                        selection.goal = SelectionGoal::None;
 9898                    }
 9899                })
 9900            });
 9901            this.insert("", window, cx);
 9902            this.refresh_edit_prediction(true, false, window, cx);
 9903        });
 9904    }
 9905
 9906    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9907        if self.mode.is_single_line() {
 9908            cx.propagate();
 9909            return;
 9910        }
 9911
 9912        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9913        if self.move_to_prev_snippet_tabstop(window, cx) {
 9914            return;
 9915        }
 9916        self.outdent(&Outdent, window, cx);
 9917    }
 9918
 9919    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9920        if self.mode.is_single_line() {
 9921            cx.propagate();
 9922            return;
 9923        }
 9924
 9925        if self.move_to_next_snippet_tabstop(window, cx) {
 9926            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9927            return;
 9928        }
 9929        if self.read_only(cx) {
 9930            return;
 9931        }
 9932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9933        let mut selections = self.selections.all_adjusted(cx);
 9934        let buffer = self.buffer.read(cx);
 9935        let snapshot = buffer.snapshot(cx);
 9936        let rows_iter = selections.iter().map(|s| s.head().row);
 9937        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9938
 9939        let has_some_cursor_in_whitespace = selections
 9940            .iter()
 9941            .filter(|selection| selection.is_empty())
 9942            .any(|selection| {
 9943                let cursor = selection.head();
 9944                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9945                cursor.column < current_indent.len
 9946            });
 9947
 9948        let mut edits = Vec::new();
 9949        let mut prev_edited_row = 0;
 9950        let mut row_delta = 0;
 9951        for selection in &mut selections {
 9952            if selection.start.row != prev_edited_row {
 9953                row_delta = 0;
 9954            }
 9955            prev_edited_row = selection.end.row;
 9956
 9957            // If the selection is non-empty, then increase the indentation of the selected lines.
 9958            if !selection.is_empty() {
 9959                row_delta =
 9960                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9961                continue;
 9962            }
 9963
 9964            let cursor = selection.head();
 9965            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9966            if let Some(suggested_indent) =
 9967                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9968            {
 9969                // Don't do anything if already at suggested indent
 9970                // and there is any other cursor which is not
 9971                if has_some_cursor_in_whitespace
 9972                    && cursor.column == current_indent.len
 9973                    && current_indent.len == suggested_indent.len
 9974                {
 9975                    continue;
 9976                }
 9977
 9978                // Adjust line and move cursor to suggested indent
 9979                // if cursor is not at suggested indent
 9980                if cursor.column < suggested_indent.len
 9981                    && cursor.column <= current_indent.len
 9982                    && current_indent.len <= suggested_indent.len
 9983                {
 9984                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9985                    selection.end = selection.start;
 9986                    if row_delta == 0 {
 9987                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9988                            cursor.row,
 9989                            current_indent,
 9990                            suggested_indent,
 9991                        ));
 9992                        row_delta = suggested_indent.len - current_indent.len;
 9993                    }
 9994                    continue;
 9995                }
 9996
 9997                // If current indent is more than suggested indent
 9998                // only move cursor to current indent and skip indent
 9999                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10000                    selection.start = Point::new(cursor.row, current_indent.len);
10001                    selection.end = selection.start;
10002                    continue;
10003                }
10004            }
10005
10006            // Otherwise, insert a hard or soft tab.
10007            let settings = buffer.language_settings_at(cursor, cx);
10008            let tab_size = if settings.hard_tabs {
10009                IndentSize::tab()
10010            } else {
10011                let tab_size = settings.tab_size.get();
10012                let indent_remainder = snapshot
10013                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10014                    .flat_map(str::chars)
10015                    .fold(row_delta % tab_size, |counter: u32, c| {
10016                        if c == '\t' {
10017                            0
10018                        } else {
10019                            (counter + 1) % tab_size
10020                        }
10021                    });
10022
10023                let chars_to_next_tab_stop = tab_size - indent_remainder;
10024                IndentSize::spaces(chars_to_next_tab_stop)
10025            };
10026            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10027            selection.end = selection.start;
10028            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10029            row_delta += tab_size.len;
10030        }
10031
10032        self.transact(window, cx, |this, window, cx| {
10033            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10034            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10035            this.refresh_edit_prediction(true, false, window, cx);
10036        });
10037    }
10038
10039    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10040        if self.read_only(cx) {
10041            return;
10042        }
10043        if self.mode.is_single_line() {
10044            cx.propagate();
10045            return;
10046        }
10047
10048        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10049        let mut selections = self.selections.all::<Point>(cx);
10050        let mut prev_edited_row = 0;
10051        let mut row_delta = 0;
10052        let mut edits = Vec::new();
10053        let buffer = self.buffer.read(cx);
10054        let snapshot = buffer.snapshot(cx);
10055        for selection in &mut selections {
10056            if selection.start.row != prev_edited_row {
10057                row_delta = 0;
10058            }
10059            prev_edited_row = selection.end.row;
10060
10061            row_delta =
10062                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10063        }
10064
10065        self.transact(window, cx, |this, window, cx| {
10066            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10067            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10068        });
10069    }
10070
10071    fn indent_selection(
10072        buffer: &MultiBuffer,
10073        snapshot: &MultiBufferSnapshot,
10074        selection: &mut Selection<Point>,
10075        edits: &mut Vec<(Range<Point>, String)>,
10076        delta_for_start_row: u32,
10077        cx: &App,
10078    ) -> u32 {
10079        let settings = buffer.language_settings_at(selection.start, cx);
10080        let tab_size = settings.tab_size.get();
10081        let indent_kind = if settings.hard_tabs {
10082            IndentKind::Tab
10083        } else {
10084            IndentKind::Space
10085        };
10086        let mut start_row = selection.start.row;
10087        let mut end_row = selection.end.row + 1;
10088
10089        // If a selection ends at the beginning of a line, don't indent
10090        // that last line.
10091        if selection.end.column == 0 && selection.end.row > selection.start.row {
10092            end_row -= 1;
10093        }
10094
10095        // Avoid re-indenting a row that has already been indented by a
10096        // previous selection, but still update this selection's column
10097        // to reflect that indentation.
10098        if delta_for_start_row > 0 {
10099            start_row += 1;
10100            selection.start.column += delta_for_start_row;
10101            if selection.end.row == selection.start.row {
10102                selection.end.column += delta_for_start_row;
10103            }
10104        }
10105
10106        let mut delta_for_end_row = 0;
10107        let has_multiple_rows = start_row + 1 != end_row;
10108        for row in start_row..end_row {
10109            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10110            let indent_delta = match (current_indent.kind, indent_kind) {
10111                (IndentKind::Space, IndentKind::Space) => {
10112                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10113                    IndentSize::spaces(columns_to_next_tab_stop)
10114                }
10115                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10116                (_, IndentKind::Tab) => IndentSize::tab(),
10117            };
10118
10119            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10120                0
10121            } else {
10122                selection.start.column
10123            };
10124            let row_start = Point::new(row, start);
10125            edits.push((
10126                row_start..row_start,
10127                indent_delta.chars().collect::<String>(),
10128            ));
10129
10130            // Update this selection's endpoints to reflect the indentation.
10131            if row == selection.start.row {
10132                selection.start.column += indent_delta.len;
10133            }
10134            if row == selection.end.row {
10135                selection.end.column += indent_delta.len;
10136                delta_for_end_row = indent_delta.len;
10137            }
10138        }
10139
10140        if selection.start.row == selection.end.row {
10141            delta_for_start_row + delta_for_end_row
10142        } else {
10143            delta_for_end_row
10144        }
10145    }
10146
10147    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10148        if self.read_only(cx) {
10149            return;
10150        }
10151        if self.mode.is_single_line() {
10152            cx.propagate();
10153            return;
10154        }
10155
10156        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10157        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10158        let selections = self.selections.all::<Point>(cx);
10159        let mut deletion_ranges = Vec::new();
10160        let mut last_outdent = None;
10161        {
10162            let buffer = self.buffer.read(cx);
10163            let snapshot = buffer.snapshot(cx);
10164            for selection in &selections {
10165                let settings = buffer.language_settings_at(selection.start, cx);
10166                let tab_size = settings.tab_size.get();
10167                let mut rows = selection.spanned_rows(false, &display_map);
10168
10169                // Avoid re-outdenting a row that has already been outdented by a
10170                // previous selection.
10171                if let Some(last_row) = last_outdent {
10172                    if last_row == rows.start {
10173                        rows.start = rows.start.next_row();
10174                    }
10175                }
10176                let has_multiple_rows = rows.len() > 1;
10177                for row in rows.iter_rows() {
10178                    let indent_size = snapshot.indent_size_for_line(row);
10179                    if indent_size.len > 0 {
10180                        let deletion_len = match indent_size.kind {
10181                            IndentKind::Space => {
10182                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10183                                if columns_to_prev_tab_stop == 0 {
10184                                    tab_size
10185                                } else {
10186                                    columns_to_prev_tab_stop
10187                                }
10188                            }
10189                            IndentKind::Tab => 1,
10190                        };
10191                        let start = if has_multiple_rows
10192                            || deletion_len > selection.start.column
10193                            || indent_size.len < selection.start.column
10194                        {
10195                            0
10196                        } else {
10197                            selection.start.column - deletion_len
10198                        };
10199                        deletion_ranges.push(
10200                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10201                        );
10202                        last_outdent = Some(row);
10203                    }
10204                }
10205            }
10206        }
10207
10208        self.transact(window, cx, |this, window, cx| {
10209            this.buffer.update(cx, |buffer, cx| {
10210                let empty_str: Arc<str> = Arc::default();
10211                buffer.edit(
10212                    deletion_ranges
10213                        .into_iter()
10214                        .map(|range| (range, empty_str.clone())),
10215                    None,
10216                    cx,
10217                );
10218            });
10219            let selections = this.selections.all::<usize>(cx);
10220            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10221        });
10222    }
10223
10224    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10225        if self.read_only(cx) {
10226            return;
10227        }
10228        if self.mode.is_single_line() {
10229            cx.propagate();
10230            return;
10231        }
10232
10233        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10234        let selections = self
10235            .selections
10236            .all::<usize>(cx)
10237            .into_iter()
10238            .map(|s| s.range());
10239
10240        self.transact(window, cx, |this, window, cx| {
10241            this.buffer.update(cx, |buffer, cx| {
10242                buffer.autoindent_ranges(selections, cx);
10243            });
10244            let selections = this.selections.all::<usize>(cx);
10245            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10246        });
10247    }
10248
10249    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10250        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10251        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10252        let selections = self.selections.all::<Point>(cx);
10253
10254        let mut new_cursors = Vec::new();
10255        let mut edit_ranges = Vec::new();
10256        let mut selections = selections.iter().peekable();
10257        while let Some(selection) = selections.next() {
10258            let mut rows = selection.spanned_rows(false, &display_map);
10259            let goal_display_column = selection.head().to_display_point(&display_map).column();
10260
10261            // Accumulate contiguous regions of rows that we want to delete.
10262            while let Some(next_selection) = selections.peek() {
10263                let next_rows = next_selection.spanned_rows(false, &display_map);
10264                if next_rows.start <= rows.end {
10265                    rows.end = next_rows.end;
10266                    selections.next().unwrap();
10267                } else {
10268                    break;
10269                }
10270            }
10271
10272            let buffer = &display_map.buffer_snapshot;
10273            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10274            let edit_end;
10275            let cursor_buffer_row;
10276            if buffer.max_point().row >= rows.end.0 {
10277                // If there's a line after the range, delete the \n from the end of the row range
10278                // and position the cursor on the next line.
10279                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10280                cursor_buffer_row = rows.end;
10281            } else {
10282                // If there isn't a line after the range, delete the \n from the line before the
10283                // start of the row range and position the cursor there.
10284                edit_start = edit_start.saturating_sub(1);
10285                edit_end = buffer.len();
10286                cursor_buffer_row = rows.start.previous_row();
10287            }
10288
10289            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10290            *cursor.column_mut() =
10291                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10292
10293            new_cursors.push((
10294                selection.id,
10295                buffer.anchor_after(cursor.to_point(&display_map)),
10296            ));
10297            edit_ranges.push(edit_start..edit_end);
10298        }
10299
10300        self.transact(window, cx, |this, window, cx| {
10301            let buffer = this.buffer.update(cx, |buffer, cx| {
10302                let empty_str: Arc<str> = Arc::default();
10303                buffer.edit(
10304                    edit_ranges
10305                        .into_iter()
10306                        .map(|range| (range, empty_str.clone())),
10307                    None,
10308                    cx,
10309                );
10310                buffer.snapshot(cx)
10311            });
10312            let new_selections = new_cursors
10313                .into_iter()
10314                .map(|(id, cursor)| {
10315                    let cursor = cursor.to_point(&buffer);
10316                    Selection {
10317                        id,
10318                        start: cursor,
10319                        end: cursor,
10320                        reversed: false,
10321                        goal: SelectionGoal::None,
10322                    }
10323                })
10324                .collect();
10325
10326            this.change_selections(Default::default(), window, cx, |s| {
10327                s.select(new_selections);
10328            });
10329        });
10330    }
10331
10332    pub fn join_lines_impl(
10333        &mut self,
10334        insert_whitespace: bool,
10335        window: &mut Window,
10336        cx: &mut Context<Self>,
10337    ) {
10338        if self.read_only(cx) {
10339            return;
10340        }
10341        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10342        for selection in self.selections.all::<Point>(cx) {
10343            let start = MultiBufferRow(selection.start.row);
10344            // Treat single line selections as if they include the next line. Otherwise this action
10345            // would do nothing for single line selections individual cursors.
10346            let end = if selection.start.row == selection.end.row {
10347                MultiBufferRow(selection.start.row + 1)
10348            } else {
10349                MultiBufferRow(selection.end.row)
10350            };
10351
10352            if let Some(last_row_range) = row_ranges.last_mut() {
10353                if start <= last_row_range.end {
10354                    last_row_range.end = end;
10355                    continue;
10356                }
10357            }
10358            row_ranges.push(start..end);
10359        }
10360
10361        let snapshot = self.buffer.read(cx).snapshot(cx);
10362        let mut cursor_positions = Vec::new();
10363        for row_range in &row_ranges {
10364            let anchor = snapshot.anchor_before(Point::new(
10365                row_range.end.previous_row().0,
10366                snapshot.line_len(row_range.end.previous_row()),
10367            ));
10368            cursor_positions.push(anchor..anchor);
10369        }
10370
10371        self.transact(window, cx, |this, window, cx| {
10372            for row_range in row_ranges.into_iter().rev() {
10373                for row in row_range.iter_rows().rev() {
10374                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10375                    let next_line_row = row.next_row();
10376                    let indent = snapshot.indent_size_for_line(next_line_row);
10377                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10378
10379                    let replace =
10380                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10381                            " "
10382                        } else {
10383                            ""
10384                        };
10385
10386                    this.buffer.update(cx, |buffer, cx| {
10387                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10388                    });
10389                }
10390            }
10391
10392            this.change_selections(Default::default(), window, cx, |s| {
10393                s.select_anchor_ranges(cursor_positions)
10394            });
10395        });
10396    }
10397
10398    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10399        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10400        self.join_lines_impl(true, window, cx);
10401    }
10402
10403    pub fn sort_lines_case_sensitive(
10404        &mut self,
10405        _: &SortLinesCaseSensitive,
10406        window: &mut Window,
10407        cx: &mut Context<Self>,
10408    ) {
10409        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10410    }
10411
10412    pub fn sort_lines_by_length(
10413        &mut self,
10414        _: &SortLinesByLength,
10415        window: &mut Window,
10416        cx: &mut Context<Self>,
10417    ) {
10418        self.manipulate_immutable_lines(window, cx, |lines| {
10419            lines.sort_by_key(|&line| line.chars().count())
10420        })
10421    }
10422
10423    pub fn sort_lines_case_insensitive(
10424        &mut self,
10425        _: &SortLinesCaseInsensitive,
10426        window: &mut Window,
10427        cx: &mut Context<Self>,
10428    ) {
10429        self.manipulate_immutable_lines(window, cx, |lines| {
10430            lines.sort_by_key(|line| line.to_lowercase())
10431        })
10432    }
10433
10434    pub fn unique_lines_case_insensitive(
10435        &mut self,
10436        _: &UniqueLinesCaseInsensitive,
10437        window: &mut Window,
10438        cx: &mut Context<Self>,
10439    ) {
10440        self.manipulate_immutable_lines(window, cx, |lines| {
10441            let mut seen = HashSet::default();
10442            lines.retain(|line| seen.insert(line.to_lowercase()));
10443        })
10444    }
10445
10446    pub fn unique_lines_case_sensitive(
10447        &mut self,
10448        _: &UniqueLinesCaseSensitive,
10449        window: &mut Window,
10450        cx: &mut Context<Self>,
10451    ) {
10452        self.manipulate_immutable_lines(window, cx, |lines| {
10453            let mut seen = HashSet::default();
10454            lines.retain(|line| seen.insert(*line));
10455        })
10456    }
10457
10458    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10459        let Some(project) = self.project.clone() else {
10460            return;
10461        };
10462        self.reload(project, window, cx)
10463            .detach_and_notify_err(window, cx);
10464    }
10465
10466    pub fn restore_file(
10467        &mut self,
10468        _: &::git::RestoreFile,
10469        window: &mut Window,
10470        cx: &mut Context<Self>,
10471    ) {
10472        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10473        let mut buffer_ids = HashSet::default();
10474        let snapshot = self.buffer().read(cx).snapshot(cx);
10475        for selection in self.selections.all::<usize>(cx) {
10476            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10477        }
10478
10479        let buffer = self.buffer().read(cx);
10480        let ranges = buffer_ids
10481            .into_iter()
10482            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10483            .collect::<Vec<_>>();
10484
10485        self.restore_hunks_in_ranges(ranges, window, cx);
10486    }
10487
10488    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10489        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10490        let selections = self
10491            .selections
10492            .all(cx)
10493            .into_iter()
10494            .map(|s| s.range())
10495            .collect();
10496        self.restore_hunks_in_ranges(selections, window, cx);
10497    }
10498
10499    pub fn restore_hunks_in_ranges(
10500        &mut self,
10501        ranges: Vec<Range<Point>>,
10502        window: &mut Window,
10503        cx: &mut Context<Editor>,
10504    ) {
10505        let mut revert_changes = HashMap::default();
10506        let chunk_by = self
10507            .snapshot(window, cx)
10508            .hunks_for_ranges(ranges)
10509            .into_iter()
10510            .chunk_by(|hunk| hunk.buffer_id);
10511        for (buffer_id, hunks) in &chunk_by {
10512            let hunks = hunks.collect::<Vec<_>>();
10513            for hunk in &hunks {
10514                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10515            }
10516            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10517        }
10518        drop(chunk_by);
10519        if !revert_changes.is_empty() {
10520            self.transact(window, cx, |editor, window, cx| {
10521                editor.restore(revert_changes, window, cx);
10522            });
10523        }
10524    }
10525
10526    pub fn open_active_item_in_terminal(
10527        &mut self,
10528        _: &OpenInTerminal,
10529        window: &mut Window,
10530        cx: &mut Context<Self>,
10531    ) {
10532        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10533            let project_path = buffer.read(cx).project_path(cx)?;
10534            let project = self.project()?.read(cx);
10535            let entry = project.entry_for_path(&project_path, cx)?;
10536            let parent = match &entry.canonical_path {
10537                Some(canonical_path) => canonical_path.to_path_buf(),
10538                None => project.absolute_path(&project_path, cx)?,
10539            }
10540            .parent()?
10541            .to_path_buf();
10542            Some(parent)
10543        }) {
10544            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10545        }
10546    }
10547
10548    fn set_breakpoint_context_menu(
10549        &mut self,
10550        display_row: DisplayRow,
10551        position: Option<Anchor>,
10552        clicked_point: gpui::Point<Pixels>,
10553        window: &mut Window,
10554        cx: &mut Context<Self>,
10555    ) {
10556        let source = self
10557            .buffer
10558            .read(cx)
10559            .snapshot(cx)
10560            .anchor_before(Point::new(display_row.0, 0u32));
10561
10562        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10563
10564        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10565            self,
10566            source,
10567            clicked_point,
10568            context_menu,
10569            window,
10570            cx,
10571        );
10572    }
10573
10574    fn add_edit_breakpoint_block(
10575        &mut self,
10576        anchor: Anchor,
10577        breakpoint: &Breakpoint,
10578        edit_action: BreakpointPromptEditAction,
10579        window: &mut Window,
10580        cx: &mut Context<Self>,
10581    ) {
10582        let weak_editor = cx.weak_entity();
10583        let bp_prompt = cx.new(|cx| {
10584            BreakpointPromptEditor::new(
10585                weak_editor,
10586                anchor,
10587                breakpoint.clone(),
10588                edit_action,
10589                window,
10590                cx,
10591            )
10592        });
10593
10594        let height = bp_prompt.update(cx, |this, cx| {
10595            this.prompt
10596                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10597        });
10598        let cloned_prompt = bp_prompt.clone();
10599        let blocks = vec![BlockProperties {
10600            style: BlockStyle::Sticky,
10601            placement: BlockPlacement::Above(anchor),
10602            height: Some(height),
10603            render: Arc::new(move |cx| {
10604                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10605                cloned_prompt.clone().into_any_element()
10606            }),
10607            priority: 0,
10608        }];
10609
10610        let focus_handle = bp_prompt.focus_handle(cx);
10611        window.focus(&focus_handle);
10612
10613        let block_ids = self.insert_blocks(blocks, None, cx);
10614        bp_prompt.update(cx, |prompt, _| {
10615            prompt.add_block_ids(block_ids);
10616        });
10617    }
10618
10619    pub(crate) fn breakpoint_at_row(
10620        &self,
10621        row: u32,
10622        window: &mut Window,
10623        cx: &mut Context<Self>,
10624    ) -> Option<(Anchor, Breakpoint)> {
10625        let snapshot = self.snapshot(window, cx);
10626        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10627
10628        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10629    }
10630
10631    pub(crate) fn breakpoint_at_anchor(
10632        &self,
10633        breakpoint_position: Anchor,
10634        snapshot: &EditorSnapshot,
10635        cx: &mut Context<Self>,
10636    ) -> Option<(Anchor, Breakpoint)> {
10637        let project = self.project.clone()?;
10638
10639        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10640            snapshot
10641                .buffer_snapshot
10642                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10643        })?;
10644
10645        let enclosing_excerpt = breakpoint_position.excerpt_id;
10646        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10647        let buffer_snapshot = buffer.read(cx).snapshot();
10648
10649        let row = buffer_snapshot
10650            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10651            .row;
10652
10653        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10654        let anchor_end = snapshot
10655            .buffer_snapshot
10656            .anchor_after(Point::new(row, line_len));
10657
10658        let bp = self
10659            .breakpoint_store
10660            .as_ref()?
10661            .read_with(cx, |breakpoint_store, cx| {
10662                breakpoint_store
10663                    .breakpoints(
10664                        &buffer,
10665                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10666                        &buffer_snapshot,
10667                        cx,
10668                    )
10669                    .next()
10670                    .and_then(|(bp, _)| {
10671                        let breakpoint_row = buffer_snapshot
10672                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10673                            .row;
10674
10675                        if breakpoint_row == row {
10676                            snapshot
10677                                .buffer_snapshot
10678                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10679                                .map(|position| (position, bp.bp.clone()))
10680                        } else {
10681                            None
10682                        }
10683                    })
10684            });
10685        bp
10686    }
10687
10688    pub fn edit_log_breakpoint(
10689        &mut self,
10690        _: &EditLogBreakpoint,
10691        window: &mut Window,
10692        cx: &mut Context<Self>,
10693    ) {
10694        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10695            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10696                message: None,
10697                state: BreakpointState::Enabled,
10698                condition: None,
10699                hit_condition: None,
10700            });
10701
10702            self.add_edit_breakpoint_block(
10703                anchor,
10704                &breakpoint,
10705                BreakpointPromptEditAction::Log,
10706                window,
10707                cx,
10708            );
10709        }
10710    }
10711
10712    fn breakpoints_at_cursors(
10713        &self,
10714        window: &mut Window,
10715        cx: &mut Context<Self>,
10716    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10717        let snapshot = self.snapshot(window, cx);
10718        let cursors = self
10719            .selections
10720            .disjoint_anchors()
10721            .into_iter()
10722            .map(|selection| {
10723                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10724
10725                let breakpoint_position = self
10726                    .breakpoint_at_row(cursor_position.row, window, cx)
10727                    .map(|bp| bp.0)
10728                    .unwrap_or_else(|| {
10729                        snapshot
10730                            .display_snapshot
10731                            .buffer_snapshot
10732                            .anchor_after(Point::new(cursor_position.row, 0))
10733                    });
10734
10735                let breakpoint = self
10736                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10737                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10738
10739                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10740            })
10741            // 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.
10742            .collect::<HashMap<Anchor, _>>();
10743
10744        cursors.into_iter().collect()
10745    }
10746
10747    pub fn enable_breakpoint(
10748        &mut self,
10749        _: &crate::actions::EnableBreakpoint,
10750        window: &mut Window,
10751        cx: &mut Context<Self>,
10752    ) {
10753        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10754            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10755                continue;
10756            };
10757            self.edit_breakpoint_at_anchor(
10758                anchor,
10759                breakpoint,
10760                BreakpointEditAction::InvertState,
10761                cx,
10762            );
10763        }
10764    }
10765
10766    pub fn disable_breakpoint(
10767        &mut self,
10768        _: &crate::actions::DisableBreakpoint,
10769        window: &mut Window,
10770        cx: &mut Context<Self>,
10771    ) {
10772        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10773            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10774                continue;
10775            };
10776            self.edit_breakpoint_at_anchor(
10777                anchor,
10778                breakpoint,
10779                BreakpointEditAction::InvertState,
10780                cx,
10781            );
10782        }
10783    }
10784
10785    pub fn toggle_breakpoint(
10786        &mut self,
10787        _: &crate::actions::ToggleBreakpoint,
10788        window: &mut Window,
10789        cx: &mut Context<Self>,
10790    ) {
10791        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10792            if let Some(breakpoint) = breakpoint {
10793                self.edit_breakpoint_at_anchor(
10794                    anchor,
10795                    breakpoint,
10796                    BreakpointEditAction::Toggle,
10797                    cx,
10798                );
10799            } else {
10800                self.edit_breakpoint_at_anchor(
10801                    anchor,
10802                    Breakpoint::new_standard(),
10803                    BreakpointEditAction::Toggle,
10804                    cx,
10805                );
10806            }
10807        }
10808    }
10809
10810    pub fn edit_breakpoint_at_anchor(
10811        &mut self,
10812        breakpoint_position: Anchor,
10813        breakpoint: Breakpoint,
10814        edit_action: BreakpointEditAction,
10815        cx: &mut Context<Self>,
10816    ) {
10817        let Some(breakpoint_store) = &self.breakpoint_store else {
10818            return;
10819        };
10820
10821        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10822            if breakpoint_position == Anchor::min() {
10823                self.buffer()
10824                    .read(cx)
10825                    .excerpt_buffer_ids()
10826                    .into_iter()
10827                    .next()
10828            } else {
10829                None
10830            }
10831        }) else {
10832            return;
10833        };
10834
10835        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10836            return;
10837        };
10838
10839        breakpoint_store.update(cx, |breakpoint_store, cx| {
10840            breakpoint_store.toggle_breakpoint(
10841                buffer,
10842                BreakpointWithPosition {
10843                    position: breakpoint_position.text_anchor,
10844                    bp: breakpoint,
10845                },
10846                edit_action,
10847                cx,
10848            );
10849        });
10850
10851        cx.notify();
10852    }
10853
10854    #[cfg(any(test, feature = "test-support"))]
10855    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10856        self.breakpoint_store.clone()
10857    }
10858
10859    pub fn prepare_restore_change(
10860        &self,
10861        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10862        hunk: &MultiBufferDiffHunk,
10863        cx: &mut App,
10864    ) -> Option<()> {
10865        if hunk.is_created_file() {
10866            return None;
10867        }
10868        let buffer = self.buffer.read(cx);
10869        let diff = buffer.diff_for(hunk.buffer_id)?;
10870        let buffer = buffer.buffer(hunk.buffer_id)?;
10871        let buffer = buffer.read(cx);
10872        let original_text = diff
10873            .read(cx)
10874            .base_text()
10875            .as_rope()
10876            .slice(hunk.diff_base_byte_range.clone());
10877        let buffer_snapshot = buffer.snapshot();
10878        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10879        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10880            probe
10881                .0
10882                .start
10883                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10884                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10885        }) {
10886            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10887            Some(())
10888        } else {
10889            None
10890        }
10891    }
10892
10893    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10894        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10895    }
10896
10897    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10898        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10899    }
10900
10901    fn manipulate_lines<M>(
10902        &mut self,
10903        window: &mut Window,
10904        cx: &mut Context<Self>,
10905        mut manipulate: M,
10906    ) where
10907        M: FnMut(&str) -> LineManipulationResult,
10908    {
10909        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10910
10911        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10912        let buffer = self.buffer.read(cx).snapshot(cx);
10913
10914        let mut edits = Vec::new();
10915
10916        let selections = self.selections.all::<Point>(cx);
10917        let mut selections = selections.iter().peekable();
10918        let mut contiguous_row_selections = Vec::new();
10919        let mut new_selections = Vec::new();
10920        let mut added_lines = 0;
10921        let mut removed_lines = 0;
10922
10923        while let Some(selection) = selections.next() {
10924            let (start_row, end_row) = consume_contiguous_rows(
10925                &mut contiguous_row_selections,
10926                selection,
10927                &display_map,
10928                &mut selections,
10929            );
10930
10931            let start_point = Point::new(start_row.0, 0);
10932            let end_point = Point::new(
10933                end_row.previous_row().0,
10934                buffer.line_len(end_row.previous_row()),
10935            );
10936            let text = buffer
10937                .text_for_range(start_point..end_point)
10938                .collect::<String>();
10939
10940            let LineManipulationResult {
10941                new_text,
10942                line_count_before,
10943                line_count_after,
10944            } = manipulate(&text);
10945
10946            edits.push((start_point..end_point, new_text));
10947
10948            // Selections must change based on added and removed line count
10949            let start_row =
10950                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10951            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10952            new_selections.push(Selection {
10953                id: selection.id,
10954                start: start_row,
10955                end: end_row,
10956                goal: SelectionGoal::None,
10957                reversed: selection.reversed,
10958            });
10959
10960            if line_count_after > line_count_before {
10961                added_lines += line_count_after - line_count_before;
10962            } else if line_count_before > line_count_after {
10963                removed_lines += line_count_before - line_count_after;
10964            }
10965        }
10966
10967        self.transact(window, cx, |this, window, cx| {
10968            let buffer = this.buffer.update(cx, |buffer, cx| {
10969                buffer.edit(edits, None, cx);
10970                buffer.snapshot(cx)
10971            });
10972
10973            // Recalculate offsets on newly edited buffer
10974            let new_selections = new_selections
10975                .iter()
10976                .map(|s| {
10977                    let start_point = Point::new(s.start.0, 0);
10978                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10979                    Selection {
10980                        id: s.id,
10981                        start: buffer.point_to_offset(start_point),
10982                        end: buffer.point_to_offset(end_point),
10983                        goal: s.goal,
10984                        reversed: s.reversed,
10985                    }
10986                })
10987                .collect();
10988
10989            this.change_selections(Default::default(), window, cx, |s| {
10990                s.select(new_selections);
10991            });
10992
10993            this.request_autoscroll(Autoscroll::fit(), cx);
10994        });
10995    }
10996
10997    fn manipulate_immutable_lines<Fn>(
10998        &mut self,
10999        window: &mut Window,
11000        cx: &mut Context<Self>,
11001        mut callback: Fn,
11002    ) where
11003        Fn: FnMut(&mut Vec<&str>),
11004    {
11005        self.manipulate_lines(window, cx, |text| {
11006            let mut lines: Vec<&str> = text.split('\n').collect();
11007            let line_count_before = lines.len();
11008
11009            callback(&mut lines);
11010
11011            LineManipulationResult {
11012                new_text: lines.join("\n"),
11013                line_count_before,
11014                line_count_after: lines.len(),
11015            }
11016        });
11017    }
11018
11019    fn manipulate_mutable_lines<Fn>(
11020        &mut self,
11021        window: &mut Window,
11022        cx: &mut Context<Self>,
11023        mut callback: Fn,
11024    ) where
11025        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11026    {
11027        self.manipulate_lines(window, cx, |text| {
11028            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11029            let line_count_before = lines.len();
11030
11031            callback(&mut lines);
11032
11033            LineManipulationResult {
11034                new_text: lines.join("\n"),
11035                line_count_before,
11036                line_count_after: lines.len(),
11037            }
11038        });
11039    }
11040
11041    pub fn convert_indentation_to_spaces(
11042        &mut self,
11043        _: &ConvertIndentationToSpaces,
11044        window: &mut Window,
11045        cx: &mut Context<Self>,
11046    ) {
11047        let settings = self.buffer.read(cx).language_settings(cx);
11048        let tab_size = settings.tab_size.get() as usize;
11049
11050        self.manipulate_mutable_lines(window, cx, |lines| {
11051            // Allocates a reasonably sized scratch buffer once for the whole loop
11052            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11053            // Avoids recomputing spaces that could be inserted many times
11054            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11055                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11056                .collect();
11057
11058            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11059                let mut chars = line.as_ref().chars();
11060                let mut col = 0;
11061                let mut changed = false;
11062
11063                while let Some(ch) = chars.next() {
11064                    match ch {
11065                        ' ' => {
11066                            reindented_line.push(' ');
11067                            col += 1;
11068                        }
11069                        '\t' => {
11070                            // \t are converted to spaces depending on the current column
11071                            let spaces_len = tab_size - (col % tab_size);
11072                            reindented_line.extend(&space_cache[spaces_len - 1]);
11073                            col += spaces_len;
11074                            changed = true;
11075                        }
11076                        _ => {
11077                            // If we dont append before break, the character is consumed
11078                            reindented_line.push(ch);
11079                            break;
11080                        }
11081                    }
11082                }
11083
11084                if !changed {
11085                    reindented_line.clear();
11086                    continue;
11087                }
11088                // Append the rest of the line and replace old reference with new one
11089                reindented_line.extend(chars);
11090                *line = Cow::Owned(reindented_line.clone());
11091                reindented_line.clear();
11092            }
11093        });
11094    }
11095
11096    pub fn convert_indentation_to_tabs(
11097        &mut self,
11098        _: &ConvertIndentationToTabs,
11099        window: &mut Window,
11100        cx: &mut Context<Self>,
11101    ) {
11102        let settings = self.buffer.read(cx).language_settings(cx);
11103        let tab_size = settings.tab_size.get() as usize;
11104
11105        self.manipulate_mutable_lines(window, cx, |lines| {
11106            // Allocates a reasonably sized buffer once for the whole loop
11107            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11108            // Avoids recomputing spaces that could be inserted many times
11109            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11110                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11111                .collect();
11112
11113            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11114                let mut chars = line.chars();
11115                let mut spaces_count = 0;
11116                let mut first_non_indent_char = None;
11117                let mut changed = false;
11118
11119                while let Some(ch) = chars.next() {
11120                    match ch {
11121                        ' ' => {
11122                            // Keep track of spaces. Append \t when we reach tab_size
11123                            spaces_count += 1;
11124                            changed = true;
11125                            if spaces_count == tab_size {
11126                                reindented_line.push('\t');
11127                                spaces_count = 0;
11128                            }
11129                        }
11130                        '\t' => {
11131                            reindented_line.push('\t');
11132                            spaces_count = 0;
11133                        }
11134                        _ => {
11135                            // Dont append it yet, we might have remaining spaces
11136                            first_non_indent_char = Some(ch);
11137                            break;
11138                        }
11139                    }
11140                }
11141
11142                if !changed {
11143                    reindented_line.clear();
11144                    continue;
11145                }
11146                // Remaining spaces that didn't make a full tab stop
11147                if spaces_count > 0 {
11148                    reindented_line.extend(&space_cache[spaces_count - 1]);
11149                }
11150                // If we consume an extra character that was not indentation, add it back
11151                if let Some(extra_char) = first_non_indent_char {
11152                    reindented_line.push(extra_char);
11153                }
11154                // Append the rest of the line and replace old reference with new one
11155                reindented_line.extend(chars);
11156                *line = Cow::Owned(reindented_line.clone());
11157                reindented_line.clear();
11158            }
11159        });
11160    }
11161
11162    pub fn convert_to_upper_case(
11163        &mut self,
11164        _: &ConvertToUpperCase,
11165        window: &mut Window,
11166        cx: &mut Context<Self>,
11167    ) {
11168        self.manipulate_text(window, cx, |text| text.to_uppercase())
11169    }
11170
11171    pub fn convert_to_lower_case(
11172        &mut self,
11173        _: &ConvertToLowerCase,
11174        window: &mut Window,
11175        cx: &mut Context<Self>,
11176    ) {
11177        self.manipulate_text(window, cx, |text| text.to_lowercase())
11178    }
11179
11180    pub fn convert_to_title_case(
11181        &mut self,
11182        _: &ConvertToTitleCase,
11183        window: &mut Window,
11184        cx: &mut Context<Self>,
11185    ) {
11186        self.manipulate_text(window, cx, |text| {
11187            text.split('\n')
11188                .map(|line| line.to_case(Case::Title))
11189                .join("\n")
11190        })
11191    }
11192
11193    pub fn convert_to_snake_case(
11194        &mut self,
11195        _: &ConvertToSnakeCase,
11196        window: &mut Window,
11197        cx: &mut Context<Self>,
11198    ) {
11199        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11200    }
11201
11202    pub fn convert_to_kebab_case(
11203        &mut self,
11204        _: &ConvertToKebabCase,
11205        window: &mut Window,
11206        cx: &mut Context<Self>,
11207    ) {
11208        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11209    }
11210
11211    pub fn convert_to_upper_camel_case(
11212        &mut self,
11213        _: &ConvertToUpperCamelCase,
11214        window: &mut Window,
11215        cx: &mut Context<Self>,
11216    ) {
11217        self.manipulate_text(window, cx, |text| {
11218            text.split('\n')
11219                .map(|line| line.to_case(Case::UpperCamel))
11220                .join("\n")
11221        })
11222    }
11223
11224    pub fn convert_to_lower_camel_case(
11225        &mut self,
11226        _: &ConvertToLowerCamelCase,
11227        window: &mut Window,
11228        cx: &mut Context<Self>,
11229    ) {
11230        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11231    }
11232
11233    pub fn convert_to_opposite_case(
11234        &mut self,
11235        _: &ConvertToOppositeCase,
11236        window: &mut Window,
11237        cx: &mut Context<Self>,
11238    ) {
11239        self.manipulate_text(window, cx, |text| {
11240            text.chars()
11241                .fold(String::with_capacity(text.len()), |mut t, c| {
11242                    if c.is_uppercase() {
11243                        t.extend(c.to_lowercase());
11244                    } else {
11245                        t.extend(c.to_uppercase());
11246                    }
11247                    t
11248                })
11249        })
11250    }
11251
11252    pub fn convert_to_sentence_case(
11253        &mut self,
11254        _: &ConvertToSentenceCase,
11255        window: &mut Window,
11256        cx: &mut Context<Self>,
11257    ) {
11258        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11259    }
11260
11261    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11262        self.manipulate_text(window, cx, |text| {
11263            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11264            if has_upper_case_characters {
11265                text.to_lowercase()
11266            } else {
11267                text.to_uppercase()
11268            }
11269        })
11270    }
11271
11272    pub fn convert_to_rot13(
11273        &mut self,
11274        _: &ConvertToRot13,
11275        window: &mut Window,
11276        cx: &mut Context<Self>,
11277    ) {
11278        self.manipulate_text(window, cx, |text| {
11279            text.chars()
11280                .map(|c| match c {
11281                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11282                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11283                    _ => c,
11284                })
11285                .collect()
11286        })
11287    }
11288
11289    pub fn convert_to_rot47(
11290        &mut self,
11291        _: &ConvertToRot47,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294    ) {
11295        self.manipulate_text(window, cx, |text| {
11296            text.chars()
11297                .map(|c| {
11298                    let code_point = c as u32;
11299                    if code_point >= 33 && code_point <= 126 {
11300                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11301                    }
11302                    c
11303                })
11304                .collect()
11305        })
11306    }
11307
11308    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11309    where
11310        Fn: FnMut(&str) -> String,
11311    {
11312        let buffer = self.buffer.read(cx).snapshot(cx);
11313
11314        let mut new_selections = Vec::new();
11315        let mut edits = Vec::new();
11316        let mut selection_adjustment = 0i32;
11317
11318        for selection in self.selections.all::<usize>(cx) {
11319            let selection_is_empty = selection.is_empty();
11320
11321            let (start, end) = if selection_is_empty {
11322                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11323                (word_range.start, word_range.end)
11324            } else {
11325                (selection.start, selection.end)
11326            };
11327
11328            let text = buffer.text_for_range(start..end).collect::<String>();
11329            let old_length = text.len() as i32;
11330            let text = callback(&text);
11331
11332            new_selections.push(Selection {
11333                start: (start as i32 - selection_adjustment) as usize,
11334                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11335                goal: SelectionGoal::None,
11336                ..selection
11337            });
11338
11339            selection_adjustment += old_length - text.len() as i32;
11340
11341            edits.push((start..end, text));
11342        }
11343
11344        self.transact(window, cx, |this, window, cx| {
11345            this.buffer.update(cx, |buffer, cx| {
11346                buffer.edit(edits, None, cx);
11347            });
11348
11349            this.change_selections(Default::default(), window, cx, |s| {
11350                s.select(new_selections);
11351            });
11352
11353            this.request_autoscroll(Autoscroll::fit(), cx);
11354        });
11355    }
11356
11357    pub fn move_selection_on_drop(
11358        &mut self,
11359        selection: &Selection<Anchor>,
11360        target: DisplayPoint,
11361        is_cut: bool,
11362        window: &mut Window,
11363        cx: &mut Context<Self>,
11364    ) {
11365        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11366        let buffer = &display_map.buffer_snapshot;
11367        let mut edits = Vec::new();
11368        let insert_point = display_map
11369            .clip_point(target, Bias::Left)
11370            .to_point(&display_map);
11371        let text = buffer
11372            .text_for_range(selection.start..selection.end)
11373            .collect::<String>();
11374        if is_cut {
11375            edits.push(((selection.start..selection.end), String::new()));
11376        }
11377        let insert_anchor = buffer.anchor_before(insert_point);
11378        edits.push(((insert_anchor..insert_anchor), text));
11379        let last_edit_start = insert_anchor.bias_left(buffer);
11380        let last_edit_end = insert_anchor.bias_right(buffer);
11381        self.transact(window, cx, |this, window, cx| {
11382            this.buffer.update(cx, |buffer, cx| {
11383                buffer.edit(edits, None, cx);
11384            });
11385            this.change_selections(Default::default(), window, cx, |s| {
11386                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11387            });
11388        });
11389    }
11390
11391    pub fn clear_selection_drag_state(&mut self) {
11392        self.selection_drag_state = SelectionDragState::None;
11393    }
11394
11395    pub fn duplicate(
11396        &mut self,
11397        upwards: bool,
11398        whole_lines: bool,
11399        window: &mut Window,
11400        cx: &mut Context<Self>,
11401    ) {
11402        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11403
11404        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11405        let buffer = &display_map.buffer_snapshot;
11406        let selections = self.selections.all::<Point>(cx);
11407
11408        let mut edits = Vec::new();
11409        let mut selections_iter = selections.iter().peekable();
11410        while let Some(selection) = selections_iter.next() {
11411            let mut rows = selection.spanned_rows(false, &display_map);
11412            // duplicate line-wise
11413            if whole_lines || selection.start == selection.end {
11414                // Avoid duplicating the same lines twice.
11415                while let Some(next_selection) = selections_iter.peek() {
11416                    let next_rows = next_selection.spanned_rows(false, &display_map);
11417                    if next_rows.start < rows.end {
11418                        rows.end = next_rows.end;
11419                        selections_iter.next().unwrap();
11420                    } else {
11421                        break;
11422                    }
11423                }
11424
11425                // Copy the text from the selected row region and splice it either at the start
11426                // or end of the region.
11427                let start = Point::new(rows.start.0, 0);
11428                let end = Point::new(
11429                    rows.end.previous_row().0,
11430                    buffer.line_len(rows.end.previous_row()),
11431                );
11432                let text = buffer
11433                    .text_for_range(start..end)
11434                    .chain(Some("\n"))
11435                    .collect::<String>();
11436                let insert_location = if upwards {
11437                    Point::new(rows.end.0, 0)
11438                } else {
11439                    start
11440                };
11441                edits.push((insert_location..insert_location, text));
11442            } else {
11443                // duplicate character-wise
11444                let start = selection.start;
11445                let end = selection.end;
11446                let text = buffer.text_for_range(start..end).collect::<String>();
11447                edits.push((selection.end..selection.end, text));
11448            }
11449        }
11450
11451        self.transact(window, cx, |this, _, cx| {
11452            this.buffer.update(cx, |buffer, cx| {
11453                buffer.edit(edits, None, cx);
11454            });
11455
11456            this.request_autoscroll(Autoscroll::fit(), cx);
11457        });
11458    }
11459
11460    pub fn duplicate_line_up(
11461        &mut self,
11462        _: &DuplicateLineUp,
11463        window: &mut Window,
11464        cx: &mut Context<Self>,
11465    ) {
11466        self.duplicate(true, true, window, cx);
11467    }
11468
11469    pub fn duplicate_line_down(
11470        &mut self,
11471        _: &DuplicateLineDown,
11472        window: &mut Window,
11473        cx: &mut Context<Self>,
11474    ) {
11475        self.duplicate(false, true, window, cx);
11476    }
11477
11478    pub fn duplicate_selection(
11479        &mut self,
11480        _: &DuplicateSelection,
11481        window: &mut Window,
11482        cx: &mut Context<Self>,
11483    ) {
11484        self.duplicate(false, false, window, cx);
11485    }
11486
11487    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11488        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11489        if self.mode.is_single_line() {
11490            cx.propagate();
11491            return;
11492        }
11493
11494        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11495        let buffer = self.buffer.read(cx).snapshot(cx);
11496
11497        let mut edits = Vec::new();
11498        let mut unfold_ranges = Vec::new();
11499        let mut refold_creases = Vec::new();
11500
11501        let selections = self.selections.all::<Point>(cx);
11502        let mut selections = selections.iter().peekable();
11503        let mut contiguous_row_selections = Vec::new();
11504        let mut new_selections = Vec::new();
11505
11506        while let Some(selection) = selections.next() {
11507            // Find all the selections that span a contiguous row range
11508            let (start_row, end_row) = consume_contiguous_rows(
11509                &mut contiguous_row_selections,
11510                selection,
11511                &display_map,
11512                &mut selections,
11513            );
11514
11515            // Move the text spanned by the row range to be before the line preceding the row range
11516            if start_row.0 > 0 {
11517                let range_to_move = Point::new(
11518                    start_row.previous_row().0,
11519                    buffer.line_len(start_row.previous_row()),
11520                )
11521                    ..Point::new(
11522                        end_row.previous_row().0,
11523                        buffer.line_len(end_row.previous_row()),
11524                    );
11525                let insertion_point = display_map
11526                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11527                    .0;
11528
11529                // Don't move lines across excerpts
11530                if buffer
11531                    .excerpt_containing(insertion_point..range_to_move.end)
11532                    .is_some()
11533                {
11534                    let text = buffer
11535                        .text_for_range(range_to_move.clone())
11536                        .flat_map(|s| s.chars())
11537                        .skip(1)
11538                        .chain(['\n'])
11539                        .collect::<String>();
11540
11541                    edits.push((
11542                        buffer.anchor_after(range_to_move.start)
11543                            ..buffer.anchor_before(range_to_move.end),
11544                        String::new(),
11545                    ));
11546                    let insertion_anchor = buffer.anchor_after(insertion_point);
11547                    edits.push((insertion_anchor..insertion_anchor, text));
11548
11549                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11550
11551                    // Move selections up
11552                    new_selections.extend(contiguous_row_selections.drain(..).map(
11553                        |mut selection| {
11554                            selection.start.row -= row_delta;
11555                            selection.end.row -= row_delta;
11556                            selection
11557                        },
11558                    ));
11559
11560                    // Move folds up
11561                    unfold_ranges.push(range_to_move.clone());
11562                    for fold in display_map.folds_in_range(
11563                        buffer.anchor_before(range_to_move.start)
11564                            ..buffer.anchor_after(range_to_move.end),
11565                    ) {
11566                        let mut start = fold.range.start.to_point(&buffer);
11567                        let mut end = fold.range.end.to_point(&buffer);
11568                        start.row -= row_delta;
11569                        end.row -= row_delta;
11570                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11571                    }
11572                }
11573            }
11574
11575            // If we didn't move line(s), preserve the existing selections
11576            new_selections.append(&mut contiguous_row_selections);
11577        }
11578
11579        self.transact(window, cx, |this, window, cx| {
11580            this.unfold_ranges(&unfold_ranges, true, true, cx);
11581            this.buffer.update(cx, |buffer, cx| {
11582                for (range, text) in edits {
11583                    buffer.edit([(range, text)], None, cx);
11584                }
11585            });
11586            this.fold_creases(refold_creases, true, window, cx);
11587            this.change_selections(Default::default(), window, cx, |s| {
11588                s.select(new_selections);
11589            })
11590        });
11591    }
11592
11593    pub fn move_line_down(
11594        &mut self,
11595        _: &MoveLineDown,
11596        window: &mut Window,
11597        cx: &mut Context<Self>,
11598    ) {
11599        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11600        if self.mode.is_single_line() {
11601            cx.propagate();
11602            return;
11603        }
11604
11605        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11606        let buffer = self.buffer.read(cx).snapshot(cx);
11607
11608        let mut edits = Vec::new();
11609        let mut unfold_ranges = Vec::new();
11610        let mut refold_creases = Vec::new();
11611
11612        let selections = self.selections.all::<Point>(cx);
11613        let mut selections = selections.iter().peekable();
11614        let mut contiguous_row_selections = Vec::new();
11615        let mut new_selections = Vec::new();
11616
11617        while let Some(selection) = selections.next() {
11618            // Find all the selections that span a contiguous row range
11619            let (start_row, end_row) = consume_contiguous_rows(
11620                &mut contiguous_row_selections,
11621                selection,
11622                &display_map,
11623                &mut selections,
11624            );
11625
11626            // Move the text spanned by the row range to be after the last line of the row range
11627            if end_row.0 <= buffer.max_point().row {
11628                let range_to_move =
11629                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11630                let insertion_point = display_map
11631                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11632                    .0;
11633
11634                // Don't move lines across excerpt boundaries
11635                if buffer
11636                    .excerpt_containing(range_to_move.start..insertion_point)
11637                    .is_some()
11638                {
11639                    let mut text = String::from("\n");
11640                    text.extend(buffer.text_for_range(range_to_move.clone()));
11641                    text.pop(); // Drop trailing newline
11642                    edits.push((
11643                        buffer.anchor_after(range_to_move.start)
11644                            ..buffer.anchor_before(range_to_move.end),
11645                        String::new(),
11646                    ));
11647                    let insertion_anchor = buffer.anchor_after(insertion_point);
11648                    edits.push((insertion_anchor..insertion_anchor, text));
11649
11650                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11651
11652                    // Move selections down
11653                    new_selections.extend(contiguous_row_selections.drain(..).map(
11654                        |mut selection| {
11655                            selection.start.row += row_delta;
11656                            selection.end.row += row_delta;
11657                            selection
11658                        },
11659                    ));
11660
11661                    // Move folds down
11662                    unfold_ranges.push(range_to_move.clone());
11663                    for fold in display_map.folds_in_range(
11664                        buffer.anchor_before(range_to_move.start)
11665                            ..buffer.anchor_after(range_to_move.end),
11666                    ) {
11667                        let mut start = fold.range.start.to_point(&buffer);
11668                        let mut end = fold.range.end.to_point(&buffer);
11669                        start.row += row_delta;
11670                        end.row += row_delta;
11671                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11672                    }
11673                }
11674            }
11675
11676            // If we didn't move line(s), preserve the existing selections
11677            new_selections.append(&mut contiguous_row_selections);
11678        }
11679
11680        self.transact(window, cx, |this, window, cx| {
11681            this.unfold_ranges(&unfold_ranges, true, true, cx);
11682            this.buffer.update(cx, |buffer, cx| {
11683                for (range, text) in edits {
11684                    buffer.edit([(range, text)], None, cx);
11685                }
11686            });
11687            this.fold_creases(refold_creases, true, window, cx);
11688            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11689        });
11690    }
11691
11692    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11693        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11694        let text_layout_details = &self.text_layout_details(window);
11695        self.transact(window, cx, |this, window, cx| {
11696            let edits = this.change_selections(Default::default(), window, cx, |s| {
11697                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11698                s.move_with(|display_map, selection| {
11699                    if !selection.is_empty() {
11700                        return;
11701                    }
11702
11703                    let mut head = selection.head();
11704                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11705                    if head.column() == display_map.line_len(head.row()) {
11706                        transpose_offset = display_map
11707                            .buffer_snapshot
11708                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11709                    }
11710
11711                    if transpose_offset == 0 {
11712                        return;
11713                    }
11714
11715                    *head.column_mut() += 1;
11716                    head = display_map.clip_point(head, Bias::Right);
11717                    let goal = SelectionGoal::HorizontalPosition(
11718                        display_map
11719                            .x_for_display_point(head, text_layout_details)
11720                            .into(),
11721                    );
11722                    selection.collapse_to(head, goal);
11723
11724                    let transpose_start = display_map
11725                        .buffer_snapshot
11726                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11727                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11728                        let transpose_end = display_map
11729                            .buffer_snapshot
11730                            .clip_offset(transpose_offset + 1, Bias::Right);
11731                        if let Some(ch) =
11732                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11733                        {
11734                            edits.push((transpose_start..transpose_offset, String::new()));
11735                            edits.push((transpose_end..transpose_end, ch.to_string()));
11736                        }
11737                    }
11738                });
11739                edits
11740            });
11741            this.buffer
11742                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11743            let selections = this.selections.all::<usize>(cx);
11744            this.change_selections(Default::default(), window, cx, |s| {
11745                s.select(selections);
11746            });
11747        });
11748    }
11749
11750    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11751        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11752        if self.mode.is_single_line() {
11753            cx.propagate();
11754            return;
11755        }
11756
11757        self.rewrap_impl(RewrapOptions::default(), cx)
11758    }
11759
11760    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11761        let buffer = self.buffer.read(cx).snapshot(cx);
11762        let selections = self.selections.all::<Point>(cx);
11763
11764        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11765        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11766            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11767                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11768                .peekable();
11769
11770            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11771                row
11772            } else {
11773                return Vec::new();
11774            };
11775
11776            let language_settings = buffer.language_settings_at(selection.head(), cx);
11777            let language_scope = buffer.language_scope_at(selection.head());
11778
11779            let indent_and_prefix_for_row =
11780                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11781                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11782                    let (comment_prefix, rewrap_prefix) =
11783                        if let Some(language_scope) = &language_scope {
11784                            let indent_end = Point::new(row, indent.len);
11785                            let comment_prefix = language_scope
11786                                .line_comment_prefixes()
11787                                .iter()
11788                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11789                                .map(|prefix| prefix.to_string());
11790                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11791                            let line_text_after_indent = buffer
11792                                .text_for_range(indent_end..line_end)
11793                                .collect::<String>();
11794                            let rewrap_prefix = language_scope
11795                                .rewrap_prefixes()
11796                                .iter()
11797                                .find_map(|prefix_regex| {
11798                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11799                                        if mat.start() == 0 {
11800                                            Some(mat.as_str().to_string())
11801                                        } else {
11802                                            None
11803                                        }
11804                                    })
11805                                })
11806                                .flatten();
11807                            (comment_prefix, rewrap_prefix)
11808                        } else {
11809                            (None, None)
11810                        };
11811                    (indent, comment_prefix, rewrap_prefix)
11812                };
11813
11814            let mut ranges = Vec::new();
11815            let from_empty_selection = selection.is_empty();
11816
11817            let mut current_range_start = first_row;
11818            let mut prev_row = first_row;
11819            let (
11820                mut current_range_indent,
11821                mut current_range_comment_prefix,
11822                mut current_range_rewrap_prefix,
11823            ) = indent_and_prefix_for_row(first_row);
11824
11825            for row in non_blank_rows_iter.skip(1) {
11826                let has_paragraph_break = row > prev_row + 1;
11827
11828                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11829                    indent_and_prefix_for_row(row);
11830
11831                let has_indent_change = row_indent != current_range_indent;
11832                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11833
11834                let has_boundary_change = has_comment_change
11835                    || row_rewrap_prefix.is_some()
11836                    || (has_indent_change && current_range_comment_prefix.is_some());
11837
11838                if has_paragraph_break || has_boundary_change {
11839                    ranges.push((
11840                        language_settings.clone(),
11841                        Point::new(current_range_start, 0)
11842                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11843                        current_range_indent,
11844                        current_range_comment_prefix.clone(),
11845                        current_range_rewrap_prefix.clone(),
11846                        from_empty_selection,
11847                    ));
11848                    current_range_start = row;
11849                    current_range_indent = row_indent;
11850                    current_range_comment_prefix = row_comment_prefix;
11851                    current_range_rewrap_prefix = row_rewrap_prefix;
11852                }
11853                prev_row = row;
11854            }
11855
11856            ranges.push((
11857                language_settings.clone(),
11858                Point::new(current_range_start, 0)
11859                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11860                current_range_indent,
11861                current_range_comment_prefix,
11862                current_range_rewrap_prefix,
11863                from_empty_selection,
11864            ));
11865
11866            ranges
11867        });
11868
11869        let mut edits = Vec::new();
11870        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11871
11872        for (
11873            language_settings,
11874            wrap_range,
11875            indent_size,
11876            comment_prefix,
11877            rewrap_prefix,
11878            from_empty_selection,
11879        ) in wrap_ranges
11880        {
11881            let mut start_row = wrap_range.start.row;
11882            let mut end_row = wrap_range.end.row;
11883
11884            // Skip selections that overlap with a range that has already been rewrapped.
11885            let selection_range = start_row..end_row;
11886            if rewrapped_row_ranges
11887                .iter()
11888                .any(|range| range.overlaps(&selection_range))
11889            {
11890                continue;
11891            }
11892
11893            let tab_size = language_settings.tab_size;
11894
11895            let indent_prefix = indent_size.chars().collect::<String>();
11896            let mut line_prefix = indent_prefix.clone();
11897            let mut inside_comment = false;
11898            if let Some(prefix) = &comment_prefix {
11899                line_prefix.push_str(prefix);
11900                inside_comment = true;
11901            }
11902            if let Some(prefix) = &rewrap_prefix {
11903                line_prefix.push_str(prefix);
11904            }
11905
11906            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11907                RewrapBehavior::InComments => inside_comment,
11908                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11909                RewrapBehavior::Anywhere => true,
11910            };
11911
11912            let should_rewrap = options.override_language_settings
11913                || allow_rewrap_based_on_language
11914                || self.hard_wrap.is_some();
11915            if !should_rewrap {
11916                continue;
11917            }
11918
11919            if from_empty_selection {
11920                'expand_upwards: while start_row > 0 {
11921                    let prev_row = start_row - 1;
11922                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11923                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11924                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11925                    {
11926                        start_row = prev_row;
11927                    } else {
11928                        break 'expand_upwards;
11929                    }
11930                }
11931
11932                'expand_downwards: while end_row < buffer.max_point().row {
11933                    let next_row = end_row + 1;
11934                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11935                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11936                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11937                    {
11938                        end_row = next_row;
11939                    } else {
11940                        break 'expand_downwards;
11941                    }
11942                }
11943            }
11944
11945            let start = Point::new(start_row, 0);
11946            let start_offset = start.to_offset(&buffer);
11947            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11948            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11949            let Some(lines_without_prefixes) = selection_text
11950                .lines()
11951                .enumerate()
11952                .map(|(ix, line)| {
11953                    let line_trimmed = line.trim_start();
11954                    if rewrap_prefix.is_some() && ix > 0 {
11955                        Ok(line_trimmed)
11956                    } else {
11957                        line_trimmed
11958                            .strip_prefix(&line_prefix.trim_start())
11959                            .with_context(|| {
11960                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11961                            })
11962                    }
11963                })
11964                .collect::<Result<Vec<_>, _>>()
11965                .log_err()
11966            else {
11967                continue;
11968            };
11969
11970            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11971                buffer
11972                    .language_settings_at(Point::new(start_row, 0), cx)
11973                    .preferred_line_length as usize
11974            });
11975
11976            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11977                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11978            } else {
11979                line_prefix.clone()
11980            };
11981
11982            let wrapped_text = wrap_with_prefix(
11983                line_prefix,
11984                subsequent_lines_prefix,
11985                lines_without_prefixes.join("\n"),
11986                wrap_column,
11987                tab_size,
11988                options.preserve_existing_whitespace,
11989            );
11990
11991            // TODO: should always use char-based diff while still supporting cursor behavior that
11992            // matches vim.
11993            let mut diff_options = DiffOptions::default();
11994            if options.override_language_settings {
11995                diff_options.max_word_diff_len = 0;
11996                diff_options.max_word_diff_line_count = 0;
11997            } else {
11998                diff_options.max_word_diff_len = usize::MAX;
11999                diff_options.max_word_diff_line_count = usize::MAX;
12000            }
12001
12002            for (old_range, new_text) in
12003                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12004            {
12005                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12006                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12007                edits.push((edit_start..edit_end, new_text));
12008            }
12009
12010            rewrapped_row_ranges.push(start_row..=end_row);
12011        }
12012
12013        self.buffer
12014            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12015    }
12016
12017    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12018        let mut text = String::new();
12019        let buffer = self.buffer.read(cx).snapshot(cx);
12020        let mut selections = self.selections.all::<Point>(cx);
12021        let mut clipboard_selections = Vec::with_capacity(selections.len());
12022        {
12023            let max_point = buffer.max_point();
12024            let mut is_first = true;
12025            for selection in &mut selections {
12026                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12027                if is_entire_line {
12028                    selection.start = Point::new(selection.start.row, 0);
12029                    if !selection.is_empty() && selection.end.column == 0 {
12030                        selection.end = cmp::min(max_point, selection.end);
12031                    } else {
12032                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12033                    }
12034                    selection.goal = SelectionGoal::None;
12035                }
12036                if is_first {
12037                    is_first = false;
12038                } else {
12039                    text += "\n";
12040                }
12041                let mut len = 0;
12042                for chunk in buffer.text_for_range(selection.start..selection.end) {
12043                    text.push_str(chunk);
12044                    len += chunk.len();
12045                }
12046                clipboard_selections.push(ClipboardSelection {
12047                    len,
12048                    is_entire_line,
12049                    first_line_indent: buffer
12050                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12051                        .len,
12052                });
12053            }
12054        }
12055
12056        self.transact(window, cx, |this, window, cx| {
12057            this.change_selections(Default::default(), window, cx, |s| {
12058                s.select(selections);
12059            });
12060            this.insert("", window, cx);
12061        });
12062        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12063    }
12064
12065    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12067        let item = self.cut_common(window, cx);
12068        cx.write_to_clipboard(item);
12069    }
12070
12071    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12072        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12073        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12074            s.move_with(|snapshot, sel| {
12075                if sel.is_empty() {
12076                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12077                }
12078            });
12079        });
12080        let item = self.cut_common(window, cx);
12081        cx.set_global(KillRing(item))
12082    }
12083
12084    pub fn kill_ring_yank(
12085        &mut self,
12086        _: &KillRingYank,
12087        window: &mut Window,
12088        cx: &mut Context<Self>,
12089    ) {
12090        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12091        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12092            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12093                (kill_ring.text().to_string(), kill_ring.metadata_json())
12094            } else {
12095                return;
12096            }
12097        } else {
12098            return;
12099        };
12100        self.do_paste(&text, metadata, false, window, cx);
12101    }
12102
12103    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12104        self.do_copy(true, cx);
12105    }
12106
12107    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12108        self.do_copy(false, cx);
12109    }
12110
12111    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12112        let selections = self.selections.all::<Point>(cx);
12113        let buffer = self.buffer.read(cx).read(cx);
12114        let mut text = String::new();
12115
12116        let mut clipboard_selections = Vec::with_capacity(selections.len());
12117        {
12118            let max_point = buffer.max_point();
12119            let mut is_first = true;
12120            for selection in &selections {
12121                let mut start = selection.start;
12122                let mut end = selection.end;
12123                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12124                if is_entire_line {
12125                    start = Point::new(start.row, 0);
12126                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12127                }
12128
12129                let mut trimmed_selections = Vec::new();
12130                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12131                    let row = MultiBufferRow(start.row);
12132                    let first_indent = buffer.indent_size_for_line(row);
12133                    if first_indent.len == 0 || start.column > first_indent.len {
12134                        trimmed_selections.push(start..end);
12135                    } else {
12136                        trimmed_selections.push(
12137                            Point::new(row.0, first_indent.len)
12138                                ..Point::new(row.0, buffer.line_len(row)),
12139                        );
12140                        for row in start.row + 1..=end.row {
12141                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12142                            if row == end.row {
12143                                line_len = end.column;
12144                            }
12145                            if line_len == 0 {
12146                                trimmed_selections
12147                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12148                                continue;
12149                            }
12150                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12151                            if row_indent_size.len >= first_indent.len {
12152                                trimmed_selections.push(
12153                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12154                                );
12155                            } else {
12156                                trimmed_selections.clear();
12157                                trimmed_selections.push(start..end);
12158                                break;
12159                            }
12160                        }
12161                    }
12162                } else {
12163                    trimmed_selections.push(start..end);
12164                }
12165
12166                for trimmed_range in trimmed_selections {
12167                    if is_first {
12168                        is_first = false;
12169                    } else {
12170                        text += "\n";
12171                    }
12172                    let mut len = 0;
12173                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12174                        text.push_str(chunk);
12175                        len += chunk.len();
12176                    }
12177                    clipboard_selections.push(ClipboardSelection {
12178                        len,
12179                        is_entire_line,
12180                        first_line_indent: buffer
12181                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12182                            .len,
12183                    });
12184                }
12185            }
12186        }
12187
12188        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12189            text,
12190            clipboard_selections,
12191        ));
12192    }
12193
12194    pub fn do_paste(
12195        &mut self,
12196        text: &String,
12197        clipboard_selections: Option<Vec<ClipboardSelection>>,
12198        handle_entire_lines: bool,
12199        window: &mut Window,
12200        cx: &mut Context<Self>,
12201    ) {
12202        if self.read_only(cx) {
12203            return;
12204        }
12205
12206        let clipboard_text = Cow::Borrowed(text);
12207
12208        self.transact(window, cx, |this, window, cx| {
12209            let had_active_edit_prediction = this.has_active_edit_prediction();
12210
12211            if let Some(mut clipboard_selections) = clipboard_selections {
12212                let old_selections = this.selections.all::<usize>(cx);
12213                let all_selections_were_entire_line =
12214                    clipboard_selections.iter().all(|s| s.is_entire_line);
12215                let first_selection_indent_column =
12216                    clipboard_selections.first().map(|s| s.first_line_indent);
12217                if clipboard_selections.len() != old_selections.len() {
12218                    clipboard_selections.drain(..);
12219                }
12220                let cursor_offset = this.selections.last::<usize>(cx).head();
12221                let mut auto_indent_on_paste = true;
12222
12223                this.buffer.update(cx, |buffer, cx| {
12224                    let snapshot = buffer.read(cx);
12225                    auto_indent_on_paste = snapshot
12226                        .language_settings_at(cursor_offset, cx)
12227                        .auto_indent_on_paste;
12228
12229                    let mut start_offset = 0;
12230                    let mut edits = Vec::new();
12231                    let mut original_indent_columns = Vec::new();
12232                    for (ix, selection) in old_selections.iter().enumerate() {
12233                        let to_insert;
12234                        let entire_line;
12235                        let original_indent_column;
12236                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12237                            let end_offset = start_offset + clipboard_selection.len;
12238                            to_insert = &clipboard_text[start_offset..end_offset];
12239                            entire_line = clipboard_selection.is_entire_line;
12240                            start_offset = end_offset + 1;
12241                            original_indent_column = Some(clipboard_selection.first_line_indent);
12242                        } else {
12243                            to_insert = clipboard_text.as_str();
12244                            entire_line = all_selections_were_entire_line;
12245                            original_indent_column = first_selection_indent_column
12246                        }
12247
12248                        // If the corresponding selection was empty when this slice of the
12249                        // clipboard text was written, then the entire line containing the
12250                        // selection was copied. If this selection is also currently empty,
12251                        // then paste the line before the current line of the buffer.
12252                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12253                            let column = selection.start.to_point(&snapshot).column as usize;
12254                            let line_start = selection.start - column;
12255                            line_start..line_start
12256                        } else {
12257                            selection.range()
12258                        };
12259
12260                        edits.push((range, to_insert));
12261                        original_indent_columns.push(original_indent_column);
12262                    }
12263                    drop(snapshot);
12264
12265                    buffer.edit(
12266                        edits,
12267                        if auto_indent_on_paste {
12268                            Some(AutoindentMode::Block {
12269                                original_indent_columns,
12270                            })
12271                        } else {
12272                            None
12273                        },
12274                        cx,
12275                    );
12276                });
12277
12278                let selections = this.selections.all::<usize>(cx);
12279                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12280            } else {
12281                this.insert(&clipboard_text, window, cx);
12282            }
12283
12284            let trigger_in_words =
12285                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12286
12287            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12288        });
12289    }
12290
12291    pub fn diff_clipboard_with_selection(
12292        &mut self,
12293        _: &DiffClipboardWithSelection,
12294        window: &mut Window,
12295        cx: &mut Context<Self>,
12296    ) {
12297        let selections = self.selections.all::<usize>(cx);
12298
12299        if selections.is_empty() {
12300            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12301            return;
12302        };
12303
12304        let clipboard_text = match cx.read_from_clipboard() {
12305            Some(item) => match item.entries().first() {
12306                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12307                _ => None,
12308            },
12309            None => None,
12310        };
12311
12312        let Some(clipboard_text) = clipboard_text else {
12313            log::warn!("Clipboard doesn't contain text.");
12314            return;
12315        };
12316
12317        window.dispatch_action(
12318            Box::new(DiffClipboardWithSelectionData {
12319                clipboard_text,
12320                editor: cx.entity(),
12321            }),
12322            cx,
12323        );
12324    }
12325
12326    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12327        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12328        if let Some(item) = cx.read_from_clipboard() {
12329            let entries = item.entries();
12330
12331            match entries.first() {
12332                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12333                // of all the pasted entries.
12334                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12335                    .do_paste(
12336                        clipboard_string.text(),
12337                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12338                        true,
12339                        window,
12340                        cx,
12341                    ),
12342                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12343            }
12344        }
12345    }
12346
12347    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12348        if self.read_only(cx) {
12349            return;
12350        }
12351
12352        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12353
12354        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12355            if let Some((selections, _)) =
12356                self.selection_history.transaction(transaction_id).cloned()
12357            {
12358                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12359                    s.select_anchors(selections.to_vec());
12360                });
12361            } else {
12362                log::error!(
12363                    "No entry in selection_history found for undo. \
12364                     This may correspond to a bug where undo does not update the selection. \
12365                     If this is occurring, please add details to \
12366                     https://github.com/zed-industries/zed/issues/22692"
12367                );
12368            }
12369            self.request_autoscroll(Autoscroll::fit(), cx);
12370            self.unmark_text(window, cx);
12371            self.refresh_edit_prediction(true, false, window, cx);
12372            cx.emit(EditorEvent::Edited { transaction_id });
12373            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12374        }
12375    }
12376
12377    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12378        if self.read_only(cx) {
12379            return;
12380        }
12381
12382        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12383
12384        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12385            if let Some((_, Some(selections))) =
12386                self.selection_history.transaction(transaction_id).cloned()
12387            {
12388                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12389                    s.select_anchors(selections.to_vec());
12390                });
12391            } else {
12392                log::error!(
12393                    "No entry in selection_history found for redo. \
12394                     This may correspond to a bug where undo does not update the selection. \
12395                     If this is occurring, please add details to \
12396                     https://github.com/zed-industries/zed/issues/22692"
12397                );
12398            }
12399            self.request_autoscroll(Autoscroll::fit(), cx);
12400            self.unmark_text(window, cx);
12401            self.refresh_edit_prediction(true, false, window, cx);
12402            cx.emit(EditorEvent::Edited { transaction_id });
12403        }
12404    }
12405
12406    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12407        self.buffer
12408            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12409    }
12410
12411    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12412        self.buffer
12413            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12414    }
12415
12416    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12417        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12418        self.change_selections(Default::default(), window, cx, |s| {
12419            s.move_with(|map, selection| {
12420                let cursor = if selection.is_empty() {
12421                    movement::left(map, selection.start)
12422                } else {
12423                    selection.start
12424                };
12425                selection.collapse_to(cursor, SelectionGoal::None);
12426            });
12427        })
12428    }
12429
12430    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12431        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12432        self.change_selections(Default::default(), window, cx, |s| {
12433            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12434        })
12435    }
12436
12437    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12439        self.change_selections(Default::default(), window, cx, |s| {
12440            s.move_with(|map, selection| {
12441                let cursor = if selection.is_empty() {
12442                    movement::right(map, selection.end)
12443                } else {
12444                    selection.end
12445                };
12446                selection.collapse_to(cursor, SelectionGoal::None)
12447            });
12448        })
12449    }
12450
12451    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12453        self.change_selections(Default::default(), window, cx, |s| {
12454            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12455        })
12456    }
12457
12458    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12459        if self.take_rename(true, window, cx).is_some() {
12460            return;
12461        }
12462
12463        if self.mode.is_single_line() {
12464            cx.propagate();
12465            return;
12466        }
12467
12468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12469
12470        let text_layout_details = &self.text_layout_details(window);
12471        let selection_count = self.selections.count();
12472        let first_selection = self.selections.first_anchor();
12473
12474        self.change_selections(Default::default(), window, cx, |s| {
12475            s.move_with(|map, selection| {
12476                if !selection.is_empty() {
12477                    selection.goal = SelectionGoal::None;
12478                }
12479                let (cursor, goal) = movement::up(
12480                    map,
12481                    selection.start,
12482                    selection.goal,
12483                    false,
12484                    text_layout_details,
12485                );
12486                selection.collapse_to(cursor, goal);
12487            });
12488        });
12489
12490        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12491        {
12492            cx.propagate();
12493        }
12494    }
12495
12496    pub fn move_up_by_lines(
12497        &mut self,
12498        action: &MoveUpByLines,
12499        window: &mut Window,
12500        cx: &mut Context<Self>,
12501    ) {
12502        if self.take_rename(true, window, cx).is_some() {
12503            return;
12504        }
12505
12506        if self.mode.is_single_line() {
12507            cx.propagate();
12508            return;
12509        }
12510
12511        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12512
12513        let text_layout_details = &self.text_layout_details(window);
12514
12515        self.change_selections(Default::default(), window, cx, |s| {
12516            s.move_with(|map, selection| {
12517                if !selection.is_empty() {
12518                    selection.goal = SelectionGoal::None;
12519                }
12520                let (cursor, goal) = movement::up_by_rows(
12521                    map,
12522                    selection.start,
12523                    action.lines,
12524                    selection.goal,
12525                    false,
12526                    text_layout_details,
12527                );
12528                selection.collapse_to(cursor, goal);
12529            });
12530        })
12531    }
12532
12533    pub fn move_down_by_lines(
12534        &mut self,
12535        action: &MoveDownByLines,
12536        window: &mut Window,
12537        cx: &mut Context<Self>,
12538    ) {
12539        if self.take_rename(true, window, cx).is_some() {
12540            return;
12541        }
12542
12543        if self.mode.is_single_line() {
12544            cx.propagate();
12545            return;
12546        }
12547
12548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12549
12550        let text_layout_details = &self.text_layout_details(window);
12551
12552        self.change_selections(Default::default(), window, cx, |s| {
12553            s.move_with(|map, selection| {
12554                if !selection.is_empty() {
12555                    selection.goal = SelectionGoal::None;
12556                }
12557                let (cursor, goal) = movement::down_by_rows(
12558                    map,
12559                    selection.start,
12560                    action.lines,
12561                    selection.goal,
12562                    false,
12563                    text_layout_details,
12564                );
12565                selection.collapse_to(cursor, goal);
12566            });
12567        })
12568    }
12569
12570    pub fn select_down_by_lines(
12571        &mut self,
12572        action: &SelectDownByLines,
12573        window: &mut Window,
12574        cx: &mut Context<Self>,
12575    ) {
12576        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12577        let text_layout_details = &self.text_layout_details(window);
12578        self.change_selections(Default::default(), window, cx, |s| {
12579            s.move_heads_with(|map, head, goal| {
12580                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12581            })
12582        })
12583    }
12584
12585    pub fn select_up_by_lines(
12586        &mut self,
12587        action: &SelectUpByLines,
12588        window: &mut Window,
12589        cx: &mut Context<Self>,
12590    ) {
12591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12592        let text_layout_details = &self.text_layout_details(window);
12593        self.change_selections(Default::default(), window, cx, |s| {
12594            s.move_heads_with(|map, head, goal| {
12595                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12596            })
12597        })
12598    }
12599
12600    pub fn select_page_up(
12601        &mut self,
12602        _: &SelectPageUp,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        let Some(row_count) = self.visible_row_count() else {
12607            return;
12608        };
12609
12610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12611
12612        let text_layout_details = &self.text_layout_details(window);
12613
12614        self.change_selections(Default::default(), window, cx, |s| {
12615            s.move_heads_with(|map, head, goal| {
12616                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12617            })
12618        })
12619    }
12620
12621    pub fn move_page_up(
12622        &mut self,
12623        action: &MovePageUp,
12624        window: &mut Window,
12625        cx: &mut Context<Self>,
12626    ) {
12627        if self.take_rename(true, window, cx).is_some() {
12628            return;
12629        }
12630
12631        if self
12632            .context_menu
12633            .borrow_mut()
12634            .as_mut()
12635            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12636            .unwrap_or(false)
12637        {
12638            return;
12639        }
12640
12641        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12642            cx.propagate();
12643            return;
12644        }
12645
12646        let Some(row_count) = self.visible_row_count() else {
12647            return;
12648        };
12649
12650        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12651
12652        let effects = if action.center_cursor {
12653            SelectionEffects::scroll(Autoscroll::center())
12654        } else {
12655            SelectionEffects::default()
12656        };
12657
12658        let text_layout_details = &self.text_layout_details(window);
12659
12660        self.change_selections(effects, window, cx, |s| {
12661            s.move_with(|map, selection| {
12662                if !selection.is_empty() {
12663                    selection.goal = SelectionGoal::None;
12664                }
12665                let (cursor, goal) = movement::up_by_rows(
12666                    map,
12667                    selection.end,
12668                    row_count,
12669                    selection.goal,
12670                    false,
12671                    text_layout_details,
12672                );
12673                selection.collapse_to(cursor, goal);
12674            });
12675        });
12676    }
12677
12678    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12680        let text_layout_details = &self.text_layout_details(window);
12681        self.change_selections(Default::default(), window, cx, |s| {
12682            s.move_heads_with(|map, head, goal| {
12683                movement::up(map, head, goal, false, text_layout_details)
12684            })
12685        })
12686    }
12687
12688    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12689        self.take_rename(true, window, cx);
12690
12691        if self.mode.is_single_line() {
12692            cx.propagate();
12693            return;
12694        }
12695
12696        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12697
12698        let text_layout_details = &self.text_layout_details(window);
12699        let selection_count = self.selections.count();
12700        let first_selection = self.selections.first_anchor();
12701
12702        self.change_selections(Default::default(), window, cx, |s| {
12703            s.move_with(|map, selection| {
12704                if !selection.is_empty() {
12705                    selection.goal = SelectionGoal::None;
12706                }
12707                let (cursor, goal) = movement::down(
12708                    map,
12709                    selection.end,
12710                    selection.goal,
12711                    false,
12712                    text_layout_details,
12713                );
12714                selection.collapse_to(cursor, goal);
12715            });
12716        });
12717
12718        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12719        {
12720            cx.propagate();
12721        }
12722    }
12723
12724    pub fn select_page_down(
12725        &mut self,
12726        _: &SelectPageDown,
12727        window: &mut Window,
12728        cx: &mut Context<Self>,
12729    ) {
12730        let Some(row_count) = self.visible_row_count() else {
12731            return;
12732        };
12733
12734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12735
12736        let text_layout_details = &self.text_layout_details(window);
12737
12738        self.change_selections(Default::default(), window, cx, |s| {
12739            s.move_heads_with(|map, head, goal| {
12740                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12741            })
12742        })
12743    }
12744
12745    pub fn move_page_down(
12746        &mut self,
12747        action: &MovePageDown,
12748        window: &mut Window,
12749        cx: &mut Context<Self>,
12750    ) {
12751        if self.take_rename(true, window, cx).is_some() {
12752            return;
12753        }
12754
12755        if self
12756            .context_menu
12757            .borrow_mut()
12758            .as_mut()
12759            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12760            .unwrap_or(false)
12761        {
12762            return;
12763        }
12764
12765        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12766            cx.propagate();
12767            return;
12768        }
12769
12770        let Some(row_count) = self.visible_row_count() else {
12771            return;
12772        };
12773
12774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12775
12776        let effects = if action.center_cursor {
12777            SelectionEffects::scroll(Autoscroll::center())
12778        } else {
12779            SelectionEffects::default()
12780        };
12781
12782        let text_layout_details = &self.text_layout_details(window);
12783        self.change_selections(effects, window, cx, |s| {
12784            s.move_with(|map, selection| {
12785                if !selection.is_empty() {
12786                    selection.goal = SelectionGoal::None;
12787                }
12788                let (cursor, goal) = movement::down_by_rows(
12789                    map,
12790                    selection.end,
12791                    row_count,
12792                    selection.goal,
12793                    false,
12794                    text_layout_details,
12795                );
12796                selection.collapse_to(cursor, goal);
12797            });
12798        });
12799    }
12800
12801    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12802        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12803        let text_layout_details = &self.text_layout_details(window);
12804        self.change_selections(Default::default(), window, cx, |s| {
12805            s.move_heads_with(|map, head, goal| {
12806                movement::down(map, head, goal, false, text_layout_details)
12807            })
12808        });
12809    }
12810
12811    pub fn context_menu_first(
12812        &mut self,
12813        _: &ContextMenuFirst,
12814        window: &mut Window,
12815        cx: &mut Context<Self>,
12816    ) {
12817        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12818            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12819        }
12820    }
12821
12822    pub fn context_menu_prev(
12823        &mut self,
12824        _: &ContextMenuPrevious,
12825        window: &mut Window,
12826        cx: &mut Context<Self>,
12827    ) {
12828        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12829            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12830        }
12831    }
12832
12833    pub fn context_menu_next(
12834        &mut self,
12835        _: &ContextMenuNext,
12836        window: &mut Window,
12837        cx: &mut Context<Self>,
12838    ) {
12839        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12840            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12841        }
12842    }
12843
12844    pub fn context_menu_last(
12845        &mut self,
12846        _: &ContextMenuLast,
12847        window: &mut Window,
12848        cx: &mut Context<Self>,
12849    ) {
12850        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12851            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12852        }
12853    }
12854
12855    pub fn signature_help_prev(
12856        &mut self,
12857        _: &SignatureHelpPrevious,
12858        _: &mut Window,
12859        cx: &mut Context<Self>,
12860    ) {
12861        if let Some(popover) = self.signature_help_state.popover_mut() {
12862            if popover.current_signature == 0 {
12863                popover.current_signature = popover.signatures.len() - 1;
12864            } else {
12865                popover.current_signature -= 1;
12866            }
12867            cx.notify();
12868        }
12869    }
12870
12871    pub fn signature_help_next(
12872        &mut self,
12873        _: &SignatureHelpNext,
12874        _: &mut Window,
12875        cx: &mut Context<Self>,
12876    ) {
12877        if let Some(popover) = self.signature_help_state.popover_mut() {
12878            if popover.current_signature + 1 == popover.signatures.len() {
12879                popover.current_signature = 0;
12880            } else {
12881                popover.current_signature += 1;
12882            }
12883            cx.notify();
12884        }
12885    }
12886
12887    pub fn move_to_previous_word_start(
12888        &mut self,
12889        _: &MoveToPreviousWordStart,
12890        window: &mut Window,
12891        cx: &mut Context<Self>,
12892    ) {
12893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12894        self.change_selections(Default::default(), window, cx, |s| {
12895            s.move_cursors_with(|map, head, _| {
12896                (
12897                    movement::previous_word_start(map, head),
12898                    SelectionGoal::None,
12899                )
12900            });
12901        })
12902    }
12903
12904    pub fn move_to_previous_subword_start(
12905        &mut self,
12906        _: &MoveToPreviousSubwordStart,
12907        window: &mut Window,
12908        cx: &mut Context<Self>,
12909    ) {
12910        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12911        self.change_selections(Default::default(), window, cx, |s| {
12912            s.move_cursors_with(|map, head, _| {
12913                (
12914                    movement::previous_subword_start(map, head),
12915                    SelectionGoal::None,
12916                )
12917            });
12918        })
12919    }
12920
12921    pub fn select_to_previous_word_start(
12922        &mut self,
12923        _: &SelectToPreviousWordStart,
12924        window: &mut Window,
12925        cx: &mut Context<Self>,
12926    ) {
12927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12928        self.change_selections(Default::default(), window, cx, |s| {
12929            s.move_heads_with(|map, head, _| {
12930                (
12931                    movement::previous_word_start(map, head),
12932                    SelectionGoal::None,
12933                )
12934            });
12935        })
12936    }
12937
12938    pub fn select_to_previous_subword_start(
12939        &mut self,
12940        _: &SelectToPreviousSubwordStart,
12941        window: &mut Window,
12942        cx: &mut Context<Self>,
12943    ) {
12944        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12945        self.change_selections(Default::default(), window, cx, |s| {
12946            s.move_heads_with(|map, head, _| {
12947                (
12948                    movement::previous_subword_start(map, head),
12949                    SelectionGoal::None,
12950                )
12951            });
12952        })
12953    }
12954
12955    pub fn delete_to_previous_word_start(
12956        &mut self,
12957        action: &DeleteToPreviousWordStart,
12958        window: &mut Window,
12959        cx: &mut Context<Self>,
12960    ) {
12961        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12962        self.transact(window, cx, |this, window, cx| {
12963            this.select_autoclose_pair(window, cx);
12964            this.change_selections(Default::default(), window, cx, |s| {
12965                s.move_with(|map, selection| {
12966                    if selection.is_empty() {
12967                        let cursor = if action.ignore_newlines {
12968                            movement::previous_word_start(map, selection.head())
12969                        } else {
12970                            movement::previous_word_start_or_newline(map, selection.head())
12971                        };
12972                        selection.set_head(cursor, SelectionGoal::None);
12973                    }
12974                });
12975            });
12976            this.insert("", window, cx);
12977        });
12978    }
12979
12980    pub fn delete_to_previous_subword_start(
12981        &mut self,
12982        _: &DeleteToPreviousSubwordStart,
12983        window: &mut Window,
12984        cx: &mut Context<Self>,
12985    ) {
12986        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12987        self.transact(window, cx, |this, window, cx| {
12988            this.select_autoclose_pair(window, cx);
12989            this.change_selections(Default::default(), window, cx, |s| {
12990                s.move_with(|map, selection| {
12991                    if selection.is_empty() {
12992                        let cursor = movement::previous_subword_start(map, selection.head());
12993                        selection.set_head(cursor, SelectionGoal::None);
12994                    }
12995                });
12996            });
12997            this.insert("", window, cx);
12998        });
12999    }
13000
13001    pub fn move_to_next_word_end(
13002        &mut self,
13003        _: &MoveToNextWordEnd,
13004        window: &mut Window,
13005        cx: &mut Context<Self>,
13006    ) {
13007        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13008        self.change_selections(Default::default(), window, cx, |s| {
13009            s.move_cursors_with(|map, head, _| {
13010                (movement::next_word_end(map, head), SelectionGoal::None)
13011            });
13012        })
13013    }
13014
13015    pub fn move_to_next_subword_end(
13016        &mut self,
13017        _: &MoveToNextSubwordEnd,
13018        window: &mut Window,
13019        cx: &mut Context<Self>,
13020    ) {
13021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13022        self.change_selections(Default::default(), window, cx, |s| {
13023            s.move_cursors_with(|map, head, _| {
13024                (movement::next_subword_end(map, head), SelectionGoal::None)
13025            });
13026        })
13027    }
13028
13029    pub fn select_to_next_word_end(
13030        &mut self,
13031        _: &SelectToNextWordEnd,
13032        window: &mut Window,
13033        cx: &mut Context<Self>,
13034    ) {
13035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13036        self.change_selections(Default::default(), window, cx, |s| {
13037            s.move_heads_with(|map, head, _| {
13038                (movement::next_word_end(map, head), SelectionGoal::None)
13039            });
13040        })
13041    }
13042
13043    pub fn select_to_next_subword_end(
13044        &mut self,
13045        _: &SelectToNextSubwordEnd,
13046        window: &mut Window,
13047        cx: &mut Context<Self>,
13048    ) {
13049        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13050        self.change_selections(Default::default(), window, cx, |s| {
13051            s.move_heads_with(|map, head, _| {
13052                (movement::next_subword_end(map, head), SelectionGoal::None)
13053            });
13054        })
13055    }
13056
13057    pub fn delete_to_next_word_end(
13058        &mut self,
13059        action: &DeleteToNextWordEnd,
13060        window: &mut Window,
13061        cx: &mut Context<Self>,
13062    ) {
13063        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13064        self.transact(window, cx, |this, window, cx| {
13065            this.change_selections(Default::default(), window, cx, |s| {
13066                s.move_with(|map, selection| {
13067                    if selection.is_empty() {
13068                        let cursor = if action.ignore_newlines {
13069                            movement::next_word_end(map, selection.head())
13070                        } else {
13071                            movement::next_word_end_or_newline(map, selection.head())
13072                        };
13073                        selection.set_head(cursor, SelectionGoal::None);
13074                    }
13075                });
13076            });
13077            this.insert("", window, cx);
13078        });
13079    }
13080
13081    pub fn delete_to_next_subword_end(
13082        &mut self,
13083        _: &DeleteToNextSubwordEnd,
13084        window: &mut Window,
13085        cx: &mut Context<Self>,
13086    ) {
13087        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13088        self.transact(window, cx, |this, window, cx| {
13089            this.change_selections(Default::default(), window, cx, |s| {
13090                s.move_with(|map, selection| {
13091                    if selection.is_empty() {
13092                        let cursor = movement::next_subword_end(map, selection.head());
13093                        selection.set_head(cursor, SelectionGoal::None);
13094                    }
13095                });
13096            });
13097            this.insert("", window, cx);
13098        });
13099    }
13100
13101    pub fn move_to_beginning_of_line(
13102        &mut self,
13103        action: &MoveToBeginningOfLine,
13104        window: &mut Window,
13105        cx: &mut Context<Self>,
13106    ) {
13107        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13108        self.change_selections(Default::default(), window, cx, |s| {
13109            s.move_cursors_with(|map, head, _| {
13110                (
13111                    movement::indented_line_beginning(
13112                        map,
13113                        head,
13114                        action.stop_at_soft_wraps,
13115                        action.stop_at_indent,
13116                    ),
13117                    SelectionGoal::None,
13118                )
13119            });
13120        })
13121    }
13122
13123    pub fn select_to_beginning_of_line(
13124        &mut self,
13125        action: &SelectToBeginningOfLine,
13126        window: &mut Window,
13127        cx: &mut Context<Self>,
13128    ) {
13129        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13130        self.change_selections(Default::default(), window, cx, |s| {
13131            s.move_heads_with(|map, head, _| {
13132                (
13133                    movement::indented_line_beginning(
13134                        map,
13135                        head,
13136                        action.stop_at_soft_wraps,
13137                        action.stop_at_indent,
13138                    ),
13139                    SelectionGoal::None,
13140                )
13141            });
13142        });
13143    }
13144
13145    pub fn delete_to_beginning_of_line(
13146        &mut self,
13147        action: &DeleteToBeginningOfLine,
13148        window: &mut Window,
13149        cx: &mut Context<Self>,
13150    ) {
13151        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13152        self.transact(window, cx, |this, window, cx| {
13153            this.change_selections(Default::default(), window, cx, |s| {
13154                s.move_with(|_, selection| {
13155                    selection.reversed = true;
13156                });
13157            });
13158
13159            this.select_to_beginning_of_line(
13160                &SelectToBeginningOfLine {
13161                    stop_at_soft_wraps: false,
13162                    stop_at_indent: action.stop_at_indent,
13163                },
13164                window,
13165                cx,
13166            );
13167            this.backspace(&Backspace, window, cx);
13168        });
13169    }
13170
13171    pub fn move_to_end_of_line(
13172        &mut self,
13173        action: &MoveToEndOfLine,
13174        window: &mut Window,
13175        cx: &mut Context<Self>,
13176    ) {
13177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13178        self.change_selections(Default::default(), window, cx, |s| {
13179            s.move_cursors_with(|map, head, _| {
13180                (
13181                    movement::line_end(map, head, action.stop_at_soft_wraps),
13182                    SelectionGoal::None,
13183                )
13184            });
13185        })
13186    }
13187
13188    pub fn select_to_end_of_line(
13189        &mut self,
13190        action: &SelectToEndOfLine,
13191        window: &mut Window,
13192        cx: &mut Context<Self>,
13193    ) {
13194        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13195        self.change_selections(Default::default(), window, cx, |s| {
13196            s.move_heads_with(|map, head, _| {
13197                (
13198                    movement::line_end(map, head, action.stop_at_soft_wraps),
13199                    SelectionGoal::None,
13200                )
13201            });
13202        })
13203    }
13204
13205    pub fn delete_to_end_of_line(
13206        &mut self,
13207        _: &DeleteToEndOfLine,
13208        window: &mut Window,
13209        cx: &mut Context<Self>,
13210    ) {
13211        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13212        self.transact(window, cx, |this, window, cx| {
13213            this.select_to_end_of_line(
13214                &SelectToEndOfLine {
13215                    stop_at_soft_wraps: false,
13216                },
13217                window,
13218                cx,
13219            );
13220            this.delete(&Delete, window, cx);
13221        });
13222    }
13223
13224    pub fn cut_to_end_of_line(
13225        &mut self,
13226        _: &CutToEndOfLine,
13227        window: &mut Window,
13228        cx: &mut Context<Self>,
13229    ) {
13230        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13231        self.transact(window, cx, |this, window, cx| {
13232            this.select_to_end_of_line(
13233                &SelectToEndOfLine {
13234                    stop_at_soft_wraps: false,
13235                },
13236                window,
13237                cx,
13238            );
13239            this.cut(&Cut, window, cx);
13240        });
13241    }
13242
13243    pub fn move_to_start_of_paragraph(
13244        &mut self,
13245        _: &MoveToStartOfParagraph,
13246        window: &mut Window,
13247        cx: &mut Context<Self>,
13248    ) {
13249        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13250            cx.propagate();
13251            return;
13252        }
13253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13254        self.change_selections(Default::default(), window, cx, |s| {
13255            s.move_with(|map, selection| {
13256                selection.collapse_to(
13257                    movement::start_of_paragraph(map, selection.head(), 1),
13258                    SelectionGoal::None,
13259                )
13260            });
13261        })
13262    }
13263
13264    pub fn move_to_end_of_paragraph(
13265        &mut self,
13266        _: &MoveToEndOfParagraph,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13271            cx.propagate();
13272            return;
13273        }
13274        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13275        self.change_selections(Default::default(), window, cx, |s| {
13276            s.move_with(|map, selection| {
13277                selection.collapse_to(
13278                    movement::end_of_paragraph(map, selection.head(), 1),
13279                    SelectionGoal::None,
13280                )
13281            });
13282        })
13283    }
13284
13285    pub fn select_to_start_of_paragraph(
13286        &mut self,
13287        _: &SelectToStartOfParagraph,
13288        window: &mut Window,
13289        cx: &mut Context<Self>,
13290    ) {
13291        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13292            cx.propagate();
13293            return;
13294        }
13295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13296        self.change_selections(Default::default(), window, cx, |s| {
13297            s.move_heads_with(|map, head, _| {
13298                (
13299                    movement::start_of_paragraph(map, head, 1),
13300                    SelectionGoal::None,
13301                )
13302            });
13303        })
13304    }
13305
13306    pub fn select_to_end_of_paragraph(
13307        &mut self,
13308        _: &SelectToEndOfParagraph,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13313            cx.propagate();
13314            return;
13315        }
13316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13317        self.change_selections(Default::default(), window, cx, |s| {
13318            s.move_heads_with(|map, head, _| {
13319                (
13320                    movement::end_of_paragraph(map, head, 1),
13321                    SelectionGoal::None,
13322                )
13323            });
13324        })
13325    }
13326
13327    pub fn move_to_start_of_excerpt(
13328        &mut self,
13329        _: &MoveToStartOfExcerpt,
13330        window: &mut Window,
13331        cx: &mut Context<Self>,
13332    ) {
13333        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13334            cx.propagate();
13335            return;
13336        }
13337        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13338        self.change_selections(Default::default(), window, cx, |s| {
13339            s.move_with(|map, selection| {
13340                selection.collapse_to(
13341                    movement::start_of_excerpt(
13342                        map,
13343                        selection.head(),
13344                        workspace::searchable::Direction::Prev,
13345                    ),
13346                    SelectionGoal::None,
13347                )
13348            });
13349        })
13350    }
13351
13352    pub fn move_to_start_of_next_excerpt(
13353        &mut self,
13354        _: &MoveToStartOfNextExcerpt,
13355        window: &mut Window,
13356        cx: &mut Context<Self>,
13357    ) {
13358        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13359            cx.propagate();
13360            return;
13361        }
13362
13363        self.change_selections(Default::default(), window, cx, |s| {
13364            s.move_with(|map, selection| {
13365                selection.collapse_to(
13366                    movement::start_of_excerpt(
13367                        map,
13368                        selection.head(),
13369                        workspace::searchable::Direction::Next,
13370                    ),
13371                    SelectionGoal::None,
13372                )
13373            });
13374        })
13375    }
13376
13377    pub fn move_to_end_of_excerpt(
13378        &mut self,
13379        _: &MoveToEndOfExcerpt,
13380        window: &mut Window,
13381        cx: &mut Context<Self>,
13382    ) {
13383        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13384            cx.propagate();
13385            return;
13386        }
13387        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13388        self.change_selections(Default::default(), window, cx, |s| {
13389            s.move_with(|map, selection| {
13390                selection.collapse_to(
13391                    movement::end_of_excerpt(
13392                        map,
13393                        selection.head(),
13394                        workspace::searchable::Direction::Next,
13395                    ),
13396                    SelectionGoal::None,
13397                )
13398            });
13399        })
13400    }
13401
13402    pub fn move_to_end_of_previous_excerpt(
13403        &mut self,
13404        _: &MoveToEndOfPreviousExcerpt,
13405        window: &mut Window,
13406        cx: &mut Context<Self>,
13407    ) {
13408        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13409            cx.propagate();
13410            return;
13411        }
13412        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13413        self.change_selections(Default::default(), window, cx, |s| {
13414            s.move_with(|map, selection| {
13415                selection.collapse_to(
13416                    movement::end_of_excerpt(
13417                        map,
13418                        selection.head(),
13419                        workspace::searchable::Direction::Prev,
13420                    ),
13421                    SelectionGoal::None,
13422                )
13423            });
13424        })
13425    }
13426
13427    pub fn select_to_start_of_excerpt(
13428        &mut self,
13429        _: &SelectToStartOfExcerpt,
13430        window: &mut Window,
13431        cx: &mut Context<Self>,
13432    ) {
13433        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13434            cx.propagate();
13435            return;
13436        }
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13438        self.change_selections(Default::default(), window, cx, |s| {
13439            s.move_heads_with(|map, head, _| {
13440                (
13441                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13442                    SelectionGoal::None,
13443                )
13444            });
13445        })
13446    }
13447
13448    pub fn select_to_start_of_next_excerpt(
13449        &mut self,
13450        _: &SelectToStartOfNextExcerpt,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13455            cx.propagate();
13456            return;
13457        }
13458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13459        self.change_selections(Default::default(), window, cx, |s| {
13460            s.move_heads_with(|map, head, _| {
13461                (
13462                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13463                    SelectionGoal::None,
13464                )
13465            });
13466        })
13467    }
13468
13469    pub fn select_to_end_of_excerpt(
13470        &mut self,
13471        _: &SelectToEndOfExcerpt,
13472        window: &mut Window,
13473        cx: &mut Context<Self>,
13474    ) {
13475        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13476            cx.propagate();
13477            return;
13478        }
13479        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13480        self.change_selections(Default::default(), window, cx, |s| {
13481            s.move_heads_with(|map, head, _| {
13482                (
13483                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13484                    SelectionGoal::None,
13485                )
13486            });
13487        })
13488    }
13489
13490    pub fn select_to_end_of_previous_excerpt(
13491        &mut self,
13492        _: &SelectToEndOfPreviousExcerpt,
13493        window: &mut Window,
13494        cx: &mut Context<Self>,
13495    ) {
13496        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13497            cx.propagate();
13498            return;
13499        }
13500        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13501        self.change_selections(Default::default(), window, cx, |s| {
13502            s.move_heads_with(|map, head, _| {
13503                (
13504                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13505                    SelectionGoal::None,
13506                )
13507            });
13508        })
13509    }
13510
13511    pub fn move_to_beginning(
13512        &mut self,
13513        _: &MoveToBeginning,
13514        window: &mut Window,
13515        cx: &mut Context<Self>,
13516    ) {
13517        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13518            cx.propagate();
13519            return;
13520        }
13521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13522        self.change_selections(Default::default(), window, cx, |s| {
13523            s.select_ranges(vec![0..0]);
13524        });
13525    }
13526
13527    pub fn select_to_beginning(
13528        &mut self,
13529        _: &SelectToBeginning,
13530        window: &mut Window,
13531        cx: &mut Context<Self>,
13532    ) {
13533        let mut selection = self.selections.last::<Point>(cx);
13534        selection.set_head(Point::zero(), SelectionGoal::None);
13535        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13536        self.change_selections(Default::default(), window, cx, |s| {
13537            s.select(vec![selection]);
13538        });
13539    }
13540
13541    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13542        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13543            cx.propagate();
13544            return;
13545        }
13546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13547        let cursor = self.buffer.read(cx).read(cx).len();
13548        self.change_selections(Default::default(), window, cx, |s| {
13549            s.select_ranges(vec![cursor..cursor])
13550        });
13551    }
13552
13553    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13554        self.nav_history = nav_history;
13555    }
13556
13557    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13558        self.nav_history.as_ref()
13559    }
13560
13561    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13562        self.push_to_nav_history(
13563            self.selections.newest_anchor().head(),
13564            None,
13565            false,
13566            true,
13567            cx,
13568        );
13569    }
13570
13571    fn push_to_nav_history(
13572        &mut self,
13573        cursor_anchor: Anchor,
13574        new_position: Option<Point>,
13575        is_deactivate: bool,
13576        always: bool,
13577        cx: &mut Context<Self>,
13578    ) {
13579        if let Some(nav_history) = self.nav_history.as_mut() {
13580            let buffer = self.buffer.read(cx).read(cx);
13581            let cursor_position = cursor_anchor.to_point(&buffer);
13582            let scroll_state = self.scroll_manager.anchor();
13583            let scroll_top_row = scroll_state.top_row(&buffer);
13584            drop(buffer);
13585
13586            if let Some(new_position) = new_position {
13587                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13588                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13589                    return;
13590                }
13591            }
13592
13593            nav_history.push(
13594                Some(NavigationData {
13595                    cursor_anchor,
13596                    cursor_position,
13597                    scroll_anchor: scroll_state,
13598                    scroll_top_row,
13599                }),
13600                cx,
13601            );
13602            cx.emit(EditorEvent::PushedToNavHistory {
13603                anchor: cursor_anchor,
13604                is_deactivate,
13605            })
13606        }
13607    }
13608
13609    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        let buffer = self.buffer.read(cx).snapshot(cx);
13612        let mut selection = self.selections.first::<usize>(cx);
13613        selection.set_head(buffer.len(), SelectionGoal::None);
13614        self.change_selections(Default::default(), window, cx, |s| {
13615            s.select(vec![selection]);
13616        });
13617    }
13618
13619    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13621        let end = self.buffer.read(cx).read(cx).len();
13622        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13623            s.select_ranges(vec![0..end]);
13624        });
13625    }
13626
13627    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13628        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13629        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13630        let mut selections = self.selections.all::<Point>(cx);
13631        let max_point = display_map.buffer_snapshot.max_point();
13632        for selection in &mut selections {
13633            let rows = selection.spanned_rows(true, &display_map);
13634            selection.start = Point::new(rows.start.0, 0);
13635            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13636            selection.reversed = false;
13637        }
13638        self.change_selections(Default::default(), window, cx, |s| {
13639            s.select(selections);
13640        });
13641    }
13642
13643    pub fn split_selection_into_lines(
13644        &mut self,
13645        action: &SplitSelectionIntoLines,
13646        window: &mut Window,
13647        cx: &mut Context<Self>,
13648    ) {
13649        let selections = self
13650            .selections
13651            .all::<Point>(cx)
13652            .into_iter()
13653            .map(|selection| selection.start..selection.end)
13654            .collect::<Vec<_>>();
13655        self.unfold_ranges(&selections, true, true, cx);
13656
13657        let mut new_selection_ranges = Vec::new();
13658        {
13659            let buffer = self.buffer.read(cx).read(cx);
13660            for selection in selections {
13661                for row in selection.start.row..selection.end.row {
13662                    let line_start = Point::new(row, 0);
13663                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13664
13665                    if action.keep_selections {
13666                        // Keep the selection range for each line
13667                        let selection_start = if row == selection.start.row {
13668                            selection.start
13669                        } else {
13670                            line_start
13671                        };
13672                        new_selection_ranges.push(selection_start..line_end);
13673                    } else {
13674                        // Collapse to cursor at end of line
13675                        new_selection_ranges.push(line_end..line_end);
13676                    }
13677                }
13678
13679                let is_multiline_selection = selection.start.row != selection.end.row;
13680                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13681                // so this action feels more ergonomic when paired with other selection operations
13682                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13683                if !should_skip_last {
13684                    if action.keep_selections {
13685                        if is_multiline_selection {
13686                            let line_start = Point::new(selection.end.row, 0);
13687                            new_selection_ranges.push(line_start..selection.end);
13688                        } else {
13689                            new_selection_ranges.push(selection.start..selection.end);
13690                        }
13691                    } else {
13692                        new_selection_ranges.push(selection.end..selection.end);
13693                    }
13694                }
13695            }
13696        }
13697        self.change_selections(Default::default(), window, cx, |s| {
13698            s.select_ranges(new_selection_ranges);
13699        });
13700    }
13701
13702    pub fn add_selection_above(
13703        &mut self,
13704        _: &AddSelectionAbove,
13705        window: &mut Window,
13706        cx: &mut Context<Self>,
13707    ) {
13708        self.add_selection(true, window, cx);
13709    }
13710
13711    pub fn add_selection_below(
13712        &mut self,
13713        _: &AddSelectionBelow,
13714        window: &mut Window,
13715        cx: &mut Context<Self>,
13716    ) {
13717        self.add_selection(false, window, cx);
13718    }
13719
13720    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13722
13723        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13724        let all_selections = self.selections.all::<Point>(cx);
13725        let text_layout_details = self.text_layout_details(window);
13726
13727        let (mut columnar_selections, new_selections_to_columnarize) = {
13728            if let Some(state) = self.add_selections_state.as_ref() {
13729                let columnar_selection_ids: HashSet<_> = state
13730                    .groups
13731                    .iter()
13732                    .flat_map(|group| group.stack.iter())
13733                    .copied()
13734                    .collect();
13735
13736                all_selections
13737                    .into_iter()
13738                    .partition(|s| columnar_selection_ids.contains(&s.id))
13739            } else {
13740                (Vec::new(), all_selections)
13741            }
13742        };
13743
13744        let mut state = self
13745            .add_selections_state
13746            .take()
13747            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13748
13749        for selection in new_selections_to_columnarize {
13750            let range = selection.display_range(&display_map).sorted();
13751            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13752            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13753            let positions = start_x.min(end_x)..start_x.max(end_x);
13754            let mut stack = Vec::new();
13755            for row in range.start.row().0..=range.end.row().0 {
13756                if let Some(selection) = self.selections.build_columnar_selection(
13757                    &display_map,
13758                    DisplayRow(row),
13759                    &positions,
13760                    selection.reversed,
13761                    &text_layout_details,
13762                ) {
13763                    stack.push(selection.id);
13764                    columnar_selections.push(selection);
13765                }
13766            }
13767            if !stack.is_empty() {
13768                if above {
13769                    stack.reverse();
13770                }
13771                state.groups.push(AddSelectionsGroup { above, stack });
13772            }
13773        }
13774
13775        let mut final_selections = Vec::new();
13776        let end_row = if above {
13777            DisplayRow(0)
13778        } else {
13779            display_map.max_point().row()
13780        };
13781
13782        let mut last_added_item_per_group = HashMap::default();
13783        for group in state.groups.iter_mut() {
13784            if let Some(last_id) = group.stack.last() {
13785                last_added_item_per_group.insert(*last_id, group);
13786            }
13787        }
13788
13789        for selection in columnar_selections {
13790            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13791                if above == group.above {
13792                    let range = selection.display_range(&display_map).sorted();
13793                    debug_assert_eq!(range.start.row(), range.end.row());
13794                    let mut row = range.start.row();
13795                    let positions =
13796                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13797                            px(start)..px(end)
13798                        } else {
13799                            let start_x =
13800                                display_map.x_for_display_point(range.start, &text_layout_details);
13801                            let end_x =
13802                                display_map.x_for_display_point(range.end, &text_layout_details);
13803                            start_x.min(end_x)..start_x.max(end_x)
13804                        };
13805
13806                    let mut maybe_new_selection = None;
13807                    while row != end_row {
13808                        if above {
13809                            row.0 -= 1;
13810                        } else {
13811                            row.0 += 1;
13812                        }
13813                        if let Some(new_selection) = self.selections.build_columnar_selection(
13814                            &display_map,
13815                            row,
13816                            &positions,
13817                            selection.reversed,
13818                            &text_layout_details,
13819                        ) {
13820                            maybe_new_selection = Some(new_selection);
13821                            break;
13822                        }
13823                    }
13824
13825                    if let Some(new_selection) = maybe_new_selection {
13826                        group.stack.push(new_selection.id);
13827                        if above {
13828                            final_selections.push(new_selection);
13829                            final_selections.push(selection);
13830                        } else {
13831                            final_selections.push(selection);
13832                            final_selections.push(new_selection);
13833                        }
13834                    } else {
13835                        final_selections.push(selection);
13836                    }
13837                } else {
13838                    group.stack.pop();
13839                }
13840            } else {
13841                final_selections.push(selection);
13842            }
13843        }
13844
13845        self.change_selections(Default::default(), window, cx, |s| {
13846            s.select(final_selections);
13847        });
13848
13849        let final_selection_ids: HashSet<_> = self
13850            .selections
13851            .all::<Point>(cx)
13852            .iter()
13853            .map(|s| s.id)
13854            .collect();
13855        state.groups.retain_mut(|group| {
13856            // selections might get merged above so we remove invalid items from stacks
13857            group.stack.retain(|id| final_selection_ids.contains(id));
13858
13859            // single selection in stack can be treated as initial state
13860            group.stack.len() > 1
13861        });
13862
13863        if !state.groups.is_empty() {
13864            self.add_selections_state = Some(state);
13865        }
13866    }
13867
13868    fn select_match_ranges(
13869        &mut self,
13870        range: Range<usize>,
13871        reversed: bool,
13872        replace_newest: bool,
13873        auto_scroll: Option<Autoscroll>,
13874        window: &mut Window,
13875        cx: &mut Context<Editor>,
13876    ) {
13877        self.unfold_ranges(
13878            std::slice::from_ref(&range),
13879            false,
13880            auto_scroll.is_some(),
13881            cx,
13882        );
13883        let effects = if let Some(scroll) = auto_scroll {
13884            SelectionEffects::scroll(scroll)
13885        } else {
13886            SelectionEffects::no_scroll()
13887        };
13888        self.change_selections(effects, window, cx, |s| {
13889            if replace_newest {
13890                s.delete(s.newest_anchor().id);
13891            }
13892            if reversed {
13893                s.insert_range(range.end..range.start);
13894            } else {
13895                s.insert_range(range);
13896            }
13897        });
13898    }
13899
13900    pub fn select_next_match_internal(
13901        &mut self,
13902        display_map: &DisplaySnapshot,
13903        replace_newest: bool,
13904        autoscroll: Option<Autoscroll>,
13905        window: &mut Window,
13906        cx: &mut Context<Self>,
13907    ) -> Result<()> {
13908        let buffer = &display_map.buffer_snapshot;
13909        let mut selections = self.selections.all::<usize>(cx);
13910        if let Some(mut select_next_state) = self.select_next_state.take() {
13911            let query = &select_next_state.query;
13912            if !select_next_state.done {
13913                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13914                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13915                let mut next_selected_range = None;
13916
13917                let bytes_after_last_selection =
13918                    buffer.bytes_in_range(last_selection.end..buffer.len());
13919                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13920                let query_matches = query
13921                    .stream_find_iter(bytes_after_last_selection)
13922                    .map(|result| (last_selection.end, result))
13923                    .chain(
13924                        query
13925                            .stream_find_iter(bytes_before_first_selection)
13926                            .map(|result| (0, result)),
13927                    );
13928
13929                for (start_offset, query_match) in query_matches {
13930                    let query_match = query_match.unwrap(); // can only fail due to I/O
13931                    let offset_range =
13932                        start_offset + query_match.start()..start_offset + query_match.end();
13933
13934                    if !select_next_state.wordwise
13935                        || (!buffer.is_inside_word(offset_range.start, false)
13936                            && !buffer.is_inside_word(offset_range.end, false))
13937                    {
13938                        // TODO: This is n^2, because we might check all the selections
13939                        if !selections
13940                            .iter()
13941                            .any(|selection| selection.range().overlaps(&offset_range))
13942                        {
13943                            next_selected_range = Some(offset_range);
13944                            break;
13945                        }
13946                    }
13947                }
13948
13949                if let Some(next_selected_range) = next_selected_range {
13950                    self.select_match_ranges(
13951                        next_selected_range,
13952                        last_selection.reversed,
13953                        replace_newest,
13954                        autoscroll,
13955                        window,
13956                        cx,
13957                    );
13958                } else {
13959                    select_next_state.done = true;
13960                }
13961            }
13962
13963            self.select_next_state = Some(select_next_state);
13964        } else {
13965            let mut only_carets = true;
13966            let mut same_text_selected = true;
13967            let mut selected_text = None;
13968
13969            let mut selections_iter = selections.iter().peekable();
13970            while let Some(selection) = selections_iter.next() {
13971                if selection.start != selection.end {
13972                    only_carets = false;
13973                }
13974
13975                if same_text_selected {
13976                    if selected_text.is_none() {
13977                        selected_text =
13978                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13979                    }
13980
13981                    if let Some(next_selection) = selections_iter.peek() {
13982                        if next_selection.range().len() == selection.range().len() {
13983                            let next_selected_text = buffer
13984                                .text_for_range(next_selection.range())
13985                                .collect::<String>();
13986                            if Some(next_selected_text) != selected_text {
13987                                same_text_selected = false;
13988                                selected_text = None;
13989                            }
13990                        } else {
13991                            same_text_selected = false;
13992                            selected_text = None;
13993                        }
13994                    }
13995                }
13996            }
13997
13998            if only_carets {
13999                for selection in &mut selections {
14000                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14001                    selection.start = word_range.start;
14002                    selection.end = word_range.end;
14003                    selection.goal = SelectionGoal::None;
14004                    selection.reversed = false;
14005                    self.select_match_ranges(
14006                        selection.start..selection.end,
14007                        selection.reversed,
14008                        replace_newest,
14009                        autoscroll,
14010                        window,
14011                        cx,
14012                    );
14013                }
14014
14015                if selections.len() == 1 {
14016                    let selection = selections
14017                        .last()
14018                        .expect("ensured that there's only one selection");
14019                    let query = buffer
14020                        .text_for_range(selection.start..selection.end)
14021                        .collect::<String>();
14022                    let is_empty = query.is_empty();
14023                    let select_state = SelectNextState {
14024                        query: AhoCorasick::new(&[query])?,
14025                        wordwise: true,
14026                        done: is_empty,
14027                    };
14028                    self.select_next_state = Some(select_state);
14029                } else {
14030                    self.select_next_state = None;
14031                }
14032            } else if let Some(selected_text) = selected_text {
14033                self.select_next_state = Some(SelectNextState {
14034                    query: AhoCorasick::new(&[selected_text])?,
14035                    wordwise: false,
14036                    done: false,
14037                });
14038                self.select_next_match_internal(
14039                    display_map,
14040                    replace_newest,
14041                    autoscroll,
14042                    window,
14043                    cx,
14044                )?;
14045            }
14046        }
14047        Ok(())
14048    }
14049
14050    pub fn select_all_matches(
14051        &mut self,
14052        _action: &SelectAllMatches,
14053        window: &mut Window,
14054        cx: &mut Context<Self>,
14055    ) -> Result<()> {
14056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14057
14058        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14059
14060        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14061        let Some(select_next_state) = self.select_next_state.as_mut() else {
14062            return Ok(());
14063        };
14064        if select_next_state.done {
14065            return Ok(());
14066        }
14067
14068        let mut new_selections = Vec::new();
14069
14070        let reversed = self.selections.oldest::<usize>(cx).reversed;
14071        let buffer = &display_map.buffer_snapshot;
14072        let query_matches = select_next_state
14073            .query
14074            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14075
14076        for query_match in query_matches.into_iter() {
14077            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14078            let offset_range = if reversed {
14079                query_match.end()..query_match.start()
14080            } else {
14081                query_match.start()..query_match.end()
14082            };
14083
14084            if !select_next_state.wordwise
14085                || (!buffer.is_inside_word(offset_range.start, false)
14086                    && !buffer.is_inside_word(offset_range.end, false))
14087            {
14088                new_selections.push(offset_range.start..offset_range.end);
14089            }
14090        }
14091
14092        select_next_state.done = true;
14093
14094        if new_selections.is_empty() {
14095            log::error!("bug: new_selections is empty in select_all_matches");
14096            return Ok(());
14097        }
14098
14099        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14100        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14101            selections.select_ranges(new_selections)
14102        });
14103
14104        Ok(())
14105    }
14106
14107    pub fn select_next(
14108        &mut self,
14109        action: &SelectNext,
14110        window: &mut Window,
14111        cx: &mut Context<Self>,
14112    ) -> Result<()> {
14113        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14114        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14115        self.select_next_match_internal(
14116            &display_map,
14117            action.replace_newest,
14118            Some(Autoscroll::newest()),
14119            window,
14120            cx,
14121        )?;
14122        Ok(())
14123    }
14124
14125    pub fn select_previous(
14126        &mut self,
14127        action: &SelectPrevious,
14128        window: &mut Window,
14129        cx: &mut Context<Self>,
14130    ) -> Result<()> {
14131        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14132        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14133        let buffer = &display_map.buffer_snapshot;
14134        let mut selections = self.selections.all::<usize>(cx);
14135        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14136            let query = &select_prev_state.query;
14137            if !select_prev_state.done {
14138                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14139                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14140                let mut next_selected_range = None;
14141                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14142                let bytes_before_last_selection =
14143                    buffer.reversed_bytes_in_range(0..last_selection.start);
14144                let bytes_after_first_selection =
14145                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14146                let query_matches = query
14147                    .stream_find_iter(bytes_before_last_selection)
14148                    .map(|result| (last_selection.start, result))
14149                    .chain(
14150                        query
14151                            .stream_find_iter(bytes_after_first_selection)
14152                            .map(|result| (buffer.len(), result)),
14153                    );
14154                for (end_offset, query_match) in query_matches {
14155                    let query_match = query_match.unwrap(); // can only fail due to I/O
14156                    let offset_range =
14157                        end_offset - query_match.end()..end_offset - query_match.start();
14158
14159                    if !select_prev_state.wordwise
14160                        || (!buffer.is_inside_word(offset_range.start, false)
14161                            && !buffer.is_inside_word(offset_range.end, false))
14162                    {
14163                        next_selected_range = Some(offset_range);
14164                        break;
14165                    }
14166                }
14167
14168                if let Some(next_selected_range) = next_selected_range {
14169                    self.select_match_ranges(
14170                        next_selected_range,
14171                        last_selection.reversed,
14172                        action.replace_newest,
14173                        Some(Autoscroll::newest()),
14174                        window,
14175                        cx,
14176                    );
14177                } else {
14178                    select_prev_state.done = true;
14179                }
14180            }
14181
14182            self.select_prev_state = Some(select_prev_state);
14183        } else {
14184            let mut only_carets = true;
14185            let mut same_text_selected = true;
14186            let mut selected_text = None;
14187
14188            let mut selections_iter = selections.iter().peekable();
14189            while let Some(selection) = selections_iter.next() {
14190                if selection.start != selection.end {
14191                    only_carets = false;
14192                }
14193
14194                if same_text_selected {
14195                    if selected_text.is_none() {
14196                        selected_text =
14197                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14198                    }
14199
14200                    if let Some(next_selection) = selections_iter.peek() {
14201                        if next_selection.range().len() == selection.range().len() {
14202                            let next_selected_text = buffer
14203                                .text_for_range(next_selection.range())
14204                                .collect::<String>();
14205                            if Some(next_selected_text) != selected_text {
14206                                same_text_selected = false;
14207                                selected_text = None;
14208                            }
14209                        } else {
14210                            same_text_selected = false;
14211                            selected_text = None;
14212                        }
14213                    }
14214                }
14215            }
14216
14217            if only_carets {
14218                for selection in &mut selections {
14219                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14220                    selection.start = word_range.start;
14221                    selection.end = word_range.end;
14222                    selection.goal = SelectionGoal::None;
14223                    selection.reversed = false;
14224                    self.select_match_ranges(
14225                        selection.start..selection.end,
14226                        selection.reversed,
14227                        action.replace_newest,
14228                        Some(Autoscroll::newest()),
14229                        window,
14230                        cx,
14231                    );
14232                }
14233                if selections.len() == 1 {
14234                    let selection = selections
14235                        .last()
14236                        .expect("ensured that there's only one selection");
14237                    let query = buffer
14238                        .text_for_range(selection.start..selection.end)
14239                        .collect::<String>();
14240                    let is_empty = query.is_empty();
14241                    let select_state = SelectNextState {
14242                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14243                        wordwise: true,
14244                        done: is_empty,
14245                    };
14246                    self.select_prev_state = Some(select_state);
14247                } else {
14248                    self.select_prev_state = None;
14249                }
14250            } else if let Some(selected_text) = selected_text {
14251                self.select_prev_state = Some(SelectNextState {
14252                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14253                    wordwise: false,
14254                    done: false,
14255                });
14256                self.select_previous(action, window, cx)?;
14257            }
14258        }
14259        Ok(())
14260    }
14261
14262    pub fn find_next_match(
14263        &mut self,
14264        _: &FindNextMatch,
14265        window: &mut Window,
14266        cx: &mut Context<Self>,
14267    ) -> Result<()> {
14268        let selections = self.selections.disjoint_anchors();
14269        match selections.first() {
14270            Some(first) if selections.len() >= 2 => {
14271                self.change_selections(Default::default(), window, cx, |s| {
14272                    s.select_ranges([first.range()]);
14273                });
14274            }
14275            _ => self.select_next(
14276                &SelectNext {
14277                    replace_newest: true,
14278                },
14279                window,
14280                cx,
14281            )?,
14282        }
14283        Ok(())
14284    }
14285
14286    pub fn find_previous_match(
14287        &mut self,
14288        _: &FindPreviousMatch,
14289        window: &mut Window,
14290        cx: &mut Context<Self>,
14291    ) -> Result<()> {
14292        let selections = self.selections.disjoint_anchors();
14293        match selections.last() {
14294            Some(last) if selections.len() >= 2 => {
14295                self.change_selections(Default::default(), window, cx, |s| {
14296                    s.select_ranges([last.range()]);
14297                });
14298            }
14299            _ => self.select_previous(
14300                &SelectPrevious {
14301                    replace_newest: true,
14302                },
14303                window,
14304                cx,
14305            )?,
14306        }
14307        Ok(())
14308    }
14309
14310    pub fn toggle_comments(
14311        &mut self,
14312        action: &ToggleComments,
14313        window: &mut Window,
14314        cx: &mut Context<Self>,
14315    ) {
14316        if self.read_only(cx) {
14317            return;
14318        }
14319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14320        let text_layout_details = &self.text_layout_details(window);
14321        self.transact(window, cx, |this, window, cx| {
14322            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14323            let mut edits = Vec::new();
14324            let mut selection_edit_ranges = Vec::new();
14325            let mut last_toggled_row = None;
14326            let snapshot = this.buffer.read(cx).read(cx);
14327            let empty_str: Arc<str> = Arc::default();
14328            let mut suffixes_inserted = Vec::new();
14329            let ignore_indent = action.ignore_indent;
14330
14331            fn comment_prefix_range(
14332                snapshot: &MultiBufferSnapshot,
14333                row: MultiBufferRow,
14334                comment_prefix: &str,
14335                comment_prefix_whitespace: &str,
14336                ignore_indent: bool,
14337            ) -> Range<Point> {
14338                let indent_size = if ignore_indent {
14339                    0
14340                } else {
14341                    snapshot.indent_size_for_line(row).len
14342                };
14343
14344                let start = Point::new(row.0, indent_size);
14345
14346                let mut line_bytes = snapshot
14347                    .bytes_in_range(start..snapshot.max_point())
14348                    .flatten()
14349                    .copied();
14350
14351                // If this line currently begins with the line comment prefix, then record
14352                // the range containing the prefix.
14353                if line_bytes
14354                    .by_ref()
14355                    .take(comment_prefix.len())
14356                    .eq(comment_prefix.bytes())
14357                {
14358                    // Include any whitespace that matches the comment prefix.
14359                    let matching_whitespace_len = line_bytes
14360                        .zip(comment_prefix_whitespace.bytes())
14361                        .take_while(|(a, b)| a == b)
14362                        .count() as u32;
14363                    let end = Point::new(
14364                        start.row,
14365                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14366                    );
14367                    start..end
14368                } else {
14369                    start..start
14370                }
14371            }
14372
14373            fn comment_suffix_range(
14374                snapshot: &MultiBufferSnapshot,
14375                row: MultiBufferRow,
14376                comment_suffix: &str,
14377                comment_suffix_has_leading_space: bool,
14378            ) -> Range<Point> {
14379                let end = Point::new(row.0, snapshot.line_len(row));
14380                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14381
14382                let mut line_end_bytes = snapshot
14383                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14384                    .flatten()
14385                    .copied();
14386
14387                let leading_space_len = if suffix_start_column > 0
14388                    && line_end_bytes.next() == Some(b' ')
14389                    && comment_suffix_has_leading_space
14390                {
14391                    1
14392                } else {
14393                    0
14394                };
14395
14396                // If this line currently begins with the line comment prefix, then record
14397                // the range containing the prefix.
14398                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14399                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14400                    start..end
14401                } else {
14402                    end..end
14403                }
14404            }
14405
14406            // TODO: Handle selections that cross excerpts
14407            for selection in &mut selections {
14408                let start_column = snapshot
14409                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14410                    .len;
14411                let language = if let Some(language) =
14412                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14413                {
14414                    language
14415                } else {
14416                    continue;
14417                };
14418
14419                selection_edit_ranges.clear();
14420
14421                // If multiple selections contain a given row, avoid processing that
14422                // row more than once.
14423                let mut start_row = MultiBufferRow(selection.start.row);
14424                if last_toggled_row == Some(start_row) {
14425                    start_row = start_row.next_row();
14426                }
14427                let end_row =
14428                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14429                        MultiBufferRow(selection.end.row - 1)
14430                    } else {
14431                        MultiBufferRow(selection.end.row)
14432                    };
14433                last_toggled_row = Some(end_row);
14434
14435                if start_row > end_row {
14436                    continue;
14437                }
14438
14439                // If the language has line comments, toggle those.
14440                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14441
14442                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14443                if ignore_indent {
14444                    full_comment_prefixes = full_comment_prefixes
14445                        .into_iter()
14446                        .map(|s| Arc::from(s.trim_end()))
14447                        .collect();
14448                }
14449
14450                if !full_comment_prefixes.is_empty() {
14451                    let first_prefix = full_comment_prefixes
14452                        .first()
14453                        .expect("prefixes is non-empty");
14454                    let prefix_trimmed_lengths = full_comment_prefixes
14455                        .iter()
14456                        .map(|p| p.trim_end_matches(' ').len())
14457                        .collect::<SmallVec<[usize; 4]>>();
14458
14459                    let mut all_selection_lines_are_comments = true;
14460
14461                    for row in start_row.0..=end_row.0 {
14462                        let row = MultiBufferRow(row);
14463                        if start_row < end_row && snapshot.is_line_blank(row) {
14464                            continue;
14465                        }
14466
14467                        let prefix_range = full_comment_prefixes
14468                            .iter()
14469                            .zip(prefix_trimmed_lengths.iter().copied())
14470                            .map(|(prefix, trimmed_prefix_len)| {
14471                                comment_prefix_range(
14472                                    snapshot.deref(),
14473                                    row,
14474                                    &prefix[..trimmed_prefix_len],
14475                                    &prefix[trimmed_prefix_len..],
14476                                    ignore_indent,
14477                                )
14478                            })
14479                            .max_by_key(|range| range.end.column - range.start.column)
14480                            .expect("prefixes is non-empty");
14481
14482                        if prefix_range.is_empty() {
14483                            all_selection_lines_are_comments = false;
14484                        }
14485
14486                        selection_edit_ranges.push(prefix_range);
14487                    }
14488
14489                    if all_selection_lines_are_comments {
14490                        edits.extend(
14491                            selection_edit_ranges
14492                                .iter()
14493                                .cloned()
14494                                .map(|range| (range, empty_str.clone())),
14495                        );
14496                    } else {
14497                        let min_column = selection_edit_ranges
14498                            .iter()
14499                            .map(|range| range.start.column)
14500                            .min()
14501                            .unwrap_or(0);
14502                        edits.extend(selection_edit_ranges.iter().map(|range| {
14503                            let position = Point::new(range.start.row, min_column);
14504                            (position..position, first_prefix.clone())
14505                        }));
14506                    }
14507                } else if let Some(BlockCommentConfig {
14508                    start: full_comment_prefix,
14509                    end: comment_suffix,
14510                    ..
14511                }) = language.block_comment()
14512                {
14513                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14514                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14515                    let prefix_range = comment_prefix_range(
14516                        snapshot.deref(),
14517                        start_row,
14518                        comment_prefix,
14519                        comment_prefix_whitespace,
14520                        ignore_indent,
14521                    );
14522                    let suffix_range = comment_suffix_range(
14523                        snapshot.deref(),
14524                        end_row,
14525                        comment_suffix.trim_start_matches(' '),
14526                        comment_suffix.starts_with(' '),
14527                    );
14528
14529                    if prefix_range.is_empty() || suffix_range.is_empty() {
14530                        edits.push((
14531                            prefix_range.start..prefix_range.start,
14532                            full_comment_prefix.clone(),
14533                        ));
14534                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14535                        suffixes_inserted.push((end_row, comment_suffix.len()));
14536                    } else {
14537                        edits.push((prefix_range, empty_str.clone()));
14538                        edits.push((suffix_range, empty_str.clone()));
14539                    }
14540                } else {
14541                    continue;
14542                }
14543            }
14544
14545            drop(snapshot);
14546            this.buffer.update(cx, |buffer, cx| {
14547                buffer.edit(edits, None, cx);
14548            });
14549
14550            // Adjust selections so that they end before any comment suffixes that
14551            // were inserted.
14552            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14553            let mut selections = this.selections.all::<Point>(cx);
14554            let snapshot = this.buffer.read(cx).read(cx);
14555            for selection in &mut selections {
14556                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14557                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14558                        Ordering::Less => {
14559                            suffixes_inserted.next();
14560                            continue;
14561                        }
14562                        Ordering::Greater => break,
14563                        Ordering::Equal => {
14564                            if selection.end.column == snapshot.line_len(row) {
14565                                if selection.is_empty() {
14566                                    selection.start.column -= suffix_len as u32;
14567                                }
14568                                selection.end.column -= suffix_len as u32;
14569                            }
14570                            break;
14571                        }
14572                    }
14573                }
14574            }
14575
14576            drop(snapshot);
14577            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14578
14579            let selections = this.selections.all::<Point>(cx);
14580            let selections_on_single_row = selections.windows(2).all(|selections| {
14581                selections[0].start.row == selections[1].start.row
14582                    && selections[0].end.row == selections[1].end.row
14583                    && selections[0].start.row == selections[0].end.row
14584            });
14585            let selections_selecting = selections
14586                .iter()
14587                .any(|selection| selection.start != selection.end);
14588            let advance_downwards = action.advance_downwards
14589                && selections_on_single_row
14590                && !selections_selecting
14591                && !matches!(this.mode, EditorMode::SingleLine { .. });
14592
14593            if advance_downwards {
14594                let snapshot = this.buffer.read(cx).snapshot(cx);
14595
14596                this.change_selections(Default::default(), window, cx, |s| {
14597                    s.move_cursors_with(|display_snapshot, display_point, _| {
14598                        let mut point = display_point.to_point(display_snapshot);
14599                        point.row += 1;
14600                        point = snapshot.clip_point(point, Bias::Left);
14601                        let display_point = point.to_display_point(display_snapshot);
14602                        let goal = SelectionGoal::HorizontalPosition(
14603                            display_snapshot
14604                                .x_for_display_point(display_point, text_layout_details)
14605                                .into(),
14606                        );
14607                        (display_point, goal)
14608                    })
14609                });
14610            }
14611        });
14612    }
14613
14614    pub fn select_enclosing_symbol(
14615        &mut self,
14616        _: &SelectEnclosingSymbol,
14617        window: &mut Window,
14618        cx: &mut Context<Self>,
14619    ) {
14620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14621
14622        let buffer = self.buffer.read(cx).snapshot(cx);
14623        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14624
14625        fn update_selection(
14626            selection: &Selection<usize>,
14627            buffer_snap: &MultiBufferSnapshot,
14628        ) -> Option<Selection<usize>> {
14629            let cursor = selection.head();
14630            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14631            for symbol in symbols.iter().rev() {
14632                let start = symbol.range.start.to_offset(buffer_snap);
14633                let end = symbol.range.end.to_offset(buffer_snap);
14634                let new_range = start..end;
14635                if start < selection.start || end > selection.end {
14636                    return Some(Selection {
14637                        id: selection.id,
14638                        start: new_range.start,
14639                        end: new_range.end,
14640                        goal: SelectionGoal::None,
14641                        reversed: selection.reversed,
14642                    });
14643                }
14644            }
14645            None
14646        }
14647
14648        let mut selected_larger_symbol = false;
14649        let new_selections = old_selections
14650            .iter()
14651            .map(|selection| match update_selection(selection, &buffer) {
14652                Some(new_selection) => {
14653                    if new_selection.range() != selection.range() {
14654                        selected_larger_symbol = true;
14655                    }
14656                    new_selection
14657                }
14658                None => selection.clone(),
14659            })
14660            .collect::<Vec<_>>();
14661
14662        if selected_larger_symbol {
14663            self.change_selections(Default::default(), window, cx, |s| {
14664                s.select(new_selections);
14665            });
14666        }
14667    }
14668
14669    pub fn select_larger_syntax_node(
14670        &mut self,
14671        _: &SelectLargerSyntaxNode,
14672        window: &mut Window,
14673        cx: &mut Context<Self>,
14674    ) {
14675        let Some(visible_row_count) = self.visible_row_count() else {
14676            return;
14677        };
14678        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14679        if old_selections.is_empty() {
14680            return;
14681        }
14682
14683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14684
14685        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14686        let buffer = self.buffer.read(cx).snapshot(cx);
14687
14688        let mut selected_larger_node = false;
14689        let mut new_selections = old_selections
14690            .iter()
14691            .map(|selection| {
14692                let old_range = selection.start..selection.end;
14693
14694                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14695                    // manually select word at selection
14696                    if ["string_content", "inline"].contains(&node.kind()) {
14697                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14698                        // ignore if word is already selected
14699                        if !word_range.is_empty() && old_range != word_range {
14700                            let (last_word_range, _) =
14701                                buffer.surrounding_word(old_range.end, false);
14702                            // only select word if start and end point belongs to same word
14703                            if word_range == last_word_range {
14704                                selected_larger_node = true;
14705                                return Selection {
14706                                    id: selection.id,
14707                                    start: word_range.start,
14708                                    end: word_range.end,
14709                                    goal: SelectionGoal::None,
14710                                    reversed: selection.reversed,
14711                                };
14712                            }
14713                        }
14714                    }
14715                }
14716
14717                let mut new_range = old_range.clone();
14718                while let Some((_node, containing_range)) =
14719                    buffer.syntax_ancestor(new_range.clone())
14720                {
14721                    new_range = match containing_range {
14722                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14723                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14724                    };
14725                    if !display_map.intersects_fold(new_range.start)
14726                        && !display_map.intersects_fold(new_range.end)
14727                    {
14728                        break;
14729                    }
14730                }
14731
14732                selected_larger_node |= new_range != old_range;
14733                Selection {
14734                    id: selection.id,
14735                    start: new_range.start,
14736                    end: new_range.end,
14737                    goal: SelectionGoal::None,
14738                    reversed: selection.reversed,
14739                }
14740            })
14741            .collect::<Vec<_>>();
14742
14743        if !selected_larger_node {
14744            return; // don't put this call in the history
14745        }
14746
14747        // scroll based on transformation done to the last selection created by the user
14748        let (last_old, last_new) = old_selections
14749            .last()
14750            .zip(new_selections.last().cloned())
14751            .expect("old_selections isn't empty");
14752
14753        // revert selection
14754        let is_selection_reversed = {
14755            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14756            new_selections.last_mut().expect("checked above").reversed =
14757                should_newest_selection_be_reversed;
14758            should_newest_selection_be_reversed
14759        };
14760
14761        if selected_larger_node {
14762            self.select_syntax_node_history.disable_clearing = true;
14763            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14764                s.select(new_selections.clone());
14765            });
14766            self.select_syntax_node_history.disable_clearing = false;
14767        }
14768
14769        let start_row = last_new.start.to_display_point(&display_map).row().0;
14770        let end_row = last_new.end.to_display_point(&display_map).row().0;
14771        let selection_height = end_row - start_row + 1;
14772        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14773
14774        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14775        let scroll_behavior = if fits_on_the_screen {
14776            self.request_autoscroll(Autoscroll::fit(), cx);
14777            SelectSyntaxNodeScrollBehavior::FitSelection
14778        } else if is_selection_reversed {
14779            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14780            SelectSyntaxNodeScrollBehavior::CursorTop
14781        } else {
14782            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14783            SelectSyntaxNodeScrollBehavior::CursorBottom
14784        };
14785
14786        self.select_syntax_node_history.push((
14787            old_selections,
14788            scroll_behavior,
14789            is_selection_reversed,
14790        ));
14791    }
14792
14793    pub fn select_smaller_syntax_node(
14794        &mut self,
14795        _: &SelectSmallerSyntaxNode,
14796        window: &mut Window,
14797        cx: &mut Context<Self>,
14798    ) {
14799        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14800
14801        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14802            self.select_syntax_node_history.pop()
14803        {
14804            if let Some(selection) = selections.last_mut() {
14805                selection.reversed = is_selection_reversed;
14806            }
14807
14808            self.select_syntax_node_history.disable_clearing = true;
14809            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14810                s.select(selections.to_vec());
14811            });
14812            self.select_syntax_node_history.disable_clearing = false;
14813
14814            match scroll_behavior {
14815                SelectSyntaxNodeScrollBehavior::CursorTop => {
14816                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14817                }
14818                SelectSyntaxNodeScrollBehavior::FitSelection => {
14819                    self.request_autoscroll(Autoscroll::fit(), cx);
14820                }
14821                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14822                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14823                }
14824            }
14825        }
14826    }
14827
14828    pub fn unwrap_syntax_node(
14829        &mut self,
14830        _: &UnwrapSyntaxNode,
14831        window: &mut Window,
14832        cx: &mut Context<Self>,
14833    ) {
14834        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14835
14836        let buffer = self.buffer.read(cx).snapshot(cx);
14837        let selections = self
14838            .selections
14839            .all::<usize>(cx)
14840            .into_iter()
14841            // subtracting the offset requires sorting
14842            .sorted_by_key(|i| i.start);
14843
14844        let full_edits = selections
14845            .into_iter()
14846            .filter_map(|selection| {
14847                // Only requires two branches once if-let-chains stabilize (#53667)
14848                let child = if !selection.is_empty() {
14849                    selection.range()
14850                } else if let Some((_, ancestor_range)) =
14851                    buffer.syntax_ancestor(selection.start..selection.end)
14852                {
14853                    match ancestor_range {
14854                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14855                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14856                    }
14857                } else {
14858                    selection.range()
14859                };
14860
14861                let mut parent = child.clone();
14862                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14863                    parent = match ancestor_range {
14864                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14865                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14866                    };
14867                    if parent.start < child.start || parent.end > child.end {
14868                        break;
14869                    }
14870                }
14871
14872                if parent == child {
14873                    return None;
14874                }
14875                let text = buffer.text_for_range(child.clone()).collect::<String>();
14876                Some((selection.id, parent, text))
14877            })
14878            .collect::<Vec<_>>();
14879
14880        self.transact(window, cx, |this, window, cx| {
14881            this.buffer.update(cx, |buffer, cx| {
14882                buffer.edit(
14883                    full_edits
14884                        .iter()
14885                        .map(|(_, p, t)| (p.clone(), t.clone()))
14886                        .collect::<Vec<_>>(),
14887                    None,
14888                    cx,
14889                );
14890            });
14891            this.change_selections(Default::default(), window, cx, |s| {
14892                let mut offset = 0;
14893                let mut selections = vec![];
14894                for (id, parent, text) in full_edits {
14895                    let start = parent.start - offset;
14896                    offset += parent.len() - text.len();
14897                    selections.push(Selection {
14898                        id: id,
14899                        start,
14900                        end: start + text.len(),
14901                        reversed: false,
14902                        goal: Default::default(),
14903                    });
14904                }
14905                s.select(selections);
14906            });
14907        });
14908    }
14909
14910    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14911        if !EditorSettings::get_global(cx).gutter.runnables {
14912            self.clear_tasks();
14913            return Task::ready(());
14914        }
14915        let project = self.project().map(Entity::downgrade);
14916        let task_sources = self.lsp_task_sources(cx);
14917        let multi_buffer = self.buffer.downgrade();
14918        cx.spawn_in(window, async move |editor, cx| {
14919            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14920            let Some(project) = project.and_then(|p| p.upgrade()) else {
14921                return;
14922            };
14923            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14924                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14925            }) else {
14926                return;
14927            };
14928
14929            let hide_runnables = project
14930                .update(cx, |project, cx| {
14931                    // Do not display any test indicators in non-dev server remote projects.
14932                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14933                })
14934                .unwrap_or(true);
14935            if hide_runnables {
14936                return;
14937            }
14938            let new_rows =
14939                cx.background_spawn({
14940                    let snapshot = display_snapshot.clone();
14941                    async move {
14942                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14943                    }
14944                })
14945                    .await;
14946            let Ok(lsp_tasks) =
14947                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14948            else {
14949                return;
14950            };
14951            let lsp_tasks = lsp_tasks.await;
14952
14953            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14954                lsp_tasks
14955                    .into_iter()
14956                    .flat_map(|(kind, tasks)| {
14957                        tasks.into_iter().filter_map(move |(location, task)| {
14958                            Some((kind.clone(), location?, task))
14959                        })
14960                    })
14961                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14962                        let buffer = location.target.buffer;
14963                        let buffer_snapshot = buffer.read(cx).snapshot();
14964                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14965                            |(excerpt_id, snapshot, _)| {
14966                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14967                                    display_snapshot
14968                                        .buffer_snapshot
14969                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14970                                } else {
14971                                    None
14972                                }
14973                            },
14974                        );
14975                        if let Some(offset) = offset {
14976                            let task_buffer_range =
14977                                location.target.range.to_point(&buffer_snapshot);
14978                            let context_buffer_range =
14979                                task_buffer_range.to_offset(&buffer_snapshot);
14980                            let context_range = BufferOffset(context_buffer_range.start)
14981                                ..BufferOffset(context_buffer_range.end);
14982
14983                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14984                                .or_insert_with(|| RunnableTasks {
14985                                    templates: Vec::new(),
14986                                    offset,
14987                                    column: task_buffer_range.start.column,
14988                                    extra_variables: HashMap::default(),
14989                                    context_range,
14990                                })
14991                                .templates
14992                                .push((kind, task.original_task().clone()));
14993                        }
14994
14995                        acc
14996                    })
14997            }) else {
14998                return;
14999            };
15000
15001            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15002                buffer.language_settings(cx).tasks.prefer_lsp
15003            }) else {
15004                return;
15005            };
15006
15007            let rows = Self::runnable_rows(
15008                project,
15009                display_snapshot,
15010                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15011                new_rows,
15012                cx.clone(),
15013            )
15014            .await;
15015            editor
15016                .update(cx, |editor, _| {
15017                    editor.clear_tasks();
15018                    for (key, mut value) in rows {
15019                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15020                            value.templates.extend(lsp_tasks.templates);
15021                        }
15022
15023                        editor.insert_tasks(key, value);
15024                    }
15025                    for (key, value) in lsp_tasks_by_rows {
15026                        editor.insert_tasks(key, value);
15027                    }
15028                })
15029                .ok();
15030        })
15031    }
15032    fn fetch_runnable_ranges(
15033        snapshot: &DisplaySnapshot,
15034        range: Range<Anchor>,
15035    ) -> Vec<language::RunnableRange> {
15036        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15037    }
15038
15039    fn runnable_rows(
15040        project: Entity<Project>,
15041        snapshot: DisplaySnapshot,
15042        prefer_lsp: bool,
15043        runnable_ranges: Vec<RunnableRange>,
15044        cx: AsyncWindowContext,
15045    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15046        cx.spawn(async move |cx| {
15047            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15048            for mut runnable in runnable_ranges {
15049                let Some(tasks) = cx
15050                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15051                    .ok()
15052                else {
15053                    continue;
15054                };
15055                let mut tasks = tasks.await;
15056
15057                if prefer_lsp {
15058                    tasks.retain(|(task_kind, _)| {
15059                        !matches!(task_kind, TaskSourceKind::Language { .. })
15060                    });
15061                }
15062                if tasks.is_empty() {
15063                    continue;
15064                }
15065
15066                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15067                let Some(row) = snapshot
15068                    .buffer_snapshot
15069                    .buffer_line_for_row(MultiBufferRow(point.row))
15070                    .map(|(_, range)| range.start.row)
15071                else {
15072                    continue;
15073                };
15074
15075                let context_range =
15076                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15077                runnable_rows.push((
15078                    (runnable.buffer_id, row),
15079                    RunnableTasks {
15080                        templates: tasks,
15081                        offset: snapshot
15082                            .buffer_snapshot
15083                            .anchor_before(runnable.run_range.start),
15084                        context_range,
15085                        column: point.column,
15086                        extra_variables: runnable.extra_captures,
15087                    },
15088                ));
15089            }
15090            runnable_rows
15091        })
15092    }
15093
15094    fn templates_with_tags(
15095        project: &Entity<Project>,
15096        runnable: &mut Runnable,
15097        cx: &mut App,
15098    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15099        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15100            let (worktree_id, file) = project
15101                .buffer_for_id(runnable.buffer, cx)
15102                .and_then(|buffer| buffer.read(cx).file())
15103                .map(|file| (file.worktree_id(cx), file.clone()))
15104                .unzip();
15105
15106            (
15107                project.task_store().read(cx).task_inventory().cloned(),
15108                worktree_id,
15109                file,
15110            )
15111        });
15112
15113        let tags = mem::take(&mut runnable.tags);
15114        let language = runnable.language.clone();
15115        cx.spawn(async move |cx| {
15116            let mut templates_with_tags = Vec::new();
15117            if let Some(inventory) = inventory {
15118                for RunnableTag(tag) in tags {
15119                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15120                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15121                    }) else {
15122                        return templates_with_tags;
15123                    };
15124                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15125                        move |(_, template)| {
15126                            template.tags.iter().any(|source_tag| source_tag == &tag)
15127                        },
15128                    ));
15129                }
15130            }
15131            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15132
15133            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15134                // Strongest source wins; if we have worktree tag binding, prefer that to
15135                // global and language bindings;
15136                // if we have a global binding, prefer that to language binding.
15137                let first_mismatch = templates_with_tags
15138                    .iter()
15139                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15140                if let Some(index) = first_mismatch {
15141                    templates_with_tags.truncate(index);
15142                }
15143            }
15144
15145            templates_with_tags
15146        })
15147    }
15148
15149    pub fn move_to_enclosing_bracket(
15150        &mut self,
15151        _: &MoveToEnclosingBracket,
15152        window: &mut Window,
15153        cx: &mut Context<Self>,
15154    ) {
15155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15156        self.change_selections(Default::default(), window, cx, |s| {
15157            s.move_offsets_with(|snapshot, selection| {
15158                let Some(enclosing_bracket_ranges) =
15159                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15160                else {
15161                    return;
15162                };
15163
15164                let mut best_length = usize::MAX;
15165                let mut best_inside = false;
15166                let mut best_in_bracket_range = false;
15167                let mut best_destination = None;
15168                for (open, close) in enclosing_bracket_ranges {
15169                    let close = close.to_inclusive();
15170                    let length = close.end() - open.start;
15171                    let inside = selection.start >= open.end && selection.end <= *close.start();
15172                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15173                        || close.contains(&selection.head());
15174
15175                    // If best is next to a bracket and current isn't, skip
15176                    if !in_bracket_range && best_in_bracket_range {
15177                        continue;
15178                    }
15179
15180                    // Prefer smaller lengths unless best is inside and current isn't
15181                    if length > best_length && (best_inside || !inside) {
15182                        continue;
15183                    }
15184
15185                    best_length = length;
15186                    best_inside = inside;
15187                    best_in_bracket_range = in_bracket_range;
15188                    best_destination = Some(
15189                        if close.contains(&selection.start) && close.contains(&selection.end) {
15190                            if inside { open.end } else { open.start }
15191                        } else if inside {
15192                            *close.start()
15193                        } else {
15194                            *close.end()
15195                        },
15196                    );
15197                }
15198
15199                if let Some(destination) = best_destination {
15200                    selection.collapse_to(destination, SelectionGoal::None);
15201                }
15202            })
15203        });
15204    }
15205
15206    pub fn undo_selection(
15207        &mut self,
15208        _: &UndoSelection,
15209        window: &mut Window,
15210        cx: &mut Context<Self>,
15211    ) {
15212        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15213        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15214            self.selection_history.mode = SelectionHistoryMode::Undoing;
15215            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15216                this.end_selection(window, cx);
15217                this.change_selections(
15218                    SelectionEffects::scroll(Autoscroll::newest()),
15219                    window,
15220                    cx,
15221                    |s| s.select_anchors(entry.selections.to_vec()),
15222                );
15223            });
15224            self.selection_history.mode = SelectionHistoryMode::Normal;
15225
15226            self.select_next_state = entry.select_next_state;
15227            self.select_prev_state = entry.select_prev_state;
15228            self.add_selections_state = entry.add_selections_state;
15229        }
15230    }
15231
15232    pub fn redo_selection(
15233        &mut self,
15234        _: &RedoSelection,
15235        window: &mut Window,
15236        cx: &mut Context<Self>,
15237    ) {
15238        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15239        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15240            self.selection_history.mode = SelectionHistoryMode::Redoing;
15241            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15242                this.end_selection(window, cx);
15243                this.change_selections(
15244                    SelectionEffects::scroll(Autoscroll::newest()),
15245                    window,
15246                    cx,
15247                    |s| s.select_anchors(entry.selections.to_vec()),
15248                );
15249            });
15250            self.selection_history.mode = SelectionHistoryMode::Normal;
15251
15252            self.select_next_state = entry.select_next_state;
15253            self.select_prev_state = entry.select_prev_state;
15254            self.add_selections_state = entry.add_selections_state;
15255        }
15256    }
15257
15258    pub fn expand_excerpts(
15259        &mut self,
15260        action: &ExpandExcerpts,
15261        _: &mut Window,
15262        cx: &mut Context<Self>,
15263    ) {
15264        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15265    }
15266
15267    pub fn expand_excerpts_down(
15268        &mut self,
15269        action: &ExpandExcerptsDown,
15270        _: &mut Window,
15271        cx: &mut Context<Self>,
15272    ) {
15273        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15274    }
15275
15276    pub fn expand_excerpts_up(
15277        &mut self,
15278        action: &ExpandExcerptsUp,
15279        _: &mut Window,
15280        cx: &mut Context<Self>,
15281    ) {
15282        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15283    }
15284
15285    pub fn expand_excerpts_for_direction(
15286        &mut self,
15287        lines: u32,
15288        direction: ExpandExcerptDirection,
15289
15290        cx: &mut Context<Self>,
15291    ) {
15292        let selections = self.selections.disjoint_anchors();
15293
15294        let lines = if lines == 0 {
15295            EditorSettings::get_global(cx).expand_excerpt_lines
15296        } else {
15297            lines
15298        };
15299
15300        self.buffer.update(cx, |buffer, cx| {
15301            let snapshot = buffer.snapshot(cx);
15302            let mut excerpt_ids = selections
15303                .iter()
15304                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15305                .collect::<Vec<_>>();
15306            excerpt_ids.sort();
15307            excerpt_ids.dedup();
15308            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15309        })
15310    }
15311
15312    pub fn expand_excerpt(
15313        &mut self,
15314        excerpt: ExcerptId,
15315        direction: ExpandExcerptDirection,
15316        window: &mut Window,
15317        cx: &mut Context<Self>,
15318    ) {
15319        let current_scroll_position = self.scroll_position(cx);
15320        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15321        let mut should_scroll_up = false;
15322
15323        if direction == ExpandExcerptDirection::Down {
15324            let multi_buffer = self.buffer.read(cx);
15325            let snapshot = multi_buffer.snapshot(cx);
15326            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15327                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15328                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15329                        let buffer_snapshot = buffer.read(cx).snapshot();
15330                        let excerpt_end_row =
15331                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15332                        let last_row = buffer_snapshot.max_point().row;
15333                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15334                        should_scroll_up = lines_below >= lines_to_expand;
15335                    }
15336                }
15337            }
15338        }
15339
15340        self.buffer.update(cx, |buffer, cx| {
15341            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15342        });
15343
15344        if should_scroll_up {
15345            let new_scroll_position =
15346                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15347            self.set_scroll_position(new_scroll_position, window, cx);
15348        }
15349    }
15350
15351    pub fn go_to_singleton_buffer_point(
15352        &mut self,
15353        point: Point,
15354        window: &mut Window,
15355        cx: &mut Context<Self>,
15356    ) {
15357        self.go_to_singleton_buffer_range(point..point, window, cx);
15358    }
15359
15360    pub fn go_to_singleton_buffer_range(
15361        &mut self,
15362        range: Range<Point>,
15363        window: &mut Window,
15364        cx: &mut Context<Self>,
15365    ) {
15366        let multibuffer = self.buffer().read(cx);
15367        let Some(buffer) = multibuffer.as_singleton() else {
15368            return;
15369        };
15370        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15371            return;
15372        };
15373        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15374            return;
15375        };
15376        self.change_selections(
15377            SelectionEffects::default().nav_history(true),
15378            window,
15379            cx,
15380            |s| s.select_anchor_ranges([start..end]),
15381        );
15382    }
15383
15384    pub fn go_to_diagnostic(
15385        &mut self,
15386        action: &GoToDiagnostic,
15387        window: &mut Window,
15388        cx: &mut Context<Self>,
15389    ) {
15390        if !self.diagnostics_enabled() {
15391            return;
15392        }
15393        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15394        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15395    }
15396
15397    pub fn go_to_prev_diagnostic(
15398        &mut self,
15399        action: &GoToPreviousDiagnostic,
15400        window: &mut Window,
15401        cx: &mut Context<Self>,
15402    ) {
15403        if !self.diagnostics_enabled() {
15404            return;
15405        }
15406        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15407        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15408    }
15409
15410    pub fn go_to_diagnostic_impl(
15411        &mut self,
15412        direction: Direction,
15413        severity: GoToDiagnosticSeverityFilter,
15414        window: &mut Window,
15415        cx: &mut Context<Self>,
15416    ) {
15417        let buffer = self.buffer.read(cx).snapshot(cx);
15418        let selection = self.selections.newest::<usize>(cx);
15419
15420        let mut active_group_id = None;
15421        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15422            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15423                active_group_id = Some(active_group.group_id);
15424            }
15425        }
15426
15427        fn filtered(
15428            snapshot: EditorSnapshot,
15429            severity: GoToDiagnosticSeverityFilter,
15430            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15431        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15432            diagnostics
15433                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15434                .filter(|entry| entry.range.start != entry.range.end)
15435                .filter(|entry| !entry.diagnostic.is_unnecessary)
15436                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15437        }
15438
15439        let snapshot = self.snapshot(window, cx);
15440        let before = filtered(
15441            snapshot.clone(),
15442            severity,
15443            buffer
15444                .diagnostics_in_range(0..selection.start)
15445                .filter(|entry| entry.range.start <= selection.start),
15446        );
15447        let after = filtered(
15448            snapshot,
15449            severity,
15450            buffer
15451                .diagnostics_in_range(selection.start..buffer.len())
15452                .filter(|entry| entry.range.start >= selection.start),
15453        );
15454
15455        let mut found: Option<DiagnosticEntry<usize>> = None;
15456        if direction == Direction::Prev {
15457            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15458            {
15459                for diagnostic in prev_diagnostics.into_iter().rev() {
15460                    if diagnostic.range.start != selection.start
15461                        || active_group_id
15462                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15463                    {
15464                        found = Some(diagnostic);
15465                        break 'outer;
15466                    }
15467                }
15468            }
15469        } else {
15470            for diagnostic in after.chain(before) {
15471                if diagnostic.range.start != selection.start
15472                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15473                {
15474                    found = Some(diagnostic);
15475                    break;
15476                }
15477            }
15478        }
15479        let Some(next_diagnostic) = found else {
15480            return;
15481        };
15482
15483        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15484            return;
15485        };
15486        self.change_selections(Default::default(), window, cx, |s| {
15487            s.select_ranges(vec![
15488                next_diagnostic.range.start..next_diagnostic.range.start,
15489            ])
15490        });
15491        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15492        self.refresh_edit_prediction(false, true, window, cx);
15493    }
15494
15495    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15496        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15497        let snapshot = self.snapshot(window, cx);
15498        let selection = self.selections.newest::<Point>(cx);
15499        self.go_to_hunk_before_or_after_position(
15500            &snapshot,
15501            selection.head(),
15502            Direction::Next,
15503            window,
15504            cx,
15505        );
15506    }
15507
15508    pub fn go_to_hunk_before_or_after_position(
15509        &mut self,
15510        snapshot: &EditorSnapshot,
15511        position: Point,
15512        direction: Direction,
15513        window: &mut Window,
15514        cx: &mut Context<Editor>,
15515    ) {
15516        let row = if direction == Direction::Next {
15517            self.hunk_after_position(snapshot, position)
15518                .map(|hunk| hunk.row_range.start)
15519        } else {
15520            self.hunk_before_position(snapshot, position)
15521        };
15522
15523        if let Some(row) = row {
15524            let destination = Point::new(row.0, 0);
15525            let autoscroll = Autoscroll::center();
15526
15527            self.unfold_ranges(&[destination..destination], false, false, cx);
15528            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15529                s.select_ranges([destination..destination]);
15530            });
15531        }
15532    }
15533
15534    fn hunk_after_position(
15535        &mut self,
15536        snapshot: &EditorSnapshot,
15537        position: Point,
15538    ) -> Option<MultiBufferDiffHunk> {
15539        snapshot
15540            .buffer_snapshot
15541            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15542            .find(|hunk| hunk.row_range.start.0 > position.row)
15543            .or_else(|| {
15544                snapshot
15545                    .buffer_snapshot
15546                    .diff_hunks_in_range(Point::zero()..position)
15547                    .find(|hunk| hunk.row_range.end.0 < position.row)
15548            })
15549    }
15550
15551    fn go_to_prev_hunk(
15552        &mut self,
15553        _: &GoToPreviousHunk,
15554        window: &mut Window,
15555        cx: &mut Context<Self>,
15556    ) {
15557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15558        let snapshot = self.snapshot(window, cx);
15559        let selection = self.selections.newest::<Point>(cx);
15560        self.go_to_hunk_before_or_after_position(
15561            &snapshot,
15562            selection.head(),
15563            Direction::Prev,
15564            window,
15565            cx,
15566        );
15567    }
15568
15569    fn hunk_before_position(
15570        &mut self,
15571        snapshot: &EditorSnapshot,
15572        position: Point,
15573    ) -> Option<MultiBufferRow> {
15574        snapshot
15575            .buffer_snapshot
15576            .diff_hunk_before(position)
15577            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15578    }
15579
15580    fn go_to_next_change(
15581        &mut self,
15582        _: &GoToNextChange,
15583        window: &mut Window,
15584        cx: &mut Context<Self>,
15585    ) {
15586        if let Some(selections) = self
15587            .change_list
15588            .next_change(1, Direction::Next)
15589            .map(|s| s.to_vec())
15590        {
15591            self.change_selections(Default::default(), window, cx, |s| {
15592                let map = s.display_map();
15593                s.select_display_ranges(selections.iter().map(|a| {
15594                    let point = a.to_display_point(&map);
15595                    point..point
15596                }))
15597            })
15598        }
15599    }
15600
15601    fn go_to_previous_change(
15602        &mut self,
15603        _: &GoToPreviousChange,
15604        window: &mut Window,
15605        cx: &mut Context<Self>,
15606    ) {
15607        if let Some(selections) = self
15608            .change_list
15609            .next_change(1, Direction::Prev)
15610            .map(|s| s.to_vec())
15611        {
15612            self.change_selections(Default::default(), window, cx, |s| {
15613                let map = s.display_map();
15614                s.select_display_ranges(selections.iter().map(|a| {
15615                    let point = a.to_display_point(&map);
15616                    point..point
15617                }))
15618            })
15619        }
15620    }
15621
15622    fn go_to_line<T: 'static>(
15623        &mut self,
15624        position: Anchor,
15625        highlight_color: Option<Hsla>,
15626        window: &mut Window,
15627        cx: &mut Context<Self>,
15628    ) {
15629        let snapshot = self.snapshot(window, cx).display_snapshot;
15630        let position = position.to_point(&snapshot.buffer_snapshot);
15631        let start = snapshot
15632            .buffer_snapshot
15633            .clip_point(Point::new(position.row, 0), Bias::Left);
15634        let end = start + Point::new(1, 0);
15635        let start = snapshot.buffer_snapshot.anchor_before(start);
15636        let end = snapshot.buffer_snapshot.anchor_before(end);
15637
15638        self.highlight_rows::<T>(
15639            start..end,
15640            highlight_color
15641                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15642            Default::default(),
15643            cx,
15644        );
15645
15646        if self.buffer.read(cx).is_singleton() {
15647            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15648        }
15649    }
15650
15651    pub fn go_to_definition(
15652        &mut self,
15653        _: &GoToDefinition,
15654        window: &mut Window,
15655        cx: &mut Context<Self>,
15656    ) -> Task<Result<Navigated>> {
15657        let definition =
15658            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15659        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15660        cx.spawn_in(window, async move |editor, cx| {
15661            if definition.await? == Navigated::Yes {
15662                return Ok(Navigated::Yes);
15663            }
15664            match fallback_strategy {
15665                GoToDefinitionFallback::None => Ok(Navigated::No),
15666                GoToDefinitionFallback::FindAllReferences => {
15667                    match editor.update_in(cx, |editor, window, cx| {
15668                        editor.find_all_references(&FindAllReferences, window, cx)
15669                    })? {
15670                        Some(references) => references.await,
15671                        None => Ok(Navigated::No),
15672                    }
15673                }
15674            }
15675        })
15676    }
15677
15678    pub fn go_to_declaration(
15679        &mut self,
15680        _: &GoToDeclaration,
15681        window: &mut Window,
15682        cx: &mut Context<Self>,
15683    ) -> Task<Result<Navigated>> {
15684        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15685    }
15686
15687    pub fn go_to_declaration_split(
15688        &mut self,
15689        _: &GoToDeclaration,
15690        window: &mut Window,
15691        cx: &mut Context<Self>,
15692    ) -> Task<Result<Navigated>> {
15693        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15694    }
15695
15696    pub fn go_to_implementation(
15697        &mut self,
15698        _: &GoToImplementation,
15699        window: &mut Window,
15700        cx: &mut Context<Self>,
15701    ) -> Task<Result<Navigated>> {
15702        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15703    }
15704
15705    pub fn go_to_implementation_split(
15706        &mut self,
15707        _: &GoToImplementationSplit,
15708        window: &mut Window,
15709        cx: &mut Context<Self>,
15710    ) -> Task<Result<Navigated>> {
15711        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15712    }
15713
15714    pub fn go_to_type_definition(
15715        &mut self,
15716        _: &GoToTypeDefinition,
15717        window: &mut Window,
15718        cx: &mut Context<Self>,
15719    ) -> Task<Result<Navigated>> {
15720        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15721    }
15722
15723    pub fn go_to_definition_split(
15724        &mut self,
15725        _: &GoToDefinitionSplit,
15726        window: &mut Window,
15727        cx: &mut Context<Self>,
15728    ) -> Task<Result<Navigated>> {
15729        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15730    }
15731
15732    pub fn go_to_type_definition_split(
15733        &mut self,
15734        _: &GoToTypeDefinitionSplit,
15735        window: &mut Window,
15736        cx: &mut Context<Self>,
15737    ) -> Task<Result<Navigated>> {
15738        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15739    }
15740
15741    fn go_to_definition_of_kind(
15742        &mut self,
15743        kind: GotoDefinitionKind,
15744        split: bool,
15745        window: &mut Window,
15746        cx: &mut Context<Self>,
15747    ) -> Task<Result<Navigated>> {
15748        let Some(provider) = self.semantics_provider.clone() else {
15749            return Task::ready(Ok(Navigated::No));
15750        };
15751        let head = self.selections.newest::<usize>(cx).head();
15752        let buffer = self.buffer.read(cx);
15753        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15754            return Task::ready(Ok(Navigated::No));
15755        };
15756        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15757            return Task::ready(Ok(Navigated::No));
15758        };
15759
15760        cx.spawn_in(window, async move |editor, cx| {
15761            let definitions = definitions.await?;
15762            let navigated = editor
15763                .update_in(cx, |editor, window, cx| {
15764                    editor.navigate_to_hover_links(
15765                        Some(kind),
15766                        definitions
15767                            .into_iter()
15768                            .filter(|location| {
15769                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15770                            })
15771                            .map(HoverLink::Text)
15772                            .collect::<Vec<_>>(),
15773                        split,
15774                        window,
15775                        cx,
15776                    )
15777                })?
15778                .await?;
15779            anyhow::Ok(navigated)
15780        })
15781    }
15782
15783    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15784        let selection = self.selections.newest_anchor();
15785        let head = selection.head();
15786        let tail = selection.tail();
15787
15788        let Some((buffer, start_position)) =
15789            self.buffer.read(cx).text_anchor_for_position(head, cx)
15790        else {
15791            return;
15792        };
15793
15794        let end_position = if head != tail {
15795            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15796                return;
15797            };
15798            Some(pos)
15799        } else {
15800            None
15801        };
15802
15803        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15804            let url = if let Some(end_pos) = end_position {
15805                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15806            } else {
15807                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15808            };
15809
15810            if let Some(url) = url {
15811                editor.update(cx, |_, cx| {
15812                    cx.open_url(&url);
15813                })
15814            } else {
15815                Ok(())
15816            }
15817        });
15818
15819        url_finder.detach();
15820    }
15821
15822    pub fn open_selected_filename(
15823        &mut self,
15824        _: &OpenSelectedFilename,
15825        window: &mut Window,
15826        cx: &mut Context<Self>,
15827    ) {
15828        let Some(workspace) = self.workspace() else {
15829            return;
15830        };
15831
15832        let position = self.selections.newest_anchor().head();
15833
15834        let Some((buffer, buffer_position)) =
15835            self.buffer.read(cx).text_anchor_for_position(position, cx)
15836        else {
15837            return;
15838        };
15839
15840        let project = self.project.clone();
15841
15842        cx.spawn_in(window, async move |_, cx| {
15843            let result = find_file(&buffer, project, buffer_position, cx).await;
15844
15845            if let Some((_, path)) = result {
15846                workspace
15847                    .update_in(cx, |workspace, window, cx| {
15848                        workspace.open_resolved_path(path, window, cx)
15849                    })?
15850                    .await?;
15851            }
15852            anyhow::Ok(())
15853        })
15854        .detach();
15855    }
15856
15857    pub(crate) fn navigate_to_hover_links(
15858        &mut self,
15859        kind: Option<GotoDefinitionKind>,
15860        definitions: Vec<HoverLink>,
15861        split: bool,
15862        window: &mut Window,
15863        cx: &mut Context<Editor>,
15864    ) -> Task<Result<Navigated>> {
15865        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15866        let mut first_url_or_file = None;
15867        let definitions: Vec<_> = definitions
15868            .into_iter()
15869            .filter_map(|def| match def {
15870                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15871                HoverLink::InlayHint(lsp_location, server_id) => {
15872                    let computation =
15873                        self.compute_target_location(lsp_location, server_id, window, cx);
15874                    Some(cx.background_spawn(computation))
15875                }
15876                HoverLink::Url(url) => {
15877                    first_url_or_file = Some(Either::Left(url));
15878                    None
15879                }
15880                HoverLink::File(path) => {
15881                    first_url_or_file = Some(Either::Right(path));
15882                    None
15883                }
15884            })
15885            .collect();
15886
15887        let workspace = self.workspace();
15888
15889        cx.spawn_in(window, async move |editor, acx| {
15890            let mut locations: Vec<Location> = future::join_all(definitions)
15891                .await
15892                .into_iter()
15893                .filter_map(|location| location.transpose())
15894                .collect::<Result<_>>()
15895                .context("location tasks")?;
15896
15897            if locations.len() > 1 {
15898                let Some(workspace) = workspace else {
15899                    return Ok(Navigated::No);
15900                };
15901
15902                let tab_kind = match kind {
15903                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15904                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15905                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15906                    Some(GotoDefinitionKind::Type) => "Types",
15907                };
15908                let title = editor
15909                    .update_in(acx, |_, _, cx| {
15910                        let target = locations
15911                            .iter()
15912                            .map(|location| {
15913                                location
15914                                    .buffer
15915                                    .read(cx)
15916                                    .text_for_range(location.range.clone())
15917                                    .collect::<String>()
15918                            })
15919                            .filter(|text| !text.contains('\n'))
15920                            .unique()
15921                            .take(3)
15922                            .join(", ");
15923                        if target.is_empty() {
15924                            tab_kind.to_owned()
15925                        } else {
15926                            format!("{tab_kind} for {target}")
15927                        }
15928                    })
15929                    .context("buffer title")?;
15930
15931                let opened = workspace
15932                    .update_in(acx, |workspace, window, cx| {
15933                        Self::open_locations_in_multibuffer(
15934                            workspace,
15935                            locations,
15936                            title,
15937                            split,
15938                            MultibufferSelectionMode::First,
15939                            window,
15940                            cx,
15941                        )
15942                    })
15943                    .is_ok();
15944
15945                anyhow::Ok(Navigated::from_bool(opened))
15946            } else if locations.is_empty() {
15947                // If there is one definition, just open it directly
15948                match first_url_or_file {
15949                    Some(Either::Left(url)) => {
15950                        acx.update(|_, cx| cx.open_url(&url))?;
15951                        Ok(Navigated::Yes)
15952                    }
15953                    Some(Either::Right(path)) => {
15954                        let Some(workspace) = workspace else {
15955                            return Ok(Navigated::No);
15956                        };
15957
15958                        workspace
15959                            .update_in(acx, |workspace, window, cx| {
15960                                workspace.open_resolved_path(path, window, cx)
15961                            })?
15962                            .await?;
15963                        Ok(Navigated::Yes)
15964                    }
15965                    None => Ok(Navigated::No),
15966                }
15967            } else {
15968                let Some(workspace) = workspace else {
15969                    return Ok(Navigated::No);
15970                };
15971
15972                let target = locations.pop().unwrap();
15973                editor.update_in(acx, |editor, window, cx| {
15974                    let pane = workspace.read(cx).active_pane().clone();
15975
15976                    let range = target.range.to_point(target.buffer.read(cx));
15977                    let range = editor.range_for_match(&range);
15978                    let range = collapse_multiline_range(range);
15979
15980                    if !split
15981                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15982                    {
15983                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15984                    } else {
15985                        window.defer(cx, move |window, cx| {
15986                            let target_editor: Entity<Self> =
15987                                workspace.update(cx, |workspace, cx| {
15988                                    let pane = if split {
15989                                        workspace.adjacent_pane(window, cx)
15990                                    } else {
15991                                        workspace.active_pane().clone()
15992                                    };
15993
15994                                    workspace.open_project_item(
15995                                        pane,
15996                                        target.buffer.clone(),
15997                                        true,
15998                                        true,
15999                                        window,
16000                                        cx,
16001                                    )
16002                                });
16003                            target_editor.update(cx, |target_editor, cx| {
16004                                // When selecting a definition in a different buffer, disable the nav history
16005                                // to avoid creating a history entry at the previous cursor location.
16006                                pane.update(cx, |pane, _| pane.disable_history());
16007                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16008                                pane.update(cx, |pane, _| pane.enable_history());
16009                            });
16010                        });
16011                    }
16012                    Navigated::Yes
16013                })
16014            }
16015        })
16016    }
16017
16018    fn compute_target_location(
16019        &self,
16020        lsp_location: lsp::Location,
16021        server_id: LanguageServerId,
16022        window: &mut Window,
16023        cx: &mut Context<Self>,
16024    ) -> Task<anyhow::Result<Option<Location>>> {
16025        let Some(project) = self.project.clone() else {
16026            return Task::ready(Ok(None));
16027        };
16028
16029        cx.spawn_in(window, async move |editor, cx| {
16030            let location_task = editor.update(cx, |_, cx| {
16031                project.update(cx, |project, cx| {
16032                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16033                })
16034            })?;
16035            let location = Some({
16036                let target_buffer_handle = location_task.await.context("open local buffer")?;
16037                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16038                    let target_start = target_buffer
16039                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16040                    let target_end = target_buffer
16041                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16042                    target_buffer.anchor_after(target_start)
16043                        ..target_buffer.anchor_before(target_end)
16044                })?;
16045                Location {
16046                    buffer: target_buffer_handle,
16047                    range,
16048                }
16049            });
16050            Ok(location)
16051        })
16052    }
16053
16054    pub fn find_all_references(
16055        &mut self,
16056        _: &FindAllReferences,
16057        window: &mut Window,
16058        cx: &mut Context<Self>,
16059    ) -> Option<Task<Result<Navigated>>> {
16060        let selection = self.selections.newest::<usize>(cx);
16061        let multi_buffer = self.buffer.read(cx);
16062        let head = selection.head();
16063
16064        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16065        let head_anchor = multi_buffer_snapshot.anchor_at(
16066            head,
16067            if head < selection.tail() {
16068                Bias::Right
16069            } else {
16070                Bias::Left
16071            },
16072        );
16073
16074        match self
16075            .find_all_references_task_sources
16076            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16077        {
16078            Ok(_) => {
16079                log::info!(
16080                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16081                );
16082                return None;
16083            }
16084            Err(i) => {
16085                self.find_all_references_task_sources.insert(i, head_anchor);
16086            }
16087        }
16088
16089        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16090        let workspace = self.workspace()?;
16091        let project = workspace.read(cx).project().clone();
16092        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16093        Some(cx.spawn_in(window, async move |editor, cx| {
16094            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16095                if let Ok(i) = editor
16096                    .find_all_references_task_sources
16097                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16098                {
16099                    editor.find_all_references_task_sources.remove(i);
16100                }
16101            });
16102
16103            let locations = references.await?;
16104            if locations.is_empty() {
16105                return anyhow::Ok(Navigated::No);
16106            }
16107
16108            workspace.update_in(cx, |workspace, window, cx| {
16109                let target = locations
16110                    .iter()
16111                    .map(|location| {
16112                        location
16113                            .buffer
16114                            .read(cx)
16115                            .text_for_range(location.range.clone())
16116                            .collect::<String>()
16117                    })
16118                    .filter(|text| !text.contains('\n'))
16119                    .unique()
16120                    .take(3)
16121                    .join(", ");
16122                let title = if target.is_empty() {
16123                    "References".to_owned()
16124                } else {
16125                    format!("References to {target}")
16126                };
16127                Self::open_locations_in_multibuffer(
16128                    workspace,
16129                    locations,
16130                    title,
16131                    false,
16132                    MultibufferSelectionMode::First,
16133                    window,
16134                    cx,
16135                );
16136                Navigated::Yes
16137            })
16138        }))
16139    }
16140
16141    /// Opens a multibuffer with the given project locations in it
16142    pub fn open_locations_in_multibuffer(
16143        workspace: &mut Workspace,
16144        mut locations: Vec<Location>,
16145        title: String,
16146        split: bool,
16147        multibuffer_selection_mode: MultibufferSelectionMode,
16148        window: &mut Window,
16149        cx: &mut Context<Workspace>,
16150    ) {
16151        if locations.is_empty() {
16152            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16153            return;
16154        }
16155
16156        // If there are multiple definitions, open them in a multibuffer
16157        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16158        let mut locations = locations.into_iter().peekable();
16159        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16160        let capability = workspace.project().read(cx).capability();
16161
16162        let excerpt_buffer = cx.new(|cx| {
16163            let mut multibuffer = MultiBuffer::new(capability);
16164            while let Some(location) = locations.next() {
16165                let buffer = location.buffer.read(cx);
16166                let mut ranges_for_buffer = Vec::new();
16167                let range = location.range.to_point(buffer);
16168                ranges_for_buffer.push(range.clone());
16169
16170                while let Some(next_location) = locations.peek() {
16171                    if next_location.buffer == location.buffer {
16172                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16173                        locations.next();
16174                    } else {
16175                        break;
16176                    }
16177                }
16178
16179                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16180                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16181                    PathKey::for_buffer(&location.buffer, cx),
16182                    location.buffer.clone(),
16183                    ranges_for_buffer,
16184                    DEFAULT_MULTIBUFFER_CONTEXT,
16185                    cx,
16186                );
16187                ranges.extend(new_ranges)
16188            }
16189
16190            multibuffer.with_title(title)
16191        });
16192
16193        let editor = cx.new(|cx| {
16194            Editor::for_multibuffer(
16195                excerpt_buffer,
16196                Some(workspace.project().clone()),
16197                window,
16198                cx,
16199            )
16200        });
16201        editor.update(cx, |editor, cx| {
16202            match multibuffer_selection_mode {
16203                MultibufferSelectionMode::First => {
16204                    if let Some(first_range) = ranges.first() {
16205                        editor.change_selections(
16206                            SelectionEffects::no_scroll(),
16207                            window,
16208                            cx,
16209                            |selections| {
16210                                selections.clear_disjoint();
16211                                selections
16212                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16213                            },
16214                        );
16215                    }
16216                    editor.highlight_background::<Self>(
16217                        &ranges,
16218                        |theme| theme.colors().editor_highlighted_line_background,
16219                        cx,
16220                    );
16221                }
16222                MultibufferSelectionMode::All => {
16223                    editor.change_selections(
16224                        SelectionEffects::no_scroll(),
16225                        window,
16226                        cx,
16227                        |selections| {
16228                            selections.clear_disjoint();
16229                            selections.select_anchor_ranges(ranges);
16230                        },
16231                    );
16232                }
16233            }
16234            editor.register_buffers_with_language_servers(cx);
16235        });
16236
16237        let item = Box::new(editor);
16238        let item_id = item.item_id();
16239
16240        if split {
16241            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16242        } else {
16243            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16244                let (preview_item_id, preview_item_idx) =
16245                    workspace.active_pane().read_with(cx, |pane, _| {
16246                        (pane.preview_item_id(), pane.preview_item_idx())
16247                    });
16248
16249                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16250
16251                if let Some(preview_item_id) = preview_item_id {
16252                    workspace.active_pane().update(cx, |pane, cx| {
16253                        pane.remove_item(preview_item_id, false, false, window, cx);
16254                    });
16255                }
16256            } else {
16257                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16258            }
16259        }
16260        workspace.active_pane().update(cx, |pane, cx| {
16261            pane.set_preview_item_id(Some(item_id), cx);
16262        });
16263    }
16264
16265    pub fn rename(
16266        &mut self,
16267        _: &Rename,
16268        window: &mut Window,
16269        cx: &mut Context<Self>,
16270    ) -> Option<Task<Result<()>>> {
16271        use language::ToOffset as _;
16272
16273        let provider = self.semantics_provider.clone()?;
16274        let selection = self.selections.newest_anchor().clone();
16275        let (cursor_buffer, cursor_buffer_position) = self
16276            .buffer
16277            .read(cx)
16278            .text_anchor_for_position(selection.head(), cx)?;
16279        let (tail_buffer, cursor_buffer_position_end) = self
16280            .buffer
16281            .read(cx)
16282            .text_anchor_for_position(selection.tail(), cx)?;
16283        if tail_buffer != cursor_buffer {
16284            return None;
16285        }
16286
16287        let snapshot = cursor_buffer.read(cx).snapshot();
16288        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16289        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16290        let prepare_rename = provider
16291            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16292            .unwrap_or_else(|| Task::ready(Ok(None)));
16293        drop(snapshot);
16294
16295        Some(cx.spawn_in(window, async move |this, cx| {
16296            let rename_range = if let Some(range) = prepare_rename.await? {
16297                Some(range)
16298            } else {
16299                this.update(cx, |this, cx| {
16300                    let buffer = this.buffer.read(cx).snapshot(cx);
16301                    let mut buffer_highlights = this
16302                        .document_highlights_for_position(selection.head(), &buffer)
16303                        .filter(|highlight| {
16304                            highlight.start.excerpt_id == selection.head().excerpt_id
16305                                && highlight.end.excerpt_id == selection.head().excerpt_id
16306                        });
16307                    buffer_highlights
16308                        .next()
16309                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16310                })?
16311            };
16312            if let Some(rename_range) = rename_range {
16313                this.update_in(cx, |this, window, cx| {
16314                    let snapshot = cursor_buffer.read(cx).snapshot();
16315                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16316                    let cursor_offset_in_rename_range =
16317                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16318                    let cursor_offset_in_rename_range_end =
16319                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16320
16321                    this.take_rename(false, window, cx);
16322                    let buffer = this.buffer.read(cx).read(cx);
16323                    let cursor_offset = selection.head().to_offset(&buffer);
16324                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16325                    let rename_end = rename_start + rename_buffer_range.len();
16326                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16327                    let mut old_highlight_id = None;
16328                    let old_name: Arc<str> = buffer
16329                        .chunks(rename_start..rename_end, true)
16330                        .map(|chunk| {
16331                            if old_highlight_id.is_none() {
16332                                old_highlight_id = chunk.syntax_highlight_id;
16333                            }
16334                            chunk.text
16335                        })
16336                        .collect::<String>()
16337                        .into();
16338
16339                    drop(buffer);
16340
16341                    // Position the selection in the rename editor so that it matches the current selection.
16342                    this.show_local_selections = false;
16343                    let rename_editor = cx.new(|cx| {
16344                        let mut editor = Editor::single_line(window, cx);
16345                        editor.buffer.update(cx, |buffer, cx| {
16346                            buffer.edit([(0..0, old_name.clone())], None, cx)
16347                        });
16348                        let rename_selection_range = match cursor_offset_in_rename_range
16349                            .cmp(&cursor_offset_in_rename_range_end)
16350                        {
16351                            Ordering::Equal => {
16352                                editor.select_all(&SelectAll, window, cx);
16353                                return editor;
16354                            }
16355                            Ordering::Less => {
16356                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16357                            }
16358                            Ordering::Greater => {
16359                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16360                            }
16361                        };
16362                        if rename_selection_range.end > old_name.len() {
16363                            editor.select_all(&SelectAll, window, cx);
16364                        } else {
16365                            editor.change_selections(Default::default(), window, cx, |s| {
16366                                s.select_ranges([rename_selection_range]);
16367                            });
16368                        }
16369                        editor
16370                    });
16371                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16372                        if e == &EditorEvent::Focused {
16373                            cx.emit(EditorEvent::FocusedIn)
16374                        }
16375                    })
16376                    .detach();
16377
16378                    let write_highlights =
16379                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16380                    let read_highlights =
16381                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16382                    let ranges = write_highlights
16383                        .iter()
16384                        .flat_map(|(_, ranges)| ranges.iter())
16385                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16386                        .cloned()
16387                        .collect();
16388
16389                    this.highlight_text::<Rename>(
16390                        ranges,
16391                        HighlightStyle {
16392                            fade_out: Some(0.6),
16393                            ..Default::default()
16394                        },
16395                        cx,
16396                    );
16397                    let rename_focus_handle = rename_editor.focus_handle(cx);
16398                    window.focus(&rename_focus_handle);
16399                    let block_id = this.insert_blocks(
16400                        [BlockProperties {
16401                            style: BlockStyle::Flex,
16402                            placement: BlockPlacement::Below(range.start),
16403                            height: Some(1),
16404                            render: Arc::new({
16405                                let rename_editor = rename_editor.clone();
16406                                move |cx: &mut BlockContext| {
16407                                    let mut text_style = cx.editor_style.text.clone();
16408                                    if let Some(highlight_style) = old_highlight_id
16409                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16410                                    {
16411                                        text_style = text_style.highlight(highlight_style);
16412                                    }
16413                                    div()
16414                                        .block_mouse_except_scroll()
16415                                        .pl(cx.anchor_x)
16416                                        .child(EditorElement::new(
16417                                            &rename_editor,
16418                                            EditorStyle {
16419                                                background: cx.theme().system().transparent,
16420                                                local_player: cx.editor_style.local_player,
16421                                                text: text_style,
16422                                                scrollbar_width: cx.editor_style.scrollbar_width,
16423                                                syntax: cx.editor_style.syntax.clone(),
16424                                                status: cx.editor_style.status.clone(),
16425                                                inlay_hints_style: HighlightStyle {
16426                                                    font_weight: Some(FontWeight::BOLD),
16427                                                    ..make_inlay_hints_style(cx.app)
16428                                                },
16429                                                edit_prediction_styles: make_suggestion_styles(
16430                                                    cx.app,
16431                                                ),
16432                                                ..EditorStyle::default()
16433                                            },
16434                                        ))
16435                                        .into_any_element()
16436                                }
16437                            }),
16438                            priority: 0,
16439                        }],
16440                        Some(Autoscroll::fit()),
16441                        cx,
16442                    )[0];
16443                    this.pending_rename = Some(RenameState {
16444                        range,
16445                        old_name,
16446                        editor: rename_editor,
16447                        block_id,
16448                    });
16449                })?;
16450            }
16451
16452            Ok(())
16453        }))
16454    }
16455
16456    pub fn confirm_rename(
16457        &mut self,
16458        _: &ConfirmRename,
16459        window: &mut Window,
16460        cx: &mut Context<Self>,
16461    ) -> Option<Task<Result<()>>> {
16462        let rename = self.take_rename(false, window, cx)?;
16463        let workspace = self.workspace()?.downgrade();
16464        let (buffer, start) = self
16465            .buffer
16466            .read(cx)
16467            .text_anchor_for_position(rename.range.start, cx)?;
16468        let (end_buffer, _) = self
16469            .buffer
16470            .read(cx)
16471            .text_anchor_for_position(rename.range.end, cx)?;
16472        if buffer != end_buffer {
16473            return None;
16474        }
16475
16476        let old_name = rename.old_name;
16477        let new_name = rename.editor.read(cx).text(cx);
16478
16479        let rename = self.semantics_provider.as_ref()?.perform_rename(
16480            &buffer,
16481            start,
16482            new_name.clone(),
16483            cx,
16484        )?;
16485
16486        Some(cx.spawn_in(window, async move |editor, cx| {
16487            let project_transaction = rename.await?;
16488            Self::open_project_transaction(
16489                &editor,
16490                workspace,
16491                project_transaction,
16492                format!("Rename: {}{}", old_name, new_name),
16493                cx,
16494            )
16495            .await?;
16496
16497            editor.update(cx, |editor, cx| {
16498                editor.refresh_document_highlights(cx);
16499            })?;
16500            Ok(())
16501        }))
16502    }
16503
16504    fn take_rename(
16505        &mut self,
16506        moving_cursor: bool,
16507        window: &mut Window,
16508        cx: &mut Context<Self>,
16509    ) -> Option<RenameState> {
16510        let rename = self.pending_rename.take()?;
16511        if rename.editor.focus_handle(cx).is_focused(window) {
16512            window.focus(&self.focus_handle);
16513        }
16514
16515        self.remove_blocks(
16516            [rename.block_id].into_iter().collect(),
16517            Some(Autoscroll::fit()),
16518            cx,
16519        );
16520        self.clear_highlights::<Rename>(cx);
16521        self.show_local_selections = true;
16522
16523        if moving_cursor {
16524            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16525                editor.selections.newest::<usize>(cx).head()
16526            });
16527
16528            // Update the selection to match the position of the selection inside
16529            // the rename editor.
16530            let snapshot = self.buffer.read(cx).read(cx);
16531            let rename_range = rename.range.to_offset(&snapshot);
16532            let cursor_in_editor = snapshot
16533                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16534                .min(rename_range.end);
16535            drop(snapshot);
16536
16537            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16538                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16539            });
16540        } else {
16541            self.refresh_document_highlights(cx);
16542        }
16543
16544        Some(rename)
16545    }
16546
16547    pub fn pending_rename(&self) -> Option<&RenameState> {
16548        self.pending_rename.as_ref()
16549    }
16550
16551    fn format(
16552        &mut self,
16553        _: &Format,
16554        window: &mut Window,
16555        cx: &mut Context<Self>,
16556    ) -> Option<Task<Result<()>>> {
16557        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16558
16559        let project = match &self.project {
16560            Some(project) => project.clone(),
16561            None => return None,
16562        };
16563
16564        Some(self.perform_format(
16565            project,
16566            FormatTrigger::Manual,
16567            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16568            window,
16569            cx,
16570        ))
16571    }
16572
16573    fn format_selections(
16574        &mut self,
16575        _: &FormatSelections,
16576        window: &mut Window,
16577        cx: &mut Context<Self>,
16578    ) -> Option<Task<Result<()>>> {
16579        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16580
16581        let project = match &self.project {
16582            Some(project) => project.clone(),
16583            None => return None,
16584        };
16585
16586        let ranges = self
16587            .selections
16588            .all_adjusted(cx)
16589            .into_iter()
16590            .map(|selection| selection.range())
16591            .collect_vec();
16592
16593        Some(self.perform_format(
16594            project,
16595            FormatTrigger::Manual,
16596            FormatTarget::Ranges(ranges),
16597            window,
16598            cx,
16599        ))
16600    }
16601
16602    fn perform_format(
16603        &mut self,
16604        project: Entity<Project>,
16605        trigger: FormatTrigger,
16606        target: FormatTarget,
16607        window: &mut Window,
16608        cx: &mut Context<Self>,
16609    ) -> Task<Result<()>> {
16610        let buffer = self.buffer.clone();
16611        let (buffers, target) = match target {
16612            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16613            FormatTarget::Ranges(selection_ranges) => {
16614                let multi_buffer = buffer.read(cx);
16615                let snapshot = multi_buffer.read(cx);
16616                let mut buffers = HashSet::default();
16617                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16618                    BTreeMap::new();
16619                for selection_range in selection_ranges {
16620                    for (buffer, buffer_range, _) in
16621                        snapshot.range_to_buffer_ranges(selection_range)
16622                    {
16623                        let buffer_id = buffer.remote_id();
16624                        let start = buffer.anchor_before(buffer_range.start);
16625                        let end = buffer.anchor_after(buffer_range.end);
16626                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16627                        buffer_id_to_ranges
16628                            .entry(buffer_id)
16629                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16630                            .or_insert_with(|| vec![start..end]);
16631                    }
16632                }
16633                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16634            }
16635        };
16636
16637        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16638        let selections_prev = transaction_id_prev
16639            .and_then(|transaction_id_prev| {
16640                // default to selections as they were after the last edit, if we have them,
16641                // instead of how they are now.
16642                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16643                // will take you back to where you made the last edit, instead of staying where you scrolled
16644                self.selection_history
16645                    .transaction(transaction_id_prev)
16646                    .map(|t| t.0.clone())
16647            })
16648            .unwrap_or_else(|| {
16649                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16650                self.selections.disjoint_anchors()
16651            });
16652
16653        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16654        let format = project.update(cx, |project, cx| {
16655            project.format(buffers, target, true, trigger, cx)
16656        });
16657
16658        cx.spawn_in(window, async move |editor, cx| {
16659            let transaction = futures::select_biased! {
16660                transaction = format.log_err().fuse() => transaction,
16661                () = timeout => {
16662                    log::warn!("timed out waiting for formatting");
16663                    None
16664                }
16665            };
16666
16667            buffer
16668                .update(cx, |buffer, cx| {
16669                    if let Some(transaction) = transaction {
16670                        if !buffer.is_singleton() {
16671                            buffer.push_transaction(&transaction.0, cx);
16672                        }
16673                    }
16674                    cx.notify();
16675                })
16676                .ok();
16677
16678            if let Some(transaction_id_now) =
16679                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16680            {
16681                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16682                if has_new_transaction {
16683                    _ = editor.update(cx, |editor, _| {
16684                        editor
16685                            .selection_history
16686                            .insert_transaction(transaction_id_now, selections_prev);
16687                    });
16688                }
16689            }
16690
16691            Ok(())
16692        })
16693    }
16694
16695    fn organize_imports(
16696        &mut self,
16697        _: &OrganizeImports,
16698        window: &mut Window,
16699        cx: &mut Context<Self>,
16700    ) -> Option<Task<Result<()>>> {
16701        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16702        let project = match &self.project {
16703            Some(project) => project.clone(),
16704            None => return None,
16705        };
16706        Some(self.perform_code_action_kind(
16707            project,
16708            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16709            window,
16710            cx,
16711        ))
16712    }
16713
16714    fn perform_code_action_kind(
16715        &mut self,
16716        project: Entity<Project>,
16717        kind: CodeActionKind,
16718        window: &mut Window,
16719        cx: &mut Context<Self>,
16720    ) -> Task<Result<()>> {
16721        let buffer = self.buffer.clone();
16722        let buffers = buffer.read(cx).all_buffers();
16723        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16724        let apply_action = project.update(cx, |project, cx| {
16725            project.apply_code_action_kind(buffers, kind, true, cx)
16726        });
16727        cx.spawn_in(window, async move |_, cx| {
16728            let transaction = futures::select_biased! {
16729                () = timeout => {
16730                    log::warn!("timed out waiting for executing code action");
16731                    None
16732                }
16733                transaction = apply_action.log_err().fuse() => transaction,
16734            };
16735            buffer
16736                .update(cx, |buffer, cx| {
16737                    // check if we need this
16738                    if let Some(transaction) = transaction {
16739                        if !buffer.is_singleton() {
16740                            buffer.push_transaction(&transaction.0, cx);
16741                        }
16742                    }
16743                    cx.notify();
16744                })
16745                .ok();
16746            Ok(())
16747        })
16748    }
16749
16750    pub fn restart_language_server(
16751        &mut self,
16752        _: &RestartLanguageServer,
16753        _: &mut Window,
16754        cx: &mut Context<Self>,
16755    ) {
16756        if let Some(project) = self.project.clone() {
16757            self.buffer.update(cx, |multi_buffer, cx| {
16758                project.update(cx, |project, cx| {
16759                    project.restart_language_servers_for_buffers(
16760                        multi_buffer.all_buffers().into_iter().collect(),
16761                        HashSet::default(),
16762                        cx,
16763                    );
16764                });
16765            })
16766        }
16767    }
16768
16769    pub fn stop_language_server(
16770        &mut self,
16771        _: &StopLanguageServer,
16772        _: &mut Window,
16773        cx: &mut Context<Self>,
16774    ) {
16775        if let Some(project) = self.project.clone() {
16776            self.buffer.update(cx, |multi_buffer, cx| {
16777                project.update(cx, |project, cx| {
16778                    project.stop_language_servers_for_buffers(
16779                        multi_buffer.all_buffers().into_iter().collect(),
16780                        HashSet::default(),
16781                        cx,
16782                    );
16783                    cx.emit(project::Event::RefreshInlayHints);
16784                });
16785            });
16786        }
16787    }
16788
16789    fn cancel_language_server_work(
16790        workspace: &mut Workspace,
16791        _: &actions::CancelLanguageServerWork,
16792        _: &mut Window,
16793        cx: &mut Context<Workspace>,
16794    ) {
16795        let project = workspace.project();
16796        let buffers = workspace
16797            .active_item(cx)
16798            .and_then(|item| item.act_as::<Editor>(cx))
16799            .map_or(HashSet::default(), |editor| {
16800                editor.read(cx).buffer.read(cx).all_buffers()
16801            });
16802        project.update(cx, |project, cx| {
16803            project.cancel_language_server_work_for_buffers(buffers, cx);
16804        });
16805    }
16806
16807    fn show_character_palette(
16808        &mut self,
16809        _: &ShowCharacterPalette,
16810        window: &mut Window,
16811        _: &mut Context<Self>,
16812    ) {
16813        window.show_character_palette();
16814    }
16815
16816    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16817        if !self.diagnostics_enabled() {
16818            return;
16819        }
16820
16821        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16822            let buffer = self.buffer.read(cx).snapshot(cx);
16823            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16824            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16825            let is_valid = buffer
16826                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16827                .any(|entry| {
16828                    entry.diagnostic.is_primary
16829                        && !entry.range.is_empty()
16830                        && entry.range.start == primary_range_start
16831                        && entry.diagnostic.message == active_diagnostics.active_message
16832                });
16833
16834            if !is_valid {
16835                self.dismiss_diagnostics(cx);
16836            }
16837        }
16838    }
16839
16840    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16841        match &self.active_diagnostics {
16842            ActiveDiagnostic::Group(group) => Some(group),
16843            _ => None,
16844        }
16845    }
16846
16847    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16848        if !self.diagnostics_enabled() {
16849            return;
16850        }
16851        self.dismiss_diagnostics(cx);
16852        self.active_diagnostics = ActiveDiagnostic::All;
16853    }
16854
16855    fn activate_diagnostics(
16856        &mut self,
16857        buffer_id: BufferId,
16858        diagnostic: DiagnosticEntry<usize>,
16859        window: &mut Window,
16860        cx: &mut Context<Self>,
16861    ) {
16862        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16863            return;
16864        }
16865        self.dismiss_diagnostics(cx);
16866        let snapshot = self.snapshot(window, cx);
16867        let buffer = self.buffer.read(cx).snapshot(cx);
16868        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16869            return;
16870        };
16871
16872        let diagnostic_group = buffer
16873            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16874            .collect::<Vec<_>>();
16875
16876        let blocks =
16877            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16878
16879        let blocks = self.display_map.update(cx, |display_map, cx| {
16880            display_map.insert_blocks(blocks, cx).into_iter().collect()
16881        });
16882        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16883            active_range: buffer.anchor_before(diagnostic.range.start)
16884                ..buffer.anchor_after(diagnostic.range.end),
16885            active_message: diagnostic.diagnostic.message.clone(),
16886            group_id: diagnostic.diagnostic.group_id,
16887            blocks,
16888        });
16889        cx.notify();
16890    }
16891
16892    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16893        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16894            return;
16895        };
16896
16897        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16898        if let ActiveDiagnostic::Group(group) = prev {
16899            self.display_map.update(cx, |display_map, cx| {
16900                display_map.remove_blocks(group.blocks, cx);
16901            });
16902            cx.notify();
16903        }
16904    }
16905
16906    /// Disable inline diagnostics rendering for this editor.
16907    pub fn disable_inline_diagnostics(&mut self) {
16908        self.inline_diagnostics_enabled = false;
16909        self.inline_diagnostics_update = Task::ready(());
16910        self.inline_diagnostics.clear();
16911    }
16912
16913    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16914        self.diagnostics_enabled = false;
16915        self.dismiss_diagnostics(cx);
16916        self.inline_diagnostics_update = Task::ready(());
16917        self.inline_diagnostics.clear();
16918    }
16919
16920    pub fn diagnostics_enabled(&self) -> bool {
16921        self.diagnostics_enabled && self.mode.is_full()
16922    }
16923
16924    pub fn inline_diagnostics_enabled(&self) -> bool {
16925        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16926    }
16927
16928    pub fn show_inline_diagnostics(&self) -> bool {
16929        self.show_inline_diagnostics
16930    }
16931
16932    pub fn toggle_inline_diagnostics(
16933        &mut self,
16934        _: &ToggleInlineDiagnostics,
16935        window: &mut Window,
16936        cx: &mut Context<Editor>,
16937    ) {
16938        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16939        self.refresh_inline_diagnostics(false, window, cx);
16940    }
16941
16942    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16943        self.diagnostics_max_severity = severity;
16944        self.display_map.update(cx, |display_map, _| {
16945            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16946        });
16947    }
16948
16949    pub fn toggle_diagnostics(
16950        &mut self,
16951        _: &ToggleDiagnostics,
16952        window: &mut Window,
16953        cx: &mut Context<Editor>,
16954    ) {
16955        if !self.diagnostics_enabled() {
16956            return;
16957        }
16958
16959        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16960            EditorSettings::get_global(cx)
16961                .diagnostics_max_severity
16962                .filter(|severity| severity != &DiagnosticSeverity::Off)
16963                .unwrap_or(DiagnosticSeverity::Hint)
16964        } else {
16965            DiagnosticSeverity::Off
16966        };
16967        self.set_max_diagnostics_severity(new_severity, cx);
16968        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16969            self.active_diagnostics = ActiveDiagnostic::None;
16970            self.inline_diagnostics_update = Task::ready(());
16971            self.inline_diagnostics.clear();
16972        } else {
16973            self.refresh_inline_diagnostics(false, window, cx);
16974        }
16975
16976        cx.notify();
16977    }
16978
16979    pub fn toggle_minimap(
16980        &mut self,
16981        _: &ToggleMinimap,
16982        window: &mut Window,
16983        cx: &mut Context<Editor>,
16984    ) {
16985        if self.supports_minimap(cx) {
16986            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16987        }
16988    }
16989
16990    fn refresh_inline_diagnostics(
16991        &mut self,
16992        debounce: bool,
16993        window: &mut Window,
16994        cx: &mut Context<Self>,
16995    ) {
16996        let max_severity = ProjectSettings::get_global(cx)
16997            .diagnostics
16998            .inline
16999            .max_severity
17000            .unwrap_or(self.diagnostics_max_severity);
17001
17002        if !self.inline_diagnostics_enabled()
17003            || !self.show_inline_diagnostics
17004            || max_severity == DiagnosticSeverity::Off
17005        {
17006            self.inline_diagnostics_update = Task::ready(());
17007            self.inline_diagnostics.clear();
17008            return;
17009        }
17010
17011        let debounce_ms = ProjectSettings::get_global(cx)
17012            .diagnostics
17013            .inline
17014            .update_debounce_ms;
17015        let debounce = if debounce && debounce_ms > 0 {
17016            Some(Duration::from_millis(debounce_ms))
17017        } else {
17018            None
17019        };
17020        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17021            if let Some(debounce) = debounce {
17022                cx.background_executor().timer(debounce).await;
17023            }
17024            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17025                editor
17026                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17027                    .ok()
17028            }) else {
17029                return;
17030            };
17031
17032            let new_inline_diagnostics = cx
17033                .background_spawn(async move {
17034                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17035                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17036                        let message = diagnostic_entry
17037                            .diagnostic
17038                            .message
17039                            .split_once('\n')
17040                            .map(|(line, _)| line)
17041                            .map(SharedString::new)
17042                            .unwrap_or_else(|| {
17043                                SharedString::from(diagnostic_entry.diagnostic.message)
17044                            });
17045                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17046                        let (Ok(i) | Err(i)) = inline_diagnostics
17047                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17048                        inline_diagnostics.insert(
17049                            i,
17050                            (
17051                                start_anchor,
17052                                InlineDiagnostic {
17053                                    message,
17054                                    group_id: diagnostic_entry.diagnostic.group_id,
17055                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17056                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17057                                    severity: diagnostic_entry.diagnostic.severity,
17058                                },
17059                            ),
17060                        );
17061                    }
17062                    inline_diagnostics
17063                })
17064                .await;
17065
17066            editor
17067                .update(cx, |editor, cx| {
17068                    editor.inline_diagnostics = new_inline_diagnostics;
17069                    cx.notify();
17070                })
17071                .ok();
17072        });
17073    }
17074
17075    fn pull_diagnostics(
17076        &mut self,
17077        buffer_id: Option<BufferId>,
17078        window: &Window,
17079        cx: &mut Context<Self>,
17080    ) -> Option<()> {
17081        if !self.mode().is_full() {
17082            return None;
17083        }
17084        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17085            .diagnostics
17086            .lsp_pull_diagnostics;
17087        if !pull_diagnostics_settings.enabled {
17088            return None;
17089        }
17090        let project = self.project()?.downgrade();
17091        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17092        let mut buffers = self.buffer.read(cx).all_buffers();
17093        if let Some(buffer_id) = buffer_id {
17094            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17095        }
17096
17097        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17098            cx.background_executor().timer(debounce).await;
17099
17100            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17101                buffers
17102                    .into_iter()
17103                    .filter_map(|buffer| {
17104                        project
17105                            .update(cx, |project, cx| {
17106                                project.lsp_store().update(cx, |lsp_store, cx| {
17107                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17108                                })
17109                            })
17110                            .ok()
17111                    })
17112                    .collect::<FuturesUnordered<_>>()
17113            }) else {
17114                return;
17115            };
17116
17117            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17118                match pull_task {
17119                    Ok(()) => {
17120                        if editor
17121                            .update_in(cx, |editor, window, cx| {
17122                                editor.update_diagnostics_state(window, cx);
17123                            })
17124                            .is_err()
17125                        {
17126                            return;
17127                        }
17128                    }
17129                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17130                }
17131            }
17132        });
17133
17134        Some(())
17135    }
17136
17137    pub fn set_selections_from_remote(
17138        &mut self,
17139        selections: Vec<Selection<Anchor>>,
17140        pending_selection: Option<Selection<Anchor>>,
17141        window: &mut Window,
17142        cx: &mut Context<Self>,
17143    ) {
17144        let old_cursor_position = self.selections.newest_anchor().head();
17145        self.selections.change_with(cx, |s| {
17146            s.select_anchors(selections);
17147            if let Some(pending_selection) = pending_selection {
17148                s.set_pending(pending_selection, SelectMode::Character);
17149            } else {
17150                s.clear_pending();
17151            }
17152        });
17153        self.selections_did_change(
17154            false,
17155            &old_cursor_position,
17156            SelectionEffects::default(),
17157            window,
17158            cx,
17159        );
17160    }
17161
17162    pub fn transact(
17163        &mut self,
17164        window: &mut Window,
17165        cx: &mut Context<Self>,
17166        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17167    ) -> Option<TransactionId> {
17168        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17169            this.start_transaction_at(Instant::now(), window, cx);
17170            update(this, window, cx);
17171            this.end_transaction_at(Instant::now(), cx)
17172        })
17173    }
17174
17175    pub fn start_transaction_at(
17176        &mut self,
17177        now: Instant,
17178        window: &mut Window,
17179        cx: &mut Context<Self>,
17180    ) -> Option<TransactionId> {
17181        self.end_selection(window, cx);
17182        if let Some(tx_id) = self
17183            .buffer
17184            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17185        {
17186            self.selection_history
17187                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17188            cx.emit(EditorEvent::TransactionBegun {
17189                transaction_id: tx_id,
17190            });
17191            Some(tx_id)
17192        } else {
17193            None
17194        }
17195    }
17196
17197    pub fn end_transaction_at(
17198        &mut self,
17199        now: Instant,
17200        cx: &mut Context<Self>,
17201    ) -> Option<TransactionId> {
17202        if let Some(transaction_id) = self
17203            .buffer
17204            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17205        {
17206            if let Some((_, end_selections)) =
17207                self.selection_history.transaction_mut(transaction_id)
17208            {
17209                *end_selections = Some(self.selections.disjoint_anchors());
17210            } else {
17211                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17212            }
17213
17214            cx.emit(EditorEvent::Edited { transaction_id });
17215            Some(transaction_id)
17216        } else {
17217            None
17218        }
17219    }
17220
17221    pub fn modify_transaction_selection_history(
17222        &mut self,
17223        transaction_id: TransactionId,
17224        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17225    ) -> bool {
17226        self.selection_history
17227            .transaction_mut(transaction_id)
17228            .map(modify)
17229            .is_some()
17230    }
17231
17232    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17233        if self.selection_mark_mode {
17234            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17235                s.move_with(|_, sel| {
17236                    sel.collapse_to(sel.head(), SelectionGoal::None);
17237                });
17238            })
17239        }
17240        self.selection_mark_mode = true;
17241        cx.notify();
17242    }
17243
17244    pub fn swap_selection_ends(
17245        &mut self,
17246        _: &actions::SwapSelectionEnds,
17247        window: &mut Window,
17248        cx: &mut Context<Self>,
17249    ) {
17250        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17251            s.move_with(|_, sel| {
17252                if sel.start != sel.end {
17253                    sel.reversed = !sel.reversed
17254                }
17255            });
17256        });
17257        self.request_autoscroll(Autoscroll::newest(), cx);
17258        cx.notify();
17259    }
17260
17261    pub fn toggle_focus(
17262        workspace: &mut Workspace,
17263        _: &actions::ToggleFocus,
17264        window: &mut Window,
17265        cx: &mut Context<Workspace>,
17266    ) {
17267        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17268            return;
17269        };
17270        workspace.activate_item(&item, true, true, window, cx);
17271    }
17272
17273    pub fn toggle_fold(
17274        &mut self,
17275        _: &actions::ToggleFold,
17276        window: &mut Window,
17277        cx: &mut Context<Self>,
17278    ) {
17279        if self.is_singleton(cx) {
17280            let selection = self.selections.newest::<Point>(cx);
17281
17282            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17283            let range = if selection.is_empty() {
17284                let point = selection.head().to_display_point(&display_map);
17285                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17286                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17287                    .to_point(&display_map);
17288                start..end
17289            } else {
17290                selection.range()
17291            };
17292            if display_map.folds_in_range(range).next().is_some() {
17293                self.unfold_lines(&Default::default(), window, cx)
17294            } else {
17295                self.fold(&Default::default(), window, cx)
17296            }
17297        } else {
17298            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17299            let buffer_ids: HashSet<_> = self
17300                .selections
17301                .disjoint_anchor_ranges()
17302                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17303                .collect();
17304
17305            let should_unfold = buffer_ids
17306                .iter()
17307                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17308
17309            for buffer_id in buffer_ids {
17310                if should_unfold {
17311                    self.unfold_buffer(buffer_id, cx);
17312                } else {
17313                    self.fold_buffer(buffer_id, cx);
17314                }
17315            }
17316        }
17317    }
17318
17319    pub fn toggle_fold_recursive(
17320        &mut self,
17321        _: &actions::ToggleFoldRecursive,
17322        window: &mut Window,
17323        cx: &mut Context<Self>,
17324    ) {
17325        let selection = self.selections.newest::<Point>(cx);
17326
17327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17328        let range = if selection.is_empty() {
17329            let point = selection.head().to_display_point(&display_map);
17330            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17331            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17332                .to_point(&display_map);
17333            start..end
17334        } else {
17335            selection.range()
17336        };
17337        if display_map.folds_in_range(range).next().is_some() {
17338            self.unfold_recursive(&Default::default(), window, cx)
17339        } else {
17340            self.fold_recursive(&Default::default(), window, cx)
17341        }
17342    }
17343
17344    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17345        if self.is_singleton(cx) {
17346            let mut to_fold = Vec::new();
17347            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17348            let selections = self.selections.all_adjusted(cx);
17349
17350            for selection in selections {
17351                let range = selection.range().sorted();
17352                let buffer_start_row = range.start.row;
17353
17354                if range.start.row != range.end.row {
17355                    let mut found = false;
17356                    let mut row = range.start.row;
17357                    while row <= range.end.row {
17358                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17359                        {
17360                            found = true;
17361                            row = crease.range().end.row + 1;
17362                            to_fold.push(crease);
17363                        } else {
17364                            row += 1
17365                        }
17366                    }
17367                    if found {
17368                        continue;
17369                    }
17370                }
17371
17372                for row in (0..=range.start.row).rev() {
17373                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17374                        if crease.range().end.row >= buffer_start_row {
17375                            to_fold.push(crease);
17376                            if row <= range.start.row {
17377                                break;
17378                            }
17379                        }
17380                    }
17381                }
17382            }
17383
17384            self.fold_creases(to_fold, true, window, cx);
17385        } else {
17386            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17387            let buffer_ids = self
17388                .selections
17389                .disjoint_anchor_ranges()
17390                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17391                .collect::<HashSet<_>>();
17392            for buffer_id in buffer_ids {
17393                self.fold_buffer(buffer_id, cx);
17394            }
17395        }
17396    }
17397
17398    pub fn toggle_fold_all(
17399        &mut self,
17400        _: &actions::ToggleFoldAll,
17401        window: &mut Window,
17402        cx: &mut Context<Self>,
17403    ) {
17404        if self.buffer.read(cx).is_singleton() {
17405            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17406            let has_folds = display_map
17407                .folds_in_range(0..display_map.buffer_snapshot.len())
17408                .next()
17409                .is_some();
17410
17411            if has_folds {
17412                self.unfold_all(&actions::UnfoldAll, window, cx);
17413            } else {
17414                self.fold_all(&actions::FoldAll, window, cx);
17415            }
17416        } else {
17417            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17418            let should_unfold = buffer_ids
17419                .iter()
17420                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17421
17422            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17423                editor
17424                    .update_in(cx, |editor, _, cx| {
17425                        for buffer_id in buffer_ids {
17426                            if should_unfold {
17427                                editor.unfold_buffer(buffer_id, cx);
17428                            } else {
17429                                editor.fold_buffer(buffer_id, cx);
17430                            }
17431                        }
17432                    })
17433                    .ok();
17434            });
17435        }
17436    }
17437
17438    fn fold_at_level(
17439        &mut self,
17440        fold_at: &FoldAtLevel,
17441        window: &mut Window,
17442        cx: &mut Context<Self>,
17443    ) {
17444        if !self.buffer.read(cx).is_singleton() {
17445            return;
17446        }
17447
17448        let fold_at_level = fold_at.0;
17449        let snapshot = self.buffer.read(cx).snapshot(cx);
17450        let mut to_fold = Vec::new();
17451        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17452
17453        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17454            while start_row < end_row {
17455                match self
17456                    .snapshot(window, cx)
17457                    .crease_for_buffer_row(MultiBufferRow(start_row))
17458                {
17459                    Some(crease) => {
17460                        let nested_start_row = crease.range().start.row + 1;
17461                        let nested_end_row = crease.range().end.row;
17462
17463                        if current_level < fold_at_level {
17464                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17465                        } else if current_level == fold_at_level {
17466                            to_fold.push(crease);
17467                        }
17468
17469                        start_row = nested_end_row + 1;
17470                    }
17471                    None => start_row += 1,
17472                }
17473            }
17474        }
17475
17476        self.fold_creases(to_fold, true, window, cx);
17477    }
17478
17479    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17480        if self.buffer.read(cx).is_singleton() {
17481            let mut fold_ranges = Vec::new();
17482            let snapshot = self.buffer.read(cx).snapshot(cx);
17483
17484            for row in 0..snapshot.max_row().0 {
17485                if let Some(foldable_range) = self
17486                    .snapshot(window, cx)
17487                    .crease_for_buffer_row(MultiBufferRow(row))
17488                {
17489                    fold_ranges.push(foldable_range);
17490                }
17491            }
17492
17493            self.fold_creases(fold_ranges, true, window, cx);
17494        } else {
17495            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17496                editor
17497                    .update_in(cx, |editor, _, cx| {
17498                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17499                            editor.fold_buffer(buffer_id, cx);
17500                        }
17501                    })
17502                    .ok();
17503            });
17504        }
17505    }
17506
17507    pub fn fold_function_bodies(
17508        &mut self,
17509        _: &actions::FoldFunctionBodies,
17510        window: &mut Window,
17511        cx: &mut Context<Self>,
17512    ) {
17513        let snapshot = self.buffer.read(cx).snapshot(cx);
17514
17515        let ranges = snapshot
17516            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17517            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17518            .collect::<Vec<_>>();
17519
17520        let creases = ranges
17521            .into_iter()
17522            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17523            .collect();
17524
17525        self.fold_creases(creases, true, window, cx);
17526    }
17527
17528    pub fn fold_recursive(
17529        &mut self,
17530        _: &actions::FoldRecursive,
17531        window: &mut Window,
17532        cx: &mut Context<Self>,
17533    ) {
17534        let mut to_fold = Vec::new();
17535        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17536        let selections = self.selections.all_adjusted(cx);
17537
17538        for selection in selections {
17539            let range = selection.range().sorted();
17540            let buffer_start_row = range.start.row;
17541
17542            if range.start.row != range.end.row {
17543                let mut found = false;
17544                for row in range.start.row..=range.end.row {
17545                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17546                        found = true;
17547                        to_fold.push(crease);
17548                    }
17549                }
17550                if found {
17551                    continue;
17552                }
17553            }
17554
17555            for row in (0..=range.start.row).rev() {
17556                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17557                    if crease.range().end.row >= buffer_start_row {
17558                        to_fold.push(crease);
17559                    } else {
17560                        break;
17561                    }
17562                }
17563            }
17564        }
17565
17566        self.fold_creases(to_fold, true, window, cx);
17567    }
17568
17569    pub fn fold_at(
17570        &mut self,
17571        buffer_row: MultiBufferRow,
17572        window: &mut Window,
17573        cx: &mut Context<Self>,
17574    ) {
17575        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17576
17577        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17578            let autoscroll = self
17579                .selections
17580                .all::<Point>(cx)
17581                .iter()
17582                .any(|selection| crease.range().overlaps(&selection.range()));
17583
17584            self.fold_creases(vec![crease], autoscroll, window, cx);
17585        }
17586    }
17587
17588    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17589        if self.is_singleton(cx) {
17590            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17591            let buffer = &display_map.buffer_snapshot;
17592            let selections = self.selections.all::<Point>(cx);
17593            let ranges = selections
17594                .iter()
17595                .map(|s| {
17596                    let range = s.display_range(&display_map).sorted();
17597                    let mut start = range.start.to_point(&display_map);
17598                    let mut end = range.end.to_point(&display_map);
17599                    start.column = 0;
17600                    end.column = buffer.line_len(MultiBufferRow(end.row));
17601                    start..end
17602                })
17603                .collect::<Vec<_>>();
17604
17605            self.unfold_ranges(&ranges, true, true, cx);
17606        } else {
17607            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17608            let buffer_ids = self
17609                .selections
17610                .disjoint_anchor_ranges()
17611                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17612                .collect::<HashSet<_>>();
17613            for buffer_id in buffer_ids {
17614                self.unfold_buffer(buffer_id, cx);
17615            }
17616        }
17617    }
17618
17619    pub fn unfold_recursive(
17620        &mut self,
17621        _: &UnfoldRecursive,
17622        _window: &mut Window,
17623        cx: &mut Context<Self>,
17624    ) {
17625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17626        let selections = self.selections.all::<Point>(cx);
17627        let ranges = selections
17628            .iter()
17629            .map(|s| {
17630                let mut range = s.display_range(&display_map).sorted();
17631                *range.start.column_mut() = 0;
17632                *range.end.column_mut() = display_map.line_len(range.end.row());
17633                let start = range.start.to_point(&display_map);
17634                let end = range.end.to_point(&display_map);
17635                start..end
17636            })
17637            .collect::<Vec<_>>();
17638
17639        self.unfold_ranges(&ranges, true, true, cx);
17640    }
17641
17642    pub fn unfold_at(
17643        &mut self,
17644        buffer_row: MultiBufferRow,
17645        _window: &mut Window,
17646        cx: &mut Context<Self>,
17647    ) {
17648        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17649
17650        let intersection_range = Point::new(buffer_row.0, 0)
17651            ..Point::new(
17652                buffer_row.0,
17653                display_map.buffer_snapshot.line_len(buffer_row),
17654            );
17655
17656        let autoscroll = self
17657            .selections
17658            .all::<Point>(cx)
17659            .iter()
17660            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17661
17662        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17663    }
17664
17665    pub fn unfold_all(
17666        &mut self,
17667        _: &actions::UnfoldAll,
17668        _window: &mut Window,
17669        cx: &mut Context<Self>,
17670    ) {
17671        if self.buffer.read(cx).is_singleton() {
17672            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17673            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17674        } else {
17675            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17676                editor
17677                    .update(cx, |editor, cx| {
17678                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17679                            editor.unfold_buffer(buffer_id, cx);
17680                        }
17681                    })
17682                    .ok();
17683            });
17684        }
17685    }
17686
17687    pub fn fold_selected_ranges(
17688        &mut self,
17689        _: &FoldSelectedRanges,
17690        window: &mut Window,
17691        cx: &mut Context<Self>,
17692    ) {
17693        let selections = self.selections.all_adjusted(cx);
17694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17695        let ranges = selections
17696            .into_iter()
17697            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17698            .collect::<Vec<_>>();
17699        self.fold_creases(ranges, true, window, cx);
17700    }
17701
17702    pub fn fold_ranges<T: ToOffset + Clone>(
17703        &mut self,
17704        ranges: Vec<Range<T>>,
17705        auto_scroll: bool,
17706        window: &mut Window,
17707        cx: &mut Context<Self>,
17708    ) {
17709        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17710        let ranges = ranges
17711            .into_iter()
17712            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17713            .collect::<Vec<_>>();
17714        self.fold_creases(ranges, auto_scroll, window, cx);
17715    }
17716
17717    pub fn fold_creases<T: ToOffset + Clone>(
17718        &mut self,
17719        creases: Vec<Crease<T>>,
17720        auto_scroll: bool,
17721        _window: &mut Window,
17722        cx: &mut Context<Self>,
17723    ) {
17724        if creases.is_empty() {
17725            return;
17726        }
17727
17728        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17729
17730        if auto_scroll {
17731            self.request_autoscroll(Autoscroll::fit(), cx);
17732        }
17733
17734        cx.notify();
17735
17736        self.scrollbar_marker_state.dirty = true;
17737        self.folds_did_change(cx);
17738    }
17739
17740    /// Removes any folds whose ranges intersect any of the given ranges.
17741    pub fn unfold_ranges<T: ToOffset + Clone>(
17742        &mut self,
17743        ranges: &[Range<T>],
17744        inclusive: bool,
17745        auto_scroll: bool,
17746        cx: &mut Context<Self>,
17747    ) {
17748        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17749            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17750        });
17751        self.folds_did_change(cx);
17752    }
17753
17754    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17755        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17756            return;
17757        }
17758        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17759        self.display_map.update(cx, |display_map, cx| {
17760            display_map.fold_buffers([buffer_id], cx)
17761        });
17762        cx.emit(EditorEvent::BufferFoldToggled {
17763            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17764            folded: true,
17765        });
17766        cx.notify();
17767    }
17768
17769    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17770        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17771            return;
17772        }
17773        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17774        self.display_map.update(cx, |display_map, cx| {
17775            display_map.unfold_buffers([buffer_id], cx);
17776        });
17777        cx.emit(EditorEvent::BufferFoldToggled {
17778            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17779            folded: false,
17780        });
17781        cx.notify();
17782    }
17783
17784    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17785        self.display_map.read(cx).is_buffer_folded(buffer)
17786    }
17787
17788    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17789        self.display_map.read(cx).folded_buffers()
17790    }
17791
17792    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17793        self.display_map.update(cx, |display_map, cx| {
17794            display_map.disable_header_for_buffer(buffer_id, cx);
17795        });
17796        cx.notify();
17797    }
17798
17799    /// Removes any folds with the given ranges.
17800    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17801        &mut self,
17802        ranges: &[Range<T>],
17803        type_id: TypeId,
17804        auto_scroll: bool,
17805        cx: &mut Context<Self>,
17806    ) {
17807        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17808            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17809        });
17810        self.folds_did_change(cx);
17811    }
17812
17813    fn remove_folds_with<T: ToOffset + Clone>(
17814        &mut self,
17815        ranges: &[Range<T>],
17816        auto_scroll: bool,
17817        cx: &mut Context<Self>,
17818        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17819    ) {
17820        if ranges.is_empty() {
17821            return;
17822        }
17823
17824        let mut buffers_affected = HashSet::default();
17825        let multi_buffer = self.buffer().read(cx);
17826        for range in ranges {
17827            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17828                buffers_affected.insert(buffer.read(cx).remote_id());
17829            };
17830        }
17831
17832        self.display_map.update(cx, update);
17833
17834        if auto_scroll {
17835            self.request_autoscroll(Autoscroll::fit(), cx);
17836        }
17837
17838        cx.notify();
17839        self.scrollbar_marker_state.dirty = true;
17840        self.active_indent_guides_state.dirty = true;
17841    }
17842
17843    pub fn update_renderer_widths(
17844        &mut self,
17845        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17846        cx: &mut Context<Self>,
17847    ) -> bool {
17848        self.display_map
17849            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17850    }
17851
17852    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17853        self.display_map.read(cx).fold_placeholder.clone()
17854    }
17855
17856    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17857        self.buffer.update(cx, |buffer, cx| {
17858            buffer.set_all_diff_hunks_expanded(cx);
17859        });
17860    }
17861
17862    pub fn expand_all_diff_hunks(
17863        &mut self,
17864        _: &ExpandAllDiffHunks,
17865        _window: &mut Window,
17866        cx: &mut Context<Self>,
17867    ) {
17868        self.buffer.update(cx, |buffer, cx| {
17869            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17870        });
17871    }
17872
17873    pub fn toggle_selected_diff_hunks(
17874        &mut self,
17875        _: &ToggleSelectedDiffHunks,
17876        _window: &mut Window,
17877        cx: &mut Context<Self>,
17878    ) {
17879        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17880        self.toggle_diff_hunks_in_ranges(ranges, cx);
17881    }
17882
17883    pub fn diff_hunks_in_ranges<'a>(
17884        &'a self,
17885        ranges: &'a [Range<Anchor>],
17886        buffer: &'a MultiBufferSnapshot,
17887    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17888        ranges.iter().flat_map(move |range| {
17889            let end_excerpt_id = range.end.excerpt_id;
17890            let range = range.to_point(buffer);
17891            let mut peek_end = range.end;
17892            if range.end.row < buffer.max_row().0 {
17893                peek_end = Point::new(range.end.row + 1, 0);
17894            }
17895            buffer
17896                .diff_hunks_in_range(range.start..peek_end)
17897                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17898        })
17899    }
17900
17901    pub fn has_stageable_diff_hunks_in_ranges(
17902        &self,
17903        ranges: &[Range<Anchor>],
17904        snapshot: &MultiBufferSnapshot,
17905    ) -> bool {
17906        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17907        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17908    }
17909
17910    pub fn toggle_staged_selected_diff_hunks(
17911        &mut self,
17912        _: &::git::ToggleStaged,
17913        _: &mut Window,
17914        cx: &mut Context<Self>,
17915    ) {
17916        let snapshot = self.buffer.read(cx).snapshot(cx);
17917        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17918        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17919        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17920    }
17921
17922    pub fn set_render_diff_hunk_controls(
17923        &mut self,
17924        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17925        cx: &mut Context<Self>,
17926    ) {
17927        self.render_diff_hunk_controls = render_diff_hunk_controls;
17928        cx.notify();
17929    }
17930
17931    pub fn stage_and_next(
17932        &mut self,
17933        _: &::git::StageAndNext,
17934        window: &mut Window,
17935        cx: &mut Context<Self>,
17936    ) {
17937        self.do_stage_or_unstage_and_next(true, window, cx);
17938    }
17939
17940    pub fn unstage_and_next(
17941        &mut self,
17942        _: &::git::UnstageAndNext,
17943        window: &mut Window,
17944        cx: &mut Context<Self>,
17945    ) {
17946        self.do_stage_or_unstage_and_next(false, window, cx);
17947    }
17948
17949    pub fn stage_or_unstage_diff_hunks(
17950        &mut self,
17951        stage: bool,
17952        ranges: Vec<Range<Anchor>>,
17953        cx: &mut Context<Self>,
17954    ) {
17955        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17956        cx.spawn(async move |this, cx| {
17957            task.await?;
17958            this.update(cx, |this, cx| {
17959                let snapshot = this.buffer.read(cx).snapshot(cx);
17960                let chunk_by = this
17961                    .diff_hunks_in_ranges(&ranges, &snapshot)
17962                    .chunk_by(|hunk| hunk.buffer_id);
17963                for (buffer_id, hunks) in &chunk_by {
17964                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17965                }
17966            })
17967        })
17968        .detach_and_log_err(cx);
17969    }
17970
17971    fn save_buffers_for_ranges_if_needed(
17972        &mut self,
17973        ranges: &[Range<Anchor>],
17974        cx: &mut Context<Editor>,
17975    ) -> Task<Result<()>> {
17976        let multibuffer = self.buffer.read(cx);
17977        let snapshot = multibuffer.read(cx);
17978        let buffer_ids: HashSet<_> = ranges
17979            .iter()
17980            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17981            .collect();
17982        drop(snapshot);
17983
17984        let mut buffers = HashSet::default();
17985        for buffer_id in buffer_ids {
17986            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17987                let buffer = buffer_entity.read(cx);
17988                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17989                {
17990                    buffers.insert(buffer_entity);
17991                }
17992            }
17993        }
17994
17995        if let Some(project) = &self.project {
17996            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17997        } else {
17998            Task::ready(Ok(()))
17999        }
18000    }
18001
18002    fn do_stage_or_unstage_and_next(
18003        &mut self,
18004        stage: bool,
18005        window: &mut Window,
18006        cx: &mut Context<Self>,
18007    ) {
18008        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18009
18010        if ranges.iter().any(|range| range.start != range.end) {
18011            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18012            return;
18013        }
18014
18015        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18016        let snapshot = self.snapshot(window, cx);
18017        let position = self.selections.newest::<Point>(cx).head();
18018        let mut row = snapshot
18019            .buffer_snapshot
18020            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18021            .find(|hunk| hunk.row_range.start.0 > position.row)
18022            .map(|hunk| hunk.row_range.start);
18023
18024        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18025        // Outside of the project diff editor, wrap around to the beginning.
18026        if !all_diff_hunks_expanded {
18027            row = row.or_else(|| {
18028                snapshot
18029                    .buffer_snapshot
18030                    .diff_hunks_in_range(Point::zero()..position)
18031                    .find(|hunk| hunk.row_range.end.0 < position.row)
18032                    .map(|hunk| hunk.row_range.start)
18033            });
18034        }
18035
18036        if let Some(row) = row {
18037            let destination = Point::new(row.0, 0);
18038            let autoscroll = Autoscroll::center();
18039
18040            self.unfold_ranges(&[destination..destination], false, false, cx);
18041            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18042                s.select_ranges([destination..destination]);
18043            });
18044        }
18045    }
18046
18047    fn do_stage_or_unstage(
18048        &self,
18049        stage: bool,
18050        buffer_id: BufferId,
18051        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18052        cx: &mut App,
18053    ) -> Option<()> {
18054        let project = self.project()?;
18055        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18056        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18057        let buffer_snapshot = buffer.read(cx).snapshot();
18058        let file_exists = buffer_snapshot
18059            .file()
18060            .is_some_and(|file| file.disk_state().exists());
18061        diff.update(cx, |diff, cx| {
18062            diff.stage_or_unstage_hunks(
18063                stage,
18064                &hunks
18065                    .map(|hunk| buffer_diff::DiffHunk {
18066                        buffer_range: hunk.buffer_range,
18067                        diff_base_byte_range: hunk.diff_base_byte_range,
18068                        secondary_status: hunk.secondary_status,
18069                        range: Point::zero()..Point::zero(), // unused
18070                    })
18071                    .collect::<Vec<_>>(),
18072                &buffer_snapshot,
18073                file_exists,
18074                cx,
18075            )
18076        });
18077        None
18078    }
18079
18080    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18081        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18082        self.buffer
18083            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18084    }
18085
18086    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18087        self.buffer.update(cx, |buffer, cx| {
18088            let ranges = vec![Anchor::min()..Anchor::max()];
18089            if !buffer.all_diff_hunks_expanded()
18090                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18091            {
18092                buffer.collapse_diff_hunks(ranges, cx);
18093                true
18094            } else {
18095                false
18096            }
18097        })
18098    }
18099
18100    fn toggle_diff_hunks_in_ranges(
18101        &mut self,
18102        ranges: Vec<Range<Anchor>>,
18103        cx: &mut Context<Editor>,
18104    ) {
18105        self.buffer.update(cx, |buffer, cx| {
18106            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18107            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18108        })
18109    }
18110
18111    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18112        self.buffer.update(cx, |buffer, cx| {
18113            let snapshot = buffer.snapshot(cx);
18114            let excerpt_id = range.end.excerpt_id;
18115            let point_range = range.to_point(&snapshot);
18116            let expand = !buffer.single_hunk_is_expanded(range, cx);
18117            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18118        })
18119    }
18120
18121    pub(crate) fn apply_all_diff_hunks(
18122        &mut self,
18123        _: &ApplyAllDiffHunks,
18124        window: &mut Window,
18125        cx: &mut Context<Self>,
18126    ) {
18127        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18128
18129        let buffers = self.buffer.read(cx).all_buffers();
18130        for branch_buffer in buffers {
18131            branch_buffer.update(cx, |branch_buffer, cx| {
18132                branch_buffer.merge_into_base(Vec::new(), cx);
18133            });
18134        }
18135
18136        if let Some(project) = self.project.clone() {
18137            self.save(
18138                SaveOptions {
18139                    format: true,
18140                    autosave: false,
18141                },
18142                project,
18143                window,
18144                cx,
18145            )
18146            .detach_and_log_err(cx);
18147        }
18148    }
18149
18150    pub(crate) fn apply_selected_diff_hunks(
18151        &mut self,
18152        _: &ApplyDiffHunk,
18153        window: &mut Window,
18154        cx: &mut Context<Self>,
18155    ) {
18156        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18157        let snapshot = self.snapshot(window, cx);
18158        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18159        let mut ranges_by_buffer = HashMap::default();
18160        self.transact(window, cx, |editor, _window, cx| {
18161            for hunk in hunks {
18162                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18163                    ranges_by_buffer
18164                        .entry(buffer.clone())
18165                        .or_insert_with(Vec::new)
18166                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18167                }
18168            }
18169
18170            for (buffer, ranges) in ranges_by_buffer {
18171                buffer.update(cx, |buffer, cx| {
18172                    buffer.merge_into_base(ranges, cx);
18173                });
18174            }
18175        });
18176
18177        if let Some(project) = self.project.clone() {
18178            self.save(
18179                SaveOptions {
18180                    format: true,
18181                    autosave: false,
18182                },
18183                project,
18184                window,
18185                cx,
18186            )
18187            .detach_and_log_err(cx);
18188        }
18189    }
18190
18191    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18192        if hovered != self.gutter_hovered {
18193            self.gutter_hovered = hovered;
18194            cx.notify();
18195        }
18196    }
18197
18198    pub fn insert_blocks(
18199        &mut self,
18200        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18201        autoscroll: Option<Autoscroll>,
18202        cx: &mut Context<Self>,
18203    ) -> Vec<CustomBlockId> {
18204        let blocks = self
18205            .display_map
18206            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18207        if let Some(autoscroll) = autoscroll {
18208            self.request_autoscroll(autoscroll, cx);
18209        }
18210        cx.notify();
18211        blocks
18212    }
18213
18214    pub fn resize_blocks(
18215        &mut self,
18216        heights: HashMap<CustomBlockId, u32>,
18217        autoscroll: Option<Autoscroll>,
18218        cx: &mut Context<Self>,
18219    ) {
18220        self.display_map
18221            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18222        if let Some(autoscroll) = autoscroll {
18223            self.request_autoscroll(autoscroll, cx);
18224        }
18225        cx.notify();
18226    }
18227
18228    pub fn replace_blocks(
18229        &mut self,
18230        renderers: HashMap<CustomBlockId, RenderBlock>,
18231        autoscroll: Option<Autoscroll>,
18232        cx: &mut Context<Self>,
18233    ) {
18234        self.display_map
18235            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18236        if let Some(autoscroll) = autoscroll {
18237            self.request_autoscroll(autoscroll, cx);
18238        }
18239        cx.notify();
18240    }
18241
18242    pub fn remove_blocks(
18243        &mut self,
18244        block_ids: HashSet<CustomBlockId>,
18245        autoscroll: Option<Autoscroll>,
18246        cx: &mut Context<Self>,
18247    ) {
18248        self.display_map.update(cx, |display_map, cx| {
18249            display_map.remove_blocks(block_ids, cx)
18250        });
18251        if let Some(autoscroll) = autoscroll {
18252            self.request_autoscroll(autoscroll, cx);
18253        }
18254        cx.notify();
18255    }
18256
18257    pub fn row_for_block(
18258        &self,
18259        block_id: CustomBlockId,
18260        cx: &mut Context<Self>,
18261    ) -> Option<DisplayRow> {
18262        self.display_map
18263            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18264    }
18265
18266    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18267        self.focused_block = Some(focused_block);
18268    }
18269
18270    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18271        self.focused_block.take()
18272    }
18273
18274    pub fn insert_creases(
18275        &mut self,
18276        creases: impl IntoIterator<Item = Crease<Anchor>>,
18277        cx: &mut Context<Self>,
18278    ) -> Vec<CreaseId> {
18279        self.display_map
18280            .update(cx, |map, cx| map.insert_creases(creases, cx))
18281    }
18282
18283    pub fn remove_creases(
18284        &mut self,
18285        ids: impl IntoIterator<Item = CreaseId>,
18286        cx: &mut Context<Self>,
18287    ) -> Vec<(CreaseId, Range<Anchor>)> {
18288        self.display_map
18289            .update(cx, |map, cx| map.remove_creases(ids, cx))
18290    }
18291
18292    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18293        self.display_map
18294            .update(cx, |map, cx| map.snapshot(cx))
18295            .longest_row()
18296    }
18297
18298    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18299        self.display_map
18300            .update(cx, |map, cx| map.snapshot(cx))
18301            .max_point()
18302    }
18303
18304    pub fn text(&self, cx: &App) -> String {
18305        self.buffer.read(cx).read(cx).text()
18306    }
18307
18308    pub fn is_empty(&self, cx: &App) -> bool {
18309        self.buffer.read(cx).read(cx).is_empty()
18310    }
18311
18312    pub fn text_option(&self, cx: &App) -> Option<String> {
18313        let text = self.text(cx);
18314        let text = text.trim();
18315
18316        if text.is_empty() {
18317            return None;
18318        }
18319
18320        Some(text.to_string())
18321    }
18322
18323    pub fn set_text(
18324        &mut self,
18325        text: impl Into<Arc<str>>,
18326        window: &mut Window,
18327        cx: &mut Context<Self>,
18328    ) {
18329        self.transact(window, cx, |this, _, cx| {
18330            this.buffer
18331                .read(cx)
18332                .as_singleton()
18333                .expect("you can only call set_text on editors for singleton buffers")
18334                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18335        });
18336    }
18337
18338    pub fn display_text(&self, cx: &mut App) -> String {
18339        self.display_map
18340            .update(cx, |map, cx| map.snapshot(cx))
18341            .text()
18342    }
18343
18344    fn create_minimap(
18345        &self,
18346        minimap_settings: MinimapSettings,
18347        window: &mut Window,
18348        cx: &mut Context<Self>,
18349    ) -> Option<Entity<Self>> {
18350        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18351            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18352    }
18353
18354    fn initialize_new_minimap(
18355        &self,
18356        minimap_settings: MinimapSettings,
18357        window: &mut Window,
18358        cx: &mut Context<Self>,
18359    ) -> Entity<Self> {
18360        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18361
18362        let mut minimap = Editor::new_internal(
18363            EditorMode::Minimap {
18364                parent: cx.weak_entity(),
18365            },
18366            self.buffer.clone(),
18367            None,
18368            Some(self.display_map.clone()),
18369            window,
18370            cx,
18371        );
18372        minimap.scroll_manager.clone_state(&self.scroll_manager);
18373        minimap.set_text_style_refinement(TextStyleRefinement {
18374            font_size: Some(MINIMAP_FONT_SIZE),
18375            font_weight: Some(MINIMAP_FONT_WEIGHT),
18376            ..Default::default()
18377        });
18378        minimap.update_minimap_configuration(minimap_settings, cx);
18379        cx.new(|_| minimap)
18380    }
18381
18382    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18383        let current_line_highlight = minimap_settings
18384            .current_line_highlight
18385            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18386        self.set_current_line_highlight(Some(current_line_highlight));
18387    }
18388
18389    pub fn minimap(&self) -> Option<&Entity<Self>> {
18390        self.minimap
18391            .as_ref()
18392            .filter(|_| self.minimap_visibility.visible())
18393    }
18394
18395    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18396        let mut wrap_guides = smallvec![];
18397
18398        if self.show_wrap_guides == Some(false) {
18399            return wrap_guides;
18400        }
18401
18402        let settings = self.buffer.read(cx).language_settings(cx);
18403        if settings.show_wrap_guides {
18404            match self.soft_wrap_mode(cx) {
18405                SoftWrap::Column(soft_wrap) => {
18406                    wrap_guides.push((soft_wrap as usize, true));
18407                }
18408                SoftWrap::Bounded(soft_wrap) => {
18409                    wrap_guides.push((soft_wrap as usize, true));
18410                }
18411                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18412            }
18413            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18414        }
18415
18416        wrap_guides
18417    }
18418
18419    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18420        let settings = self.buffer.read(cx).language_settings(cx);
18421        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18422        match mode {
18423            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18424                SoftWrap::None
18425            }
18426            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18427            language_settings::SoftWrap::PreferredLineLength => {
18428                SoftWrap::Column(settings.preferred_line_length)
18429            }
18430            language_settings::SoftWrap::Bounded => {
18431                SoftWrap::Bounded(settings.preferred_line_length)
18432            }
18433        }
18434    }
18435
18436    pub fn set_soft_wrap_mode(
18437        &mut self,
18438        mode: language_settings::SoftWrap,
18439
18440        cx: &mut Context<Self>,
18441    ) {
18442        self.soft_wrap_mode_override = Some(mode);
18443        cx.notify();
18444    }
18445
18446    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18447        self.hard_wrap = hard_wrap;
18448        cx.notify();
18449    }
18450
18451    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18452        self.text_style_refinement = Some(style);
18453    }
18454
18455    /// called by the Element so we know what style we were most recently rendered with.
18456    pub(crate) fn set_style(
18457        &mut self,
18458        style: EditorStyle,
18459        window: &mut Window,
18460        cx: &mut Context<Self>,
18461    ) {
18462        // We intentionally do not inform the display map about the minimap style
18463        // so that wrapping is not recalculated and stays consistent for the editor
18464        // and its linked minimap.
18465        if !self.mode.is_minimap() {
18466            let rem_size = window.rem_size();
18467            self.display_map.update(cx, |map, cx| {
18468                map.set_font(
18469                    style.text.font(),
18470                    style.text.font_size.to_pixels(rem_size),
18471                    cx,
18472                )
18473            });
18474        }
18475        self.style = Some(style);
18476    }
18477
18478    pub fn style(&self) -> Option<&EditorStyle> {
18479        self.style.as_ref()
18480    }
18481
18482    // Called by the element. This method is not designed to be called outside of the editor
18483    // element's layout code because it does not notify when rewrapping is computed synchronously.
18484    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18485        self.display_map
18486            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18487    }
18488
18489    pub fn set_soft_wrap(&mut self) {
18490        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18491    }
18492
18493    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18494        if self.soft_wrap_mode_override.is_some() {
18495            self.soft_wrap_mode_override.take();
18496        } else {
18497            let soft_wrap = match self.soft_wrap_mode(cx) {
18498                SoftWrap::GitDiff => return,
18499                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18500                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18501                    language_settings::SoftWrap::None
18502                }
18503            };
18504            self.soft_wrap_mode_override = Some(soft_wrap);
18505        }
18506        cx.notify();
18507    }
18508
18509    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18510        let Some(workspace) = self.workspace() else {
18511            return;
18512        };
18513        let fs = workspace.read(cx).app_state().fs.clone();
18514        let current_show = TabBarSettings::get_global(cx).show;
18515        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18516            setting.show = Some(!current_show);
18517        });
18518    }
18519
18520    pub fn toggle_indent_guides(
18521        &mut self,
18522        _: &ToggleIndentGuides,
18523        _: &mut Window,
18524        cx: &mut Context<Self>,
18525    ) {
18526        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18527            self.buffer
18528                .read(cx)
18529                .language_settings(cx)
18530                .indent_guides
18531                .enabled
18532        });
18533        self.show_indent_guides = Some(!currently_enabled);
18534        cx.notify();
18535    }
18536
18537    fn should_show_indent_guides(&self) -> Option<bool> {
18538        self.show_indent_guides
18539    }
18540
18541    pub fn toggle_line_numbers(
18542        &mut self,
18543        _: &ToggleLineNumbers,
18544        _: &mut Window,
18545        cx: &mut Context<Self>,
18546    ) {
18547        let mut editor_settings = EditorSettings::get_global(cx).clone();
18548        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18549        EditorSettings::override_global(editor_settings, cx);
18550    }
18551
18552    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18553        if let Some(show_line_numbers) = self.show_line_numbers {
18554            return show_line_numbers;
18555        }
18556        EditorSettings::get_global(cx).gutter.line_numbers
18557    }
18558
18559    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18560        self.use_relative_line_numbers
18561            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18562    }
18563
18564    pub fn toggle_relative_line_numbers(
18565        &mut self,
18566        _: &ToggleRelativeLineNumbers,
18567        _: &mut Window,
18568        cx: &mut Context<Self>,
18569    ) {
18570        let is_relative = self.should_use_relative_line_numbers(cx);
18571        self.set_relative_line_number(Some(!is_relative), cx)
18572    }
18573
18574    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18575        self.use_relative_line_numbers = is_relative;
18576        cx.notify();
18577    }
18578
18579    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18580        self.show_gutter = show_gutter;
18581        cx.notify();
18582    }
18583
18584    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18585        self.show_scrollbars = ScrollbarAxes {
18586            horizontal: show,
18587            vertical: show,
18588        };
18589        cx.notify();
18590    }
18591
18592    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18593        self.show_scrollbars.vertical = show;
18594        cx.notify();
18595    }
18596
18597    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18598        self.show_scrollbars.horizontal = show;
18599        cx.notify();
18600    }
18601
18602    pub fn set_minimap_visibility(
18603        &mut self,
18604        minimap_visibility: MinimapVisibility,
18605        window: &mut Window,
18606        cx: &mut Context<Self>,
18607    ) {
18608        if self.minimap_visibility != minimap_visibility {
18609            if minimap_visibility.visible() && self.minimap.is_none() {
18610                let minimap_settings = EditorSettings::get_global(cx).minimap;
18611                self.minimap =
18612                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18613            }
18614            self.minimap_visibility = minimap_visibility;
18615            cx.notify();
18616        }
18617    }
18618
18619    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18620        self.set_show_scrollbars(false, cx);
18621        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18622    }
18623
18624    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18625        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18626    }
18627
18628    /// Normally the text in full mode and auto height editors is padded on the
18629    /// left side by roughly half a character width for improved hit testing.
18630    ///
18631    /// Use this method to disable this for cases where this is not wanted (e.g.
18632    /// if you want to align the editor text with some other text above or below)
18633    /// or if you want to add this padding to single-line editors.
18634    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18635        self.offset_content = offset_content;
18636        cx.notify();
18637    }
18638
18639    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18640        self.show_line_numbers = Some(show_line_numbers);
18641        cx.notify();
18642    }
18643
18644    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18645        self.disable_expand_excerpt_buttons = true;
18646        cx.notify();
18647    }
18648
18649    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18650        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18651        cx.notify();
18652    }
18653
18654    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18655        self.show_code_actions = Some(show_code_actions);
18656        cx.notify();
18657    }
18658
18659    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18660        self.show_runnables = Some(show_runnables);
18661        cx.notify();
18662    }
18663
18664    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18665        self.show_breakpoints = Some(show_breakpoints);
18666        cx.notify();
18667    }
18668
18669    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18670        if self.display_map.read(cx).masked != masked {
18671            self.display_map.update(cx, |map, _| map.masked = masked);
18672        }
18673        cx.notify()
18674    }
18675
18676    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18677        self.show_wrap_guides = Some(show_wrap_guides);
18678        cx.notify();
18679    }
18680
18681    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18682        self.show_indent_guides = Some(show_indent_guides);
18683        cx.notify();
18684    }
18685
18686    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18687        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18688            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18689                if let Some(dir) = file.abs_path(cx).parent() {
18690                    return Some(dir.to_owned());
18691                }
18692            }
18693
18694            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18695                return Some(project_path.path.to_path_buf());
18696            }
18697        }
18698
18699        None
18700    }
18701
18702    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18703        self.active_excerpt(cx)?
18704            .1
18705            .read(cx)
18706            .file()
18707            .and_then(|f| f.as_local())
18708    }
18709
18710    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18711        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18712            let buffer = buffer.read(cx);
18713            if let Some(project_path) = buffer.project_path(cx) {
18714                let project = self.project()?.read(cx);
18715                project.absolute_path(&project_path, cx)
18716            } else {
18717                buffer
18718                    .file()
18719                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18720            }
18721        })
18722    }
18723
18724    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18725        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18726            let project_path = buffer.read(cx).project_path(cx)?;
18727            let project = self.project()?.read(cx);
18728            let entry = project.entry_for_path(&project_path, cx)?;
18729            let path = entry.path.to_path_buf();
18730            Some(path)
18731        })
18732    }
18733
18734    pub fn reveal_in_finder(
18735        &mut self,
18736        _: &RevealInFileManager,
18737        _window: &mut Window,
18738        cx: &mut Context<Self>,
18739    ) {
18740        if let Some(target) = self.target_file(cx) {
18741            cx.reveal_path(&target.abs_path(cx));
18742        }
18743    }
18744
18745    pub fn copy_path(
18746        &mut self,
18747        _: &zed_actions::workspace::CopyPath,
18748        _window: &mut Window,
18749        cx: &mut Context<Self>,
18750    ) {
18751        if let Some(path) = self.target_file_abs_path(cx) {
18752            if let Some(path) = path.to_str() {
18753                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18754            }
18755        }
18756    }
18757
18758    pub fn copy_relative_path(
18759        &mut self,
18760        _: &zed_actions::workspace::CopyRelativePath,
18761        _window: &mut Window,
18762        cx: &mut Context<Self>,
18763    ) {
18764        if let Some(path) = self.target_file_path(cx) {
18765            if let Some(path) = path.to_str() {
18766                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18767            }
18768        }
18769    }
18770
18771    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18772        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18773            buffer.read(cx).project_path(cx)
18774        } else {
18775            None
18776        }
18777    }
18778
18779    // Returns true if the editor handled a go-to-line request
18780    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18781        maybe!({
18782            let breakpoint_store = self.breakpoint_store.as_ref()?;
18783
18784            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18785            else {
18786                self.clear_row_highlights::<ActiveDebugLine>();
18787                return None;
18788            };
18789
18790            let position = active_stack_frame.position;
18791            let buffer_id = position.buffer_id?;
18792            let snapshot = self
18793                .project
18794                .as_ref()?
18795                .read(cx)
18796                .buffer_for_id(buffer_id, cx)?
18797                .read(cx)
18798                .snapshot();
18799
18800            let mut handled = false;
18801            for (id, ExcerptRange { context, .. }) in
18802                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18803            {
18804                if context.start.cmp(&position, &snapshot).is_ge()
18805                    || context.end.cmp(&position, &snapshot).is_lt()
18806                {
18807                    continue;
18808                }
18809                let snapshot = self.buffer.read(cx).snapshot(cx);
18810                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18811
18812                handled = true;
18813                self.clear_row_highlights::<ActiveDebugLine>();
18814
18815                self.go_to_line::<ActiveDebugLine>(
18816                    multibuffer_anchor,
18817                    Some(cx.theme().colors().editor_debugger_active_line_background),
18818                    window,
18819                    cx,
18820                );
18821
18822                cx.notify();
18823            }
18824
18825            handled.then_some(())
18826        })
18827        .is_some()
18828    }
18829
18830    pub fn copy_file_name_without_extension(
18831        &mut self,
18832        _: &CopyFileNameWithoutExtension,
18833        _: &mut Window,
18834        cx: &mut Context<Self>,
18835    ) {
18836        if let Some(file) = self.target_file(cx) {
18837            if let Some(file_stem) = file.path().file_stem() {
18838                if let Some(name) = file_stem.to_str() {
18839                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18840                }
18841            }
18842        }
18843    }
18844
18845    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18846        if let Some(file) = self.target_file(cx) {
18847            if let Some(file_name) = file.path().file_name() {
18848                if let Some(name) = file_name.to_str() {
18849                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18850                }
18851            }
18852        }
18853    }
18854
18855    pub fn toggle_git_blame(
18856        &mut self,
18857        _: &::git::Blame,
18858        window: &mut Window,
18859        cx: &mut Context<Self>,
18860    ) {
18861        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18862
18863        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18864            self.start_git_blame(true, window, cx);
18865        }
18866
18867        cx.notify();
18868    }
18869
18870    pub fn toggle_git_blame_inline(
18871        &mut self,
18872        _: &ToggleGitBlameInline,
18873        window: &mut Window,
18874        cx: &mut Context<Self>,
18875    ) {
18876        self.toggle_git_blame_inline_internal(true, window, cx);
18877        cx.notify();
18878    }
18879
18880    pub fn open_git_blame_commit(
18881        &mut self,
18882        _: &OpenGitBlameCommit,
18883        window: &mut Window,
18884        cx: &mut Context<Self>,
18885    ) {
18886        self.open_git_blame_commit_internal(window, cx);
18887    }
18888
18889    fn open_git_blame_commit_internal(
18890        &mut self,
18891        window: &mut Window,
18892        cx: &mut Context<Self>,
18893    ) -> Option<()> {
18894        let blame = self.blame.as_ref()?;
18895        let snapshot = self.snapshot(window, cx);
18896        let cursor = self.selections.newest::<Point>(cx).head();
18897        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18898        let blame_entry = blame
18899            .update(cx, |blame, cx| {
18900                blame
18901                    .blame_for_rows(
18902                        &[RowInfo {
18903                            buffer_id: Some(buffer.remote_id()),
18904                            buffer_row: Some(point.row),
18905                            ..Default::default()
18906                        }],
18907                        cx,
18908                    )
18909                    .next()
18910            })
18911            .flatten()?;
18912        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18913        let repo = blame.read(cx).repository(cx)?;
18914        let workspace = self.workspace()?.downgrade();
18915        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18916        None
18917    }
18918
18919    pub fn git_blame_inline_enabled(&self) -> bool {
18920        self.git_blame_inline_enabled
18921    }
18922
18923    pub fn toggle_selection_menu(
18924        &mut self,
18925        _: &ToggleSelectionMenu,
18926        _: &mut Window,
18927        cx: &mut Context<Self>,
18928    ) {
18929        self.show_selection_menu = self
18930            .show_selection_menu
18931            .map(|show_selections_menu| !show_selections_menu)
18932            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18933
18934        cx.notify();
18935    }
18936
18937    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18938        self.show_selection_menu
18939            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18940    }
18941
18942    fn start_git_blame(
18943        &mut self,
18944        user_triggered: bool,
18945        window: &mut Window,
18946        cx: &mut Context<Self>,
18947    ) {
18948        if let Some(project) = self.project() {
18949            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18950                return;
18951            };
18952
18953            if buffer.read(cx).file().is_none() {
18954                return;
18955            }
18956
18957            let focused = self.focus_handle(cx).contains_focused(window, cx);
18958
18959            let project = project.clone();
18960            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18961            self.blame_subscription =
18962                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18963            self.blame = Some(blame);
18964        }
18965    }
18966
18967    fn toggle_git_blame_inline_internal(
18968        &mut self,
18969        user_triggered: bool,
18970        window: &mut Window,
18971        cx: &mut Context<Self>,
18972    ) {
18973        if self.git_blame_inline_enabled {
18974            self.git_blame_inline_enabled = false;
18975            self.show_git_blame_inline = false;
18976            self.show_git_blame_inline_delay_task.take();
18977        } else {
18978            self.git_blame_inline_enabled = true;
18979            self.start_git_blame_inline(user_triggered, window, cx);
18980        }
18981
18982        cx.notify();
18983    }
18984
18985    fn start_git_blame_inline(
18986        &mut self,
18987        user_triggered: bool,
18988        window: &mut Window,
18989        cx: &mut Context<Self>,
18990    ) {
18991        self.start_git_blame(user_triggered, window, cx);
18992
18993        if ProjectSettings::get_global(cx)
18994            .git
18995            .inline_blame_delay()
18996            .is_some()
18997        {
18998            self.start_inline_blame_timer(window, cx);
18999        } else {
19000            self.show_git_blame_inline = true
19001        }
19002    }
19003
19004    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19005        self.blame.as_ref()
19006    }
19007
19008    pub fn show_git_blame_gutter(&self) -> bool {
19009        self.show_git_blame_gutter
19010    }
19011
19012    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19013        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19014    }
19015
19016    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19017        self.show_git_blame_inline
19018            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19019            && !self.newest_selection_head_on_empty_line(cx)
19020            && self.has_blame_entries(cx)
19021    }
19022
19023    fn has_blame_entries(&self, cx: &App) -> bool {
19024        self.blame()
19025            .map_or(false, |blame| blame.read(cx).has_generated_entries())
19026    }
19027
19028    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19029        let cursor_anchor = self.selections.newest_anchor().head();
19030
19031        let snapshot = self.buffer.read(cx).snapshot(cx);
19032        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19033
19034        snapshot.line_len(buffer_row) == 0
19035    }
19036
19037    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19038        let buffer_and_selection = maybe!({
19039            let selection = self.selections.newest::<Point>(cx);
19040            let selection_range = selection.range();
19041
19042            let multi_buffer = self.buffer().read(cx);
19043            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19044            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19045
19046            let (buffer, range, _) = if selection.reversed {
19047                buffer_ranges.first()
19048            } else {
19049                buffer_ranges.last()
19050            }?;
19051
19052            let selection = text::ToPoint::to_point(&range.start, buffer).row
19053                ..text::ToPoint::to_point(&range.end, buffer).row;
19054            Some((
19055                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
19056                selection,
19057            ))
19058        });
19059
19060        let Some((buffer, selection)) = buffer_and_selection else {
19061            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19062        };
19063
19064        let Some(project) = self.project() else {
19065            return Task::ready(Err(anyhow!("editor does not have project")));
19066        };
19067
19068        project.update(cx, |project, cx| {
19069            project.get_permalink_to_line(&buffer, selection, cx)
19070        })
19071    }
19072
19073    pub fn copy_permalink_to_line(
19074        &mut self,
19075        _: &CopyPermalinkToLine,
19076        window: &mut Window,
19077        cx: &mut Context<Self>,
19078    ) {
19079        let permalink_task = self.get_permalink_to_line(cx);
19080        let workspace = self.workspace();
19081
19082        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19083            Ok(permalink) => {
19084                cx.update(|_, cx| {
19085                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19086                })
19087                .ok();
19088            }
19089            Err(err) => {
19090                let message = format!("Failed to copy permalink: {err}");
19091
19092                anyhow::Result::<()>::Err(err).log_err();
19093
19094                if let Some(workspace) = workspace {
19095                    workspace
19096                        .update_in(cx, |workspace, _, cx| {
19097                            struct CopyPermalinkToLine;
19098
19099                            workspace.show_toast(
19100                                Toast::new(
19101                                    NotificationId::unique::<CopyPermalinkToLine>(),
19102                                    message,
19103                                ),
19104                                cx,
19105                            )
19106                        })
19107                        .ok();
19108                }
19109            }
19110        })
19111        .detach();
19112    }
19113
19114    pub fn copy_file_location(
19115        &mut self,
19116        _: &CopyFileLocation,
19117        _: &mut Window,
19118        cx: &mut Context<Self>,
19119    ) {
19120        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19121        if let Some(file) = self.target_file(cx) {
19122            if let Some(path) = file.path().to_str() {
19123                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19124            }
19125        }
19126    }
19127
19128    pub fn open_permalink_to_line(
19129        &mut self,
19130        _: &OpenPermalinkToLine,
19131        window: &mut Window,
19132        cx: &mut Context<Self>,
19133    ) {
19134        let permalink_task = self.get_permalink_to_line(cx);
19135        let workspace = self.workspace();
19136
19137        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19138            Ok(permalink) => {
19139                cx.update(|_, cx| {
19140                    cx.open_url(permalink.as_ref());
19141                })
19142                .ok();
19143            }
19144            Err(err) => {
19145                let message = format!("Failed to open permalink: {err}");
19146
19147                anyhow::Result::<()>::Err(err).log_err();
19148
19149                if let Some(workspace) = workspace {
19150                    workspace
19151                        .update(cx, |workspace, cx| {
19152                            struct OpenPermalinkToLine;
19153
19154                            workspace.show_toast(
19155                                Toast::new(
19156                                    NotificationId::unique::<OpenPermalinkToLine>(),
19157                                    message,
19158                                ),
19159                                cx,
19160                            )
19161                        })
19162                        .ok();
19163                }
19164            }
19165        })
19166        .detach();
19167    }
19168
19169    pub fn insert_uuid_v4(
19170        &mut self,
19171        _: &InsertUuidV4,
19172        window: &mut Window,
19173        cx: &mut Context<Self>,
19174    ) {
19175        self.insert_uuid(UuidVersion::V4, window, cx);
19176    }
19177
19178    pub fn insert_uuid_v7(
19179        &mut self,
19180        _: &InsertUuidV7,
19181        window: &mut Window,
19182        cx: &mut Context<Self>,
19183    ) {
19184        self.insert_uuid(UuidVersion::V7, window, cx);
19185    }
19186
19187    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19188        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19189        self.transact(window, cx, |this, window, cx| {
19190            let edits = this
19191                .selections
19192                .all::<Point>(cx)
19193                .into_iter()
19194                .map(|selection| {
19195                    let uuid = match version {
19196                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19197                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19198                    };
19199
19200                    (selection.range(), uuid.to_string())
19201                });
19202            this.edit(edits, cx);
19203            this.refresh_edit_prediction(true, false, window, cx);
19204        });
19205    }
19206
19207    pub fn open_selections_in_multibuffer(
19208        &mut self,
19209        _: &OpenSelectionsInMultibuffer,
19210        window: &mut Window,
19211        cx: &mut Context<Self>,
19212    ) {
19213        let multibuffer = self.buffer.read(cx);
19214
19215        let Some(buffer) = multibuffer.as_singleton() else {
19216            return;
19217        };
19218
19219        let Some(workspace) = self.workspace() else {
19220            return;
19221        };
19222
19223        let title = multibuffer.title(cx).to_string();
19224
19225        let locations = self
19226            .selections
19227            .all_anchors(cx)
19228            .into_iter()
19229            .map(|selection| Location {
19230                buffer: buffer.clone(),
19231                range: selection.start.text_anchor..selection.end.text_anchor,
19232            })
19233            .collect::<Vec<_>>();
19234
19235        cx.spawn_in(window, async move |_, cx| {
19236            workspace.update_in(cx, |workspace, window, cx| {
19237                Self::open_locations_in_multibuffer(
19238                    workspace,
19239                    locations,
19240                    format!("Selections for '{title}'"),
19241                    false,
19242                    MultibufferSelectionMode::All,
19243                    window,
19244                    cx,
19245                );
19246            })
19247        })
19248        .detach();
19249    }
19250
19251    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19252    /// last highlight added will be used.
19253    ///
19254    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19255    pub fn highlight_rows<T: 'static>(
19256        &mut self,
19257        range: Range<Anchor>,
19258        color: Hsla,
19259        options: RowHighlightOptions,
19260        cx: &mut Context<Self>,
19261    ) {
19262        let snapshot = self.buffer().read(cx).snapshot(cx);
19263        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19264        let ix = row_highlights.binary_search_by(|highlight| {
19265            Ordering::Equal
19266                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19267                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19268        });
19269
19270        if let Err(mut ix) = ix {
19271            let index = post_inc(&mut self.highlight_order);
19272
19273            // If this range intersects with the preceding highlight, then merge it with
19274            // the preceding highlight. Otherwise insert a new highlight.
19275            let mut merged = false;
19276            if ix > 0 {
19277                let prev_highlight = &mut row_highlights[ix - 1];
19278                if prev_highlight
19279                    .range
19280                    .end
19281                    .cmp(&range.start, &snapshot)
19282                    .is_ge()
19283                {
19284                    ix -= 1;
19285                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19286                        prev_highlight.range.end = range.end;
19287                    }
19288                    merged = true;
19289                    prev_highlight.index = index;
19290                    prev_highlight.color = color;
19291                    prev_highlight.options = options;
19292                }
19293            }
19294
19295            if !merged {
19296                row_highlights.insert(
19297                    ix,
19298                    RowHighlight {
19299                        range: range.clone(),
19300                        index,
19301                        color,
19302                        options,
19303                        type_id: TypeId::of::<T>(),
19304                    },
19305                );
19306            }
19307
19308            // If any of the following highlights intersect with this one, merge them.
19309            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19310                let highlight = &row_highlights[ix];
19311                if next_highlight
19312                    .range
19313                    .start
19314                    .cmp(&highlight.range.end, &snapshot)
19315                    .is_le()
19316                {
19317                    if next_highlight
19318                        .range
19319                        .end
19320                        .cmp(&highlight.range.end, &snapshot)
19321                        .is_gt()
19322                    {
19323                        row_highlights[ix].range.end = next_highlight.range.end;
19324                    }
19325                    row_highlights.remove(ix + 1);
19326                } else {
19327                    break;
19328                }
19329            }
19330        }
19331    }
19332
19333    /// Remove any highlighted row ranges of the given type that intersect the
19334    /// given ranges.
19335    pub fn remove_highlighted_rows<T: 'static>(
19336        &mut self,
19337        ranges_to_remove: Vec<Range<Anchor>>,
19338        cx: &mut Context<Self>,
19339    ) {
19340        let snapshot = self.buffer().read(cx).snapshot(cx);
19341        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19342        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19343        row_highlights.retain(|highlight| {
19344            while let Some(range_to_remove) = ranges_to_remove.peek() {
19345                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19346                    Ordering::Less | Ordering::Equal => {
19347                        ranges_to_remove.next();
19348                    }
19349                    Ordering::Greater => {
19350                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19351                            Ordering::Less | Ordering::Equal => {
19352                                return false;
19353                            }
19354                            Ordering::Greater => break,
19355                        }
19356                    }
19357                }
19358            }
19359
19360            true
19361        })
19362    }
19363
19364    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19365    pub fn clear_row_highlights<T: 'static>(&mut self) {
19366        self.highlighted_rows.remove(&TypeId::of::<T>());
19367    }
19368
19369    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19370    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19371        self.highlighted_rows
19372            .get(&TypeId::of::<T>())
19373            .map_or(&[] as &[_], |vec| vec.as_slice())
19374            .iter()
19375            .map(|highlight| (highlight.range.clone(), highlight.color))
19376    }
19377
19378    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19379    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19380    /// Allows to ignore certain kinds of highlights.
19381    pub fn highlighted_display_rows(
19382        &self,
19383        window: &mut Window,
19384        cx: &mut App,
19385    ) -> BTreeMap<DisplayRow, LineHighlight> {
19386        let snapshot = self.snapshot(window, cx);
19387        let mut used_highlight_orders = HashMap::default();
19388        self.highlighted_rows
19389            .iter()
19390            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19391            .fold(
19392                BTreeMap::<DisplayRow, LineHighlight>::new(),
19393                |mut unique_rows, highlight| {
19394                    let start = highlight.range.start.to_display_point(&snapshot);
19395                    let end = highlight.range.end.to_display_point(&snapshot);
19396                    let start_row = start.row().0;
19397                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19398                        && end.column() == 0
19399                    {
19400                        end.row().0.saturating_sub(1)
19401                    } else {
19402                        end.row().0
19403                    };
19404                    for row in start_row..=end_row {
19405                        let used_index =
19406                            used_highlight_orders.entry(row).or_insert(highlight.index);
19407                        if highlight.index >= *used_index {
19408                            *used_index = highlight.index;
19409                            unique_rows.insert(
19410                                DisplayRow(row),
19411                                LineHighlight {
19412                                    include_gutter: highlight.options.include_gutter,
19413                                    border: None,
19414                                    background: highlight.color.into(),
19415                                    type_id: Some(highlight.type_id),
19416                                },
19417                            );
19418                        }
19419                    }
19420                    unique_rows
19421                },
19422            )
19423    }
19424
19425    pub fn highlighted_display_row_for_autoscroll(
19426        &self,
19427        snapshot: &DisplaySnapshot,
19428    ) -> Option<DisplayRow> {
19429        self.highlighted_rows
19430            .values()
19431            .flat_map(|highlighted_rows| highlighted_rows.iter())
19432            .filter_map(|highlight| {
19433                if highlight.options.autoscroll {
19434                    Some(highlight.range.start.to_display_point(snapshot).row())
19435                } else {
19436                    None
19437                }
19438            })
19439            .min()
19440    }
19441
19442    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19443        self.highlight_background::<SearchWithinRange>(
19444            ranges,
19445            |colors| colors.colors().editor_document_highlight_read_background,
19446            cx,
19447        )
19448    }
19449
19450    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19451        self.breadcrumb_header = Some(new_header);
19452    }
19453
19454    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19455        self.clear_background_highlights::<SearchWithinRange>(cx);
19456    }
19457
19458    pub fn highlight_background<T: 'static>(
19459        &mut self,
19460        ranges: &[Range<Anchor>],
19461        color_fetcher: fn(&Theme) -> Hsla,
19462        cx: &mut Context<Self>,
19463    ) {
19464        self.background_highlights.insert(
19465            HighlightKey::Type(TypeId::of::<T>()),
19466            (color_fetcher, Arc::from(ranges)),
19467        );
19468        self.scrollbar_marker_state.dirty = true;
19469        cx.notify();
19470    }
19471
19472    pub fn highlight_background_key<T: 'static>(
19473        &mut self,
19474        key: usize,
19475        ranges: &[Range<Anchor>],
19476        color_fetcher: fn(&Theme) -> Hsla,
19477        cx: &mut Context<Self>,
19478    ) {
19479        self.background_highlights.insert(
19480            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19481            (color_fetcher, Arc::from(ranges)),
19482        );
19483        self.scrollbar_marker_state.dirty = true;
19484        cx.notify();
19485    }
19486
19487    pub fn clear_background_highlights<T: 'static>(
19488        &mut self,
19489        cx: &mut Context<Self>,
19490    ) -> Option<BackgroundHighlight> {
19491        let text_highlights = self
19492            .background_highlights
19493            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19494        if !text_highlights.1.is_empty() {
19495            self.scrollbar_marker_state.dirty = true;
19496            cx.notify();
19497        }
19498        Some(text_highlights)
19499    }
19500
19501    pub fn highlight_gutter<T: 'static>(
19502        &mut self,
19503        ranges: impl Into<Vec<Range<Anchor>>>,
19504        color_fetcher: fn(&App) -> Hsla,
19505        cx: &mut Context<Self>,
19506    ) {
19507        self.gutter_highlights
19508            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19509        cx.notify();
19510    }
19511
19512    pub fn clear_gutter_highlights<T: 'static>(
19513        &mut self,
19514        cx: &mut Context<Self>,
19515    ) -> Option<GutterHighlight> {
19516        cx.notify();
19517        self.gutter_highlights.remove(&TypeId::of::<T>())
19518    }
19519
19520    pub fn insert_gutter_highlight<T: 'static>(
19521        &mut self,
19522        range: Range<Anchor>,
19523        color_fetcher: fn(&App) -> Hsla,
19524        cx: &mut Context<Self>,
19525    ) {
19526        let snapshot = self.buffer().read(cx).snapshot(cx);
19527        let mut highlights = self
19528            .gutter_highlights
19529            .remove(&TypeId::of::<T>())
19530            .map(|(_, highlights)| highlights)
19531            .unwrap_or_default();
19532        let ix = highlights.binary_search_by(|highlight| {
19533            Ordering::Equal
19534                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19535                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19536        });
19537        if let Err(ix) = ix {
19538            highlights.insert(ix, range);
19539        }
19540        self.gutter_highlights
19541            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19542    }
19543
19544    pub fn remove_gutter_highlights<T: 'static>(
19545        &mut self,
19546        ranges_to_remove: Vec<Range<Anchor>>,
19547        cx: &mut Context<Self>,
19548    ) {
19549        let snapshot = self.buffer().read(cx).snapshot(cx);
19550        let Some((color_fetcher, mut gutter_highlights)) =
19551            self.gutter_highlights.remove(&TypeId::of::<T>())
19552        else {
19553            return;
19554        };
19555        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19556        gutter_highlights.retain(|highlight| {
19557            while let Some(range_to_remove) = ranges_to_remove.peek() {
19558                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19559                    Ordering::Less | Ordering::Equal => {
19560                        ranges_to_remove.next();
19561                    }
19562                    Ordering::Greater => {
19563                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19564                            Ordering::Less | Ordering::Equal => {
19565                                return false;
19566                            }
19567                            Ordering::Greater => break,
19568                        }
19569                    }
19570                }
19571            }
19572
19573            true
19574        });
19575        self.gutter_highlights
19576            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19577    }
19578
19579    #[cfg(feature = "test-support")]
19580    pub fn all_text_highlights(
19581        &self,
19582        window: &mut Window,
19583        cx: &mut Context<Self>,
19584    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19585        let snapshot = self.snapshot(window, cx);
19586        self.display_map.update(cx, |display_map, _| {
19587            display_map
19588                .all_text_highlights()
19589                .map(|highlight| {
19590                    let (style, ranges) = highlight.as_ref();
19591                    (
19592                        *style,
19593                        ranges
19594                            .iter()
19595                            .map(|range| range.clone().to_display_points(&snapshot))
19596                            .collect(),
19597                    )
19598                })
19599                .collect()
19600        })
19601    }
19602
19603    #[cfg(feature = "test-support")]
19604    pub fn all_text_background_highlights(
19605        &self,
19606        window: &mut Window,
19607        cx: &mut Context<Self>,
19608    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19609        let snapshot = self.snapshot(window, cx);
19610        let buffer = &snapshot.buffer_snapshot;
19611        let start = buffer.anchor_before(0);
19612        let end = buffer.anchor_after(buffer.len());
19613        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19614    }
19615
19616    #[cfg(feature = "test-support")]
19617    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19618        let snapshot = self.buffer().read(cx).snapshot(cx);
19619
19620        let highlights = self
19621            .background_highlights
19622            .get(&HighlightKey::Type(TypeId::of::<
19623                items::BufferSearchHighlights,
19624            >()));
19625
19626        if let Some((_color, ranges)) = highlights {
19627            ranges
19628                .iter()
19629                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19630                .collect_vec()
19631        } else {
19632            vec![]
19633        }
19634    }
19635
19636    fn document_highlights_for_position<'a>(
19637        &'a self,
19638        position: Anchor,
19639        buffer: &'a MultiBufferSnapshot,
19640    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19641        let read_highlights = self
19642            .background_highlights
19643            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19644            .map(|h| &h.1);
19645        let write_highlights = self
19646            .background_highlights
19647            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19648            .map(|h| &h.1);
19649        let left_position = position.bias_left(buffer);
19650        let right_position = position.bias_right(buffer);
19651        read_highlights
19652            .into_iter()
19653            .chain(write_highlights)
19654            .flat_map(move |ranges| {
19655                let start_ix = match ranges.binary_search_by(|probe| {
19656                    let cmp = probe.end.cmp(&left_position, buffer);
19657                    if cmp.is_ge() {
19658                        Ordering::Greater
19659                    } else {
19660                        Ordering::Less
19661                    }
19662                }) {
19663                    Ok(i) | Err(i) => i,
19664                };
19665
19666                ranges[start_ix..]
19667                    .iter()
19668                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19669            })
19670    }
19671
19672    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19673        self.background_highlights
19674            .get(&HighlightKey::Type(TypeId::of::<T>()))
19675            .map_or(false, |(_, highlights)| !highlights.is_empty())
19676    }
19677
19678    pub fn background_highlights_in_range(
19679        &self,
19680        search_range: Range<Anchor>,
19681        display_snapshot: &DisplaySnapshot,
19682        theme: &Theme,
19683    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19684        let mut results = Vec::new();
19685        for (color_fetcher, ranges) in self.background_highlights.values() {
19686            let color = color_fetcher(theme);
19687            let start_ix = match ranges.binary_search_by(|probe| {
19688                let cmp = probe
19689                    .end
19690                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19691                if cmp.is_gt() {
19692                    Ordering::Greater
19693                } else {
19694                    Ordering::Less
19695                }
19696            }) {
19697                Ok(i) | Err(i) => i,
19698            };
19699            for range in &ranges[start_ix..] {
19700                if range
19701                    .start
19702                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19703                    .is_ge()
19704                {
19705                    break;
19706                }
19707
19708                let start = range.start.to_display_point(display_snapshot);
19709                let end = range.end.to_display_point(display_snapshot);
19710                results.push((start..end, color))
19711            }
19712        }
19713        results
19714    }
19715
19716    pub fn background_highlight_row_ranges<T: 'static>(
19717        &self,
19718        search_range: Range<Anchor>,
19719        display_snapshot: &DisplaySnapshot,
19720        count: usize,
19721    ) -> Vec<RangeInclusive<DisplayPoint>> {
19722        let mut results = Vec::new();
19723        let Some((_, ranges)) = self
19724            .background_highlights
19725            .get(&HighlightKey::Type(TypeId::of::<T>()))
19726        else {
19727            return vec![];
19728        };
19729
19730        let start_ix = match ranges.binary_search_by(|probe| {
19731            let cmp = probe
19732                .end
19733                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19734            if cmp.is_gt() {
19735                Ordering::Greater
19736            } else {
19737                Ordering::Less
19738            }
19739        }) {
19740            Ok(i) | Err(i) => i,
19741        };
19742        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19743            if let (Some(start_display), Some(end_display)) = (start, end) {
19744                results.push(
19745                    start_display.to_display_point(display_snapshot)
19746                        ..=end_display.to_display_point(display_snapshot),
19747                );
19748            }
19749        };
19750        let mut start_row: Option<Point> = None;
19751        let mut end_row: Option<Point> = None;
19752        if ranges.len() > count {
19753            return Vec::new();
19754        }
19755        for range in &ranges[start_ix..] {
19756            if range
19757                .start
19758                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19759                .is_ge()
19760            {
19761                break;
19762            }
19763            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19764            if let Some(current_row) = &end_row {
19765                if end.row == current_row.row {
19766                    continue;
19767                }
19768            }
19769            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19770            if start_row.is_none() {
19771                assert_eq!(end_row, None);
19772                start_row = Some(start);
19773                end_row = Some(end);
19774                continue;
19775            }
19776            if let Some(current_end) = end_row.as_mut() {
19777                if start.row > current_end.row + 1 {
19778                    push_region(start_row, end_row);
19779                    start_row = Some(start);
19780                    end_row = Some(end);
19781                } else {
19782                    // Merge two hunks.
19783                    *current_end = end;
19784                }
19785            } else {
19786                unreachable!();
19787            }
19788        }
19789        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19790        push_region(start_row, end_row);
19791        results
19792    }
19793
19794    pub fn gutter_highlights_in_range(
19795        &self,
19796        search_range: Range<Anchor>,
19797        display_snapshot: &DisplaySnapshot,
19798        cx: &App,
19799    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19800        let mut results = Vec::new();
19801        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19802            let color = color_fetcher(cx);
19803            let start_ix = match ranges.binary_search_by(|probe| {
19804                let cmp = probe
19805                    .end
19806                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19807                if cmp.is_gt() {
19808                    Ordering::Greater
19809                } else {
19810                    Ordering::Less
19811                }
19812            }) {
19813                Ok(i) | Err(i) => i,
19814            };
19815            for range in &ranges[start_ix..] {
19816                if range
19817                    .start
19818                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19819                    .is_ge()
19820                {
19821                    break;
19822                }
19823
19824                let start = range.start.to_display_point(display_snapshot);
19825                let end = range.end.to_display_point(display_snapshot);
19826                results.push((start..end, color))
19827            }
19828        }
19829        results
19830    }
19831
19832    /// Get the text ranges corresponding to the redaction query
19833    pub fn redacted_ranges(
19834        &self,
19835        search_range: Range<Anchor>,
19836        display_snapshot: &DisplaySnapshot,
19837        cx: &App,
19838    ) -> Vec<Range<DisplayPoint>> {
19839        display_snapshot
19840            .buffer_snapshot
19841            .redacted_ranges(search_range, |file| {
19842                if let Some(file) = file {
19843                    file.is_private()
19844                        && EditorSettings::get(
19845                            Some(SettingsLocation {
19846                                worktree_id: file.worktree_id(cx),
19847                                path: file.path().as_ref(),
19848                            }),
19849                            cx,
19850                        )
19851                        .redact_private_values
19852                } else {
19853                    false
19854                }
19855            })
19856            .map(|range| {
19857                range.start.to_display_point(display_snapshot)
19858                    ..range.end.to_display_point(display_snapshot)
19859            })
19860            .collect()
19861    }
19862
19863    pub fn highlight_text_key<T: 'static>(
19864        &mut self,
19865        key: usize,
19866        ranges: Vec<Range<Anchor>>,
19867        style: HighlightStyle,
19868        cx: &mut Context<Self>,
19869    ) {
19870        self.display_map.update(cx, |map, _| {
19871            map.highlight_text(
19872                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19873                ranges,
19874                style,
19875            );
19876        });
19877        cx.notify();
19878    }
19879
19880    pub fn highlight_text<T: 'static>(
19881        &mut self,
19882        ranges: Vec<Range<Anchor>>,
19883        style: HighlightStyle,
19884        cx: &mut Context<Self>,
19885    ) {
19886        self.display_map.update(cx, |map, _| {
19887            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19888        });
19889        cx.notify();
19890    }
19891
19892    pub(crate) fn highlight_inlays<T: 'static>(
19893        &mut self,
19894        highlights: Vec<InlayHighlight>,
19895        style: HighlightStyle,
19896        cx: &mut Context<Self>,
19897    ) {
19898        self.display_map.update(cx, |map, _| {
19899            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19900        });
19901        cx.notify();
19902    }
19903
19904    pub fn text_highlights<'a, T: 'static>(
19905        &'a self,
19906        cx: &'a App,
19907    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19908        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19909    }
19910
19911    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19912        let cleared = self
19913            .display_map
19914            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19915        if cleared {
19916            cx.notify();
19917        }
19918    }
19919
19920    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19921        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19922            && self.focus_handle.is_focused(window)
19923    }
19924
19925    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19926        self.show_cursor_when_unfocused = is_enabled;
19927        cx.notify();
19928    }
19929
19930    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19931        cx.notify();
19932    }
19933
19934    fn on_debug_session_event(
19935        &mut self,
19936        _session: Entity<Session>,
19937        event: &SessionEvent,
19938        cx: &mut Context<Self>,
19939    ) {
19940        match event {
19941            SessionEvent::InvalidateInlineValue => {
19942                self.refresh_inline_values(cx);
19943            }
19944            _ => {}
19945        }
19946    }
19947
19948    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19949        let Some(project) = self.project.clone() else {
19950            return;
19951        };
19952
19953        if !self.inline_value_cache.enabled {
19954            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19955            self.splice_inlays(&inlays, Vec::new(), cx);
19956            return;
19957        }
19958
19959        let current_execution_position = self
19960            .highlighted_rows
19961            .get(&TypeId::of::<ActiveDebugLine>())
19962            .and_then(|lines| lines.last().map(|line| line.range.end));
19963
19964        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19965            let inline_values = editor
19966                .update(cx, |editor, cx| {
19967                    let Some(current_execution_position) = current_execution_position else {
19968                        return Some(Task::ready(Ok(Vec::new())));
19969                    };
19970
19971                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19972                        let snapshot = buffer.snapshot(cx);
19973
19974                        let excerpt = snapshot.excerpt_containing(
19975                            current_execution_position..current_execution_position,
19976                        )?;
19977
19978                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19979                    })?;
19980
19981                    let range =
19982                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19983
19984                    project.inline_values(buffer, range, cx)
19985                })
19986                .ok()
19987                .flatten()?
19988                .await
19989                .context("refreshing debugger inlays")
19990                .log_err()?;
19991
19992            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19993
19994            for (buffer_id, inline_value) in inline_values
19995                .into_iter()
19996                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19997            {
19998                buffer_inline_values
19999                    .entry(buffer_id)
20000                    .or_default()
20001                    .push(inline_value);
20002            }
20003
20004            editor
20005                .update(cx, |editor, cx| {
20006                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20007                    let mut new_inlays = Vec::default();
20008
20009                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20010                        let buffer_id = buffer_snapshot.remote_id();
20011                        buffer_inline_values
20012                            .get(&buffer_id)
20013                            .into_iter()
20014                            .flatten()
20015                            .for_each(|hint| {
20016                                let inlay = Inlay::debugger(
20017                                    post_inc(&mut editor.next_inlay_id),
20018                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20019                                    hint.text(),
20020                                );
20021                                if !inlay.text.chars().contains(&'\n') {
20022                                    new_inlays.push(inlay);
20023                                }
20024                            });
20025                    }
20026
20027                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20028                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20029
20030                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20031                })
20032                .ok()?;
20033            Some(())
20034        });
20035    }
20036
20037    fn on_buffer_event(
20038        &mut self,
20039        multibuffer: &Entity<MultiBuffer>,
20040        event: &multi_buffer::Event,
20041        window: &mut Window,
20042        cx: &mut Context<Self>,
20043    ) {
20044        match event {
20045            multi_buffer::Event::Edited {
20046                singleton_buffer_edited,
20047                edited_buffer,
20048            } => {
20049                self.scrollbar_marker_state.dirty = true;
20050                self.active_indent_guides_state.dirty = true;
20051                self.refresh_active_diagnostics(cx);
20052                self.refresh_code_actions(window, cx);
20053                self.refresh_selected_text_highlights(true, window, cx);
20054                self.refresh_single_line_folds(window, cx);
20055                refresh_matching_bracket_highlights(self, window, cx);
20056                if self.has_active_edit_prediction() {
20057                    self.update_visible_edit_prediction(window, cx);
20058                }
20059                if let Some(project) = self.project.as_ref() {
20060                    if let Some(edited_buffer) = edited_buffer {
20061                        project.update(cx, |project, cx| {
20062                            self.registered_buffers
20063                                .entry(edited_buffer.read(cx).remote_id())
20064                                .or_insert_with(|| {
20065                                    project.register_buffer_with_language_servers(edited_buffer, cx)
20066                                });
20067                        });
20068                    }
20069                }
20070                cx.emit(EditorEvent::BufferEdited);
20071                cx.emit(SearchEvent::MatchesInvalidated);
20072
20073                if let Some(buffer) = edited_buffer {
20074                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20075                }
20076
20077                if *singleton_buffer_edited {
20078                    if let Some(buffer) = edited_buffer {
20079                        if buffer.read(cx).file().is_none() {
20080                            cx.emit(EditorEvent::TitleChanged);
20081                        }
20082                    }
20083                    if let Some(project) = &self.project {
20084                        #[allow(clippy::mutable_key_type)]
20085                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20086                            multibuffer
20087                                .all_buffers()
20088                                .into_iter()
20089                                .filter_map(|buffer| {
20090                                    buffer.update(cx, |buffer, cx| {
20091                                        let language = buffer.language()?;
20092                                        let should_discard = project.update(cx, |project, cx| {
20093                                            project.is_local()
20094                                                && !project.has_language_servers_for(buffer, cx)
20095                                        });
20096                                        should_discard.not().then_some(language.clone())
20097                                    })
20098                                })
20099                                .collect::<HashSet<_>>()
20100                        });
20101                        if !languages_affected.is_empty() {
20102                            self.refresh_inlay_hints(
20103                                InlayHintRefreshReason::BufferEdited(languages_affected),
20104                                cx,
20105                            );
20106                        }
20107                    }
20108                }
20109
20110                let Some(project) = &self.project else { return };
20111                let (telemetry, is_via_ssh) = {
20112                    let project = project.read(cx);
20113                    let telemetry = project.client().telemetry().clone();
20114                    let is_via_ssh = project.is_via_ssh();
20115                    (telemetry, is_via_ssh)
20116                };
20117                refresh_linked_ranges(self, window, cx);
20118                telemetry.log_edit_event("editor", is_via_ssh);
20119            }
20120            multi_buffer::Event::ExcerptsAdded {
20121                buffer,
20122                predecessor,
20123                excerpts,
20124            } => {
20125                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20126                let buffer_id = buffer.read(cx).remote_id();
20127                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
20128                    if let Some(project) = &self.project {
20129                        update_uncommitted_diff_for_buffer(
20130                            cx.entity(),
20131                            project,
20132                            [buffer.clone()],
20133                            self.buffer.clone(),
20134                            cx,
20135                        )
20136                        .detach();
20137                    }
20138                }
20139                self.update_lsp_data(false, Some(buffer_id), window, cx);
20140                cx.emit(EditorEvent::ExcerptsAdded {
20141                    buffer: buffer.clone(),
20142                    predecessor: *predecessor,
20143                    excerpts: excerpts.clone(),
20144                });
20145                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20146            }
20147            multi_buffer::Event::ExcerptsRemoved {
20148                ids,
20149                removed_buffer_ids,
20150            } => {
20151                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20152                let buffer = self.buffer.read(cx);
20153                self.registered_buffers
20154                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20155                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20156                cx.emit(EditorEvent::ExcerptsRemoved {
20157                    ids: ids.clone(),
20158                    removed_buffer_ids: removed_buffer_ids.clone(),
20159                });
20160            }
20161            multi_buffer::Event::ExcerptsEdited {
20162                excerpt_ids,
20163                buffer_ids,
20164            } => {
20165                self.display_map.update(cx, |map, cx| {
20166                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20167                });
20168                cx.emit(EditorEvent::ExcerptsEdited {
20169                    ids: excerpt_ids.clone(),
20170                });
20171            }
20172            multi_buffer::Event::ExcerptsExpanded { ids } => {
20173                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20174                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20175            }
20176            multi_buffer::Event::Reparsed(buffer_id) => {
20177                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20178                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20179
20180                cx.emit(EditorEvent::Reparsed(*buffer_id));
20181            }
20182            multi_buffer::Event::DiffHunksToggled => {
20183                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20184            }
20185            multi_buffer::Event::LanguageChanged(buffer_id) => {
20186                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20187                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20188                cx.emit(EditorEvent::Reparsed(*buffer_id));
20189                cx.notify();
20190            }
20191            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20192            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20193            multi_buffer::Event::FileHandleChanged
20194            | multi_buffer::Event::Reloaded
20195            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20196            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20197            multi_buffer::Event::DiagnosticsUpdated => {
20198                self.update_diagnostics_state(window, cx);
20199            }
20200            _ => {}
20201        };
20202    }
20203
20204    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20205        if !self.diagnostics_enabled() {
20206            return;
20207        }
20208        self.refresh_active_diagnostics(cx);
20209        self.refresh_inline_diagnostics(true, window, cx);
20210        self.scrollbar_marker_state.dirty = true;
20211        cx.notify();
20212    }
20213
20214    pub fn start_temporary_diff_override(&mut self) {
20215        self.load_diff_task.take();
20216        self.temporary_diff_override = true;
20217    }
20218
20219    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20220        self.temporary_diff_override = false;
20221        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20222        self.buffer.update(cx, |buffer, cx| {
20223            buffer.set_all_diff_hunks_collapsed(cx);
20224        });
20225
20226        if let Some(project) = self.project.clone() {
20227            self.load_diff_task = Some(
20228                update_uncommitted_diff_for_buffer(
20229                    cx.entity(),
20230                    &project,
20231                    self.buffer.read(cx).all_buffers(),
20232                    self.buffer.clone(),
20233                    cx,
20234                )
20235                .shared(),
20236            );
20237        }
20238    }
20239
20240    fn on_display_map_changed(
20241        &mut self,
20242        _: Entity<DisplayMap>,
20243        _: &mut Window,
20244        cx: &mut Context<Self>,
20245    ) {
20246        cx.notify();
20247    }
20248
20249    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20250        if self.diagnostics_enabled() {
20251            let new_severity = EditorSettings::get_global(cx)
20252                .diagnostics_max_severity
20253                .unwrap_or(DiagnosticSeverity::Hint);
20254            self.set_max_diagnostics_severity(new_severity, cx);
20255        }
20256        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20257        self.update_edit_prediction_settings(cx);
20258        self.refresh_edit_prediction(true, false, window, cx);
20259        self.refresh_inline_values(cx);
20260        self.refresh_inlay_hints(
20261            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20262                self.selections.newest_anchor().head(),
20263                &self.buffer.read(cx).snapshot(cx),
20264                cx,
20265            )),
20266            cx,
20267        );
20268
20269        let old_cursor_shape = self.cursor_shape;
20270        let old_show_breadcrumbs = self.show_breadcrumbs;
20271
20272        {
20273            let editor_settings = EditorSettings::get_global(cx);
20274            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20275            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20276            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20277            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20278        }
20279
20280        if old_cursor_shape != self.cursor_shape {
20281            cx.emit(EditorEvent::CursorShapeChanged);
20282        }
20283
20284        if old_show_breadcrumbs != self.show_breadcrumbs {
20285            cx.emit(EditorEvent::BreadcrumbsChanged);
20286        }
20287
20288        let project_settings = ProjectSettings::get_global(cx);
20289        self.serialize_dirty_buffers =
20290            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20291
20292        if self.mode.is_full() {
20293            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20294            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20295            if self.show_inline_diagnostics != show_inline_diagnostics {
20296                self.show_inline_diagnostics = show_inline_diagnostics;
20297                self.refresh_inline_diagnostics(false, window, cx);
20298            }
20299
20300            if self.git_blame_inline_enabled != inline_blame_enabled {
20301                self.toggle_git_blame_inline_internal(false, window, cx);
20302            }
20303
20304            let minimap_settings = EditorSettings::get_global(cx).minimap;
20305            if self.minimap_visibility != MinimapVisibility::Disabled {
20306                if self.minimap_visibility.settings_visibility()
20307                    != minimap_settings.minimap_enabled()
20308                {
20309                    self.set_minimap_visibility(
20310                        MinimapVisibility::for_mode(self.mode(), cx),
20311                        window,
20312                        cx,
20313                    );
20314                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20315                    minimap_entity.update(cx, |minimap_editor, cx| {
20316                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20317                    })
20318                }
20319            }
20320        }
20321
20322        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20323            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20324        }) {
20325            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20326                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20327            }
20328            self.refresh_colors(false, None, window, cx);
20329        }
20330
20331        cx.notify();
20332    }
20333
20334    pub fn set_searchable(&mut self, searchable: bool) {
20335        self.searchable = searchable;
20336    }
20337
20338    pub fn searchable(&self) -> bool {
20339        self.searchable
20340    }
20341
20342    fn open_proposed_changes_editor(
20343        &mut self,
20344        _: &OpenProposedChangesEditor,
20345        window: &mut Window,
20346        cx: &mut Context<Self>,
20347    ) {
20348        let Some(workspace) = self.workspace() else {
20349            cx.propagate();
20350            return;
20351        };
20352
20353        let selections = self.selections.all::<usize>(cx);
20354        let multi_buffer = self.buffer.read(cx);
20355        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20356        let mut new_selections_by_buffer = HashMap::default();
20357        for selection in selections {
20358            for (buffer, range, _) in
20359                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20360            {
20361                let mut range = range.to_point(buffer);
20362                range.start.column = 0;
20363                range.end.column = buffer.line_len(range.end.row);
20364                new_selections_by_buffer
20365                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20366                    .or_insert(Vec::new())
20367                    .push(range)
20368            }
20369        }
20370
20371        let proposed_changes_buffers = new_selections_by_buffer
20372            .into_iter()
20373            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20374            .collect::<Vec<_>>();
20375        let proposed_changes_editor = cx.new(|cx| {
20376            ProposedChangesEditor::new(
20377                "Proposed changes",
20378                proposed_changes_buffers,
20379                self.project.clone(),
20380                window,
20381                cx,
20382            )
20383        });
20384
20385        window.defer(cx, move |window, cx| {
20386            workspace.update(cx, |workspace, cx| {
20387                workspace.active_pane().update(cx, |pane, cx| {
20388                    pane.add_item(
20389                        Box::new(proposed_changes_editor),
20390                        true,
20391                        true,
20392                        None,
20393                        window,
20394                        cx,
20395                    );
20396                });
20397            });
20398        });
20399    }
20400
20401    pub fn open_excerpts_in_split(
20402        &mut self,
20403        _: &OpenExcerptsSplit,
20404        window: &mut Window,
20405        cx: &mut Context<Self>,
20406    ) {
20407        self.open_excerpts_common(None, true, window, cx)
20408    }
20409
20410    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20411        self.open_excerpts_common(None, false, window, cx)
20412    }
20413
20414    fn open_excerpts_common(
20415        &mut self,
20416        jump_data: Option<JumpData>,
20417        split: bool,
20418        window: &mut Window,
20419        cx: &mut Context<Self>,
20420    ) {
20421        let Some(workspace) = self.workspace() else {
20422            cx.propagate();
20423            return;
20424        };
20425
20426        if self.buffer.read(cx).is_singleton() {
20427            cx.propagate();
20428            return;
20429        }
20430
20431        let mut new_selections_by_buffer = HashMap::default();
20432        match &jump_data {
20433            Some(JumpData::MultiBufferPoint {
20434                excerpt_id,
20435                position,
20436                anchor,
20437                line_offset_from_top,
20438            }) => {
20439                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20440                if let Some(buffer) = multi_buffer_snapshot
20441                    .buffer_id_for_excerpt(*excerpt_id)
20442                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20443                {
20444                    let buffer_snapshot = buffer.read(cx).snapshot();
20445                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20446                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20447                    } else {
20448                        buffer_snapshot.clip_point(*position, Bias::Left)
20449                    };
20450                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20451                    new_selections_by_buffer.insert(
20452                        buffer,
20453                        (
20454                            vec![jump_to_offset..jump_to_offset],
20455                            Some(*line_offset_from_top),
20456                        ),
20457                    );
20458                }
20459            }
20460            Some(JumpData::MultiBufferRow {
20461                row,
20462                line_offset_from_top,
20463            }) => {
20464                let point = MultiBufferPoint::new(row.0, 0);
20465                if let Some((buffer, buffer_point, _)) =
20466                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20467                {
20468                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20469                    new_selections_by_buffer
20470                        .entry(buffer)
20471                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20472                        .0
20473                        .push(buffer_offset..buffer_offset)
20474                }
20475            }
20476            None => {
20477                let selections = self.selections.all::<usize>(cx);
20478                let multi_buffer = self.buffer.read(cx);
20479                for selection in selections {
20480                    for (snapshot, range, _, anchor) in multi_buffer
20481                        .snapshot(cx)
20482                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20483                    {
20484                        if let Some(anchor) = anchor {
20485                            // selection is in a deleted hunk
20486                            let Some(buffer_id) = anchor.buffer_id else {
20487                                continue;
20488                            };
20489                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20490                                continue;
20491                            };
20492                            let offset = text::ToOffset::to_offset(
20493                                &anchor.text_anchor,
20494                                &buffer_handle.read(cx).snapshot(),
20495                            );
20496                            let range = offset..offset;
20497                            new_selections_by_buffer
20498                                .entry(buffer_handle)
20499                                .or_insert((Vec::new(), None))
20500                                .0
20501                                .push(range)
20502                        } else {
20503                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20504                            else {
20505                                continue;
20506                            };
20507                            new_selections_by_buffer
20508                                .entry(buffer_handle)
20509                                .or_insert((Vec::new(), None))
20510                                .0
20511                                .push(range)
20512                        }
20513                    }
20514                }
20515            }
20516        }
20517
20518        new_selections_by_buffer
20519            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20520
20521        if new_selections_by_buffer.is_empty() {
20522            return;
20523        }
20524
20525        // We defer the pane interaction because we ourselves are a workspace item
20526        // and activating a new item causes the pane to call a method on us reentrantly,
20527        // which panics if we're on the stack.
20528        window.defer(cx, move |window, cx| {
20529            workspace.update(cx, |workspace, cx| {
20530                let pane = if split {
20531                    workspace.adjacent_pane(window, cx)
20532                } else {
20533                    workspace.active_pane().clone()
20534                };
20535
20536                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20537                    let editor = buffer
20538                        .read(cx)
20539                        .file()
20540                        .is_none()
20541                        .then(|| {
20542                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20543                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20544                            // Instead, we try to activate the existing editor in the pane first.
20545                            let (editor, pane_item_index) =
20546                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20547                                    let editor = item.downcast::<Editor>()?;
20548                                    let singleton_buffer =
20549                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20550                                    if singleton_buffer == buffer {
20551                                        Some((editor, i))
20552                                    } else {
20553                                        None
20554                                    }
20555                                })?;
20556                            pane.update(cx, |pane, cx| {
20557                                pane.activate_item(pane_item_index, true, true, window, cx)
20558                            });
20559                            Some(editor)
20560                        })
20561                        .flatten()
20562                        .unwrap_or_else(|| {
20563                            workspace.open_project_item::<Self>(
20564                                pane.clone(),
20565                                buffer,
20566                                true,
20567                                true,
20568                                window,
20569                                cx,
20570                            )
20571                        });
20572
20573                    editor.update(cx, |editor, cx| {
20574                        let autoscroll = match scroll_offset {
20575                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20576                            None => Autoscroll::newest(),
20577                        };
20578                        let nav_history = editor.nav_history.take();
20579                        editor.change_selections(
20580                            SelectionEffects::scroll(autoscroll),
20581                            window,
20582                            cx,
20583                            |s| {
20584                                s.select_ranges(ranges);
20585                            },
20586                        );
20587                        editor.nav_history = nav_history;
20588                    });
20589                }
20590            })
20591        });
20592    }
20593
20594    // For now, don't allow opening excerpts in buffers that aren't backed by
20595    // regular project files.
20596    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20597        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20598    }
20599
20600    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20601        let snapshot = self.buffer.read(cx).read(cx);
20602        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20603        Some(
20604            ranges
20605                .iter()
20606                .map(move |range| {
20607                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20608                })
20609                .collect(),
20610        )
20611    }
20612
20613    fn selection_replacement_ranges(
20614        &self,
20615        range: Range<OffsetUtf16>,
20616        cx: &mut App,
20617    ) -> Vec<Range<OffsetUtf16>> {
20618        let selections = self.selections.all::<OffsetUtf16>(cx);
20619        let newest_selection = selections
20620            .iter()
20621            .max_by_key(|selection| selection.id)
20622            .unwrap();
20623        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20624        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20625        let snapshot = self.buffer.read(cx).read(cx);
20626        selections
20627            .into_iter()
20628            .map(|mut selection| {
20629                selection.start.0 =
20630                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20631                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20632                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20633                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20634            })
20635            .collect()
20636    }
20637
20638    fn report_editor_event(
20639        &self,
20640        reported_event: ReportEditorEvent,
20641        file_extension: Option<String>,
20642        cx: &App,
20643    ) {
20644        if cfg!(any(test, feature = "test-support")) {
20645            return;
20646        }
20647
20648        let Some(project) = &self.project else { return };
20649
20650        // If None, we are in a file without an extension
20651        let file = self
20652            .buffer
20653            .read(cx)
20654            .as_singleton()
20655            .and_then(|b| b.read(cx).file());
20656        let file_extension = file_extension.or(file
20657            .as_ref()
20658            .and_then(|file| Path::new(file.file_name(cx)).extension())
20659            .and_then(|e| e.to_str())
20660            .map(|a| a.to_string()));
20661
20662        let vim_mode = vim_enabled(cx);
20663
20664        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20665        let copilot_enabled = edit_predictions_provider
20666            == language::language_settings::EditPredictionProvider::Copilot;
20667        let copilot_enabled_for_language = self
20668            .buffer
20669            .read(cx)
20670            .language_settings(cx)
20671            .show_edit_predictions;
20672
20673        let project = project.read(cx);
20674        let event_type = reported_event.event_type();
20675
20676        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20677            telemetry::event!(
20678                event_type,
20679                type = if auto_saved {"autosave"} else {"manual"},
20680                file_extension,
20681                vim_mode,
20682                copilot_enabled,
20683                copilot_enabled_for_language,
20684                edit_predictions_provider,
20685                is_via_ssh = project.is_via_ssh(),
20686            );
20687        } else {
20688            telemetry::event!(
20689                event_type,
20690                file_extension,
20691                vim_mode,
20692                copilot_enabled,
20693                copilot_enabled_for_language,
20694                edit_predictions_provider,
20695                is_via_ssh = project.is_via_ssh(),
20696            );
20697        };
20698    }
20699
20700    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20701    /// with each line being an array of {text, highlight} objects.
20702    fn copy_highlight_json(
20703        &mut self,
20704        _: &CopyHighlightJson,
20705        window: &mut Window,
20706        cx: &mut Context<Self>,
20707    ) {
20708        #[derive(Serialize)]
20709        struct Chunk<'a> {
20710            text: String,
20711            highlight: Option<&'a str>,
20712        }
20713
20714        let snapshot = self.buffer.read(cx).snapshot(cx);
20715        let range = self
20716            .selected_text_range(false, window, cx)
20717            .and_then(|selection| {
20718                if selection.range.is_empty() {
20719                    None
20720                } else {
20721                    Some(selection.range)
20722                }
20723            })
20724            .unwrap_or_else(|| 0..snapshot.len());
20725
20726        let chunks = snapshot.chunks(range, true);
20727        let mut lines = Vec::new();
20728        let mut line: VecDeque<Chunk> = VecDeque::new();
20729
20730        let Some(style) = self.style.as_ref() else {
20731            return;
20732        };
20733
20734        for chunk in chunks {
20735            let highlight = chunk
20736                .syntax_highlight_id
20737                .and_then(|id| id.name(&style.syntax));
20738            let mut chunk_lines = chunk.text.split('\n').peekable();
20739            while let Some(text) = chunk_lines.next() {
20740                let mut merged_with_last_token = false;
20741                if let Some(last_token) = line.back_mut() {
20742                    if last_token.highlight == highlight {
20743                        last_token.text.push_str(text);
20744                        merged_with_last_token = true;
20745                    }
20746                }
20747
20748                if !merged_with_last_token {
20749                    line.push_back(Chunk {
20750                        text: text.into(),
20751                        highlight,
20752                    });
20753                }
20754
20755                if chunk_lines.peek().is_some() {
20756                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20757                        line.pop_front();
20758                    }
20759                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20760                        line.pop_back();
20761                    }
20762
20763                    lines.push(mem::take(&mut line));
20764                }
20765            }
20766        }
20767
20768        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20769            return;
20770        };
20771        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20772    }
20773
20774    pub fn open_context_menu(
20775        &mut self,
20776        _: &OpenContextMenu,
20777        window: &mut Window,
20778        cx: &mut Context<Self>,
20779    ) {
20780        self.request_autoscroll(Autoscroll::newest(), cx);
20781        let position = self.selections.newest_display(cx).start;
20782        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20783    }
20784
20785    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20786        &self.inlay_hint_cache
20787    }
20788
20789    pub fn replay_insert_event(
20790        &mut self,
20791        text: &str,
20792        relative_utf16_range: Option<Range<isize>>,
20793        window: &mut Window,
20794        cx: &mut Context<Self>,
20795    ) {
20796        if !self.input_enabled {
20797            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20798            return;
20799        }
20800        if let Some(relative_utf16_range) = relative_utf16_range {
20801            let selections = self.selections.all::<OffsetUtf16>(cx);
20802            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20803                let new_ranges = selections.into_iter().map(|range| {
20804                    let start = OffsetUtf16(
20805                        range
20806                            .head()
20807                            .0
20808                            .saturating_add_signed(relative_utf16_range.start),
20809                    );
20810                    let end = OffsetUtf16(
20811                        range
20812                            .head()
20813                            .0
20814                            .saturating_add_signed(relative_utf16_range.end),
20815                    );
20816                    start..end
20817                });
20818                s.select_ranges(new_ranges);
20819            });
20820        }
20821
20822        self.handle_input(text, window, cx);
20823    }
20824
20825    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20826        let Some(provider) = self.semantics_provider.as_ref() else {
20827            return false;
20828        };
20829
20830        let mut supports = false;
20831        self.buffer().update(cx, |this, cx| {
20832            this.for_each_buffer(|buffer| {
20833                supports |= provider.supports_inlay_hints(buffer, cx);
20834            });
20835        });
20836
20837        supports
20838    }
20839
20840    pub fn is_focused(&self, window: &Window) -> bool {
20841        self.focus_handle.is_focused(window)
20842    }
20843
20844    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20845        cx.emit(EditorEvent::Focused);
20846
20847        if let Some(descendant) = self
20848            .last_focused_descendant
20849            .take()
20850            .and_then(|descendant| descendant.upgrade())
20851        {
20852            window.focus(&descendant);
20853        } else {
20854            if let Some(blame) = self.blame.as_ref() {
20855                blame.update(cx, GitBlame::focus)
20856            }
20857
20858            self.blink_manager.update(cx, BlinkManager::enable);
20859            self.show_cursor_names(window, cx);
20860            self.buffer.update(cx, |buffer, cx| {
20861                buffer.finalize_last_transaction(cx);
20862                if self.leader_id.is_none() {
20863                    buffer.set_active_selections(
20864                        &self.selections.disjoint_anchors(),
20865                        self.selections.line_mode,
20866                        self.cursor_shape,
20867                        cx,
20868                    );
20869                }
20870            });
20871        }
20872    }
20873
20874    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20875        cx.emit(EditorEvent::FocusedIn)
20876    }
20877
20878    fn handle_focus_out(
20879        &mut self,
20880        event: FocusOutEvent,
20881        _window: &mut Window,
20882        cx: &mut Context<Self>,
20883    ) {
20884        if event.blurred != self.focus_handle {
20885            self.last_focused_descendant = Some(event.blurred);
20886        }
20887        self.selection_drag_state = SelectionDragState::None;
20888        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20889    }
20890
20891    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20892        self.blink_manager.update(cx, BlinkManager::disable);
20893        self.buffer
20894            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20895
20896        if let Some(blame) = self.blame.as_ref() {
20897            blame.update(cx, GitBlame::blur)
20898        }
20899        if !self.hover_state.focused(window, cx) {
20900            hide_hover(self, cx);
20901        }
20902        if !self
20903            .context_menu
20904            .borrow()
20905            .as_ref()
20906            .is_some_and(|context_menu| context_menu.focused(window, cx))
20907        {
20908            self.hide_context_menu(window, cx);
20909        }
20910        self.discard_edit_prediction(false, cx);
20911        cx.emit(EditorEvent::Blurred);
20912        cx.notify();
20913    }
20914
20915    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20916        let mut pending: String = window
20917            .pending_input_keystrokes()
20918            .into_iter()
20919            .flatten()
20920            .filter_map(|keystroke| {
20921                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20922                    keystroke.key_char.clone()
20923                } else {
20924                    None
20925                }
20926            })
20927            .collect();
20928
20929        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20930            pending = "".to_string();
20931        }
20932
20933        let existing_pending = self
20934            .text_highlights::<PendingInput>(cx)
20935            .map(|(_, ranges)| ranges.to_vec());
20936        if existing_pending.is_none() && pending.is_empty() {
20937            return;
20938        }
20939        let transaction =
20940            self.transact(window, cx, |this, window, cx| {
20941                let selections = this.selections.all::<usize>(cx);
20942                let edits = selections
20943                    .iter()
20944                    .map(|selection| (selection.end..selection.end, pending.clone()));
20945                this.edit(edits, cx);
20946                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20947                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20948                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20949                    }));
20950                });
20951                if let Some(existing_ranges) = existing_pending {
20952                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20953                    this.edit(edits, cx);
20954                }
20955            });
20956
20957        let snapshot = self.snapshot(window, cx);
20958        let ranges = self
20959            .selections
20960            .all::<usize>(cx)
20961            .into_iter()
20962            .map(|selection| {
20963                snapshot.buffer_snapshot.anchor_after(selection.end)
20964                    ..snapshot
20965                        .buffer_snapshot
20966                        .anchor_before(selection.end + pending.len())
20967            })
20968            .collect();
20969
20970        if pending.is_empty() {
20971            self.clear_highlights::<PendingInput>(cx);
20972        } else {
20973            self.highlight_text::<PendingInput>(
20974                ranges,
20975                HighlightStyle {
20976                    underline: Some(UnderlineStyle {
20977                        thickness: px(1.),
20978                        color: None,
20979                        wavy: false,
20980                    }),
20981                    ..Default::default()
20982                },
20983                cx,
20984            );
20985        }
20986
20987        self.ime_transaction = self.ime_transaction.or(transaction);
20988        if let Some(transaction) = self.ime_transaction {
20989            self.buffer.update(cx, |buffer, cx| {
20990                buffer.group_until_transaction(transaction, cx);
20991            });
20992        }
20993
20994        if self.text_highlights::<PendingInput>(cx).is_none() {
20995            self.ime_transaction.take();
20996        }
20997    }
20998
20999    pub fn register_action_renderer(
21000        &mut self,
21001        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21002    ) -> Subscription {
21003        let id = self.next_editor_action_id.post_inc();
21004        self.editor_actions
21005            .borrow_mut()
21006            .insert(id, Box::new(listener));
21007
21008        let editor_actions = self.editor_actions.clone();
21009        Subscription::new(move || {
21010            editor_actions.borrow_mut().remove(&id);
21011        })
21012    }
21013
21014    pub fn register_action<A: Action>(
21015        &mut self,
21016        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21017    ) -> Subscription {
21018        let id = self.next_editor_action_id.post_inc();
21019        let listener = Arc::new(listener);
21020        self.editor_actions.borrow_mut().insert(
21021            id,
21022            Box::new(move |_, window, _| {
21023                let listener = listener.clone();
21024                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21025                    let action = action.downcast_ref().unwrap();
21026                    if phase == DispatchPhase::Bubble {
21027                        listener(action, window, cx)
21028                    }
21029                })
21030            }),
21031        );
21032
21033        let editor_actions = self.editor_actions.clone();
21034        Subscription::new(move || {
21035            editor_actions.borrow_mut().remove(&id);
21036        })
21037    }
21038
21039    pub fn file_header_size(&self) -> u32 {
21040        FILE_HEADER_HEIGHT
21041    }
21042
21043    pub fn restore(
21044        &mut self,
21045        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21046        window: &mut Window,
21047        cx: &mut Context<Self>,
21048    ) {
21049        let workspace = self.workspace();
21050        let project = self.project();
21051        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21052            let mut tasks = Vec::new();
21053            for (buffer_id, changes) in revert_changes {
21054                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21055                    buffer.update(cx, |buffer, cx| {
21056                        buffer.edit(
21057                            changes
21058                                .into_iter()
21059                                .map(|(range, text)| (range, text.to_string())),
21060                            None,
21061                            cx,
21062                        );
21063                    });
21064
21065                    if let Some(project) =
21066                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21067                    {
21068                        project.update(cx, |project, cx| {
21069                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21070                        })
21071                    }
21072                }
21073            }
21074            tasks
21075        });
21076        cx.spawn_in(window, async move |_, cx| {
21077            for (buffer, task) in save_tasks {
21078                let result = task.await;
21079                if result.is_err() {
21080                    let Some(path) = buffer
21081                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21082                        .ok()
21083                    else {
21084                        continue;
21085                    };
21086                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21087                        let Some(task) = cx
21088                            .update_window_entity(workspace, |workspace, window, cx| {
21089                                workspace
21090                                    .open_path_preview(path, None, false, false, false, window, cx)
21091                            })
21092                            .ok()
21093                        else {
21094                            continue;
21095                        };
21096                        task.await.log_err();
21097                    }
21098                }
21099            }
21100        })
21101        .detach();
21102        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21103            selections.refresh()
21104        });
21105    }
21106
21107    pub fn to_pixel_point(
21108        &self,
21109        source: multi_buffer::Anchor,
21110        editor_snapshot: &EditorSnapshot,
21111        window: &mut Window,
21112    ) -> Option<gpui::Point<Pixels>> {
21113        let source_point = source.to_display_point(editor_snapshot);
21114        self.display_to_pixel_point(source_point, editor_snapshot, window)
21115    }
21116
21117    pub fn display_to_pixel_point(
21118        &self,
21119        source: DisplayPoint,
21120        editor_snapshot: &EditorSnapshot,
21121        window: &mut Window,
21122    ) -> Option<gpui::Point<Pixels>> {
21123        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21124        let text_layout_details = self.text_layout_details(window);
21125        let scroll_top = text_layout_details
21126            .scroll_anchor
21127            .scroll_position(editor_snapshot)
21128            .y;
21129
21130        if source.row().as_f32() < scroll_top.floor() {
21131            return None;
21132        }
21133        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21134        let source_y = line_height * (source.row().as_f32() - scroll_top);
21135        Some(gpui::Point::new(source_x, source_y))
21136    }
21137
21138    pub fn has_visible_completions_menu(&self) -> bool {
21139        !self.edit_prediction_preview_is_active()
21140            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
21141                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21142            })
21143    }
21144
21145    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21146        if self.mode.is_minimap() {
21147            return;
21148        }
21149        self.addons
21150            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21151    }
21152
21153    pub fn unregister_addon<T: Addon>(&mut self) {
21154        self.addons.remove(&std::any::TypeId::of::<T>());
21155    }
21156
21157    pub fn addon<T: Addon>(&self) -> Option<&T> {
21158        let type_id = std::any::TypeId::of::<T>();
21159        self.addons
21160            .get(&type_id)
21161            .and_then(|item| item.to_any().downcast_ref::<T>())
21162    }
21163
21164    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21165        let type_id = std::any::TypeId::of::<T>();
21166        self.addons
21167            .get_mut(&type_id)
21168            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21169    }
21170
21171    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21172        let text_layout_details = self.text_layout_details(window);
21173        let style = &text_layout_details.editor_style;
21174        let font_id = window.text_system().resolve_font(&style.text.font());
21175        let font_size = style.text.font_size.to_pixels(window.rem_size());
21176        let line_height = style.text.line_height_in_pixels(window.rem_size());
21177        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21178        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21179
21180        CharacterDimensions {
21181            em_width,
21182            em_advance,
21183            line_height,
21184        }
21185    }
21186
21187    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21188        self.load_diff_task.clone()
21189    }
21190
21191    fn read_metadata_from_db(
21192        &mut self,
21193        item_id: u64,
21194        workspace_id: WorkspaceId,
21195        window: &mut Window,
21196        cx: &mut Context<Editor>,
21197    ) {
21198        if self.is_singleton(cx)
21199            && !self.mode.is_minimap()
21200            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21201        {
21202            let buffer_snapshot = OnceCell::new();
21203
21204            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21205                if !folds.is_empty() {
21206                    let snapshot =
21207                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21208                    self.fold_ranges(
21209                        folds
21210                            .into_iter()
21211                            .map(|(start, end)| {
21212                                snapshot.clip_offset(start, Bias::Left)
21213                                    ..snapshot.clip_offset(end, Bias::Right)
21214                            })
21215                            .collect(),
21216                        false,
21217                        window,
21218                        cx,
21219                    );
21220                }
21221            }
21222
21223            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21224                if !selections.is_empty() {
21225                    let snapshot =
21226                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21227                    // skip adding the initial selection to selection history
21228                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21229                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21230                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21231                            snapshot.clip_offset(start, Bias::Left)
21232                                ..snapshot.clip_offset(end, Bias::Right)
21233                        }));
21234                    });
21235                    self.selection_history.mode = SelectionHistoryMode::Normal;
21236                }
21237            };
21238        }
21239
21240        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21241    }
21242
21243    fn update_lsp_data(
21244        &mut self,
21245        ignore_cache: bool,
21246        for_buffer: Option<BufferId>,
21247        window: &mut Window,
21248        cx: &mut Context<'_, Self>,
21249    ) {
21250        self.pull_diagnostics(for_buffer, window, cx);
21251        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21252    }
21253}
21254
21255fn vim_enabled(cx: &App) -> bool {
21256    cx.global::<SettingsStore>()
21257        .raw_user_settings()
21258        .get("vim_mode")
21259        == Some(&serde_json::Value::Bool(true))
21260}
21261
21262fn process_completion_for_edit(
21263    completion: &Completion,
21264    intent: CompletionIntent,
21265    buffer: &Entity<Buffer>,
21266    cursor_position: &text::Anchor,
21267    cx: &mut Context<Editor>,
21268) -> CompletionEdit {
21269    let buffer = buffer.read(cx);
21270    let buffer_snapshot = buffer.snapshot();
21271    let (snippet, new_text) = if completion.is_snippet() {
21272        // Workaround for typescript language server issues so that methods don't expand within
21273        // strings and functions with type expressions. The previous point is used because the query
21274        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21275        let mut snippet_source = completion.new_text.clone();
21276        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21277        previous_point.column = previous_point.column.saturating_sub(1);
21278        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21279            if scope.prefers_label_for_snippet_in_completion() {
21280                if let Some(label) = completion.label() {
21281                    if matches!(
21282                        completion.kind(),
21283                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21284                    ) {
21285                        snippet_source = label;
21286                    }
21287                }
21288            }
21289        }
21290        match Snippet::parse(&snippet_source).log_err() {
21291            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21292            None => (None, completion.new_text.clone()),
21293        }
21294    } else {
21295        (None, completion.new_text.clone())
21296    };
21297
21298    let mut range_to_replace = {
21299        let replace_range = &completion.replace_range;
21300        if let CompletionSource::Lsp {
21301            insert_range: Some(insert_range),
21302            ..
21303        } = &completion.source
21304        {
21305            debug_assert_eq!(
21306                insert_range.start, replace_range.start,
21307                "insert_range and replace_range should start at the same position"
21308            );
21309            debug_assert!(
21310                insert_range
21311                    .start
21312                    .cmp(cursor_position, &buffer_snapshot)
21313                    .is_le(),
21314                "insert_range should start before or at cursor position"
21315            );
21316            debug_assert!(
21317                replace_range
21318                    .start
21319                    .cmp(cursor_position, &buffer_snapshot)
21320                    .is_le(),
21321                "replace_range should start before or at cursor position"
21322            );
21323
21324            let should_replace = match intent {
21325                CompletionIntent::CompleteWithInsert => false,
21326                CompletionIntent::CompleteWithReplace => true,
21327                CompletionIntent::Complete | CompletionIntent::Compose => {
21328                    let insert_mode =
21329                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21330                            .completions
21331                            .lsp_insert_mode;
21332                    match insert_mode {
21333                        LspInsertMode::Insert => false,
21334                        LspInsertMode::Replace => true,
21335                        LspInsertMode::ReplaceSubsequence => {
21336                            let mut text_to_replace = buffer.chars_for_range(
21337                                buffer.anchor_before(replace_range.start)
21338                                    ..buffer.anchor_after(replace_range.end),
21339                            );
21340                            let mut current_needle = text_to_replace.next();
21341                            for haystack_ch in completion.label.text.chars() {
21342                                if let Some(needle_ch) = current_needle {
21343                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21344                                        current_needle = text_to_replace.next();
21345                                    }
21346                                }
21347                            }
21348                            current_needle.is_none()
21349                        }
21350                        LspInsertMode::ReplaceSuffix => {
21351                            if replace_range
21352                                .end
21353                                .cmp(cursor_position, &buffer_snapshot)
21354                                .is_gt()
21355                            {
21356                                let range_after_cursor = *cursor_position..replace_range.end;
21357                                let text_after_cursor = buffer
21358                                    .text_for_range(
21359                                        buffer.anchor_before(range_after_cursor.start)
21360                                            ..buffer.anchor_after(range_after_cursor.end),
21361                                    )
21362                                    .collect::<String>()
21363                                    .to_ascii_lowercase();
21364                                completion
21365                                    .label
21366                                    .text
21367                                    .to_ascii_lowercase()
21368                                    .ends_with(&text_after_cursor)
21369                            } else {
21370                                true
21371                            }
21372                        }
21373                    }
21374                }
21375            };
21376
21377            if should_replace {
21378                replace_range.clone()
21379            } else {
21380                insert_range.clone()
21381            }
21382        } else {
21383            replace_range.clone()
21384        }
21385    };
21386
21387    if range_to_replace
21388        .end
21389        .cmp(cursor_position, &buffer_snapshot)
21390        .is_lt()
21391    {
21392        range_to_replace.end = *cursor_position;
21393    }
21394
21395    CompletionEdit {
21396        new_text,
21397        replace_range: range_to_replace.to_offset(buffer),
21398        snippet,
21399    }
21400}
21401
21402struct CompletionEdit {
21403    new_text: String,
21404    replace_range: Range<usize>,
21405    snippet: Option<Snippet>,
21406}
21407
21408fn insert_extra_newline_brackets(
21409    buffer: &MultiBufferSnapshot,
21410    range: Range<usize>,
21411    language: &language::LanguageScope,
21412) -> bool {
21413    let leading_whitespace_len = buffer
21414        .reversed_chars_at(range.start)
21415        .take_while(|c| c.is_whitespace() && *c != '\n')
21416        .map(|c| c.len_utf8())
21417        .sum::<usize>();
21418    let trailing_whitespace_len = buffer
21419        .chars_at(range.end)
21420        .take_while(|c| c.is_whitespace() && *c != '\n')
21421        .map(|c| c.len_utf8())
21422        .sum::<usize>();
21423    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21424
21425    language.brackets().any(|(pair, enabled)| {
21426        let pair_start = pair.start.trim_end();
21427        let pair_end = pair.end.trim_start();
21428
21429        enabled
21430            && pair.newline
21431            && buffer.contains_str_at(range.end, pair_end)
21432            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21433    })
21434}
21435
21436fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21437    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21438        [(buffer, range, _)] => (*buffer, range.clone()),
21439        _ => return false,
21440    };
21441    let pair = {
21442        let mut result: Option<BracketMatch> = None;
21443
21444        for pair in buffer
21445            .all_bracket_ranges(range.clone())
21446            .filter(move |pair| {
21447                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21448            })
21449        {
21450            let len = pair.close_range.end - pair.open_range.start;
21451
21452            if let Some(existing) = &result {
21453                let existing_len = existing.close_range.end - existing.open_range.start;
21454                if len > existing_len {
21455                    continue;
21456                }
21457            }
21458
21459            result = Some(pair);
21460        }
21461
21462        result
21463    };
21464    let Some(pair) = pair else {
21465        return false;
21466    };
21467    pair.newline_only
21468        && buffer
21469            .chars_for_range(pair.open_range.end..range.start)
21470            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21471            .all(|c| c.is_whitespace() && c != '\n')
21472}
21473
21474fn update_uncommitted_diff_for_buffer(
21475    editor: Entity<Editor>,
21476    project: &Entity<Project>,
21477    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21478    buffer: Entity<MultiBuffer>,
21479    cx: &mut App,
21480) -> Task<()> {
21481    let mut tasks = Vec::new();
21482    project.update(cx, |project, cx| {
21483        for buffer in buffers {
21484            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21485                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21486            }
21487        }
21488    });
21489    cx.spawn(async move |cx| {
21490        let diffs = future::join_all(tasks).await;
21491        if editor
21492            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21493            .unwrap_or(false)
21494        {
21495            return;
21496        }
21497
21498        buffer
21499            .update(cx, |buffer, cx| {
21500                for diff in diffs.into_iter().flatten() {
21501                    buffer.add_diff(diff, cx);
21502                }
21503            })
21504            .ok();
21505    })
21506}
21507
21508fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21509    let tab_size = tab_size.get() as usize;
21510    let mut width = offset;
21511
21512    for ch in text.chars() {
21513        width += if ch == '\t' {
21514            tab_size - (width % tab_size)
21515        } else {
21516            1
21517        };
21518    }
21519
21520    width - offset
21521}
21522
21523#[cfg(test)]
21524mod tests {
21525    use super::*;
21526
21527    #[test]
21528    fn test_string_size_with_expanded_tabs() {
21529        let nz = |val| NonZeroU32::new(val).unwrap();
21530        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21531        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21532        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21533        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21534        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21535        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21536        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21537        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21538    }
21539}
21540
21541/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21542struct WordBreakingTokenizer<'a> {
21543    input: &'a str,
21544}
21545
21546impl<'a> WordBreakingTokenizer<'a> {
21547    fn new(input: &'a str) -> Self {
21548        Self { input }
21549    }
21550}
21551
21552fn is_char_ideographic(ch: char) -> bool {
21553    use unicode_script::Script::*;
21554    use unicode_script::UnicodeScript;
21555    matches!(ch.script(), Han | Tangut | Yi)
21556}
21557
21558fn is_grapheme_ideographic(text: &str) -> bool {
21559    text.chars().any(is_char_ideographic)
21560}
21561
21562fn is_grapheme_whitespace(text: &str) -> bool {
21563    text.chars().any(|x| x.is_whitespace())
21564}
21565
21566fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21567    text.chars().next().map_or(false, |ch| {
21568        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21569    })
21570}
21571
21572#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21573enum WordBreakToken<'a> {
21574    Word { token: &'a str, grapheme_len: usize },
21575    InlineWhitespace { token: &'a str, grapheme_len: usize },
21576    Newline,
21577}
21578
21579impl<'a> Iterator for WordBreakingTokenizer<'a> {
21580    /// Yields a span, the count of graphemes in the token, and whether it was
21581    /// whitespace. Note that it also breaks at word boundaries.
21582    type Item = WordBreakToken<'a>;
21583
21584    fn next(&mut self) -> Option<Self::Item> {
21585        use unicode_segmentation::UnicodeSegmentation;
21586        if self.input.is_empty() {
21587            return None;
21588        }
21589
21590        let mut iter = self.input.graphemes(true).peekable();
21591        let mut offset = 0;
21592        let mut grapheme_len = 0;
21593        if let Some(first_grapheme) = iter.next() {
21594            let is_newline = first_grapheme == "\n";
21595            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21596            offset += first_grapheme.len();
21597            grapheme_len += 1;
21598            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21599                if let Some(grapheme) = iter.peek().copied() {
21600                    if should_stay_with_preceding_ideograph(grapheme) {
21601                        offset += grapheme.len();
21602                        grapheme_len += 1;
21603                    }
21604                }
21605            } else {
21606                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21607                let mut next_word_bound = words.peek().copied();
21608                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21609                    next_word_bound = words.next();
21610                }
21611                while let Some(grapheme) = iter.peek().copied() {
21612                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21613                        break;
21614                    };
21615                    if is_grapheme_whitespace(grapheme) != is_whitespace
21616                        || (grapheme == "\n") != is_newline
21617                    {
21618                        break;
21619                    };
21620                    offset += grapheme.len();
21621                    grapheme_len += 1;
21622                    iter.next();
21623                }
21624            }
21625            let token = &self.input[..offset];
21626            self.input = &self.input[offset..];
21627            if token == "\n" {
21628                Some(WordBreakToken::Newline)
21629            } else if is_whitespace {
21630                Some(WordBreakToken::InlineWhitespace {
21631                    token,
21632                    grapheme_len,
21633                })
21634            } else {
21635                Some(WordBreakToken::Word {
21636                    token,
21637                    grapheme_len,
21638                })
21639            }
21640        } else {
21641            None
21642        }
21643    }
21644}
21645
21646#[test]
21647fn test_word_breaking_tokenizer() {
21648    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21649        ("", &[]),
21650        ("  ", &[whitespace("  ", 2)]),
21651        ("Ʒ", &[word("Ʒ", 1)]),
21652        ("Ǽ", &[word("Ǽ", 1)]),
21653        ("", &[word("", 1)]),
21654        ("⋑⋑", &[word("⋑⋑", 2)]),
21655        (
21656            "原理,进而",
21657            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21658        ),
21659        (
21660            "hello world",
21661            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21662        ),
21663        (
21664            "hello, world",
21665            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21666        ),
21667        (
21668            "  hello world",
21669            &[
21670                whitespace("  ", 2),
21671                word("hello", 5),
21672                whitespace(" ", 1),
21673                word("world", 5),
21674            ],
21675        ),
21676        (
21677            "这是什么 \n 钢笔",
21678            &[
21679                word("", 1),
21680                word("", 1),
21681                word("", 1),
21682                word("", 1),
21683                whitespace(" ", 1),
21684                newline(),
21685                whitespace(" ", 1),
21686                word("", 1),
21687                word("", 1),
21688            ],
21689        ),
21690        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21691    ];
21692
21693    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21694        WordBreakToken::Word {
21695            token,
21696            grapheme_len,
21697        }
21698    }
21699
21700    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21701        WordBreakToken::InlineWhitespace {
21702            token,
21703            grapheme_len,
21704        }
21705    }
21706
21707    fn newline() -> WordBreakToken<'static> {
21708        WordBreakToken::Newline
21709    }
21710
21711    for (input, result) in tests {
21712        assert_eq!(
21713            WordBreakingTokenizer::new(input)
21714                .collect::<Vec<_>>()
21715                .as_slice(),
21716            *result,
21717        );
21718    }
21719}
21720
21721fn wrap_with_prefix(
21722    first_line_prefix: String,
21723    subsequent_lines_prefix: String,
21724    unwrapped_text: String,
21725    wrap_column: usize,
21726    tab_size: NonZeroU32,
21727    preserve_existing_whitespace: bool,
21728) -> String {
21729    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21730    let subsequent_lines_prefix_len =
21731        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21732    let mut wrapped_text = String::new();
21733    let mut current_line = first_line_prefix.clone();
21734    let mut is_first_line = true;
21735
21736    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21737    let mut current_line_len = first_line_prefix_len;
21738    let mut in_whitespace = false;
21739    for token in tokenizer {
21740        let have_preceding_whitespace = in_whitespace;
21741        match token {
21742            WordBreakToken::Word {
21743                token,
21744                grapheme_len,
21745            } => {
21746                in_whitespace = false;
21747                let current_prefix_len = if is_first_line {
21748                    first_line_prefix_len
21749                } else {
21750                    subsequent_lines_prefix_len
21751                };
21752                if current_line_len + grapheme_len > wrap_column
21753                    && current_line_len != current_prefix_len
21754                {
21755                    wrapped_text.push_str(current_line.trim_end());
21756                    wrapped_text.push('\n');
21757                    is_first_line = false;
21758                    current_line = subsequent_lines_prefix.clone();
21759                    current_line_len = subsequent_lines_prefix_len;
21760                }
21761                current_line.push_str(token);
21762                current_line_len += grapheme_len;
21763            }
21764            WordBreakToken::InlineWhitespace {
21765                mut token,
21766                mut grapheme_len,
21767            } => {
21768                in_whitespace = true;
21769                if have_preceding_whitespace && !preserve_existing_whitespace {
21770                    continue;
21771                }
21772                if !preserve_existing_whitespace {
21773                    token = " ";
21774                    grapheme_len = 1;
21775                }
21776                let current_prefix_len = if is_first_line {
21777                    first_line_prefix_len
21778                } else {
21779                    subsequent_lines_prefix_len
21780                };
21781                if current_line_len + grapheme_len > wrap_column {
21782                    wrapped_text.push_str(current_line.trim_end());
21783                    wrapped_text.push('\n');
21784                    is_first_line = false;
21785                    current_line = subsequent_lines_prefix.clone();
21786                    current_line_len = subsequent_lines_prefix_len;
21787                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21788                    current_line.push_str(token);
21789                    current_line_len += grapheme_len;
21790                }
21791            }
21792            WordBreakToken::Newline => {
21793                in_whitespace = true;
21794                let current_prefix_len = if is_first_line {
21795                    first_line_prefix_len
21796                } else {
21797                    subsequent_lines_prefix_len
21798                };
21799                if preserve_existing_whitespace {
21800                    wrapped_text.push_str(current_line.trim_end());
21801                    wrapped_text.push('\n');
21802                    is_first_line = false;
21803                    current_line = subsequent_lines_prefix.clone();
21804                    current_line_len = subsequent_lines_prefix_len;
21805                } else if have_preceding_whitespace {
21806                    continue;
21807                } else if current_line_len + 1 > wrap_column
21808                    && current_line_len != current_prefix_len
21809                {
21810                    wrapped_text.push_str(current_line.trim_end());
21811                    wrapped_text.push('\n');
21812                    is_first_line = false;
21813                    current_line = subsequent_lines_prefix.clone();
21814                    current_line_len = subsequent_lines_prefix_len;
21815                } else if current_line_len != current_prefix_len {
21816                    current_line.push(' ');
21817                    current_line_len += 1;
21818                }
21819            }
21820        }
21821    }
21822
21823    if !current_line.is_empty() {
21824        wrapped_text.push_str(&current_line);
21825    }
21826    wrapped_text
21827}
21828
21829#[test]
21830fn test_wrap_with_prefix() {
21831    assert_eq!(
21832        wrap_with_prefix(
21833            "# ".to_string(),
21834            "# ".to_string(),
21835            "abcdefg".to_string(),
21836            4,
21837            NonZeroU32::new(4).unwrap(),
21838            false,
21839        ),
21840        "# abcdefg"
21841    );
21842    assert_eq!(
21843        wrap_with_prefix(
21844            "".to_string(),
21845            "".to_string(),
21846            "\thello world".to_string(),
21847            8,
21848            NonZeroU32::new(4).unwrap(),
21849            false,
21850        ),
21851        "hello\nworld"
21852    );
21853    assert_eq!(
21854        wrap_with_prefix(
21855            "// ".to_string(),
21856            "// ".to_string(),
21857            "xx \nyy zz aa bb cc".to_string(),
21858            12,
21859            NonZeroU32::new(4).unwrap(),
21860            false,
21861        ),
21862        "// xx yy zz\n// aa bb cc"
21863    );
21864    assert_eq!(
21865        wrap_with_prefix(
21866            String::new(),
21867            String::new(),
21868            "这是什么 \n 钢笔".to_string(),
21869            3,
21870            NonZeroU32::new(4).unwrap(),
21871            false,
21872        ),
21873        "这是什\n么 钢\n"
21874    );
21875}
21876
21877pub trait CollaborationHub {
21878    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21879    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21880    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21881}
21882
21883impl CollaborationHub for Entity<Project> {
21884    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21885        self.read(cx).collaborators()
21886    }
21887
21888    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21889        self.read(cx).user_store().read(cx).participant_indices()
21890    }
21891
21892    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21893        let this = self.read(cx);
21894        let user_ids = this.collaborators().values().map(|c| c.user_id);
21895        this.user_store().read(cx).participant_names(user_ids, cx)
21896    }
21897}
21898
21899pub trait SemanticsProvider {
21900    fn hover(
21901        &self,
21902        buffer: &Entity<Buffer>,
21903        position: text::Anchor,
21904        cx: &mut App,
21905    ) -> Option<Task<Vec<project::Hover>>>;
21906
21907    fn inline_values(
21908        &self,
21909        buffer_handle: Entity<Buffer>,
21910        range: Range<text::Anchor>,
21911        cx: &mut App,
21912    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21913
21914    fn inlay_hints(
21915        &self,
21916        buffer_handle: Entity<Buffer>,
21917        range: Range<text::Anchor>,
21918        cx: &mut App,
21919    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21920
21921    fn resolve_inlay_hint(
21922        &self,
21923        hint: InlayHint,
21924        buffer_handle: Entity<Buffer>,
21925        server_id: LanguageServerId,
21926        cx: &mut App,
21927    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21928
21929    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21930
21931    fn document_highlights(
21932        &self,
21933        buffer: &Entity<Buffer>,
21934        position: text::Anchor,
21935        cx: &mut App,
21936    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21937
21938    fn definitions(
21939        &self,
21940        buffer: &Entity<Buffer>,
21941        position: text::Anchor,
21942        kind: GotoDefinitionKind,
21943        cx: &mut App,
21944    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21945
21946    fn range_for_rename(
21947        &self,
21948        buffer: &Entity<Buffer>,
21949        position: text::Anchor,
21950        cx: &mut App,
21951    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21952
21953    fn perform_rename(
21954        &self,
21955        buffer: &Entity<Buffer>,
21956        position: text::Anchor,
21957        new_name: String,
21958        cx: &mut App,
21959    ) -> Option<Task<Result<ProjectTransaction>>>;
21960}
21961
21962pub trait CompletionProvider {
21963    fn completions(
21964        &self,
21965        excerpt_id: ExcerptId,
21966        buffer: &Entity<Buffer>,
21967        buffer_position: text::Anchor,
21968        trigger: CompletionContext,
21969        window: &mut Window,
21970        cx: &mut Context<Editor>,
21971    ) -> Task<Result<Vec<CompletionResponse>>>;
21972
21973    fn resolve_completions(
21974        &self,
21975        _buffer: Entity<Buffer>,
21976        _completion_indices: Vec<usize>,
21977        _completions: Rc<RefCell<Box<[Completion]>>>,
21978        _cx: &mut Context<Editor>,
21979    ) -> Task<Result<bool>> {
21980        Task::ready(Ok(false))
21981    }
21982
21983    fn apply_additional_edits_for_completion(
21984        &self,
21985        _buffer: Entity<Buffer>,
21986        _completions: Rc<RefCell<Box<[Completion]>>>,
21987        _completion_index: usize,
21988        _push_to_history: bool,
21989        _cx: &mut Context<Editor>,
21990    ) -> Task<Result<Option<language::Transaction>>> {
21991        Task::ready(Ok(None))
21992    }
21993
21994    fn is_completion_trigger(
21995        &self,
21996        buffer: &Entity<Buffer>,
21997        position: language::Anchor,
21998        text: &str,
21999        trigger_in_words: bool,
22000        menu_is_open: bool,
22001        cx: &mut Context<Editor>,
22002    ) -> bool;
22003
22004    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22005
22006    fn sort_completions(&self) -> bool {
22007        true
22008    }
22009
22010    fn filter_completions(&self) -> bool {
22011        true
22012    }
22013}
22014
22015pub trait CodeActionProvider {
22016    fn id(&self) -> Arc<str>;
22017
22018    fn code_actions(
22019        &self,
22020        buffer: &Entity<Buffer>,
22021        range: Range<text::Anchor>,
22022        window: &mut Window,
22023        cx: &mut App,
22024    ) -> Task<Result<Vec<CodeAction>>>;
22025
22026    fn apply_code_action(
22027        &self,
22028        buffer_handle: Entity<Buffer>,
22029        action: CodeAction,
22030        excerpt_id: ExcerptId,
22031        push_to_history: bool,
22032        window: &mut Window,
22033        cx: &mut App,
22034    ) -> Task<Result<ProjectTransaction>>;
22035}
22036
22037impl CodeActionProvider for Entity<Project> {
22038    fn id(&self) -> Arc<str> {
22039        "project".into()
22040    }
22041
22042    fn code_actions(
22043        &self,
22044        buffer: &Entity<Buffer>,
22045        range: Range<text::Anchor>,
22046        _window: &mut Window,
22047        cx: &mut App,
22048    ) -> Task<Result<Vec<CodeAction>>> {
22049        self.update(cx, |project, cx| {
22050            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22051            let code_actions = project.code_actions(buffer, range, None, cx);
22052            cx.background_spawn(async move {
22053                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22054                Ok(code_lens_actions
22055                    .context("code lens fetch")?
22056                    .into_iter()
22057                    .chain(code_actions.context("code action fetch")?)
22058                    .collect())
22059            })
22060        })
22061    }
22062
22063    fn apply_code_action(
22064        &self,
22065        buffer_handle: Entity<Buffer>,
22066        action: CodeAction,
22067        _excerpt_id: ExcerptId,
22068        push_to_history: bool,
22069        _window: &mut Window,
22070        cx: &mut App,
22071    ) -> Task<Result<ProjectTransaction>> {
22072        self.update(cx, |project, cx| {
22073            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22074        })
22075    }
22076}
22077
22078fn snippet_completions(
22079    project: &Project,
22080    buffer: &Entity<Buffer>,
22081    buffer_position: text::Anchor,
22082    cx: &mut App,
22083) -> Task<Result<CompletionResponse>> {
22084    let languages = buffer.read(cx).languages_at(buffer_position);
22085    let snippet_store = project.snippets().read(cx);
22086
22087    let scopes: Vec<_> = languages
22088        .iter()
22089        .filter_map(|language| {
22090            let language_name = language.lsp_id();
22091            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22092
22093            if snippets.is_empty() {
22094                None
22095            } else {
22096                Some((language.default_scope(), snippets))
22097            }
22098        })
22099        .collect();
22100
22101    if scopes.is_empty() {
22102        return Task::ready(Ok(CompletionResponse {
22103            completions: vec![],
22104            is_incomplete: false,
22105        }));
22106    }
22107
22108    let snapshot = buffer.read(cx).text_snapshot();
22109    let chars: String = snapshot
22110        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22111        .collect();
22112    let executor = cx.background_executor().clone();
22113
22114    cx.background_spawn(async move {
22115        let mut is_incomplete = false;
22116        let mut completions: Vec<Completion> = Vec::new();
22117        for (scope, snippets) in scopes.into_iter() {
22118            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22119            let mut last_word = chars
22120                .chars()
22121                .take_while(|c| classifier.is_word(*c))
22122                .collect::<String>();
22123            last_word = last_word.chars().rev().collect();
22124
22125            if last_word.is_empty() {
22126                return Ok(CompletionResponse {
22127                    completions: vec![],
22128                    is_incomplete: true,
22129                });
22130            }
22131
22132            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22133            let to_lsp = |point: &text::Anchor| {
22134                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22135                point_to_lsp(end)
22136            };
22137            let lsp_end = to_lsp(&buffer_position);
22138
22139            let candidates = snippets
22140                .iter()
22141                .enumerate()
22142                .flat_map(|(ix, snippet)| {
22143                    snippet
22144                        .prefix
22145                        .iter()
22146                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22147                })
22148                .collect::<Vec<StringMatchCandidate>>();
22149
22150            const MAX_RESULTS: usize = 100;
22151            let mut matches = fuzzy::match_strings(
22152                &candidates,
22153                &last_word,
22154                last_word.chars().any(|c| c.is_uppercase()),
22155                true,
22156                MAX_RESULTS,
22157                &Default::default(),
22158                executor.clone(),
22159            )
22160            .await;
22161
22162            if matches.len() >= MAX_RESULTS {
22163                is_incomplete = true;
22164            }
22165
22166            // Remove all candidates where the query's start does not match the start of any word in the candidate
22167            if let Some(query_start) = last_word.chars().next() {
22168                matches.retain(|string_match| {
22169                    split_words(&string_match.string).any(|word| {
22170                        // Check that the first codepoint of the word as lowercase matches the first
22171                        // codepoint of the query as lowercase
22172                        word.chars()
22173                            .flat_map(|codepoint| codepoint.to_lowercase())
22174                            .zip(query_start.to_lowercase())
22175                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22176                    })
22177                });
22178            }
22179
22180            let matched_strings = matches
22181                .into_iter()
22182                .map(|m| m.string)
22183                .collect::<HashSet<_>>();
22184
22185            completions.extend(snippets.iter().filter_map(|snippet| {
22186                let matching_prefix = snippet
22187                    .prefix
22188                    .iter()
22189                    .find(|prefix| matched_strings.contains(*prefix))?;
22190                let start = as_offset - last_word.len();
22191                let start = snapshot.anchor_before(start);
22192                let range = start..buffer_position;
22193                let lsp_start = to_lsp(&start);
22194                let lsp_range = lsp::Range {
22195                    start: lsp_start,
22196                    end: lsp_end,
22197                };
22198                Some(Completion {
22199                    replace_range: range,
22200                    new_text: snippet.body.clone(),
22201                    source: CompletionSource::Lsp {
22202                        insert_range: None,
22203                        server_id: LanguageServerId(usize::MAX),
22204                        resolved: true,
22205                        lsp_completion: Box::new(lsp::CompletionItem {
22206                            label: snippet.prefix.first().unwrap().clone(),
22207                            kind: Some(CompletionItemKind::SNIPPET),
22208                            label_details: snippet.description.as_ref().map(|description| {
22209                                lsp::CompletionItemLabelDetails {
22210                                    detail: Some(description.clone()),
22211                                    description: None,
22212                                }
22213                            }),
22214                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22215                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22216                                lsp::InsertReplaceEdit {
22217                                    new_text: snippet.body.clone(),
22218                                    insert: lsp_range,
22219                                    replace: lsp_range,
22220                                },
22221                            )),
22222                            filter_text: Some(snippet.body.clone()),
22223                            sort_text: Some(char::MAX.to_string()),
22224                            ..lsp::CompletionItem::default()
22225                        }),
22226                        lsp_defaults: None,
22227                    },
22228                    label: CodeLabel {
22229                        text: matching_prefix.clone(),
22230                        runs: Vec::new(),
22231                        filter_range: 0..matching_prefix.len(),
22232                    },
22233                    icon_path: None,
22234                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22235                        single_line: snippet.name.clone().into(),
22236                        plain_text: snippet
22237                            .description
22238                            .clone()
22239                            .map(|description| description.into()),
22240                    }),
22241                    insert_text_mode: None,
22242                    confirm: None,
22243                })
22244            }))
22245        }
22246
22247        Ok(CompletionResponse {
22248            completions,
22249            is_incomplete,
22250        })
22251    })
22252}
22253
22254impl CompletionProvider for Entity<Project> {
22255    fn completions(
22256        &self,
22257        _excerpt_id: ExcerptId,
22258        buffer: &Entity<Buffer>,
22259        buffer_position: text::Anchor,
22260        options: CompletionContext,
22261        _window: &mut Window,
22262        cx: &mut Context<Editor>,
22263    ) -> Task<Result<Vec<CompletionResponse>>> {
22264        self.update(cx, |project, cx| {
22265            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22266            let project_completions = project.completions(buffer, buffer_position, options, cx);
22267            cx.background_spawn(async move {
22268                let mut responses = project_completions.await?;
22269                let snippets = snippets.await?;
22270                if !snippets.completions.is_empty() {
22271                    responses.push(snippets);
22272                }
22273                Ok(responses)
22274            })
22275        })
22276    }
22277
22278    fn resolve_completions(
22279        &self,
22280        buffer: Entity<Buffer>,
22281        completion_indices: Vec<usize>,
22282        completions: Rc<RefCell<Box<[Completion]>>>,
22283        cx: &mut Context<Editor>,
22284    ) -> Task<Result<bool>> {
22285        self.update(cx, |project, cx| {
22286            project.lsp_store().update(cx, |lsp_store, cx| {
22287                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22288            })
22289        })
22290    }
22291
22292    fn apply_additional_edits_for_completion(
22293        &self,
22294        buffer: Entity<Buffer>,
22295        completions: Rc<RefCell<Box<[Completion]>>>,
22296        completion_index: usize,
22297        push_to_history: bool,
22298        cx: &mut Context<Editor>,
22299    ) -> Task<Result<Option<language::Transaction>>> {
22300        self.update(cx, |project, cx| {
22301            project.lsp_store().update(cx, |lsp_store, cx| {
22302                lsp_store.apply_additional_edits_for_completion(
22303                    buffer,
22304                    completions,
22305                    completion_index,
22306                    push_to_history,
22307                    cx,
22308                )
22309            })
22310        })
22311    }
22312
22313    fn is_completion_trigger(
22314        &self,
22315        buffer: &Entity<Buffer>,
22316        position: language::Anchor,
22317        text: &str,
22318        trigger_in_words: bool,
22319        menu_is_open: bool,
22320        cx: &mut Context<Editor>,
22321    ) -> bool {
22322        let mut chars = text.chars();
22323        let char = if let Some(char) = chars.next() {
22324            char
22325        } else {
22326            return false;
22327        };
22328        if chars.next().is_some() {
22329            return false;
22330        }
22331
22332        let buffer = buffer.read(cx);
22333        let snapshot = buffer.snapshot();
22334        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22335            return false;
22336        }
22337        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22338        if trigger_in_words && classifier.is_word(char) {
22339            return true;
22340        }
22341
22342        buffer.completion_triggers().contains(text)
22343    }
22344}
22345
22346impl SemanticsProvider for Entity<Project> {
22347    fn hover(
22348        &self,
22349        buffer: &Entity<Buffer>,
22350        position: text::Anchor,
22351        cx: &mut App,
22352    ) -> Option<Task<Vec<project::Hover>>> {
22353        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22354    }
22355
22356    fn document_highlights(
22357        &self,
22358        buffer: &Entity<Buffer>,
22359        position: text::Anchor,
22360        cx: &mut App,
22361    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22362        Some(self.update(cx, |project, cx| {
22363            project.document_highlights(buffer, position, cx)
22364        }))
22365    }
22366
22367    fn definitions(
22368        &self,
22369        buffer: &Entity<Buffer>,
22370        position: text::Anchor,
22371        kind: GotoDefinitionKind,
22372        cx: &mut App,
22373    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22374        Some(self.update(cx, |project, cx| match kind {
22375            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22376            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22377            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22378            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22379        }))
22380    }
22381
22382    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22383        self.update(cx, |project, cx| {
22384            if project
22385                .active_debug_session(cx)
22386                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22387            {
22388                return true;
22389            }
22390
22391            buffer.update(cx, |buffer, cx| {
22392                project.any_language_server_supports_inlay_hints(buffer, cx)
22393            })
22394        })
22395    }
22396
22397    fn inline_values(
22398        &self,
22399        buffer_handle: Entity<Buffer>,
22400        range: Range<text::Anchor>,
22401        cx: &mut App,
22402    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22403        self.update(cx, |project, cx| {
22404            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22405
22406            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22407        })
22408    }
22409
22410    fn inlay_hints(
22411        &self,
22412        buffer_handle: Entity<Buffer>,
22413        range: Range<text::Anchor>,
22414        cx: &mut App,
22415    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22416        Some(self.update(cx, |project, cx| {
22417            project.inlay_hints(buffer_handle, range, cx)
22418        }))
22419    }
22420
22421    fn resolve_inlay_hint(
22422        &self,
22423        hint: InlayHint,
22424        buffer_handle: Entity<Buffer>,
22425        server_id: LanguageServerId,
22426        cx: &mut App,
22427    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22428        Some(self.update(cx, |project, cx| {
22429            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22430        }))
22431    }
22432
22433    fn range_for_rename(
22434        &self,
22435        buffer: &Entity<Buffer>,
22436        position: text::Anchor,
22437        cx: &mut App,
22438    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22439        Some(self.update(cx, |project, cx| {
22440            let buffer = buffer.clone();
22441            let task = project.prepare_rename(buffer.clone(), position, cx);
22442            cx.spawn(async move |_, cx| {
22443                Ok(match task.await? {
22444                    PrepareRenameResponse::Success(range) => Some(range),
22445                    PrepareRenameResponse::InvalidPosition => None,
22446                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22447                        // Fallback on using TreeSitter info to determine identifier range
22448                        buffer.read_with(cx, |buffer, _| {
22449                            let snapshot = buffer.snapshot();
22450                            let (range, kind) = snapshot.surrounding_word(position, false);
22451                            if kind != Some(CharKind::Word) {
22452                                return None;
22453                            }
22454                            Some(
22455                                snapshot.anchor_before(range.start)
22456                                    ..snapshot.anchor_after(range.end),
22457                            )
22458                        })?
22459                    }
22460                })
22461            })
22462        }))
22463    }
22464
22465    fn perform_rename(
22466        &self,
22467        buffer: &Entity<Buffer>,
22468        position: text::Anchor,
22469        new_name: String,
22470        cx: &mut App,
22471    ) -> Option<Task<Result<ProjectTransaction>>> {
22472        Some(self.update(cx, |project, cx| {
22473            project.perform_rename(buffer.clone(), position, new_name, cx)
22474        }))
22475    }
22476}
22477
22478fn inlay_hint_settings(
22479    location: Anchor,
22480    snapshot: &MultiBufferSnapshot,
22481    cx: &mut Context<Editor>,
22482) -> InlayHintSettings {
22483    let file = snapshot.file_at(location);
22484    let language = snapshot.language_at(location).map(|l| l.name());
22485    language_settings(language, file, cx).inlay_hints
22486}
22487
22488fn consume_contiguous_rows(
22489    contiguous_row_selections: &mut Vec<Selection<Point>>,
22490    selection: &Selection<Point>,
22491    display_map: &DisplaySnapshot,
22492    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22493) -> (MultiBufferRow, MultiBufferRow) {
22494    contiguous_row_selections.push(selection.clone());
22495    let start_row = starting_row(selection, display_map);
22496    let mut end_row = ending_row(selection, display_map);
22497
22498    while let Some(next_selection) = selections.peek() {
22499        if next_selection.start.row <= end_row.0 {
22500            end_row = ending_row(next_selection, display_map);
22501            contiguous_row_selections.push(selections.next().unwrap().clone());
22502        } else {
22503            break;
22504        }
22505    }
22506    (start_row, end_row)
22507}
22508
22509fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22510    if selection.start.column > 0 {
22511        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22512    } else {
22513        MultiBufferRow(selection.start.row)
22514    }
22515}
22516
22517fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22518    if next_selection.end.column > 0 || next_selection.is_empty() {
22519        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22520    } else {
22521        MultiBufferRow(next_selection.end.row)
22522    }
22523}
22524
22525impl EditorSnapshot {
22526    pub fn remote_selections_in_range<'a>(
22527        &'a self,
22528        range: &'a Range<Anchor>,
22529        collaboration_hub: &dyn CollaborationHub,
22530        cx: &'a App,
22531    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22532        let participant_names = collaboration_hub.user_names(cx);
22533        let participant_indices = collaboration_hub.user_participant_indices(cx);
22534        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22535        let collaborators_by_replica_id = collaborators_by_peer_id
22536            .values()
22537            .map(|collaborator| (collaborator.replica_id, collaborator))
22538            .collect::<HashMap<_, _>>();
22539        self.buffer_snapshot
22540            .selections_in_range(range, false)
22541            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22542                if replica_id == AGENT_REPLICA_ID {
22543                    Some(RemoteSelection {
22544                        replica_id,
22545                        selection,
22546                        cursor_shape,
22547                        line_mode,
22548                        collaborator_id: CollaboratorId::Agent,
22549                        user_name: Some("Agent".into()),
22550                        color: cx.theme().players().agent(),
22551                    })
22552                } else {
22553                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22554                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22555                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22556                    Some(RemoteSelection {
22557                        replica_id,
22558                        selection,
22559                        cursor_shape,
22560                        line_mode,
22561                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22562                        user_name,
22563                        color: if let Some(index) = participant_index {
22564                            cx.theme().players().color_for_participant(index.0)
22565                        } else {
22566                            cx.theme().players().absent()
22567                        },
22568                    })
22569                }
22570            })
22571    }
22572
22573    pub fn hunks_for_ranges(
22574        &self,
22575        ranges: impl IntoIterator<Item = Range<Point>>,
22576    ) -> Vec<MultiBufferDiffHunk> {
22577        let mut hunks = Vec::new();
22578        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22579            HashMap::default();
22580        for query_range in ranges {
22581            let query_rows =
22582                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22583            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22584                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22585            ) {
22586                // Include deleted hunks that are adjacent to the query range, because
22587                // otherwise they would be missed.
22588                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22589                if hunk.status().is_deleted() {
22590                    intersects_range |= hunk.row_range.start == query_rows.end;
22591                    intersects_range |= hunk.row_range.end == query_rows.start;
22592                }
22593                if intersects_range {
22594                    if !processed_buffer_rows
22595                        .entry(hunk.buffer_id)
22596                        .or_default()
22597                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22598                    {
22599                        continue;
22600                    }
22601                    hunks.push(hunk);
22602                }
22603            }
22604        }
22605
22606        hunks
22607    }
22608
22609    fn display_diff_hunks_for_rows<'a>(
22610        &'a self,
22611        display_rows: Range<DisplayRow>,
22612        folded_buffers: &'a HashSet<BufferId>,
22613    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22614        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22615        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22616
22617        self.buffer_snapshot
22618            .diff_hunks_in_range(buffer_start..buffer_end)
22619            .filter_map(|hunk| {
22620                if folded_buffers.contains(&hunk.buffer_id) {
22621                    return None;
22622                }
22623
22624                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22625                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22626
22627                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22628                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22629
22630                let display_hunk = if hunk_display_start.column() != 0 {
22631                    DisplayDiffHunk::Folded {
22632                        display_row: hunk_display_start.row(),
22633                    }
22634                } else {
22635                    let mut end_row = hunk_display_end.row();
22636                    if hunk_display_end.column() > 0 {
22637                        end_row.0 += 1;
22638                    }
22639                    let is_created_file = hunk.is_created_file();
22640                    DisplayDiffHunk::Unfolded {
22641                        status: hunk.status(),
22642                        diff_base_byte_range: hunk.diff_base_byte_range,
22643                        display_row_range: hunk_display_start.row()..end_row,
22644                        multi_buffer_range: Anchor::range_in_buffer(
22645                            hunk.excerpt_id,
22646                            hunk.buffer_id,
22647                            hunk.buffer_range,
22648                        ),
22649                        is_created_file,
22650                    }
22651                };
22652
22653                Some(display_hunk)
22654            })
22655    }
22656
22657    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22658        self.display_snapshot.buffer_snapshot.language_at(position)
22659    }
22660
22661    pub fn is_focused(&self) -> bool {
22662        self.is_focused
22663    }
22664
22665    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22666        self.placeholder_text.as_ref()
22667    }
22668
22669    pub fn scroll_position(&self) -> gpui::Point<f32> {
22670        self.scroll_anchor.scroll_position(&self.display_snapshot)
22671    }
22672
22673    fn gutter_dimensions(
22674        &self,
22675        font_id: FontId,
22676        font_size: Pixels,
22677        max_line_number_width: Pixels,
22678        cx: &App,
22679    ) -> Option<GutterDimensions> {
22680        if !self.show_gutter {
22681            return None;
22682        }
22683
22684        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22685        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22686
22687        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22688            matches!(
22689                ProjectSettings::get_global(cx).git.git_gutter,
22690                Some(GitGutterSetting::TrackedFiles)
22691            )
22692        });
22693        let gutter_settings = EditorSettings::get_global(cx).gutter;
22694        let show_line_numbers = self
22695            .show_line_numbers
22696            .unwrap_or(gutter_settings.line_numbers);
22697        let line_gutter_width = if show_line_numbers {
22698            // Avoid flicker-like gutter resizes when the line number gains another digit by
22699            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22700            let min_width_for_number_on_gutter =
22701                ch_advance * gutter_settings.min_line_number_digits as f32;
22702            max_line_number_width.max(min_width_for_number_on_gutter)
22703        } else {
22704            0.0.into()
22705        };
22706
22707        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22708        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22709
22710        let git_blame_entries_width =
22711            self.git_blame_gutter_max_author_length
22712                .map(|max_author_length| {
22713                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22714                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22715
22716                    /// The number of characters to dedicate to gaps and margins.
22717                    const SPACING_WIDTH: usize = 4;
22718
22719                    let max_char_count = max_author_length.min(renderer.max_author_length())
22720                        + ::git::SHORT_SHA_LENGTH
22721                        + MAX_RELATIVE_TIMESTAMP.len()
22722                        + SPACING_WIDTH;
22723
22724                    ch_advance * max_char_count
22725                });
22726
22727        let is_singleton = self.buffer_snapshot.is_singleton();
22728
22729        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22730        left_padding += if !is_singleton {
22731            ch_width * 4.0
22732        } else if show_runnables || show_breakpoints {
22733            ch_width * 3.0
22734        } else if show_git_gutter && show_line_numbers {
22735            ch_width * 2.0
22736        } else if show_git_gutter || show_line_numbers {
22737            ch_width
22738        } else {
22739            px(0.)
22740        };
22741
22742        let shows_folds = is_singleton && gutter_settings.folds;
22743
22744        let right_padding = if shows_folds && show_line_numbers {
22745            ch_width * 4.0
22746        } else if shows_folds || (!is_singleton && show_line_numbers) {
22747            ch_width * 3.0
22748        } else if show_line_numbers {
22749            ch_width
22750        } else {
22751            px(0.)
22752        };
22753
22754        Some(GutterDimensions {
22755            left_padding,
22756            right_padding,
22757            width: line_gutter_width + left_padding + right_padding,
22758            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22759            git_blame_entries_width,
22760        })
22761    }
22762
22763    pub fn render_crease_toggle(
22764        &self,
22765        buffer_row: MultiBufferRow,
22766        row_contains_cursor: bool,
22767        editor: Entity<Editor>,
22768        window: &mut Window,
22769        cx: &mut App,
22770    ) -> Option<AnyElement> {
22771        let folded = self.is_line_folded(buffer_row);
22772        let mut is_foldable = false;
22773
22774        if let Some(crease) = self
22775            .crease_snapshot
22776            .query_row(buffer_row, &self.buffer_snapshot)
22777        {
22778            is_foldable = true;
22779            match crease {
22780                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22781                    if let Some(render_toggle) = render_toggle {
22782                        let toggle_callback =
22783                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22784                                if folded {
22785                                    editor.update(cx, |editor, cx| {
22786                                        editor.fold_at(buffer_row, window, cx)
22787                                    });
22788                                } else {
22789                                    editor.update(cx, |editor, cx| {
22790                                        editor.unfold_at(buffer_row, window, cx)
22791                                    });
22792                                }
22793                            });
22794                        return Some((render_toggle)(
22795                            buffer_row,
22796                            folded,
22797                            toggle_callback,
22798                            window,
22799                            cx,
22800                        ));
22801                    }
22802                }
22803            }
22804        }
22805
22806        is_foldable |= self.starts_indent(buffer_row);
22807
22808        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22809            Some(
22810                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22811                    .toggle_state(folded)
22812                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22813                        if folded {
22814                            this.unfold_at(buffer_row, window, cx);
22815                        } else {
22816                            this.fold_at(buffer_row, window, cx);
22817                        }
22818                    }))
22819                    .into_any_element(),
22820            )
22821        } else {
22822            None
22823        }
22824    }
22825
22826    pub fn render_crease_trailer(
22827        &self,
22828        buffer_row: MultiBufferRow,
22829        window: &mut Window,
22830        cx: &mut App,
22831    ) -> Option<AnyElement> {
22832        let folded = self.is_line_folded(buffer_row);
22833        if let Crease::Inline { render_trailer, .. } = self
22834            .crease_snapshot
22835            .query_row(buffer_row, &self.buffer_snapshot)?
22836        {
22837            let render_trailer = render_trailer.as_ref()?;
22838            Some(render_trailer(buffer_row, folded, window, cx))
22839        } else {
22840            None
22841        }
22842    }
22843}
22844
22845impl Deref for EditorSnapshot {
22846    type Target = DisplaySnapshot;
22847
22848    fn deref(&self) -> &Self::Target {
22849        &self.display_snapshot
22850    }
22851}
22852
22853#[derive(Clone, Debug, PartialEq, Eq)]
22854pub enum EditorEvent {
22855    InputIgnored {
22856        text: Arc<str>,
22857    },
22858    InputHandled {
22859        utf16_range_to_replace: Option<Range<isize>>,
22860        text: Arc<str>,
22861    },
22862    ExcerptsAdded {
22863        buffer: Entity<Buffer>,
22864        predecessor: ExcerptId,
22865        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22866    },
22867    ExcerptsRemoved {
22868        ids: Vec<ExcerptId>,
22869        removed_buffer_ids: Vec<BufferId>,
22870    },
22871    BufferFoldToggled {
22872        ids: Vec<ExcerptId>,
22873        folded: bool,
22874    },
22875    ExcerptsEdited {
22876        ids: Vec<ExcerptId>,
22877    },
22878    ExcerptsExpanded {
22879        ids: Vec<ExcerptId>,
22880    },
22881    BufferEdited,
22882    Edited {
22883        transaction_id: clock::Lamport,
22884    },
22885    Reparsed(BufferId),
22886    Focused,
22887    FocusedIn,
22888    Blurred,
22889    DirtyChanged,
22890    Saved,
22891    TitleChanged,
22892    DiffBaseChanged,
22893    SelectionsChanged {
22894        local: bool,
22895    },
22896    ScrollPositionChanged {
22897        local: bool,
22898        autoscroll: bool,
22899    },
22900    Closed,
22901    TransactionUndone {
22902        transaction_id: clock::Lamport,
22903    },
22904    TransactionBegun {
22905        transaction_id: clock::Lamport,
22906    },
22907    Reloaded,
22908    CursorShapeChanged,
22909    BreadcrumbsChanged,
22910    PushedToNavHistory {
22911        anchor: Anchor,
22912        is_deactivate: bool,
22913    },
22914}
22915
22916impl EventEmitter<EditorEvent> for Editor {}
22917
22918impl Focusable for Editor {
22919    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22920        self.focus_handle.clone()
22921    }
22922}
22923
22924impl Render for Editor {
22925    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22926        let settings = ThemeSettings::get_global(cx);
22927
22928        let mut text_style = match self.mode {
22929            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22930                color: cx.theme().colors().editor_foreground,
22931                font_family: settings.ui_font.family.clone(),
22932                font_features: settings.ui_font.features.clone(),
22933                font_fallbacks: settings.ui_font.fallbacks.clone(),
22934                font_size: rems(0.875).into(),
22935                font_weight: settings.ui_font.weight,
22936                line_height: relative(settings.buffer_line_height.value()),
22937                ..Default::default()
22938            },
22939            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22940                color: cx.theme().colors().editor_foreground,
22941                font_family: settings.buffer_font.family.clone(),
22942                font_features: settings.buffer_font.features.clone(),
22943                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22944                font_size: settings.buffer_font_size(cx).into(),
22945                font_weight: settings.buffer_font.weight,
22946                line_height: relative(settings.buffer_line_height.value()),
22947                ..Default::default()
22948            },
22949        };
22950        if let Some(text_style_refinement) = &self.text_style_refinement {
22951            text_style.refine(text_style_refinement)
22952        }
22953
22954        let background = match self.mode {
22955            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22956            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22957            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22958            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22959        };
22960
22961        EditorElement::new(
22962            &cx.entity(),
22963            EditorStyle {
22964                background,
22965                border: cx.theme().colors().border,
22966                local_player: cx.theme().players().local(),
22967                text: text_style,
22968                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22969                syntax: cx.theme().syntax().clone(),
22970                status: cx.theme().status().clone(),
22971                inlay_hints_style: make_inlay_hints_style(cx),
22972                edit_prediction_styles: make_suggestion_styles(cx),
22973                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22974                show_underlines: self.diagnostics_enabled(),
22975            },
22976        )
22977    }
22978}
22979
22980impl EntityInputHandler for Editor {
22981    fn text_for_range(
22982        &mut self,
22983        range_utf16: Range<usize>,
22984        adjusted_range: &mut Option<Range<usize>>,
22985        _: &mut Window,
22986        cx: &mut Context<Self>,
22987    ) -> Option<String> {
22988        let snapshot = self.buffer.read(cx).read(cx);
22989        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22990        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22991        if (start.0..end.0) != range_utf16 {
22992            adjusted_range.replace(start.0..end.0);
22993        }
22994        Some(snapshot.text_for_range(start..end).collect())
22995    }
22996
22997    fn selected_text_range(
22998        &mut self,
22999        ignore_disabled_input: bool,
23000        _: &mut Window,
23001        cx: &mut Context<Self>,
23002    ) -> Option<UTF16Selection> {
23003        // Prevent the IME menu from appearing when holding down an alphabetic key
23004        // while input is disabled.
23005        if !ignore_disabled_input && !self.input_enabled {
23006            return None;
23007        }
23008
23009        let selection = self.selections.newest::<OffsetUtf16>(cx);
23010        let range = selection.range();
23011
23012        Some(UTF16Selection {
23013            range: range.start.0..range.end.0,
23014            reversed: selection.reversed,
23015        })
23016    }
23017
23018    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23019        let snapshot = self.buffer.read(cx).read(cx);
23020        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23021        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23022    }
23023
23024    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23025        self.clear_highlights::<InputComposition>(cx);
23026        self.ime_transaction.take();
23027    }
23028
23029    fn replace_text_in_range(
23030        &mut self,
23031        range_utf16: Option<Range<usize>>,
23032        text: &str,
23033        window: &mut Window,
23034        cx: &mut Context<Self>,
23035    ) {
23036        if !self.input_enabled {
23037            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23038            return;
23039        }
23040
23041        self.transact(window, cx, |this, window, cx| {
23042            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23043                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23044                Some(this.selection_replacement_ranges(range_utf16, cx))
23045            } else {
23046                this.marked_text_ranges(cx)
23047            };
23048
23049            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23050                let newest_selection_id = this.selections.newest_anchor().id;
23051                this.selections
23052                    .all::<OffsetUtf16>(cx)
23053                    .iter()
23054                    .zip(ranges_to_replace.iter())
23055                    .find_map(|(selection, range)| {
23056                        if selection.id == newest_selection_id {
23057                            Some(
23058                                (range.start.0 as isize - selection.head().0 as isize)
23059                                    ..(range.end.0 as isize - selection.head().0 as isize),
23060                            )
23061                        } else {
23062                            None
23063                        }
23064                    })
23065            });
23066
23067            cx.emit(EditorEvent::InputHandled {
23068                utf16_range_to_replace: range_to_replace,
23069                text: text.into(),
23070            });
23071
23072            if let Some(new_selected_ranges) = new_selected_ranges {
23073                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23074                    selections.select_ranges(new_selected_ranges)
23075                });
23076                this.backspace(&Default::default(), window, cx);
23077            }
23078
23079            this.handle_input(text, window, cx);
23080        });
23081
23082        if let Some(transaction) = self.ime_transaction {
23083            self.buffer.update(cx, |buffer, cx| {
23084                buffer.group_until_transaction(transaction, cx);
23085            });
23086        }
23087
23088        self.unmark_text(window, cx);
23089    }
23090
23091    fn replace_and_mark_text_in_range(
23092        &mut self,
23093        range_utf16: Option<Range<usize>>,
23094        text: &str,
23095        new_selected_range_utf16: Option<Range<usize>>,
23096        window: &mut Window,
23097        cx: &mut Context<Self>,
23098    ) {
23099        if !self.input_enabled {
23100            return;
23101        }
23102
23103        let transaction = self.transact(window, cx, |this, window, cx| {
23104            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23105                let snapshot = this.buffer.read(cx).read(cx);
23106                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23107                    for marked_range in &mut marked_ranges {
23108                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23109                        marked_range.start.0 += relative_range_utf16.start;
23110                        marked_range.start =
23111                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23112                        marked_range.end =
23113                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23114                    }
23115                }
23116                Some(marked_ranges)
23117            } else if let Some(range_utf16) = range_utf16 {
23118                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23119                Some(this.selection_replacement_ranges(range_utf16, cx))
23120            } else {
23121                None
23122            };
23123
23124            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23125                let newest_selection_id = this.selections.newest_anchor().id;
23126                this.selections
23127                    .all::<OffsetUtf16>(cx)
23128                    .iter()
23129                    .zip(ranges_to_replace.iter())
23130                    .find_map(|(selection, range)| {
23131                        if selection.id == newest_selection_id {
23132                            Some(
23133                                (range.start.0 as isize - selection.head().0 as isize)
23134                                    ..(range.end.0 as isize - selection.head().0 as isize),
23135                            )
23136                        } else {
23137                            None
23138                        }
23139                    })
23140            });
23141
23142            cx.emit(EditorEvent::InputHandled {
23143                utf16_range_to_replace: range_to_replace,
23144                text: text.into(),
23145            });
23146
23147            if let Some(ranges) = ranges_to_replace {
23148                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23149                    s.select_ranges(ranges)
23150                });
23151            }
23152
23153            let marked_ranges = {
23154                let snapshot = this.buffer.read(cx).read(cx);
23155                this.selections
23156                    .disjoint_anchors()
23157                    .iter()
23158                    .map(|selection| {
23159                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23160                    })
23161                    .collect::<Vec<_>>()
23162            };
23163
23164            if text.is_empty() {
23165                this.unmark_text(window, cx);
23166            } else {
23167                this.highlight_text::<InputComposition>(
23168                    marked_ranges.clone(),
23169                    HighlightStyle {
23170                        underline: Some(UnderlineStyle {
23171                            thickness: px(1.),
23172                            color: None,
23173                            wavy: false,
23174                        }),
23175                        ..Default::default()
23176                    },
23177                    cx,
23178                );
23179            }
23180
23181            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23182            let use_autoclose = this.use_autoclose;
23183            let use_auto_surround = this.use_auto_surround;
23184            this.set_use_autoclose(false);
23185            this.set_use_auto_surround(false);
23186            this.handle_input(text, window, cx);
23187            this.set_use_autoclose(use_autoclose);
23188            this.set_use_auto_surround(use_auto_surround);
23189
23190            if let Some(new_selected_range) = new_selected_range_utf16 {
23191                let snapshot = this.buffer.read(cx).read(cx);
23192                let new_selected_ranges = marked_ranges
23193                    .into_iter()
23194                    .map(|marked_range| {
23195                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23196                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23197                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23198                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23199                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23200                    })
23201                    .collect::<Vec<_>>();
23202
23203                drop(snapshot);
23204                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23205                    selections.select_ranges(new_selected_ranges)
23206                });
23207            }
23208        });
23209
23210        self.ime_transaction = self.ime_transaction.or(transaction);
23211        if let Some(transaction) = self.ime_transaction {
23212            self.buffer.update(cx, |buffer, cx| {
23213                buffer.group_until_transaction(transaction, cx);
23214            });
23215        }
23216
23217        if self.text_highlights::<InputComposition>(cx).is_none() {
23218            self.ime_transaction.take();
23219        }
23220    }
23221
23222    fn bounds_for_range(
23223        &mut self,
23224        range_utf16: Range<usize>,
23225        element_bounds: gpui::Bounds<Pixels>,
23226        window: &mut Window,
23227        cx: &mut Context<Self>,
23228    ) -> Option<gpui::Bounds<Pixels>> {
23229        let text_layout_details = self.text_layout_details(window);
23230        let CharacterDimensions {
23231            em_width,
23232            em_advance,
23233            line_height,
23234        } = self.character_dimensions(window);
23235
23236        let snapshot = self.snapshot(window, cx);
23237        let scroll_position = snapshot.scroll_position();
23238        let scroll_left = scroll_position.x * em_advance;
23239
23240        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23241        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23242            + self.gutter_dimensions.full_width();
23243        let y = line_height * (start.row().as_f32() - scroll_position.y);
23244
23245        Some(Bounds {
23246            origin: element_bounds.origin + point(x, y),
23247            size: size(em_width, line_height),
23248        })
23249    }
23250
23251    fn character_index_for_point(
23252        &mut self,
23253        point: gpui::Point<Pixels>,
23254        _window: &mut Window,
23255        _cx: &mut Context<Self>,
23256    ) -> Option<usize> {
23257        let position_map = self.last_position_map.as_ref()?;
23258        if !position_map.text_hitbox.contains(&point) {
23259            return None;
23260        }
23261        let display_point = position_map.point_for_position(point).previous_valid;
23262        let anchor = position_map
23263            .snapshot
23264            .display_point_to_anchor(display_point, Bias::Left);
23265        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23266        Some(utf16_offset.0)
23267    }
23268}
23269
23270trait SelectionExt {
23271    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23272    fn spanned_rows(
23273        &self,
23274        include_end_if_at_line_start: bool,
23275        map: &DisplaySnapshot,
23276    ) -> Range<MultiBufferRow>;
23277}
23278
23279impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23280    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23281        let start = self
23282            .start
23283            .to_point(&map.buffer_snapshot)
23284            .to_display_point(map);
23285        let end = self
23286            .end
23287            .to_point(&map.buffer_snapshot)
23288            .to_display_point(map);
23289        if self.reversed {
23290            end..start
23291        } else {
23292            start..end
23293        }
23294    }
23295
23296    fn spanned_rows(
23297        &self,
23298        include_end_if_at_line_start: bool,
23299        map: &DisplaySnapshot,
23300    ) -> Range<MultiBufferRow> {
23301        let start = self.start.to_point(&map.buffer_snapshot);
23302        let mut end = self.end.to_point(&map.buffer_snapshot);
23303        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23304            end.row -= 1;
23305        }
23306
23307        let buffer_start = map.prev_line_boundary(start).0;
23308        let buffer_end = map.next_line_boundary(end).0;
23309        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23310    }
23311}
23312
23313impl<T: InvalidationRegion> InvalidationStack<T> {
23314    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23315    where
23316        S: Clone + ToOffset,
23317    {
23318        while let Some(region) = self.last() {
23319            let all_selections_inside_invalidation_ranges =
23320                if selections.len() == region.ranges().len() {
23321                    selections
23322                        .iter()
23323                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23324                        .all(|(selection, invalidation_range)| {
23325                            let head = selection.head().to_offset(buffer);
23326                            invalidation_range.start <= head && invalidation_range.end >= head
23327                        })
23328                } else {
23329                    false
23330                };
23331
23332            if all_selections_inside_invalidation_ranges {
23333                break;
23334            } else {
23335                self.pop();
23336            }
23337        }
23338    }
23339}
23340
23341impl<T> Default for InvalidationStack<T> {
23342    fn default() -> Self {
23343        Self(Default::default())
23344    }
23345}
23346
23347impl<T> Deref for InvalidationStack<T> {
23348    type Target = Vec<T>;
23349
23350    fn deref(&self) -> &Self::Target {
23351        &self.0
23352    }
23353}
23354
23355impl<T> DerefMut for InvalidationStack<T> {
23356    fn deref_mut(&mut self) -> &mut Self::Target {
23357        &mut self.0
23358    }
23359}
23360
23361impl InvalidationRegion for SnippetState {
23362    fn ranges(&self) -> &[Range<Anchor>] {
23363        &self.ranges[self.active_index]
23364    }
23365}
23366
23367fn edit_prediction_edit_text(
23368    current_snapshot: &BufferSnapshot,
23369    edits: &[(Range<Anchor>, String)],
23370    edit_preview: &EditPreview,
23371    include_deletions: bool,
23372    cx: &App,
23373) -> HighlightedText {
23374    let edits = edits
23375        .iter()
23376        .map(|(anchor, text)| {
23377            (
23378                anchor.start.text_anchor..anchor.end.text_anchor,
23379                text.clone(),
23380            )
23381        })
23382        .collect::<Vec<_>>();
23383
23384    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23385}
23386
23387fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23388    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23389    // Just show the raw edit text with basic styling
23390    let mut text = String::new();
23391    let mut highlights = Vec::new();
23392
23393    let insertion_highlight_style = HighlightStyle {
23394        color: Some(cx.theme().colors().text),
23395        ..Default::default()
23396    };
23397
23398    for (_, edit_text) in edits {
23399        let start_offset = text.len();
23400        text.push_str(edit_text);
23401        let end_offset = text.len();
23402
23403        if start_offset < end_offset {
23404            highlights.push((start_offset..end_offset, insertion_highlight_style));
23405        }
23406    }
23407
23408    HighlightedText {
23409        text: text.into(),
23410        highlights,
23411    }
23412}
23413
23414pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23415    match severity {
23416        lsp::DiagnosticSeverity::ERROR => colors.error,
23417        lsp::DiagnosticSeverity::WARNING => colors.warning,
23418        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23419        lsp::DiagnosticSeverity::HINT => colors.info,
23420        _ => colors.ignored,
23421    }
23422}
23423
23424pub fn styled_runs_for_code_label<'a>(
23425    label: &'a CodeLabel,
23426    syntax_theme: &'a theme::SyntaxTheme,
23427) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23428    let fade_out = HighlightStyle {
23429        fade_out: Some(0.35),
23430        ..Default::default()
23431    };
23432
23433    let mut prev_end = label.filter_range.end;
23434    label
23435        .runs
23436        .iter()
23437        .enumerate()
23438        .flat_map(move |(ix, (range, highlight_id))| {
23439            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23440                style
23441            } else {
23442                return Default::default();
23443            };
23444            let mut muted_style = style;
23445            muted_style.highlight(fade_out);
23446
23447            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23448            if range.start >= label.filter_range.end {
23449                if range.start > prev_end {
23450                    runs.push((prev_end..range.start, fade_out));
23451                }
23452                runs.push((range.clone(), muted_style));
23453            } else if range.end <= label.filter_range.end {
23454                runs.push((range.clone(), style));
23455            } else {
23456                runs.push((range.start..label.filter_range.end, style));
23457                runs.push((label.filter_range.end..range.end, muted_style));
23458            }
23459            prev_end = cmp::max(prev_end, range.end);
23460
23461            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23462                runs.push((prev_end..label.text.len(), fade_out));
23463            }
23464
23465            runs
23466        })
23467}
23468
23469pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23470    let mut prev_index = 0;
23471    let mut prev_codepoint: Option<char> = None;
23472    text.char_indices()
23473        .chain([(text.len(), '\0')])
23474        .filter_map(move |(index, codepoint)| {
23475            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23476            let is_boundary = index == text.len()
23477                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23478                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23479            if is_boundary {
23480                let chunk = &text[prev_index..index];
23481                prev_index = index;
23482                Some(chunk)
23483            } else {
23484                None
23485            }
23486        })
23487}
23488
23489pub trait RangeToAnchorExt: Sized {
23490    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23491
23492    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23493        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23494        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23495    }
23496}
23497
23498impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23499    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23500        let start_offset = self.start.to_offset(snapshot);
23501        let end_offset = self.end.to_offset(snapshot);
23502        if start_offset == end_offset {
23503            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23504        } else {
23505            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23506        }
23507    }
23508}
23509
23510pub trait RowExt {
23511    fn as_f32(&self) -> f32;
23512
23513    fn next_row(&self) -> Self;
23514
23515    fn previous_row(&self) -> Self;
23516
23517    fn minus(&self, other: Self) -> u32;
23518}
23519
23520impl RowExt for DisplayRow {
23521    fn as_f32(&self) -> f32 {
23522        self.0 as f32
23523    }
23524
23525    fn next_row(&self) -> Self {
23526        Self(self.0 + 1)
23527    }
23528
23529    fn previous_row(&self) -> Self {
23530        Self(self.0.saturating_sub(1))
23531    }
23532
23533    fn minus(&self, other: Self) -> u32 {
23534        self.0 - other.0
23535    }
23536}
23537
23538impl RowExt for MultiBufferRow {
23539    fn as_f32(&self) -> f32 {
23540        self.0 as f32
23541    }
23542
23543    fn next_row(&self) -> Self {
23544        Self(self.0 + 1)
23545    }
23546
23547    fn previous_row(&self) -> Self {
23548        Self(self.0.saturating_sub(1))
23549    }
23550
23551    fn minus(&self, other: Self) -> u32 {
23552        self.0 - other.0
23553    }
23554}
23555
23556trait RowRangeExt {
23557    type Row;
23558
23559    fn len(&self) -> usize;
23560
23561    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23562}
23563
23564impl RowRangeExt for Range<MultiBufferRow> {
23565    type Row = MultiBufferRow;
23566
23567    fn len(&self) -> usize {
23568        (self.end.0 - self.start.0) as usize
23569    }
23570
23571    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23572        (self.start.0..self.end.0).map(MultiBufferRow)
23573    }
23574}
23575
23576impl RowRangeExt for Range<DisplayRow> {
23577    type Row = DisplayRow;
23578
23579    fn len(&self) -> usize {
23580        (self.end.0 - self.start.0) as usize
23581    }
23582
23583    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23584        (self.start.0..self.end.0).map(DisplayRow)
23585    }
23586}
23587
23588/// If select range has more than one line, we
23589/// just point the cursor to range.start.
23590fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23591    if range.start.row == range.end.row {
23592        range
23593    } else {
23594        range.start..range.start
23595    }
23596}
23597pub struct KillRing(ClipboardItem);
23598impl Global for KillRing {}
23599
23600const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23601
23602enum BreakpointPromptEditAction {
23603    Log,
23604    Condition,
23605    HitCondition,
23606}
23607
23608struct BreakpointPromptEditor {
23609    pub(crate) prompt: Entity<Editor>,
23610    editor: WeakEntity<Editor>,
23611    breakpoint_anchor: Anchor,
23612    breakpoint: Breakpoint,
23613    edit_action: BreakpointPromptEditAction,
23614    block_ids: HashSet<CustomBlockId>,
23615    editor_margins: Arc<Mutex<EditorMargins>>,
23616    _subscriptions: Vec<Subscription>,
23617}
23618
23619impl BreakpointPromptEditor {
23620    const MAX_LINES: u8 = 4;
23621
23622    fn new(
23623        editor: WeakEntity<Editor>,
23624        breakpoint_anchor: Anchor,
23625        breakpoint: Breakpoint,
23626        edit_action: BreakpointPromptEditAction,
23627        window: &mut Window,
23628        cx: &mut Context<Self>,
23629    ) -> Self {
23630        let base_text = match edit_action {
23631            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23632            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23633            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23634        }
23635        .map(|msg| msg.to_string())
23636        .unwrap_or_default();
23637
23638        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23639        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23640
23641        let prompt = cx.new(|cx| {
23642            let mut prompt = Editor::new(
23643                EditorMode::AutoHeight {
23644                    min_lines: 1,
23645                    max_lines: Some(Self::MAX_LINES as usize),
23646                },
23647                buffer,
23648                None,
23649                window,
23650                cx,
23651            );
23652            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23653            prompt.set_show_cursor_when_unfocused(false, cx);
23654            prompt.set_placeholder_text(
23655                match edit_action {
23656                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23657                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23658                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23659                },
23660                cx,
23661            );
23662
23663            prompt
23664        });
23665
23666        Self {
23667            prompt,
23668            editor,
23669            breakpoint_anchor,
23670            breakpoint,
23671            edit_action,
23672            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23673            block_ids: Default::default(),
23674            _subscriptions: vec![],
23675        }
23676    }
23677
23678    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23679        self.block_ids.extend(block_ids)
23680    }
23681
23682    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23683        if let Some(editor) = self.editor.upgrade() {
23684            let message = self
23685                .prompt
23686                .read(cx)
23687                .buffer
23688                .read(cx)
23689                .as_singleton()
23690                .expect("A multi buffer in breakpoint prompt isn't possible")
23691                .read(cx)
23692                .as_rope()
23693                .to_string();
23694
23695            editor.update(cx, |editor, cx| {
23696                editor.edit_breakpoint_at_anchor(
23697                    self.breakpoint_anchor,
23698                    self.breakpoint.clone(),
23699                    match self.edit_action {
23700                        BreakpointPromptEditAction::Log => {
23701                            BreakpointEditAction::EditLogMessage(message.into())
23702                        }
23703                        BreakpointPromptEditAction::Condition => {
23704                            BreakpointEditAction::EditCondition(message.into())
23705                        }
23706                        BreakpointPromptEditAction::HitCondition => {
23707                            BreakpointEditAction::EditHitCondition(message.into())
23708                        }
23709                    },
23710                    cx,
23711                );
23712
23713                editor.remove_blocks(self.block_ids.clone(), None, cx);
23714                cx.focus_self(window);
23715            });
23716        }
23717    }
23718
23719    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23720        self.editor
23721            .update(cx, |editor, cx| {
23722                editor.remove_blocks(self.block_ids.clone(), None, cx);
23723                window.focus(&editor.focus_handle);
23724            })
23725            .log_err();
23726    }
23727
23728    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23729        let settings = ThemeSettings::get_global(cx);
23730        let text_style = TextStyle {
23731            color: if self.prompt.read(cx).read_only(cx) {
23732                cx.theme().colors().text_disabled
23733            } else {
23734                cx.theme().colors().text
23735            },
23736            font_family: settings.buffer_font.family.clone(),
23737            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23738            font_size: settings.buffer_font_size(cx).into(),
23739            font_weight: settings.buffer_font.weight,
23740            line_height: relative(settings.buffer_line_height.value()),
23741            ..Default::default()
23742        };
23743        EditorElement::new(
23744            &self.prompt,
23745            EditorStyle {
23746                background: cx.theme().colors().editor_background,
23747                local_player: cx.theme().players().local(),
23748                text: text_style,
23749                ..Default::default()
23750            },
23751        )
23752    }
23753}
23754
23755impl Render for BreakpointPromptEditor {
23756    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23757        let editor_margins = *self.editor_margins.lock();
23758        let gutter_dimensions = editor_margins.gutter;
23759        h_flex()
23760            .key_context("Editor")
23761            .bg(cx.theme().colors().editor_background)
23762            .border_y_1()
23763            .border_color(cx.theme().status().info_border)
23764            .size_full()
23765            .py(window.line_height() / 2.5)
23766            .on_action(cx.listener(Self::confirm))
23767            .on_action(cx.listener(Self::cancel))
23768            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23769            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23770    }
23771}
23772
23773impl Focusable for BreakpointPromptEditor {
23774    fn focus_handle(&self, cx: &App) -> FocusHandle {
23775        self.prompt.focus_handle(cx)
23776    }
23777}
23778
23779fn all_edits_insertions_or_deletions(
23780    edits: &Vec<(Range<Anchor>, String)>,
23781    snapshot: &MultiBufferSnapshot,
23782) -> bool {
23783    let mut all_insertions = true;
23784    let mut all_deletions = true;
23785
23786    for (range, new_text) in edits.iter() {
23787        let range_is_empty = range.to_offset(snapshot).is_empty();
23788        let text_is_empty = new_text.is_empty();
23789
23790        if range_is_empty != text_is_empty {
23791            if range_is_empty {
23792                all_deletions = false;
23793            } else {
23794                all_insertions = false;
23795            }
23796        } else {
23797            return false;
23798        }
23799
23800        if !all_insertions && !all_deletions {
23801            return false;
23802        }
23803    }
23804    all_insertions || all_deletions
23805}
23806
23807struct MissingEditPredictionKeybindingTooltip;
23808
23809impl Render for MissingEditPredictionKeybindingTooltip {
23810    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23811        ui::tooltip_container(window, cx, |container, _, cx| {
23812            container
23813                .flex_shrink_0()
23814                .max_w_80()
23815                .min_h(rems_from_px(124.))
23816                .justify_between()
23817                .child(
23818                    v_flex()
23819                        .flex_1()
23820                        .text_ui_sm(cx)
23821                        .child(Label::new("Conflict with Accept Keybinding"))
23822                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23823                )
23824                .child(
23825                    h_flex()
23826                        .pb_1()
23827                        .gap_1()
23828                        .items_end()
23829                        .w_full()
23830                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23831                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23832                        }))
23833                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23834                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23835                        })),
23836                )
23837        })
23838    }
23839}
23840
23841#[derive(Debug, Clone, Copy, PartialEq)]
23842pub struct LineHighlight {
23843    pub background: Background,
23844    pub border: Option<gpui::Hsla>,
23845    pub include_gutter: bool,
23846    pub type_id: Option<TypeId>,
23847}
23848
23849struct LineManipulationResult {
23850    pub new_text: String,
23851    pub line_count_before: usize,
23852    pub line_count_after: usize,
23853}
23854
23855fn render_diff_hunk_controls(
23856    row: u32,
23857    status: &DiffHunkStatus,
23858    hunk_range: Range<Anchor>,
23859    is_created_file: bool,
23860    line_height: Pixels,
23861    editor: &Entity<Editor>,
23862    _window: &mut Window,
23863    cx: &mut App,
23864) -> AnyElement {
23865    h_flex()
23866        .h(line_height)
23867        .mr_1()
23868        .gap_1()
23869        .px_0p5()
23870        .pb_1()
23871        .border_x_1()
23872        .border_b_1()
23873        .border_color(cx.theme().colors().border_variant)
23874        .rounded_b_lg()
23875        .bg(cx.theme().colors().editor_background)
23876        .gap_1()
23877        .block_mouse_except_scroll()
23878        .shadow_md()
23879        .child(if status.has_secondary_hunk() {
23880            Button::new(("stage", row as u64), "Stage")
23881                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23882                .tooltip({
23883                    let focus_handle = editor.focus_handle(cx);
23884                    move |window, cx| {
23885                        Tooltip::for_action_in(
23886                            "Stage Hunk",
23887                            &::git::ToggleStaged,
23888                            &focus_handle,
23889                            window,
23890                            cx,
23891                        )
23892                    }
23893                })
23894                .on_click({
23895                    let editor = editor.clone();
23896                    move |_event, _window, cx| {
23897                        editor.update(cx, |editor, cx| {
23898                            editor.stage_or_unstage_diff_hunks(
23899                                true,
23900                                vec![hunk_range.start..hunk_range.start],
23901                                cx,
23902                            );
23903                        });
23904                    }
23905                })
23906        } else {
23907            Button::new(("unstage", row as u64), "Unstage")
23908                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23909                .tooltip({
23910                    let focus_handle = editor.focus_handle(cx);
23911                    move |window, cx| {
23912                        Tooltip::for_action_in(
23913                            "Unstage Hunk",
23914                            &::git::ToggleStaged,
23915                            &focus_handle,
23916                            window,
23917                            cx,
23918                        )
23919                    }
23920                })
23921                .on_click({
23922                    let editor = editor.clone();
23923                    move |_event, _window, cx| {
23924                        editor.update(cx, |editor, cx| {
23925                            editor.stage_or_unstage_diff_hunks(
23926                                false,
23927                                vec![hunk_range.start..hunk_range.start],
23928                                cx,
23929                            );
23930                        });
23931                    }
23932                })
23933        })
23934        .child(
23935            Button::new(("restore", row as u64), "Restore")
23936                .tooltip({
23937                    let focus_handle = editor.focus_handle(cx);
23938                    move |window, cx| {
23939                        Tooltip::for_action_in(
23940                            "Restore Hunk",
23941                            &::git::Restore,
23942                            &focus_handle,
23943                            window,
23944                            cx,
23945                        )
23946                    }
23947                })
23948                .on_click({
23949                    let editor = editor.clone();
23950                    move |_event, window, cx| {
23951                        editor.update(cx, |editor, cx| {
23952                            let snapshot = editor.snapshot(window, cx);
23953                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23954                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23955                        });
23956                    }
23957                })
23958                .disabled(is_created_file),
23959        )
23960        .when(
23961            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23962            |el| {
23963                el.child(
23964                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23965                        .shape(IconButtonShape::Square)
23966                        .icon_size(IconSize::Small)
23967                        // .disabled(!has_multiple_hunks)
23968                        .tooltip({
23969                            let focus_handle = editor.focus_handle(cx);
23970                            move |window, cx| {
23971                                Tooltip::for_action_in(
23972                                    "Next Hunk",
23973                                    &GoToHunk,
23974                                    &focus_handle,
23975                                    window,
23976                                    cx,
23977                                )
23978                            }
23979                        })
23980                        .on_click({
23981                            let editor = editor.clone();
23982                            move |_event, window, cx| {
23983                                editor.update(cx, |editor, cx| {
23984                                    let snapshot = editor.snapshot(window, cx);
23985                                    let position =
23986                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23987                                    editor.go_to_hunk_before_or_after_position(
23988                                        &snapshot,
23989                                        position,
23990                                        Direction::Next,
23991                                        window,
23992                                        cx,
23993                                    );
23994                                    editor.expand_selected_diff_hunks(cx);
23995                                });
23996                            }
23997                        }),
23998                )
23999                .child(
24000                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24001                        .shape(IconButtonShape::Square)
24002                        .icon_size(IconSize::Small)
24003                        // .disabled(!has_multiple_hunks)
24004                        .tooltip({
24005                            let focus_handle = editor.focus_handle(cx);
24006                            move |window, cx| {
24007                                Tooltip::for_action_in(
24008                                    "Previous Hunk",
24009                                    &GoToPreviousHunk,
24010                                    &focus_handle,
24011                                    window,
24012                                    cx,
24013                                )
24014                            }
24015                        })
24016                        .on_click({
24017                            let editor = editor.clone();
24018                            move |_event, window, cx| {
24019                                editor.update(cx, |editor, cx| {
24020                                    let snapshot = editor.snapshot(window, cx);
24021                                    let point =
24022                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24023                                    editor.go_to_hunk_before_or_after_position(
24024                                        &snapshot,
24025                                        point,
24026                                        Direction::Prev,
24027                                        window,
24028                                        cx,
24029                                    );
24030                                    editor.expand_selected_diff_hunks(cx);
24031                                });
24032                            }
24033                        }),
24034                )
24035            },
24036        )
24037        .into_any_element()
24038}