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