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        matches!(*self, Self::Disabled)
  786    }
  787
  788    fn settings_visibility(&self) -> bool {
  789        match *self {
  790            Self::Enabled {
  791                setting_configuration,
  792                ..
  793            } => setting_configuration,
  794            _ => false,
  795        }
  796    }
  797
  798    fn visible(&self) -> bool {
  799        match *self {
  800            Self::Enabled {
  801                setting_configuration,
  802                toggle_override,
  803            } => setting_configuration ^ toggle_override,
  804            _ => false,
  805        }
  806    }
  807
  808    fn toggle_visibility(&self) -> Self {
  809        match *self {
  810            Self::Enabled {
  811                toggle_override,
  812                setting_configuration,
  813            } => Self::Enabled {
  814                setting_configuration,
  815                toggle_override: !toggle_override,
  816            },
  817            Self::Disabled => Self::Disabled,
  818        }
  819    }
  820}
  821
  822#[derive(Clone, Debug)]
  823struct RunnableTasks {
  824    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  825    offset: multi_buffer::Anchor,
  826    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  827    column: u32,
  828    // Values of all named captures, including those starting with '_'
  829    extra_variables: HashMap<String, String>,
  830    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  831    context_range: Range<BufferOffset>,
  832}
  833
  834impl RunnableTasks {
  835    fn resolve<'a>(
  836        &'a self,
  837        cx: &'a task::TaskContext,
  838    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  839        self.templates.iter().filter_map(|(kind, template)| {
  840            template
  841                .resolve_task(&kind.to_id_base(), cx)
  842                .map(|task| (kind.clone(), task))
  843        })
  844    }
  845}
  846
  847#[derive(Clone)]
  848pub struct ResolvedTasks {
  849    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  850    position: Anchor,
  851}
  852
  853#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  854struct BufferOffset(usize);
  855
  856// Addons allow storing per-editor state in other crates (e.g. Vim)
  857pub trait Addon: 'static {
  858    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  859
  860    fn render_buffer_header_controls(
  861        &self,
  862        _: &ExcerptInfo,
  863        _: &Window,
  864        _: &App,
  865    ) -> Option<AnyElement> {
  866        None
  867    }
  868
  869    fn to_any(&self) -> &dyn std::any::Any;
  870
  871    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  872        None
  873    }
  874}
  875
  876struct ChangeLocation {
  877    current: Option<Vec<Anchor>>,
  878    original: Vec<Anchor>,
  879}
  880impl ChangeLocation {
  881    fn locations(&self) -> &[Anchor] {
  882        self.current.as_ref().unwrap_or(&self.original)
  883    }
  884}
  885
  886/// A set of caret positions, registered when the editor was edited.
  887pub struct ChangeList {
  888    changes: Vec<ChangeLocation>,
  889    /// Currently "selected" change.
  890    position: Option<usize>,
  891}
  892
  893impl ChangeList {
  894    pub fn new() -> Self {
  895        Self {
  896            changes: Vec::new(),
  897            position: None,
  898        }
  899    }
  900
  901    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  902    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  903    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  904        if self.changes.is_empty() {
  905            return None;
  906        }
  907
  908        let prev = self.position.unwrap_or(self.changes.len());
  909        let next = if direction == Direction::Prev {
  910            prev.saturating_sub(count)
  911        } else {
  912            (prev + count).min(self.changes.len() - 1)
  913        };
  914        self.position = Some(next);
  915        self.changes.get(next).map(|change| change.locations())
  916    }
  917
  918    /// Adds a new change to the list, resetting the change list position.
  919    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  920        self.position.take();
  921        if let Some(last) = self.changes.last_mut()
  922            && group
  923        {
  924            last.current = Some(new_positions)
  925        } else {
  926            self.changes.push(ChangeLocation {
  927                original: new_positions,
  928                current: None,
  929            });
  930        }
  931    }
  932
  933    pub fn last(&self) -> Option<&[Anchor]> {
  934        self.changes.last().map(|change| change.locations())
  935    }
  936
  937    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  938        self.changes.last().map(|change| change.original.as_slice())
  939    }
  940
  941    pub fn invert_last_group(&mut self) {
  942        if let Some(last) = self.changes.last_mut()
  943            && let Some(current) = last.current.as_mut()
  944        {
  945            mem::swap(&mut last.original, current);
  946        }
  947    }
  948}
  949
  950#[derive(Clone)]
  951struct InlineBlamePopoverState {
  952    scroll_handle: ScrollHandle,
  953    commit_message: Option<ParsedCommitMessage>,
  954    markdown: Entity<Markdown>,
  955}
  956
  957struct InlineBlamePopover {
  958    position: gpui::Point<Pixels>,
  959    hide_task: Option<Task<()>>,
  960    popover_bounds: Option<Bounds<Pixels>>,
  961    popover_state: InlineBlamePopoverState,
  962    keyboard_grace: bool,
  963}
  964
  965enum SelectionDragState {
  966    /// State when no drag related activity is detected.
  967    None,
  968    /// State when the mouse is down on a selection that is about to be dragged.
  969    ReadyToDrag {
  970        selection: Selection<Anchor>,
  971        click_position: gpui::Point<Pixels>,
  972        mouse_down_time: Instant,
  973    },
  974    /// State when the mouse is dragging the selection in the editor.
  975    Dragging {
  976        selection: Selection<Anchor>,
  977        drop_cursor: Selection<Anchor>,
  978        hide_drop_cursor: bool,
  979    },
  980}
  981
  982enum ColumnarSelectionState {
  983    FromMouse {
  984        selection_tail: Anchor,
  985        display_point: Option<DisplayPoint>,
  986    },
  987    FromSelection {
  988        selection_tail: Anchor,
  989    },
  990}
  991
  992/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  993/// a breakpoint on them.
  994#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  995struct PhantomBreakpointIndicator {
  996    display_row: DisplayRow,
  997    /// There's a small debounce between hovering over the line and showing the indicator.
  998    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  999    is_active: bool,
 1000    collides_with_existing_breakpoint: bool,
 1001}
 1002
 1003/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1004///
 1005/// See the [module level documentation](self) for more information.
 1006pub struct Editor {
 1007    focus_handle: FocusHandle,
 1008    last_focused_descendant: Option<WeakFocusHandle>,
 1009    /// The text buffer being edited
 1010    buffer: Entity<MultiBuffer>,
 1011    /// Map of how text in the buffer should be displayed.
 1012    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1013    pub display_map: Entity<DisplayMap>,
 1014    pub selections: SelectionsCollection,
 1015    pub scroll_manager: ScrollManager,
 1016    /// When inline assist editors are linked, they all render cursors because
 1017    /// typing enters text into each of them, even the ones that aren't focused.
 1018    pub(crate) show_cursor_when_unfocused: bool,
 1019    columnar_selection_state: Option<ColumnarSelectionState>,
 1020    add_selections_state: Option<AddSelectionsState>,
 1021    select_next_state: Option<SelectNextState>,
 1022    select_prev_state: Option<SelectNextState>,
 1023    selection_history: SelectionHistory,
 1024    defer_selection_effects: bool,
 1025    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1026    autoclose_regions: Vec<AutocloseRegion>,
 1027    snippet_stack: InvalidationStack<SnippetState>,
 1028    select_syntax_node_history: SelectSyntaxNodeHistory,
 1029    ime_transaction: Option<TransactionId>,
 1030    pub diagnostics_max_severity: DiagnosticSeverity,
 1031    active_diagnostics: ActiveDiagnostic,
 1032    show_inline_diagnostics: bool,
 1033    inline_diagnostics_update: Task<()>,
 1034    inline_diagnostics_enabled: bool,
 1035    diagnostics_enabled: bool,
 1036    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1037    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1038    hard_wrap: Option<usize>,
 1039    project: Option<Entity<Project>>,
 1040    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1041    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1042    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1043    blink_manager: Entity<BlinkManager>,
 1044    show_cursor_names: bool,
 1045    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1046    pub show_local_selections: bool,
 1047    mode: EditorMode,
 1048    show_breadcrumbs: bool,
 1049    show_gutter: bool,
 1050    show_scrollbars: ScrollbarAxes,
 1051    minimap_visibility: MinimapVisibility,
 1052    offset_content: bool,
 1053    disable_expand_excerpt_buttons: bool,
 1054    show_line_numbers: Option<bool>,
 1055    use_relative_line_numbers: Option<bool>,
 1056    show_git_diff_gutter: Option<bool>,
 1057    show_code_actions: Option<bool>,
 1058    show_runnables: Option<bool>,
 1059    show_breakpoints: Option<bool>,
 1060    show_wrap_guides: Option<bool>,
 1061    show_indent_guides: Option<bool>,
 1062    placeholder_text: Option<Arc<str>>,
 1063    highlight_order: usize,
 1064    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1065    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1066    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1067    scrollbar_marker_state: ScrollbarMarkerState,
 1068    active_indent_guides_state: ActiveIndentGuidesState,
 1069    nav_history: Option<ItemNavHistory>,
 1070    context_menu: RefCell<Option<CodeContextMenu>>,
 1071    context_menu_options: Option<ContextMenuOptions>,
 1072    mouse_context_menu: Option<MouseContextMenu>,
 1073    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1074    inline_blame_popover: Option<InlineBlamePopover>,
 1075    inline_blame_popover_show_task: Option<Task<()>>,
 1076    signature_help_state: SignatureHelpState,
 1077    auto_signature_help: Option<bool>,
 1078    find_all_references_task_sources: Vec<Anchor>,
 1079    next_completion_id: CompletionId,
 1080    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1081    code_actions_task: Option<Task<Result<()>>>,
 1082    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1083    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1084    document_highlights_task: Option<Task<()>>,
 1085    linked_editing_range_task: Option<Task<Option<()>>>,
 1086    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1087    pending_rename: Option<RenameState>,
 1088    searchable: bool,
 1089    cursor_shape: CursorShape,
 1090    current_line_highlight: Option<CurrentLineHighlight>,
 1091    collapse_matches: bool,
 1092    autoindent_mode: Option<AutoindentMode>,
 1093    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1094    input_enabled: bool,
 1095    use_modal_editing: bool,
 1096    read_only: bool,
 1097    leader_id: Option<CollaboratorId>,
 1098    remote_id: Option<ViewId>,
 1099    pub hover_state: HoverState,
 1100    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1101    gutter_hovered: bool,
 1102    hovered_link_state: Option<HoveredLinkState>,
 1103    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1104    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1105    active_edit_prediction: Option<EditPredictionState>,
 1106    /// Used to prevent flickering as the user types while the menu is open
 1107    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1108    edit_prediction_settings: EditPredictionSettings,
 1109    edit_predictions_hidden_for_vim_mode: bool,
 1110    show_edit_predictions_override: Option<bool>,
 1111    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1112    edit_prediction_preview: EditPredictionPreview,
 1113    edit_prediction_indent_conflict: bool,
 1114    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1115    inlay_hint_cache: InlayHintCache,
 1116    next_inlay_id: usize,
 1117    _subscriptions: Vec<Subscription>,
 1118    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1119    gutter_dimensions: GutterDimensions,
 1120    style: Option<EditorStyle>,
 1121    text_style_refinement: Option<TextStyleRefinement>,
 1122    next_editor_action_id: EditorActionId,
 1123    editor_actions: Rc<
 1124        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1125    >,
 1126    use_autoclose: bool,
 1127    use_auto_surround: bool,
 1128    auto_replace_emoji_shortcode: bool,
 1129    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1130    show_git_blame_gutter: bool,
 1131    show_git_blame_inline: bool,
 1132    show_git_blame_inline_delay_task: Option<Task<()>>,
 1133    git_blame_inline_enabled: bool,
 1134    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1135    serialize_dirty_buffers: bool,
 1136    show_selection_menu: Option<bool>,
 1137    blame: Option<Entity<GitBlame>>,
 1138    blame_subscription: Option<Subscription>,
 1139    custom_context_menu: Option<
 1140        Box<
 1141            dyn 'static
 1142                + Fn(
 1143                    &mut Self,
 1144                    DisplayPoint,
 1145                    &mut Window,
 1146                    &mut Context<Self>,
 1147                ) -> Option<Entity<ui::ContextMenu>>,
 1148        >,
 1149    >,
 1150    last_bounds: Option<Bounds<Pixels>>,
 1151    last_position_map: Option<Rc<PositionMap>>,
 1152    expect_bounds_change: Option<Bounds<Pixels>>,
 1153    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1154    tasks_update_task: Option<Task<()>>,
 1155    breakpoint_store: Option<Entity<BreakpointStore>>,
 1156    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1157    hovered_diff_hunk_row: Option<DisplayRow>,
 1158    pull_diagnostics_task: Task<()>,
 1159    in_project_search: bool,
 1160    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1161    breadcrumb_header: Option<String>,
 1162    focused_block: Option<FocusedBlock>,
 1163    next_scroll_position: NextScrollCursorCenterTopBottom,
 1164    addons: HashMap<TypeId, Box<dyn Addon>>,
 1165    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1166    load_diff_task: Option<Shared<Task<()>>>,
 1167    /// Whether we are temporarily displaying a diff other than git's
 1168    temporary_diff_override: bool,
 1169    selection_mark_mode: bool,
 1170    toggle_fold_multiple_buffers: Task<()>,
 1171    _scroll_cursor_center_top_bottom_task: Task<()>,
 1172    serialize_selections: Task<()>,
 1173    serialize_folds: Task<()>,
 1174    mouse_cursor_hidden: bool,
 1175    minimap: Option<Entity<Self>>,
 1176    hide_mouse_mode: HideMouseMode,
 1177    pub change_list: ChangeList,
 1178    inline_value_cache: InlineValueCache,
 1179    selection_drag_state: SelectionDragState,
 1180    next_color_inlay_id: usize,
 1181    colors: Option<LspColorData>,
 1182    folding_newlines: Task<()>,
 1183}
 1184
 1185#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1186enum NextScrollCursorCenterTopBottom {
 1187    #[default]
 1188    Center,
 1189    Top,
 1190    Bottom,
 1191}
 1192
 1193impl NextScrollCursorCenterTopBottom {
 1194    fn next(&self) -> Self {
 1195        match self {
 1196            Self::Center => Self::Top,
 1197            Self::Top => Self::Bottom,
 1198            Self::Bottom => Self::Center,
 1199        }
 1200    }
 1201}
 1202
 1203#[derive(Clone)]
 1204pub struct EditorSnapshot {
 1205    pub mode: EditorMode,
 1206    show_gutter: bool,
 1207    show_line_numbers: Option<bool>,
 1208    show_git_diff_gutter: Option<bool>,
 1209    show_code_actions: Option<bool>,
 1210    show_runnables: Option<bool>,
 1211    show_breakpoints: Option<bool>,
 1212    git_blame_gutter_max_author_length: Option<usize>,
 1213    pub display_snapshot: DisplaySnapshot,
 1214    pub placeholder_text: Option<Arc<str>>,
 1215    is_focused: bool,
 1216    scroll_anchor: ScrollAnchor,
 1217    ongoing_scroll: OngoingScroll,
 1218    current_line_highlight: CurrentLineHighlight,
 1219    gutter_hovered: bool,
 1220}
 1221
 1222#[derive(Default, Debug, Clone, Copy)]
 1223pub struct GutterDimensions {
 1224    pub left_padding: Pixels,
 1225    pub right_padding: Pixels,
 1226    pub width: Pixels,
 1227    pub margin: Pixels,
 1228    pub git_blame_entries_width: Option<Pixels>,
 1229}
 1230
 1231impl GutterDimensions {
 1232    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1233        Self {
 1234            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1235            ..Default::default()
 1236        }
 1237    }
 1238
 1239    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1240        -cx.text_system().descent(font_id, font_size)
 1241    }
 1242    /// The full width of the space taken up by the gutter.
 1243    pub fn full_width(&self) -> Pixels {
 1244        self.margin + self.width
 1245    }
 1246
 1247    /// The width of the space reserved for the fold indicators,
 1248    /// use alongside 'justify_end' and `gutter_width` to
 1249    /// right align content with the line numbers
 1250    pub fn fold_area_width(&self) -> Pixels {
 1251        self.margin + self.right_padding
 1252    }
 1253}
 1254
 1255struct CharacterDimensions {
 1256    em_width: Pixels,
 1257    em_advance: Pixels,
 1258    line_height: Pixels,
 1259}
 1260
 1261#[derive(Debug)]
 1262pub struct RemoteSelection {
 1263    pub replica_id: ReplicaId,
 1264    pub selection: Selection<Anchor>,
 1265    pub cursor_shape: CursorShape,
 1266    pub collaborator_id: CollaboratorId,
 1267    pub line_mode: bool,
 1268    pub user_name: Option<SharedString>,
 1269    pub color: PlayerColor,
 1270}
 1271
 1272#[derive(Clone, Debug)]
 1273struct SelectionHistoryEntry {
 1274    selections: Arc<[Selection<Anchor>]>,
 1275    select_next_state: Option<SelectNextState>,
 1276    select_prev_state: Option<SelectNextState>,
 1277    add_selections_state: Option<AddSelectionsState>,
 1278}
 1279
 1280#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1281enum SelectionHistoryMode {
 1282    Normal,
 1283    Undoing,
 1284    Redoing,
 1285    Skipping,
 1286}
 1287
 1288#[derive(Clone, PartialEq, Eq, Hash)]
 1289struct HoveredCursor {
 1290    replica_id: u16,
 1291    selection_id: usize,
 1292}
 1293
 1294impl Default for SelectionHistoryMode {
 1295    fn default() -> Self {
 1296        Self::Normal
 1297    }
 1298}
 1299
 1300#[derive(Debug)]
 1301/// SelectionEffects controls the side-effects of updating the selection.
 1302///
 1303/// The default behaviour does "what you mostly want":
 1304/// - it pushes to the nav history if the cursor moved by >10 lines
 1305/// - it re-triggers completion requests
 1306/// - it scrolls to fit
 1307///
 1308/// You might want to modify these behaviours. For example when doing a "jump"
 1309/// like go to definition, we always want to add to nav history; but when scrolling
 1310/// in vim mode we never do.
 1311///
 1312/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1313/// move.
 1314#[derive(Clone)]
 1315pub struct SelectionEffects {
 1316    nav_history: Option<bool>,
 1317    completions: bool,
 1318    scroll: Option<Autoscroll>,
 1319}
 1320
 1321impl Default for SelectionEffects {
 1322    fn default() -> Self {
 1323        Self {
 1324            nav_history: None,
 1325            completions: true,
 1326            scroll: Some(Autoscroll::fit()),
 1327        }
 1328    }
 1329}
 1330impl SelectionEffects {
 1331    pub fn scroll(scroll: Autoscroll) -> Self {
 1332        Self {
 1333            scroll: Some(scroll),
 1334            ..Default::default()
 1335        }
 1336    }
 1337
 1338    pub fn no_scroll() -> Self {
 1339        Self {
 1340            scroll: None,
 1341            ..Default::default()
 1342        }
 1343    }
 1344
 1345    pub fn completions(self, completions: bool) -> Self {
 1346        Self {
 1347            completions,
 1348            ..self
 1349        }
 1350    }
 1351
 1352    pub fn nav_history(self, nav_history: bool) -> Self {
 1353        Self {
 1354            nav_history: Some(nav_history),
 1355            ..self
 1356        }
 1357    }
 1358}
 1359
 1360struct DeferredSelectionEffectsState {
 1361    changed: bool,
 1362    effects: SelectionEffects,
 1363    old_cursor_position: Anchor,
 1364    history_entry: SelectionHistoryEntry,
 1365}
 1366
 1367#[derive(Default)]
 1368struct SelectionHistory {
 1369    #[allow(clippy::type_complexity)]
 1370    selections_by_transaction:
 1371        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1372    mode: SelectionHistoryMode,
 1373    undo_stack: VecDeque<SelectionHistoryEntry>,
 1374    redo_stack: VecDeque<SelectionHistoryEntry>,
 1375}
 1376
 1377impl SelectionHistory {
 1378    #[track_caller]
 1379    fn insert_transaction(
 1380        &mut self,
 1381        transaction_id: TransactionId,
 1382        selections: Arc<[Selection<Anchor>]>,
 1383    ) {
 1384        if selections.is_empty() {
 1385            log::error!(
 1386                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1387                std::panic::Location::caller()
 1388            );
 1389            return;
 1390        }
 1391        self.selections_by_transaction
 1392            .insert(transaction_id, (selections, None));
 1393    }
 1394
 1395    #[allow(clippy::type_complexity)]
 1396    fn transaction(
 1397        &self,
 1398        transaction_id: TransactionId,
 1399    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1400        self.selections_by_transaction.get(&transaction_id)
 1401    }
 1402
 1403    #[allow(clippy::type_complexity)]
 1404    fn transaction_mut(
 1405        &mut self,
 1406        transaction_id: TransactionId,
 1407    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1408        self.selections_by_transaction.get_mut(&transaction_id)
 1409    }
 1410
 1411    fn push(&mut self, entry: SelectionHistoryEntry) {
 1412        if !entry.selections.is_empty() {
 1413            match self.mode {
 1414                SelectionHistoryMode::Normal => {
 1415                    self.push_undo(entry);
 1416                    self.redo_stack.clear();
 1417                }
 1418                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1419                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1420                SelectionHistoryMode::Skipping => {}
 1421            }
 1422        }
 1423    }
 1424
 1425    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1426        if self
 1427            .undo_stack
 1428            .back()
 1429            .is_none_or(|e| e.selections != entry.selections)
 1430        {
 1431            self.undo_stack.push_back(entry);
 1432            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1433                self.undo_stack.pop_front();
 1434            }
 1435        }
 1436    }
 1437
 1438    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1439        if self
 1440            .redo_stack
 1441            .back()
 1442            .is_none_or(|e| e.selections != entry.selections)
 1443        {
 1444            self.redo_stack.push_back(entry);
 1445            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1446                self.redo_stack.pop_front();
 1447            }
 1448        }
 1449    }
 1450}
 1451
 1452#[derive(Clone, Copy)]
 1453pub struct RowHighlightOptions {
 1454    pub autoscroll: bool,
 1455    pub include_gutter: bool,
 1456}
 1457
 1458impl Default for RowHighlightOptions {
 1459    fn default() -> Self {
 1460        Self {
 1461            autoscroll: Default::default(),
 1462            include_gutter: true,
 1463        }
 1464    }
 1465}
 1466
 1467struct RowHighlight {
 1468    index: usize,
 1469    range: Range<Anchor>,
 1470    color: Hsla,
 1471    options: RowHighlightOptions,
 1472    type_id: TypeId,
 1473}
 1474
 1475#[derive(Clone, Debug)]
 1476struct AddSelectionsState {
 1477    groups: Vec<AddSelectionsGroup>,
 1478}
 1479
 1480#[derive(Clone, Debug)]
 1481struct AddSelectionsGroup {
 1482    above: bool,
 1483    stack: Vec<usize>,
 1484}
 1485
 1486#[derive(Clone)]
 1487struct SelectNextState {
 1488    query: AhoCorasick,
 1489    wordwise: bool,
 1490    done: bool,
 1491}
 1492
 1493impl std::fmt::Debug for SelectNextState {
 1494    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1495        f.debug_struct(std::any::type_name::<Self>())
 1496            .field("wordwise", &self.wordwise)
 1497            .field("done", &self.done)
 1498            .finish()
 1499    }
 1500}
 1501
 1502#[derive(Debug)]
 1503struct AutocloseRegion {
 1504    selection_id: usize,
 1505    range: Range<Anchor>,
 1506    pair: BracketPair,
 1507}
 1508
 1509#[derive(Debug)]
 1510struct SnippetState {
 1511    ranges: Vec<Vec<Range<Anchor>>>,
 1512    active_index: usize,
 1513    choices: Vec<Option<Vec<String>>>,
 1514}
 1515
 1516#[doc(hidden)]
 1517pub struct RenameState {
 1518    pub range: Range<Anchor>,
 1519    pub old_name: Arc<str>,
 1520    pub editor: Entity<Editor>,
 1521    block_id: CustomBlockId,
 1522}
 1523
 1524struct InvalidationStack<T>(Vec<T>);
 1525
 1526struct RegisteredEditPredictionProvider {
 1527    provider: Arc<dyn EditPredictionProviderHandle>,
 1528    _subscription: Subscription,
 1529}
 1530
 1531#[derive(Debug, PartialEq, Eq)]
 1532pub struct ActiveDiagnosticGroup {
 1533    pub active_range: Range<Anchor>,
 1534    pub active_message: String,
 1535    pub group_id: usize,
 1536    pub blocks: HashSet<CustomBlockId>,
 1537}
 1538
 1539#[derive(Debug, PartialEq, Eq)]
 1540
 1541pub(crate) enum ActiveDiagnostic {
 1542    None,
 1543    All,
 1544    Group(ActiveDiagnosticGroup),
 1545}
 1546
 1547#[derive(Serialize, Deserialize, Clone, Debug)]
 1548pub struct ClipboardSelection {
 1549    /// The number of bytes in this selection.
 1550    pub len: usize,
 1551    /// Whether this was a full-line selection.
 1552    pub is_entire_line: bool,
 1553    /// The indentation of the first line when this content was originally copied.
 1554    pub first_line_indent: u32,
 1555}
 1556
 1557// selections, scroll behavior, was newest selection reversed
 1558type SelectSyntaxNodeHistoryState = (
 1559    Box<[Selection<usize>]>,
 1560    SelectSyntaxNodeScrollBehavior,
 1561    bool,
 1562);
 1563
 1564#[derive(Default)]
 1565struct SelectSyntaxNodeHistory {
 1566    stack: Vec<SelectSyntaxNodeHistoryState>,
 1567    // disable temporarily to allow changing selections without losing the stack
 1568    pub disable_clearing: bool,
 1569}
 1570
 1571impl SelectSyntaxNodeHistory {
 1572    pub fn try_clear(&mut self) {
 1573        if !self.disable_clearing {
 1574            self.stack.clear();
 1575        }
 1576    }
 1577
 1578    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1579        self.stack.push(selection);
 1580    }
 1581
 1582    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1583        self.stack.pop()
 1584    }
 1585}
 1586
 1587enum SelectSyntaxNodeScrollBehavior {
 1588    CursorTop,
 1589    FitSelection,
 1590    CursorBottom,
 1591}
 1592
 1593#[derive(Debug)]
 1594pub(crate) struct NavigationData {
 1595    cursor_anchor: Anchor,
 1596    cursor_position: Point,
 1597    scroll_anchor: ScrollAnchor,
 1598    scroll_top_row: u32,
 1599}
 1600
 1601#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1602pub enum GotoDefinitionKind {
 1603    Symbol,
 1604    Declaration,
 1605    Type,
 1606    Implementation,
 1607}
 1608
 1609#[derive(Debug, Clone)]
 1610enum InlayHintRefreshReason {
 1611    ModifiersChanged(bool),
 1612    Toggle(bool),
 1613    SettingsChange(InlayHintSettings),
 1614    NewLinesShown,
 1615    BufferEdited(HashSet<Arc<Language>>),
 1616    RefreshRequested,
 1617    ExcerptsRemoved(Vec<ExcerptId>),
 1618}
 1619
 1620impl InlayHintRefreshReason {
 1621    fn description(&self) -> &'static str {
 1622        match self {
 1623            Self::ModifiersChanged(_) => "modifiers changed",
 1624            Self::Toggle(_) => "toggle",
 1625            Self::SettingsChange(_) => "settings change",
 1626            Self::NewLinesShown => "new lines shown",
 1627            Self::BufferEdited(_) => "buffer edited",
 1628            Self::RefreshRequested => "refresh requested",
 1629            Self::ExcerptsRemoved(_) => "excerpts removed",
 1630        }
 1631    }
 1632}
 1633
 1634pub enum FormatTarget {
 1635    Buffers(HashSet<Entity<Buffer>>),
 1636    Ranges(Vec<Range<MultiBufferPoint>>),
 1637}
 1638
 1639pub(crate) struct FocusedBlock {
 1640    id: BlockId,
 1641    focus_handle: WeakFocusHandle,
 1642}
 1643
 1644#[derive(Clone)]
 1645enum JumpData {
 1646    MultiBufferRow {
 1647        row: MultiBufferRow,
 1648        line_offset_from_top: u32,
 1649    },
 1650    MultiBufferPoint {
 1651        excerpt_id: ExcerptId,
 1652        position: Point,
 1653        anchor: text::Anchor,
 1654        line_offset_from_top: u32,
 1655    },
 1656}
 1657
 1658pub enum MultibufferSelectionMode {
 1659    First,
 1660    All,
 1661}
 1662
 1663#[derive(Clone, Copy, Debug, Default)]
 1664pub struct RewrapOptions {
 1665    pub override_language_settings: bool,
 1666    pub preserve_existing_whitespace: bool,
 1667}
 1668
 1669impl Editor {
 1670    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1674    }
 1675
 1676    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1677        let buffer = cx.new(|cx| Buffer::local("", cx));
 1678        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1679        Self::new(EditorMode::full(), buffer, None, window, cx)
 1680    }
 1681
 1682    pub fn auto_height(
 1683        min_lines: usize,
 1684        max_lines: usize,
 1685        window: &mut Window,
 1686        cx: &mut Context<Self>,
 1687    ) -> Self {
 1688        let buffer = cx.new(|cx| Buffer::local("", cx));
 1689        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1690        Self::new(
 1691            EditorMode::AutoHeight {
 1692                min_lines,
 1693                max_lines: Some(max_lines),
 1694            },
 1695            buffer,
 1696            None,
 1697            window,
 1698            cx,
 1699        )
 1700    }
 1701
 1702    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1703    /// The editor grows as tall as needed to fit its content.
 1704    pub fn auto_height_unbounded(
 1705        min_lines: usize,
 1706        window: &mut Window,
 1707        cx: &mut Context<Self>,
 1708    ) -> Self {
 1709        let buffer = cx.new(|cx| Buffer::local("", cx));
 1710        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1711        Self::new(
 1712            EditorMode::AutoHeight {
 1713                min_lines,
 1714                max_lines: None,
 1715            },
 1716            buffer,
 1717            None,
 1718            window,
 1719            cx,
 1720        )
 1721    }
 1722
 1723    pub fn for_buffer(
 1724        buffer: Entity<Buffer>,
 1725        project: Option<Entity<Project>>,
 1726        window: &mut Window,
 1727        cx: &mut Context<Self>,
 1728    ) -> Self {
 1729        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1730        Self::new(EditorMode::full(), buffer, project, window, cx)
 1731    }
 1732
 1733    pub fn for_multibuffer(
 1734        buffer: Entity<MultiBuffer>,
 1735        project: Option<Entity<Project>>,
 1736        window: &mut Window,
 1737        cx: &mut Context<Self>,
 1738    ) -> Self {
 1739        Self::new(EditorMode::full(), buffer, project, window, cx)
 1740    }
 1741
 1742    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1743        let mut clone = Self::new(
 1744            self.mode.clone(),
 1745            self.buffer.clone(),
 1746            self.project.clone(),
 1747            window,
 1748            cx,
 1749        );
 1750        self.display_map.update(cx, |display_map, cx| {
 1751            let snapshot = display_map.snapshot(cx);
 1752            clone.display_map.update(cx, |display_map, cx| {
 1753                display_map.set_state(&snapshot, cx);
 1754            });
 1755        });
 1756        clone.folds_did_change(cx);
 1757        clone.selections.clone_state(&self.selections);
 1758        clone.scroll_manager.clone_state(&self.scroll_manager);
 1759        clone.searchable = self.searchable;
 1760        clone.read_only = self.read_only;
 1761        clone
 1762    }
 1763
 1764    pub fn new(
 1765        mode: EditorMode,
 1766        buffer: Entity<MultiBuffer>,
 1767        project: Option<Entity<Project>>,
 1768        window: &mut Window,
 1769        cx: &mut Context<Self>,
 1770    ) -> Self {
 1771        Editor::new_internal(mode, buffer, project, None, window, cx)
 1772    }
 1773
 1774    fn new_internal(
 1775        mode: EditorMode,
 1776        buffer: Entity<MultiBuffer>,
 1777        project: Option<Entity<Project>>,
 1778        display_map: Option<Entity<DisplayMap>>,
 1779        window: &mut Window,
 1780        cx: &mut Context<Self>,
 1781    ) -> Self {
 1782        debug_assert!(
 1783            display_map.is_none() || mode.is_minimap(),
 1784            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1785        );
 1786
 1787        let full_mode = mode.is_full();
 1788        let is_minimap = mode.is_minimap();
 1789        let diagnostics_max_severity = if full_mode {
 1790            EditorSettings::get_global(cx)
 1791                .diagnostics_max_severity
 1792                .unwrap_or(DiagnosticSeverity::Hint)
 1793        } else {
 1794            DiagnosticSeverity::Off
 1795        };
 1796        let style = window.text_style();
 1797        let font_size = style.font_size.to_pixels(window.rem_size());
 1798        let editor = cx.entity().downgrade();
 1799        let fold_placeholder = FoldPlaceholder {
 1800            constrain_width: true,
 1801            render: Arc::new(move |fold_id, fold_range, cx| {
 1802                let editor = editor.clone();
 1803                div()
 1804                    .id(fold_id)
 1805                    .bg(cx.theme().colors().ghost_element_background)
 1806                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1807                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1808                    .rounded_xs()
 1809                    .size_full()
 1810                    .cursor_pointer()
 1811                    .child("")
 1812                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1813                    .on_click(move |_, _window, cx| {
 1814                        editor
 1815                            .update(cx, |editor, cx| {
 1816                                editor.unfold_ranges(
 1817                                    &[fold_range.start..fold_range.end],
 1818                                    true,
 1819                                    false,
 1820                                    cx,
 1821                                );
 1822                                cx.stop_propagation();
 1823                            })
 1824                            .ok();
 1825                    })
 1826                    .into_any()
 1827            }),
 1828            merge_adjacent: true,
 1829            ..FoldPlaceholder::default()
 1830        };
 1831        let display_map = display_map.unwrap_or_else(|| {
 1832            cx.new(|cx| {
 1833                DisplayMap::new(
 1834                    buffer.clone(),
 1835                    style.font(),
 1836                    font_size,
 1837                    None,
 1838                    FILE_HEADER_HEIGHT,
 1839                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1840                    fold_placeholder,
 1841                    diagnostics_max_severity,
 1842                    cx,
 1843                )
 1844            })
 1845        });
 1846
 1847        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1848
 1849        let blink_manager = cx.new(|cx| {
 1850            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1851            if is_minimap {
 1852                blink_manager.disable(cx);
 1853            }
 1854            blink_manager
 1855        });
 1856
 1857        let soft_wrap_mode_override =
 1858            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1859
 1860        let mut project_subscriptions = Vec::new();
 1861        if full_mode && let Some(project) = project.as_ref() {
 1862            project_subscriptions.push(cx.subscribe_in(
 1863                project,
 1864                window,
 1865                |editor, _, event, window, cx| match event {
 1866                    project::Event::RefreshCodeLens => {
 1867                        // we always query lens with actions, without storing them, always refreshing them
 1868                    }
 1869                    project::Event::RefreshInlayHints => {
 1870                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1871                    }
 1872                    project::Event::LanguageServerAdded(..)
 1873                    | project::Event::LanguageServerRemoved(..) => {
 1874                        if editor.tasks_update_task.is_none() {
 1875                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1876                        }
 1877                    }
 1878                    project::Event::SnippetEdit(id, snippet_edits) => {
 1879                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1880                            let focus_handle = editor.focus_handle(cx);
 1881                            if focus_handle.is_focused(window) {
 1882                                let snapshot = buffer.read(cx).snapshot();
 1883                                for (range, snippet) in snippet_edits {
 1884                                    let editor_range =
 1885                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1886                                    editor
 1887                                        .insert_snippet(
 1888                                            &[editor_range],
 1889                                            snippet.clone(),
 1890                                            window,
 1891                                            cx,
 1892                                        )
 1893                                        .ok();
 1894                                }
 1895                            }
 1896                        }
 1897                    }
 1898                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1899                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1900                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1901                        }
 1902                    }
 1903                    _ => {}
 1904                },
 1905            ));
 1906            if let Some(task_inventory) = project
 1907                .read(cx)
 1908                .task_store()
 1909                .read(cx)
 1910                .task_inventory()
 1911                .cloned()
 1912            {
 1913                project_subscriptions.push(cx.observe_in(
 1914                    &task_inventory,
 1915                    window,
 1916                    |editor, _, window, cx| {
 1917                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1918                    },
 1919                ));
 1920            };
 1921
 1922            project_subscriptions.push(cx.subscribe_in(
 1923                &project.read(cx).breakpoint_store(),
 1924                window,
 1925                |editor, _, event, window, cx| match event {
 1926                    BreakpointStoreEvent::ClearDebugLines => {
 1927                        editor.clear_row_highlights::<ActiveDebugLine>();
 1928                        editor.refresh_inline_values(cx);
 1929                    }
 1930                    BreakpointStoreEvent::SetDebugLine => {
 1931                        if editor.go_to_active_debug_line(window, cx) {
 1932                            cx.stop_propagation();
 1933                        }
 1934
 1935                        editor.refresh_inline_values(cx);
 1936                    }
 1937                    _ => {}
 1938                },
 1939            ));
 1940            let git_store = project.read(cx).git_store().clone();
 1941            let project = project.clone();
 1942            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1943                if let GitStoreEvent::RepositoryUpdated(
 1944                    _,
 1945                    RepositoryEvent::Updated {
 1946                        new_instance: true, ..
 1947                    },
 1948                    _,
 1949                ) = event
 1950                {
 1951                    this.load_diff_task = Some(
 1952                        update_uncommitted_diff_for_buffer(
 1953                            cx.entity(),
 1954                            &project,
 1955                            this.buffer.read(cx).all_buffers(),
 1956                            this.buffer.clone(),
 1957                            cx,
 1958                        )
 1959                        .shared(),
 1960                    );
 1961                }
 1962            }));
 1963        }
 1964
 1965        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1966
 1967        let inlay_hint_settings =
 1968            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1969        let focus_handle = cx.focus_handle();
 1970        if !is_minimap {
 1971            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1972                .detach();
 1973            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1974                .detach();
 1975            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1976                .detach();
 1977            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1978                .detach();
 1979            cx.observe_pending_input(window, Self::observe_pending_input)
 1980                .detach();
 1981        }
 1982
 1983        let show_indent_guides =
 1984            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 1985                Some(false)
 1986            } else {
 1987                None
 1988            };
 1989
 1990        let breakpoint_store = match (&mode, project.as_ref()) {
 1991            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1992            _ => None,
 1993        };
 1994
 1995        let mut code_action_providers = Vec::new();
 1996        let mut load_uncommitted_diff = None;
 1997        if let Some(project) = project.clone() {
 1998            load_uncommitted_diff = Some(
 1999                update_uncommitted_diff_for_buffer(
 2000                    cx.entity(),
 2001                    &project,
 2002                    buffer.read(cx).all_buffers(),
 2003                    buffer.clone(),
 2004                    cx,
 2005                )
 2006                .shared(),
 2007            );
 2008            code_action_providers.push(Rc::new(project) as Rc<_>);
 2009        }
 2010
 2011        let mut editor = Self {
 2012            focus_handle,
 2013            show_cursor_when_unfocused: false,
 2014            last_focused_descendant: None,
 2015            buffer: buffer.clone(),
 2016            display_map: display_map.clone(),
 2017            selections,
 2018            scroll_manager: ScrollManager::new(cx),
 2019            columnar_selection_state: None,
 2020            add_selections_state: None,
 2021            select_next_state: None,
 2022            select_prev_state: None,
 2023            selection_history: SelectionHistory::default(),
 2024            defer_selection_effects: false,
 2025            deferred_selection_effects_state: None,
 2026            autoclose_regions: Vec::new(),
 2027            snippet_stack: InvalidationStack::default(),
 2028            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2029            ime_transaction: None,
 2030            active_diagnostics: ActiveDiagnostic::None,
 2031            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2032            inline_diagnostics_update: Task::ready(()),
 2033            inline_diagnostics: Vec::new(),
 2034            soft_wrap_mode_override,
 2035            diagnostics_max_severity,
 2036            hard_wrap: None,
 2037            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2038            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2039            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2040            project,
 2041            blink_manager: blink_manager.clone(),
 2042            show_local_selections: true,
 2043            show_scrollbars: ScrollbarAxes {
 2044                horizontal: full_mode,
 2045                vertical: full_mode,
 2046            },
 2047            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2048            offset_content: !matches!(mode, EditorMode::SingleLine),
 2049            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2050            show_gutter: full_mode,
 2051            show_line_numbers: (!full_mode).then_some(false),
 2052            use_relative_line_numbers: None,
 2053            disable_expand_excerpt_buttons: !full_mode,
 2054            show_git_diff_gutter: None,
 2055            show_code_actions: None,
 2056            show_runnables: None,
 2057            show_breakpoints: None,
 2058            show_wrap_guides: None,
 2059            show_indent_guides,
 2060            placeholder_text: None,
 2061            highlight_order: 0,
 2062            highlighted_rows: HashMap::default(),
 2063            background_highlights: TreeMap::default(),
 2064            gutter_highlights: TreeMap::default(),
 2065            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2066            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2067            nav_history: None,
 2068            context_menu: RefCell::new(None),
 2069            context_menu_options: None,
 2070            mouse_context_menu: None,
 2071            completion_tasks: Vec::new(),
 2072            inline_blame_popover: None,
 2073            inline_blame_popover_show_task: None,
 2074            signature_help_state: SignatureHelpState::default(),
 2075            auto_signature_help: None,
 2076            find_all_references_task_sources: Vec::new(),
 2077            next_completion_id: 0,
 2078            next_inlay_id: 0,
 2079            code_action_providers,
 2080            available_code_actions: None,
 2081            code_actions_task: None,
 2082            quick_selection_highlight_task: None,
 2083            debounced_selection_highlight_task: None,
 2084            document_highlights_task: None,
 2085            linked_editing_range_task: None,
 2086            pending_rename: None,
 2087            searchable: !is_minimap,
 2088            cursor_shape: EditorSettings::get_global(cx)
 2089                .cursor_shape
 2090                .unwrap_or_default(),
 2091            current_line_highlight: None,
 2092            autoindent_mode: Some(AutoindentMode::EachLine),
 2093            collapse_matches: false,
 2094            workspace: None,
 2095            input_enabled: !is_minimap,
 2096            use_modal_editing: full_mode,
 2097            read_only: is_minimap,
 2098            use_autoclose: true,
 2099            use_auto_surround: true,
 2100            auto_replace_emoji_shortcode: false,
 2101            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2102            leader_id: None,
 2103            remote_id: None,
 2104            hover_state: HoverState::default(),
 2105            pending_mouse_down: None,
 2106            hovered_link_state: None,
 2107            edit_prediction_provider: None,
 2108            active_edit_prediction: None,
 2109            stale_edit_prediction_in_menu: None,
 2110            edit_prediction_preview: EditPredictionPreview::Inactive {
 2111                released_too_fast: false,
 2112            },
 2113            inline_diagnostics_enabled: full_mode,
 2114            diagnostics_enabled: full_mode,
 2115            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2116            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2117            gutter_hovered: false,
 2118            pixel_position_of_newest_cursor: None,
 2119            last_bounds: None,
 2120            last_position_map: None,
 2121            expect_bounds_change: None,
 2122            gutter_dimensions: GutterDimensions::default(),
 2123            style: None,
 2124            show_cursor_names: false,
 2125            hovered_cursors: HashMap::default(),
 2126            next_editor_action_id: EditorActionId::default(),
 2127            editor_actions: Rc::default(),
 2128            edit_predictions_hidden_for_vim_mode: false,
 2129            show_edit_predictions_override: None,
 2130            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2131            edit_prediction_settings: EditPredictionSettings::Disabled,
 2132            edit_prediction_indent_conflict: false,
 2133            edit_prediction_requires_modifier_in_indent_conflict: true,
 2134            custom_context_menu: None,
 2135            show_git_blame_gutter: false,
 2136            show_git_blame_inline: false,
 2137            show_selection_menu: None,
 2138            show_git_blame_inline_delay_task: None,
 2139            git_blame_inline_enabled: full_mode
 2140                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2141            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2142            serialize_dirty_buffers: !is_minimap
 2143                && ProjectSettings::get_global(cx)
 2144                    .session
 2145                    .restore_unsaved_buffers,
 2146            blame: None,
 2147            blame_subscription: None,
 2148            tasks: BTreeMap::default(),
 2149
 2150            breakpoint_store,
 2151            gutter_breakpoint_indicator: (None, None),
 2152            hovered_diff_hunk_row: None,
 2153            _subscriptions: (!is_minimap)
 2154                .then(|| {
 2155                    vec![
 2156                        cx.observe(&buffer, Self::on_buffer_changed),
 2157                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2158                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2159                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2160                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2161                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2162                        cx.observe_window_activation(window, |editor, window, cx| {
 2163                            let active = window.is_window_active();
 2164                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2165                                if active {
 2166                                    blink_manager.enable(cx);
 2167                                } else {
 2168                                    blink_manager.disable(cx);
 2169                                }
 2170                            });
 2171                            if active {
 2172                                editor.show_mouse_cursor(cx);
 2173                            }
 2174                        }),
 2175                    ]
 2176                })
 2177                .unwrap_or_default(),
 2178            tasks_update_task: None,
 2179            pull_diagnostics_task: Task::ready(()),
 2180            colors: None,
 2181            next_color_inlay_id: 0,
 2182            linked_edit_ranges: Default::default(),
 2183            in_project_search: false,
 2184            previous_search_ranges: None,
 2185            breadcrumb_header: None,
 2186            focused_block: None,
 2187            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2188            addons: HashMap::default(),
 2189            registered_buffers: HashMap::default(),
 2190            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2191            selection_mark_mode: false,
 2192            toggle_fold_multiple_buffers: Task::ready(()),
 2193            serialize_selections: Task::ready(()),
 2194            serialize_folds: Task::ready(()),
 2195            text_style_refinement: None,
 2196            load_diff_task: load_uncommitted_diff,
 2197            temporary_diff_override: false,
 2198            mouse_cursor_hidden: false,
 2199            minimap: None,
 2200            hide_mouse_mode: EditorSettings::get_global(cx)
 2201                .hide_mouse
 2202                .unwrap_or_default(),
 2203            change_list: ChangeList::new(),
 2204            mode,
 2205            selection_drag_state: SelectionDragState::None,
 2206            folding_newlines: Task::ready(()),
 2207        };
 2208
 2209        if is_minimap {
 2210            return editor;
 2211        }
 2212
 2213        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2214            editor
 2215                ._subscriptions
 2216                .push(cx.observe(breakpoints, |_, _, cx| {
 2217                    cx.notify();
 2218                }));
 2219        }
 2220        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2221        editor._subscriptions.extend(project_subscriptions);
 2222
 2223        editor._subscriptions.push(cx.subscribe_in(
 2224            &cx.entity(),
 2225            window,
 2226            |editor, _, e: &EditorEvent, window, cx| match e {
 2227                EditorEvent::ScrollPositionChanged { local, .. } => {
 2228                    if *local {
 2229                        let new_anchor = editor.scroll_manager.anchor();
 2230                        let snapshot = editor.snapshot(window, cx);
 2231                        editor.update_restoration_data(cx, move |data| {
 2232                            data.scroll_position = (
 2233                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2234                                new_anchor.offset,
 2235                            );
 2236                        });
 2237                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2238                        editor.inline_blame_popover.take();
 2239                    }
 2240                }
 2241                EditorEvent::Edited { .. } => {
 2242                    if !vim_enabled(cx) {
 2243                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2244                        let pop_state = editor
 2245                            .change_list
 2246                            .last()
 2247                            .map(|previous| {
 2248                                previous.len() == selections.len()
 2249                                    && previous.iter().enumerate().all(|(ix, p)| {
 2250                                        p.to_display_point(&map).row()
 2251                                            == selections[ix].head().row()
 2252                                    })
 2253                            })
 2254                            .unwrap_or(false);
 2255                        let new_positions = selections
 2256                            .into_iter()
 2257                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2258                            .collect();
 2259                        editor
 2260                            .change_list
 2261                            .push_to_change_list(pop_state, new_positions);
 2262                    }
 2263                }
 2264                _ => (),
 2265            },
 2266        ));
 2267
 2268        if let Some(dap_store) = editor
 2269            .project
 2270            .as_ref()
 2271            .map(|project| project.read(cx).dap_store())
 2272        {
 2273            let weak_editor = cx.weak_entity();
 2274
 2275            editor
 2276                ._subscriptions
 2277                .push(
 2278                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2279                        let session_entity = cx.entity();
 2280                        weak_editor
 2281                            .update(cx, |editor, cx| {
 2282                                editor._subscriptions.push(
 2283                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2284                                );
 2285                            })
 2286                            .ok();
 2287                    }),
 2288                );
 2289
 2290            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2291                editor
 2292                    ._subscriptions
 2293                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2294            }
 2295        }
 2296
 2297        // skip adding the initial selection to selection history
 2298        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2299        editor.end_selection(window, cx);
 2300        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2301
 2302        editor.scroll_manager.show_scrollbars(window, cx);
 2303        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2304
 2305        if full_mode {
 2306            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2307            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2308
 2309            if editor.git_blame_inline_enabled {
 2310                editor.start_git_blame_inline(false, window, cx);
 2311            }
 2312
 2313            editor.go_to_active_debug_line(window, cx);
 2314
 2315            if let Some(buffer) = buffer.read(cx).as_singleton()
 2316                && let Some(project) = editor.project()
 2317            {
 2318                let handle = project.update(cx, |project, cx| {
 2319                    project.register_buffer_with_language_servers(&buffer, cx)
 2320                });
 2321                editor
 2322                    .registered_buffers
 2323                    .insert(buffer.read(cx).remote_id(), handle);
 2324            }
 2325
 2326            editor.minimap =
 2327                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2328            editor.colors = Some(LspColorData::new(cx));
 2329            editor.update_lsp_data(false, None, window, cx);
 2330        }
 2331
 2332        if editor.mode.is_full() {
 2333            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2334        }
 2335
 2336        editor
 2337    }
 2338
 2339    pub fn deploy_mouse_context_menu(
 2340        &mut self,
 2341        position: gpui::Point<Pixels>,
 2342        context_menu: Entity<ContextMenu>,
 2343        window: &mut Window,
 2344        cx: &mut Context<Self>,
 2345    ) {
 2346        self.mouse_context_menu = Some(MouseContextMenu::new(
 2347            self,
 2348            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2349            context_menu,
 2350            window,
 2351            cx,
 2352        ));
 2353    }
 2354
 2355    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2356        self.mouse_context_menu
 2357            .as_ref()
 2358            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2359    }
 2360
 2361    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2362        if self
 2363            .selections
 2364            .pending
 2365            .as_ref()
 2366            .is_some_and(|pending_selection| {
 2367                let snapshot = self.buffer().read(cx).snapshot(cx);
 2368                pending_selection
 2369                    .selection
 2370                    .range()
 2371                    .includes(range, &snapshot)
 2372            })
 2373        {
 2374            return true;
 2375        }
 2376
 2377        self.selections
 2378            .disjoint_in_range::<usize>(range.clone(), cx)
 2379            .into_iter()
 2380            .any(|selection| {
 2381                // This is needed to cover a corner case, if we just check for an existing
 2382                // selection in the fold range, having a cursor at the start of the fold
 2383                // marks it as selected. Non-empty selections don't cause this.
 2384                let length = selection.end - selection.start;
 2385                length > 0
 2386            })
 2387    }
 2388
 2389    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2390        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2391    }
 2392
 2393    fn key_context_internal(
 2394        &self,
 2395        has_active_edit_prediction: bool,
 2396        window: &Window,
 2397        cx: &App,
 2398    ) -> KeyContext {
 2399        let mut key_context = KeyContext::new_with_defaults();
 2400        key_context.add("Editor");
 2401        let mode = match self.mode {
 2402            EditorMode::SingleLine => "single_line",
 2403            EditorMode::AutoHeight { .. } => "auto_height",
 2404            EditorMode::Minimap { .. } => "minimap",
 2405            EditorMode::Full { .. } => "full",
 2406        };
 2407
 2408        if EditorSettings::jupyter_enabled(cx) {
 2409            key_context.add("jupyter");
 2410        }
 2411
 2412        key_context.set("mode", mode);
 2413        if self.pending_rename.is_some() {
 2414            key_context.add("renaming");
 2415        }
 2416
 2417        match self.context_menu.borrow().as_ref() {
 2418            Some(CodeContextMenu::Completions(menu)) => {
 2419                if menu.visible() {
 2420                    key_context.add("menu");
 2421                    key_context.add("showing_completions");
 2422                }
 2423            }
 2424            Some(CodeContextMenu::CodeActions(menu)) => {
 2425                if menu.visible() {
 2426                    key_context.add("menu");
 2427                    key_context.add("showing_code_actions")
 2428                }
 2429            }
 2430            None => {}
 2431        }
 2432
 2433        if self.signature_help_state.has_multiple_signatures() {
 2434            key_context.add("showing_signature_help");
 2435        }
 2436
 2437        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2438        if !self.focus_handle(cx).contains_focused(window, cx)
 2439            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2440        {
 2441            for addon in self.addons.values() {
 2442                addon.extend_key_context(&mut key_context, cx)
 2443            }
 2444        }
 2445
 2446        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2447            if let Some(extension) = singleton_buffer
 2448                .read(cx)
 2449                .file()
 2450                .and_then(|file| file.path().extension()?.to_str())
 2451            {
 2452                key_context.set("extension", extension.to_string());
 2453            }
 2454        } else {
 2455            key_context.add("multibuffer");
 2456        }
 2457
 2458        if has_active_edit_prediction {
 2459            if self.edit_prediction_in_conflict() {
 2460                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2461            } else {
 2462                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2463                key_context.add("copilot_suggestion");
 2464            }
 2465        }
 2466
 2467        if self.selection_mark_mode {
 2468            key_context.add("selection_mode");
 2469        }
 2470
 2471        key_context
 2472    }
 2473
 2474    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2475        if self.mouse_cursor_hidden {
 2476            self.mouse_cursor_hidden = false;
 2477            cx.notify();
 2478        }
 2479    }
 2480
 2481    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2482        let hide_mouse_cursor = match origin {
 2483            HideMouseCursorOrigin::TypingAction => {
 2484                matches!(
 2485                    self.hide_mouse_mode,
 2486                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2487                )
 2488            }
 2489            HideMouseCursorOrigin::MovementAction => {
 2490                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2491            }
 2492        };
 2493        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2494            self.mouse_cursor_hidden = hide_mouse_cursor;
 2495            cx.notify();
 2496        }
 2497    }
 2498
 2499    pub fn edit_prediction_in_conflict(&self) -> bool {
 2500        if !self.show_edit_predictions_in_menu() {
 2501            return false;
 2502        }
 2503
 2504        let showing_completions = self
 2505            .context_menu
 2506            .borrow()
 2507            .as_ref()
 2508            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2509
 2510        showing_completions
 2511            || self.edit_prediction_requires_modifier()
 2512            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2513            // bindings to insert tab characters.
 2514            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2515    }
 2516
 2517    pub fn accept_edit_prediction_keybind(
 2518        &self,
 2519        accept_partial: bool,
 2520        window: &Window,
 2521        cx: &App,
 2522    ) -> AcceptEditPredictionBinding {
 2523        let key_context = self.key_context_internal(true, window, cx);
 2524        let in_conflict = self.edit_prediction_in_conflict();
 2525
 2526        let bindings = if accept_partial {
 2527            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2528        } else {
 2529            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2530        };
 2531
 2532        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2533        // just the first one.
 2534        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2535            !in_conflict
 2536                || binding
 2537                    .keystrokes()
 2538                    .first()
 2539                    .is_some_and(|keystroke| keystroke.modifiers.modified())
 2540        }))
 2541    }
 2542
 2543    pub fn new_file(
 2544        workspace: &mut Workspace,
 2545        _: &workspace::NewFile,
 2546        window: &mut Window,
 2547        cx: &mut Context<Workspace>,
 2548    ) {
 2549        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2550            "Failed to create buffer",
 2551            window,
 2552            cx,
 2553            |e, _, _| match e.error_code() {
 2554                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2555                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2556                e.error_tag("required").unwrap_or("the latest version")
 2557            )),
 2558                _ => None,
 2559            },
 2560        );
 2561    }
 2562
 2563    pub fn new_in_workspace(
 2564        workspace: &mut Workspace,
 2565        window: &mut Window,
 2566        cx: &mut Context<Workspace>,
 2567    ) -> Task<Result<Entity<Editor>>> {
 2568        let project = workspace.project().clone();
 2569        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2570
 2571        cx.spawn_in(window, async move |workspace, cx| {
 2572            let buffer = create.await?;
 2573            workspace.update_in(cx, |workspace, window, cx| {
 2574                let editor =
 2575                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2576                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2577                editor
 2578            })
 2579        })
 2580    }
 2581
 2582    fn new_file_vertical(
 2583        workspace: &mut Workspace,
 2584        _: &workspace::NewFileSplitVertical,
 2585        window: &mut Window,
 2586        cx: &mut Context<Workspace>,
 2587    ) {
 2588        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2589    }
 2590
 2591    fn new_file_horizontal(
 2592        workspace: &mut Workspace,
 2593        _: &workspace::NewFileSplitHorizontal,
 2594        window: &mut Window,
 2595        cx: &mut Context<Workspace>,
 2596    ) {
 2597        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2598    }
 2599
 2600    fn new_file_in_direction(
 2601        workspace: &mut Workspace,
 2602        direction: SplitDirection,
 2603        window: &mut Window,
 2604        cx: &mut Context<Workspace>,
 2605    ) {
 2606        let project = workspace.project().clone();
 2607        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2608
 2609        cx.spawn_in(window, async move |workspace, cx| {
 2610            let buffer = create.await?;
 2611            workspace.update_in(cx, move |workspace, window, cx| {
 2612                workspace.split_item(
 2613                    direction,
 2614                    Box::new(
 2615                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2616                    ),
 2617                    window,
 2618                    cx,
 2619                )
 2620            })?;
 2621            anyhow::Ok(())
 2622        })
 2623        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2624            match e.error_code() {
 2625                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2626                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2627                e.error_tag("required").unwrap_or("the latest version")
 2628            )),
 2629                _ => None,
 2630            }
 2631        });
 2632    }
 2633
 2634    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2635        self.leader_id
 2636    }
 2637
 2638    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2639        &self.buffer
 2640    }
 2641
 2642    pub fn project(&self) -> Option<&Entity<Project>> {
 2643        self.project.as_ref()
 2644    }
 2645
 2646    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2647        self.workspace.as_ref()?.0.upgrade()
 2648    }
 2649
 2650    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2651        self.buffer().read(cx).title(cx)
 2652    }
 2653
 2654    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2655        let git_blame_gutter_max_author_length = self
 2656            .render_git_blame_gutter(cx)
 2657            .then(|| {
 2658                if let Some(blame) = self.blame.as_ref() {
 2659                    let max_author_length =
 2660                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2661                    Some(max_author_length)
 2662                } else {
 2663                    None
 2664                }
 2665            })
 2666            .flatten();
 2667
 2668        EditorSnapshot {
 2669            mode: self.mode.clone(),
 2670            show_gutter: self.show_gutter,
 2671            show_line_numbers: self.show_line_numbers,
 2672            show_git_diff_gutter: self.show_git_diff_gutter,
 2673            show_code_actions: self.show_code_actions,
 2674            show_runnables: self.show_runnables,
 2675            show_breakpoints: self.show_breakpoints,
 2676            git_blame_gutter_max_author_length,
 2677            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2678            scroll_anchor: self.scroll_manager.anchor(),
 2679            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2680            placeholder_text: self.placeholder_text.clone(),
 2681            is_focused: self.focus_handle.is_focused(window),
 2682            current_line_highlight: self
 2683                .current_line_highlight
 2684                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2685            gutter_hovered: self.gutter_hovered,
 2686        }
 2687    }
 2688
 2689    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2690        self.buffer.read(cx).language_at(point, cx)
 2691    }
 2692
 2693    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2694        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2695    }
 2696
 2697    pub fn active_excerpt(
 2698        &self,
 2699        cx: &App,
 2700    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2701        self.buffer
 2702            .read(cx)
 2703            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2704    }
 2705
 2706    pub fn mode(&self) -> &EditorMode {
 2707        &self.mode
 2708    }
 2709
 2710    pub fn set_mode(&mut self, mode: EditorMode) {
 2711        self.mode = mode;
 2712    }
 2713
 2714    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2715        self.collaboration_hub.as_deref()
 2716    }
 2717
 2718    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2719        self.collaboration_hub = Some(hub);
 2720    }
 2721
 2722    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2723        self.in_project_search = in_project_search;
 2724    }
 2725
 2726    pub fn set_custom_context_menu(
 2727        &mut self,
 2728        f: impl 'static
 2729        + Fn(
 2730            &mut Self,
 2731            DisplayPoint,
 2732            &mut Window,
 2733            &mut Context<Self>,
 2734        ) -> Option<Entity<ui::ContextMenu>>,
 2735    ) {
 2736        self.custom_context_menu = Some(Box::new(f))
 2737    }
 2738
 2739    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2740        self.completion_provider = provider;
 2741    }
 2742
 2743    #[cfg(any(test, feature = "test-support"))]
 2744    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2745        self.completion_provider.clone()
 2746    }
 2747
 2748    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2749        self.semantics_provider.clone()
 2750    }
 2751
 2752    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2753        self.semantics_provider = provider;
 2754    }
 2755
 2756    pub fn set_edit_prediction_provider<T>(
 2757        &mut self,
 2758        provider: Option<Entity<T>>,
 2759        window: &mut Window,
 2760        cx: &mut Context<Self>,
 2761    ) where
 2762        T: EditPredictionProvider,
 2763    {
 2764        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2765            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2766                if this.focus_handle.is_focused(window) {
 2767                    this.update_visible_edit_prediction(window, cx);
 2768                }
 2769            }),
 2770            provider: Arc::new(provider),
 2771        });
 2772        self.update_edit_prediction_settings(cx);
 2773        self.refresh_edit_prediction(false, false, window, cx);
 2774    }
 2775
 2776    pub fn placeholder_text(&self) -> Option<&str> {
 2777        self.placeholder_text.as_deref()
 2778    }
 2779
 2780    pub fn set_placeholder_text(
 2781        &mut self,
 2782        placeholder_text: impl Into<Arc<str>>,
 2783        cx: &mut Context<Self>,
 2784    ) {
 2785        let placeholder_text = Some(placeholder_text.into());
 2786        if self.placeholder_text != placeholder_text {
 2787            self.placeholder_text = placeholder_text;
 2788            cx.notify();
 2789        }
 2790    }
 2791
 2792    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2793        self.cursor_shape = cursor_shape;
 2794
 2795        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2796        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2797
 2798        cx.notify();
 2799    }
 2800
 2801    pub fn set_current_line_highlight(
 2802        &mut self,
 2803        current_line_highlight: Option<CurrentLineHighlight>,
 2804    ) {
 2805        self.current_line_highlight = current_line_highlight;
 2806    }
 2807
 2808    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2809        self.collapse_matches = collapse_matches;
 2810    }
 2811
 2812    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2813        let buffers = self.buffer.read(cx).all_buffers();
 2814        let Some(project) = self.project.as_ref() else {
 2815            return;
 2816        };
 2817        project.update(cx, |project, cx| {
 2818            for buffer in buffers {
 2819                self.registered_buffers
 2820                    .entry(buffer.read(cx).remote_id())
 2821                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2822            }
 2823        })
 2824    }
 2825
 2826    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2827        if self.collapse_matches {
 2828            return range.start..range.start;
 2829        }
 2830        range.clone()
 2831    }
 2832
 2833    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2834        if self.display_map.read(cx).clip_at_line_ends != clip {
 2835            self.display_map
 2836                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2837        }
 2838    }
 2839
 2840    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2841        self.input_enabled = input_enabled;
 2842    }
 2843
 2844    pub fn set_edit_predictions_hidden_for_vim_mode(
 2845        &mut self,
 2846        hidden: bool,
 2847        window: &mut Window,
 2848        cx: &mut Context<Self>,
 2849    ) {
 2850        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2851            self.edit_predictions_hidden_for_vim_mode = hidden;
 2852            if hidden {
 2853                self.update_visible_edit_prediction(window, cx);
 2854            } else {
 2855                self.refresh_edit_prediction(true, false, window, cx);
 2856            }
 2857        }
 2858    }
 2859
 2860    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2861        self.menu_edit_predictions_policy = value;
 2862    }
 2863
 2864    pub fn set_autoindent(&mut self, autoindent: bool) {
 2865        if autoindent {
 2866            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2867        } else {
 2868            self.autoindent_mode = None;
 2869        }
 2870    }
 2871
 2872    pub fn read_only(&self, cx: &App) -> bool {
 2873        self.read_only || self.buffer.read(cx).read_only()
 2874    }
 2875
 2876    pub fn set_read_only(&mut self, read_only: bool) {
 2877        self.read_only = read_only;
 2878    }
 2879
 2880    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2881        self.use_autoclose = autoclose;
 2882    }
 2883
 2884    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2885        self.use_auto_surround = auto_surround;
 2886    }
 2887
 2888    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2889        self.auto_replace_emoji_shortcode = auto_replace;
 2890    }
 2891
 2892    pub fn toggle_edit_predictions(
 2893        &mut self,
 2894        _: &ToggleEditPrediction,
 2895        window: &mut Window,
 2896        cx: &mut Context<Self>,
 2897    ) {
 2898        if self.show_edit_predictions_override.is_some() {
 2899            self.set_show_edit_predictions(None, window, cx);
 2900        } else {
 2901            let show_edit_predictions = !self.edit_predictions_enabled();
 2902            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2903        }
 2904    }
 2905
 2906    pub fn set_show_edit_predictions(
 2907        &mut self,
 2908        show_edit_predictions: Option<bool>,
 2909        window: &mut Window,
 2910        cx: &mut Context<Self>,
 2911    ) {
 2912        self.show_edit_predictions_override = show_edit_predictions;
 2913        self.update_edit_prediction_settings(cx);
 2914
 2915        if let Some(false) = show_edit_predictions {
 2916            self.discard_edit_prediction(false, cx);
 2917        } else {
 2918            self.refresh_edit_prediction(false, true, window, cx);
 2919        }
 2920    }
 2921
 2922    fn edit_predictions_disabled_in_scope(
 2923        &self,
 2924        buffer: &Entity<Buffer>,
 2925        buffer_position: language::Anchor,
 2926        cx: &App,
 2927    ) -> bool {
 2928        let snapshot = buffer.read(cx).snapshot();
 2929        let settings = snapshot.settings_at(buffer_position, cx);
 2930
 2931        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2932            return false;
 2933        };
 2934
 2935        scope.override_name().is_some_and(|scope_name| {
 2936            settings
 2937                .edit_predictions_disabled_in
 2938                .iter()
 2939                .any(|s| s == scope_name)
 2940        })
 2941    }
 2942
 2943    pub fn set_use_modal_editing(&mut self, to: bool) {
 2944        self.use_modal_editing = to;
 2945    }
 2946
 2947    pub fn use_modal_editing(&self) -> bool {
 2948        self.use_modal_editing
 2949    }
 2950
 2951    fn selections_did_change(
 2952        &mut self,
 2953        local: bool,
 2954        old_cursor_position: &Anchor,
 2955        effects: SelectionEffects,
 2956        window: &mut Window,
 2957        cx: &mut Context<Self>,
 2958    ) {
 2959        window.invalidate_character_coordinates();
 2960
 2961        // Copy selections to primary selection buffer
 2962        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2963        if local {
 2964            let selections = self.selections.all::<usize>(cx);
 2965            let buffer_handle = self.buffer.read(cx).read(cx);
 2966
 2967            let mut text = String::new();
 2968            for (index, selection) in selections.iter().enumerate() {
 2969                let text_for_selection = buffer_handle
 2970                    .text_for_range(selection.start..selection.end)
 2971                    .collect::<String>();
 2972
 2973                text.push_str(&text_for_selection);
 2974                if index != selections.len() - 1 {
 2975                    text.push('\n');
 2976                }
 2977            }
 2978
 2979            if !text.is_empty() {
 2980                cx.write_to_primary(ClipboardItem::new_string(text));
 2981            }
 2982        }
 2983
 2984        let selection_anchors = self.selections.disjoint_anchors();
 2985
 2986        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2987            self.buffer.update(cx, |buffer, cx| {
 2988                buffer.set_active_selections(
 2989                    &selection_anchors,
 2990                    self.selections.line_mode,
 2991                    self.cursor_shape,
 2992                    cx,
 2993                )
 2994            });
 2995        }
 2996        let display_map = self
 2997            .display_map
 2998            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2999        let buffer = &display_map.buffer_snapshot;
 3000        if self.selections.count() == 1 {
 3001            self.add_selections_state = None;
 3002        }
 3003        self.select_next_state = None;
 3004        self.select_prev_state = None;
 3005        self.select_syntax_node_history.try_clear();
 3006        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3007        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3008        self.take_rename(false, window, cx);
 3009
 3010        let newest_selection = self.selections.newest_anchor();
 3011        let new_cursor_position = newest_selection.head();
 3012        let selection_start = newest_selection.start;
 3013
 3014        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3015            self.push_to_nav_history(
 3016                *old_cursor_position,
 3017                Some(new_cursor_position.to_point(buffer)),
 3018                false,
 3019                effects.nav_history == Some(true),
 3020                cx,
 3021            );
 3022        }
 3023
 3024        if local {
 3025            if let Some(buffer_id) = new_cursor_position.buffer_id
 3026                && !self.registered_buffers.contains_key(&buffer_id)
 3027                && let Some(project) = self.project.as_ref()
 3028            {
 3029                project.update(cx, |project, cx| {
 3030                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3031                        return;
 3032                    };
 3033                    self.registered_buffers.insert(
 3034                        buffer_id,
 3035                        project.register_buffer_with_language_servers(&buffer, cx),
 3036                    );
 3037                })
 3038            }
 3039
 3040            let mut context_menu = self.context_menu.borrow_mut();
 3041            let completion_menu = match context_menu.as_ref() {
 3042                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3043                Some(CodeContextMenu::CodeActions(_)) => {
 3044                    *context_menu = None;
 3045                    None
 3046                }
 3047                None => None,
 3048            };
 3049            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3050            drop(context_menu);
 3051
 3052            if effects.completions
 3053                && let Some(completion_position) = completion_position
 3054            {
 3055                let start_offset = selection_start.to_offset(buffer);
 3056                let position_matches = start_offset == completion_position.to_offset(buffer);
 3057                let continue_showing = if position_matches {
 3058                    if self.snippet_stack.is_empty() {
 3059                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3060                    } else {
 3061                        // Snippet choices can be shown even when the cursor is in whitespace.
 3062                        // Dismissing the menu with actions like backspace is handled by
 3063                        // invalidation regions.
 3064                        true
 3065                    }
 3066                } else {
 3067                    false
 3068                };
 3069
 3070                if continue_showing {
 3071                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3072                } else {
 3073                    self.hide_context_menu(window, cx);
 3074                }
 3075            }
 3076
 3077            hide_hover(self, cx);
 3078
 3079            if old_cursor_position.to_display_point(&display_map).row()
 3080                != new_cursor_position.to_display_point(&display_map).row()
 3081            {
 3082                self.available_code_actions.take();
 3083            }
 3084            self.refresh_code_actions(window, cx);
 3085            self.refresh_document_highlights(cx);
 3086            self.refresh_selected_text_highlights(false, window, cx);
 3087            refresh_matching_bracket_highlights(self, window, cx);
 3088            self.update_visible_edit_prediction(window, cx);
 3089            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3090            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3091            self.inline_blame_popover.take();
 3092            if self.git_blame_inline_enabled {
 3093                self.start_inline_blame_timer(window, cx);
 3094            }
 3095        }
 3096
 3097        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3098        cx.emit(EditorEvent::SelectionsChanged { local });
 3099
 3100        let selections = &self.selections.disjoint;
 3101        if selections.len() == 1 {
 3102            cx.emit(SearchEvent::ActiveMatchChanged)
 3103        }
 3104        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3105            let inmemory_selections = selections
 3106                .iter()
 3107                .map(|s| {
 3108                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3109                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3110                })
 3111                .collect();
 3112            self.update_restoration_data(cx, |data| {
 3113                data.selections = inmemory_selections;
 3114            });
 3115
 3116            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3117                && let Some(workspace_id) =
 3118                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3119            {
 3120                let snapshot = self.buffer().read(cx).snapshot(cx);
 3121                let selections = selections.clone();
 3122                let background_executor = cx.background_executor().clone();
 3123                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3124                self.serialize_selections = cx.background_spawn(async move {
 3125                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3126                            let db_selections = selections
 3127                                .iter()
 3128                                .map(|selection| {
 3129                                    (
 3130                                        selection.start.to_offset(&snapshot),
 3131                                        selection.end.to_offset(&snapshot),
 3132                                    )
 3133                                })
 3134                                .collect();
 3135
 3136                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3137                                .await
 3138                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3139                                .log_err();
 3140                        });
 3141            }
 3142        }
 3143
 3144        cx.notify();
 3145    }
 3146
 3147    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3148        use text::ToOffset as _;
 3149        use text::ToPoint as _;
 3150
 3151        if self.mode.is_minimap()
 3152            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3153        {
 3154            return;
 3155        }
 3156
 3157        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3158            return;
 3159        };
 3160
 3161        let snapshot = singleton.read(cx).snapshot();
 3162        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3163            let display_snapshot = display_map.snapshot(cx);
 3164
 3165            display_snapshot
 3166                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3167                .map(|fold| {
 3168                    fold.range.start.text_anchor.to_point(&snapshot)
 3169                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3170                })
 3171                .collect()
 3172        });
 3173        self.update_restoration_data(cx, |data| {
 3174            data.folds = inmemory_folds;
 3175        });
 3176
 3177        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3178            return;
 3179        };
 3180        let background_executor = cx.background_executor().clone();
 3181        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3182        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3183            display_map
 3184                .snapshot(cx)
 3185                .folds_in_range(0..snapshot.len())
 3186                .map(|fold| {
 3187                    (
 3188                        fold.range.start.text_anchor.to_offset(&snapshot),
 3189                        fold.range.end.text_anchor.to_offset(&snapshot),
 3190                    )
 3191                })
 3192                .collect()
 3193        });
 3194        self.serialize_folds = cx.background_spawn(async move {
 3195            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3196            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3197                .await
 3198                .with_context(|| {
 3199                    format!(
 3200                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3201                    )
 3202                })
 3203                .log_err();
 3204        });
 3205    }
 3206
 3207    pub fn sync_selections(
 3208        &mut self,
 3209        other: Entity<Editor>,
 3210        cx: &mut Context<Self>,
 3211    ) -> gpui::Subscription {
 3212        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3213        self.selections.change_with(cx, |selections| {
 3214            selections.select_anchors(other_selections);
 3215        });
 3216
 3217        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3218            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3219                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3220                if other_selections.is_empty() {
 3221                    return;
 3222                }
 3223                this.selections.change_with(cx, |selections| {
 3224                    selections.select_anchors(other_selections);
 3225                });
 3226            }
 3227        });
 3228
 3229        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3230            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3231                let these_selections = this.selections.disjoint.to_vec();
 3232                if these_selections.is_empty() {
 3233                    return;
 3234                }
 3235                other.update(cx, |other_editor, cx| {
 3236                    other_editor.selections.change_with(cx, |selections| {
 3237                        selections.select_anchors(these_selections);
 3238                    })
 3239                });
 3240            }
 3241        });
 3242
 3243        Subscription::join(other_subscription, this_subscription)
 3244    }
 3245
 3246    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3247    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3248    /// effects of selection change occur at the end of the transaction.
 3249    pub fn change_selections<R>(
 3250        &mut self,
 3251        effects: SelectionEffects,
 3252        window: &mut Window,
 3253        cx: &mut Context<Self>,
 3254        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3255    ) -> R {
 3256        if let Some(state) = &mut self.deferred_selection_effects_state {
 3257            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3258            state.effects.completions = effects.completions;
 3259            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3260            let (changed, result) = self.selections.change_with(cx, change);
 3261            state.changed |= changed;
 3262            return result;
 3263        }
 3264        let mut state = DeferredSelectionEffectsState {
 3265            changed: false,
 3266            effects,
 3267            old_cursor_position: self.selections.newest_anchor().head(),
 3268            history_entry: SelectionHistoryEntry {
 3269                selections: self.selections.disjoint_anchors(),
 3270                select_next_state: self.select_next_state.clone(),
 3271                select_prev_state: self.select_prev_state.clone(),
 3272                add_selections_state: self.add_selections_state.clone(),
 3273            },
 3274        };
 3275        let (changed, result) = self.selections.change_with(cx, change);
 3276        state.changed = state.changed || changed;
 3277        if self.defer_selection_effects {
 3278            self.deferred_selection_effects_state = Some(state);
 3279        } else {
 3280            self.apply_selection_effects(state, window, cx);
 3281        }
 3282        result
 3283    }
 3284
 3285    /// Defers the effects of selection change, so that the effects of multiple calls to
 3286    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3287    /// to selection history and the state of popovers based on selection position aren't
 3288    /// erroneously updated.
 3289    pub fn with_selection_effects_deferred<R>(
 3290        &mut self,
 3291        window: &mut Window,
 3292        cx: &mut Context<Self>,
 3293        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3294    ) -> R {
 3295        let already_deferred = self.defer_selection_effects;
 3296        self.defer_selection_effects = true;
 3297        let result = update(self, window, cx);
 3298        if !already_deferred {
 3299            self.defer_selection_effects = false;
 3300            if let Some(state) = self.deferred_selection_effects_state.take() {
 3301                self.apply_selection_effects(state, window, cx);
 3302            }
 3303        }
 3304        result
 3305    }
 3306
 3307    fn apply_selection_effects(
 3308        &mut self,
 3309        state: DeferredSelectionEffectsState,
 3310        window: &mut Window,
 3311        cx: &mut Context<Self>,
 3312    ) {
 3313        if state.changed {
 3314            self.selection_history.push(state.history_entry);
 3315
 3316            if let Some(autoscroll) = state.effects.scroll {
 3317                self.request_autoscroll(autoscroll, cx);
 3318            }
 3319
 3320            let old_cursor_position = &state.old_cursor_position;
 3321
 3322            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3323
 3324            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3325                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3326            }
 3327        }
 3328    }
 3329
 3330    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3331    where
 3332        I: IntoIterator<Item = (Range<S>, T)>,
 3333        S: ToOffset,
 3334        T: Into<Arc<str>>,
 3335    {
 3336        if self.read_only(cx) {
 3337            return;
 3338        }
 3339
 3340        self.buffer
 3341            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3342    }
 3343
 3344    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3345    where
 3346        I: IntoIterator<Item = (Range<S>, T)>,
 3347        S: ToOffset,
 3348        T: Into<Arc<str>>,
 3349    {
 3350        if self.read_only(cx) {
 3351            return;
 3352        }
 3353
 3354        self.buffer.update(cx, |buffer, cx| {
 3355            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3356        });
 3357    }
 3358
 3359    pub fn edit_with_block_indent<I, S, T>(
 3360        &mut self,
 3361        edits: I,
 3362        original_indent_columns: Vec<Option<u32>>,
 3363        cx: &mut Context<Self>,
 3364    ) where
 3365        I: IntoIterator<Item = (Range<S>, T)>,
 3366        S: ToOffset,
 3367        T: Into<Arc<str>>,
 3368    {
 3369        if self.read_only(cx) {
 3370            return;
 3371        }
 3372
 3373        self.buffer.update(cx, |buffer, cx| {
 3374            buffer.edit(
 3375                edits,
 3376                Some(AutoindentMode::Block {
 3377                    original_indent_columns,
 3378                }),
 3379                cx,
 3380            )
 3381        });
 3382    }
 3383
 3384    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3385        self.hide_context_menu(window, cx);
 3386
 3387        match phase {
 3388            SelectPhase::Begin {
 3389                position,
 3390                add,
 3391                click_count,
 3392            } => self.begin_selection(position, add, click_count, window, cx),
 3393            SelectPhase::BeginColumnar {
 3394                position,
 3395                goal_column,
 3396                reset,
 3397                mode,
 3398            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3399            SelectPhase::Extend {
 3400                position,
 3401                click_count,
 3402            } => self.extend_selection(position, click_count, window, cx),
 3403            SelectPhase::Update {
 3404                position,
 3405                goal_column,
 3406                scroll_delta,
 3407            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3408            SelectPhase::End => self.end_selection(window, cx),
 3409        }
 3410    }
 3411
 3412    fn extend_selection(
 3413        &mut self,
 3414        position: DisplayPoint,
 3415        click_count: usize,
 3416        window: &mut Window,
 3417        cx: &mut Context<Self>,
 3418    ) {
 3419        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3420        let tail = self.selections.newest::<usize>(cx).tail();
 3421        self.begin_selection(position, false, click_count, window, cx);
 3422
 3423        let position = position.to_offset(&display_map, Bias::Left);
 3424        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3425
 3426        let mut pending_selection = self
 3427            .selections
 3428            .pending_anchor()
 3429            .expect("extend_selection not called with pending selection");
 3430        if position >= tail {
 3431            pending_selection.start = tail_anchor;
 3432        } else {
 3433            pending_selection.end = tail_anchor;
 3434            pending_selection.reversed = true;
 3435        }
 3436
 3437        let mut pending_mode = self.selections.pending_mode().unwrap();
 3438        match &mut pending_mode {
 3439            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3440            _ => {}
 3441        }
 3442
 3443        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3444            SelectionEffects::scroll(Autoscroll::fit())
 3445        } else {
 3446            SelectionEffects::no_scroll()
 3447        };
 3448
 3449        self.change_selections(effects, window, cx, |s| {
 3450            s.set_pending(pending_selection, pending_mode)
 3451        });
 3452    }
 3453
 3454    fn begin_selection(
 3455        &mut self,
 3456        position: DisplayPoint,
 3457        add: bool,
 3458        click_count: usize,
 3459        window: &mut Window,
 3460        cx: &mut Context<Self>,
 3461    ) {
 3462        if !self.focus_handle.is_focused(window) {
 3463            self.last_focused_descendant = None;
 3464            window.focus(&self.focus_handle);
 3465        }
 3466
 3467        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3468        let buffer = &display_map.buffer_snapshot;
 3469        let position = display_map.clip_point(position, Bias::Left);
 3470
 3471        let start;
 3472        let end;
 3473        let mode;
 3474        let mut auto_scroll;
 3475        match click_count {
 3476            1 => {
 3477                start = buffer.anchor_before(position.to_point(&display_map));
 3478                end = start;
 3479                mode = SelectMode::Character;
 3480                auto_scroll = true;
 3481            }
 3482            2 => {
 3483                let position = display_map
 3484                    .clip_point(position, Bias::Left)
 3485                    .to_offset(&display_map, Bias::Left);
 3486                let (range, _) = buffer.surrounding_word(position, false);
 3487                start = buffer.anchor_before(range.start);
 3488                end = buffer.anchor_before(range.end);
 3489                mode = SelectMode::Word(start..end);
 3490                auto_scroll = true;
 3491            }
 3492            3 => {
 3493                let position = display_map
 3494                    .clip_point(position, Bias::Left)
 3495                    .to_point(&display_map);
 3496                let line_start = display_map.prev_line_boundary(position).0;
 3497                let next_line_start = buffer.clip_point(
 3498                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3499                    Bias::Left,
 3500                );
 3501                start = buffer.anchor_before(line_start);
 3502                end = buffer.anchor_before(next_line_start);
 3503                mode = SelectMode::Line(start..end);
 3504                auto_scroll = true;
 3505            }
 3506            _ => {
 3507                start = buffer.anchor_before(0);
 3508                end = buffer.anchor_before(buffer.len());
 3509                mode = SelectMode::All;
 3510                auto_scroll = false;
 3511            }
 3512        }
 3513        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3514
 3515        let point_to_delete: Option<usize> = {
 3516            let selected_points: Vec<Selection<Point>> =
 3517                self.selections.disjoint_in_range(start..end, cx);
 3518
 3519            if !add || click_count > 1 {
 3520                None
 3521            } else if !selected_points.is_empty() {
 3522                Some(selected_points[0].id)
 3523            } else {
 3524                let clicked_point_already_selected =
 3525                    self.selections.disjoint.iter().find(|selection| {
 3526                        selection.start.to_point(buffer) == start.to_point(buffer)
 3527                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3528                    });
 3529
 3530                clicked_point_already_selected.map(|selection| selection.id)
 3531            }
 3532        };
 3533
 3534        let selections_count = self.selections.count();
 3535        let effects = if auto_scroll {
 3536            SelectionEffects::default()
 3537        } else {
 3538            SelectionEffects::no_scroll()
 3539        };
 3540
 3541        self.change_selections(effects, window, cx, |s| {
 3542            if let Some(point_to_delete) = point_to_delete {
 3543                s.delete(point_to_delete);
 3544
 3545                if selections_count == 1 {
 3546                    s.set_pending_anchor_range(start..end, mode);
 3547                }
 3548            } else {
 3549                if !add {
 3550                    s.clear_disjoint();
 3551                }
 3552
 3553                s.set_pending_anchor_range(start..end, mode);
 3554            }
 3555        });
 3556    }
 3557
 3558    fn begin_columnar_selection(
 3559        &mut self,
 3560        position: DisplayPoint,
 3561        goal_column: u32,
 3562        reset: bool,
 3563        mode: ColumnarMode,
 3564        window: &mut Window,
 3565        cx: &mut Context<Self>,
 3566    ) {
 3567        if !self.focus_handle.is_focused(window) {
 3568            self.last_focused_descendant = None;
 3569            window.focus(&self.focus_handle);
 3570        }
 3571
 3572        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3573
 3574        if reset {
 3575            let pointer_position = display_map
 3576                .buffer_snapshot
 3577                .anchor_before(position.to_point(&display_map));
 3578
 3579            self.change_selections(
 3580                SelectionEffects::scroll(Autoscroll::newest()),
 3581                window,
 3582                cx,
 3583                |s| {
 3584                    s.clear_disjoint();
 3585                    s.set_pending_anchor_range(
 3586                        pointer_position..pointer_position,
 3587                        SelectMode::Character,
 3588                    );
 3589                },
 3590            );
 3591        };
 3592
 3593        let tail = self.selections.newest::<Point>(cx).tail();
 3594        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3595        self.columnar_selection_state = match mode {
 3596            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3597                selection_tail: selection_anchor,
 3598                display_point: if reset {
 3599                    if position.column() != goal_column {
 3600                        Some(DisplayPoint::new(position.row(), goal_column))
 3601                    } else {
 3602                        None
 3603                    }
 3604                } else {
 3605                    None
 3606                },
 3607            }),
 3608            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3609                selection_tail: selection_anchor,
 3610            }),
 3611        };
 3612
 3613        if !reset {
 3614            self.select_columns(position, goal_column, &display_map, window, cx);
 3615        }
 3616    }
 3617
 3618    fn update_selection(
 3619        &mut self,
 3620        position: DisplayPoint,
 3621        goal_column: u32,
 3622        scroll_delta: gpui::Point<f32>,
 3623        window: &mut Window,
 3624        cx: &mut Context<Self>,
 3625    ) {
 3626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3627
 3628        if self.columnar_selection_state.is_some() {
 3629            self.select_columns(position, goal_column, &display_map, window, cx);
 3630        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3631            let buffer = &display_map.buffer_snapshot;
 3632            let head;
 3633            let tail;
 3634            let mode = self.selections.pending_mode().unwrap();
 3635            match &mode {
 3636                SelectMode::Character => {
 3637                    head = position.to_point(&display_map);
 3638                    tail = pending.tail().to_point(buffer);
 3639                }
 3640                SelectMode::Word(original_range) => {
 3641                    let offset = display_map
 3642                        .clip_point(position, Bias::Left)
 3643                        .to_offset(&display_map, Bias::Left);
 3644                    let original_range = original_range.to_offset(buffer);
 3645
 3646                    let head_offset = if buffer.is_inside_word(offset, false)
 3647                        || original_range.contains(&offset)
 3648                    {
 3649                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3650                        if word_range.start < original_range.start {
 3651                            word_range.start
 3652                        } else {
 3653                            word_range.end
 3654                        }
 3655                    } else {
 3656                        offset
 3657                    };
 3658
 3659                    head = head_offset.to_point(buffer);
 3660                    if head_offset <= original_range.start {
 3661                        tail = original_range.end.to_point(buffer);
 3662                    } else {
 3663                        tail = original_range.start.to_point(buffer);
 3664                    }
 3665                }
 3666                SelectMode::Line(original_range) => {
 3667                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3668
 3669                    let position = display_map
 3670                        .clip_point(position, Bias::Left)
 3671                        .to_point(&display_map);
 3672                    let line_start = display_map.prev_line_boundary(position).0;
 3673                    let next_line_start = buffer.clip_point(
 3674                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3675                        Bias::Left,
 3676                    );
 3677
 3678                    if line_start < original_range.start {
 3679                        head = line_start
 3680                    } else {
 3681                        head = next_line_start
 3682                    }
 3683
 3684                    if head <= original_range.start {
 3685                        tail = original_range.end;
 3686                    } else {
 3687                        tail = original_range.start;
 3688                    }
 3689                }
 3690                SelectMode::All => {
 3691                    return;
 3692                }
 3693            };
 3694
 3695            if head < tail {
 3696                pending.start = buffer.anchor_before(head);
 3697                pending.end = buffer.anchor_before(tail);
 3698                pending.reversed = true;
 3699            } else {
 3700                pending.start = buffer.anchor_before(tail);
 3701                pending.end = buffer.anchor_before(head);
 3702                pending.reversed = false;
 3703            }
 3704
 3705            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3706                s.set_pending(pending, mode);
 3707            });
 3708        } else {
 3709            log::error!("update_selection dispatched with no pending selection");
 3710            return;
 3711        }
 3712
 3713        self.apply_scroll_delta(scroll_delta, window, cx);
 3714        cx.notify();
 3715    }
 3716
 3717    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3718        self.columnar_selection_state.take();
 3719        if self.selections.pending_anchor().is_some() {
 3720            let selections = self.selections.all::<usize>(cx);
 3721            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3722                s.select(selections);
 3723                s.clear_pending();
 3724            });
 3725        }
 3726    }
 3727
 3728    fn select_columns(
 3729        &mut self,
 3730        head: DisplayPoint,
 3731        goal_column: u32,
 3732        display_map: &DisplaySnapshot,
 3733        window: &mut Window,
 3734        cx: &mut Context<Self>,
 3735    ) {
 3736        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3737            return;
 3738        };
 3739
 3740        let tail = match columnar_state {
 3741            ColumnarSelectionState::FromMouse {
 3742                selection_tail,
 3743                display_point,
 3744            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3745            ColumnarSelectionState::FromSelection { selection_tail } => {
 3746                selection_tail.to_display_point(display_map)
 3747            }
 3748        };
 3749
 3750        let start_row = cmp::min(tail.row(), head.row());
 3751        let end_row = cmp::max(tail.row(), head.row());
 3752        let start_column = cmp::min(tail.column(), goal_column);
 3753        let end_column = cmp::max(tail.column(), goal_column);
 3754        let reversed = start_column < tail.column();
 3755
 3756        let selection_ranges = (start_row.0..=end_row.0)
 3757            .map(DisplayRow)
 3758            .filter_map(|row| {
 3759                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3760                    || start_column <= display_map.line_len(row))
 3761                    && !display_map.is_block_line(row)
 3762                {
 3763                    let start = display_map
 3764                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3765                        .to_point(display_map);
 3766                    let end = display_map
 3767                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3768                        .to_point(display_map);
 3769                    if reversed {
 3770                        Some(end..start)
 3771                    } else {
 3772                        Some(start..end)
 3773                    }
 3774                } else {
 3775                    None
 3776                }
 3777            })
 3778            .collect::<Vec<_>>();
 3779
 3780        let ranges = match columnar_state {
 3781            ColumnarSelectionState::FromMouse { .. } => {
 3782                let mut non_empty_ranges = selection_ranges
 3783                    .iter()
 3784                    .filter(|selection_range| selection_range.start != selection_range.end)
 3785                    .peekable();
 3786                if non_empty_ranges.peek().is_some() {
 3787                    non_empty_ranges.cloned().collect()
 3788                } else {
 3789                    selection_ranges
 3790                }
 3791            }
 3792            _ => selection_ranges,
 3793        };
 3794
 3795        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3796            s.select_ranges(ranges);
 3797        });
 3798        cx.notify();
 3799    }
 3800
 3801    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3802        self.selections
 3803            .all_adjusted(cx)
 3804            .iter()
 3805            .any(|selection| !selection.is_empty())
 3806    }
 3807
 3808    pub fn has_pending_nonempty_selection(&self) -> bool {
 3809        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3810            Some(Selection { start, end, .. }) => start != end,
 3811            None => false,
 3812        };
 3813
 3814        pending_nonempty_selection
 3815            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3816    }
 3817
 3818    pub fn has_pending_selection(&self) -> bool {
 3819        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3820    }
 3821
 3822    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3823        self.selection_mark_mode = false;
 3824        self.selection_drag_state = SelectionDragState::None;
 3825
 3826        if self.clear_expanded_diff_hunks(cx) {
 3827            cx.notify();
 3828            return;
 3829        }
 3830        if self.dismiss_menus_and_popups(true, window, cx) {
 3831            return;
 3832        }
 3833
 3834        if self.mode.is_full()
 3835            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3836        {
 3837            return;
 3838        }
 3839
 3840        cx.propagate();
 3841    }
 3842
 3843    pub fn dismiss_menus_and_popups(
 3844        &mut self,
 3845        is_user_requested: bool,
 3846        window: &mut Window,
 3847        cx: &mut Context<Self>,
 3848    ) -> bool {
 3849        if self.take_rename(false, window, cx).is_some() {
 3850            return true;
 3851        }
 3852
 3853        if hide_hover(self, cx) {
 3854            return true;
 3855        }
 3856
 3857        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3858            return true;
 3859        }
 3860
 3861        if self.hide_context_menu(window, cx).is_some() {
 3862            return true;
 3863        }
 3864
 3865        if self.mouse_context_menu.take().is_some() {
 3866            return true;
 3867        }
 3868
 3869        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3870            return true;
 3871        }
 3872
 3873        if self.snippet_stack.pop().is_some() {
 3874            return true;
 3875        }
 3876
 3877        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3878            self.dismiss_diagnostics(cx);
 3879            return true;
 3880        }
 3881
 3882        false
 3883    }
 3884
 3885    fn linked_editing_ranges_for(
 3886        &self,
 3887        selection: Range<text::Anchor>,
 3888        cx: &App,
 3889    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3890        if self.linked_edit_ranges.is_empty() {
 3891            return None;
 3892        }
 3893        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3894            selection.end.buffer_id.and_then(|end_buffer_id| {
 3895                if selection.start.buffer_id != Some(end_buffer_id) {
 3896                    return None;
 3897                }
 3898                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3899                let snapshot = buffer.read(cx).snapshot();
 3900                self.linked_edit_ranges
 3901                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3902                    .map(|ranges| (ranges, snapshot, buffer))
 3903            })?;
 3904        use text::ToOffset as TO;
 3905        // find offset from the start of current range to current cursor position
 3906        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3907
 3908        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3909        let start_difference = start_offset - start_byte_offset;
 3910        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3911        let end_difference = end_offset - start_byte_offset;
 3912        // Current range has associated linked ranges.
 3913        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3914        for range in linked_ranges.iter() {
 3915            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3916            let end_offset = start_offset + end_difference;
 3917            let start_offset = start_offset + start_difference;
 3918            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3919                continue;
 3920            }
 3921            if self.selections.disjoint_anchor_ranges().any(|s| {
 3922                if s.start.buffer_id != selection.start.buffer_id
 3923                    || s.end.buffer_id != selection.end.buffer_id
 3924                {
 3925                    return false;
 3926                }
 3927                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3928                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3929            }) {
 3930                continue;
 3931            }
 3932            let start = buffer_snapshot.anchor_after(start_offset);
 3933            let end = buffer_snapshot.anchor_after(end_offset);
 3934            linked_edits
 3935                .entry(buffer.clone())
 3936                .or_default()
 3937                .push(start..end);
 3938        }
 3939        Some(linked_edits)
 3940    }
 3941
 3942    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3943        let text: Arc<str> = text.into();
 3944
 3945        if self.read_only(cx) {
 3946            return;
 3947        }
 3948
 3949        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3950
 3951        let selections = self.selections.all_adjusted(cx);
 3952        let mut bracket_inserted = false;
 3953        let mut edits = Vec::new();
 3954        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3955        let mut new_selections = Vec::with_capacity(selections.len());
 3956        let mut new_autoclose_regions = Vec::new();
 3957        let snapshot = self.buffer.read(cx).read(cx);
 3958        let mut clear_linked_edit_ranges = false;
 3959
 3960        for (selection, autoclose_region) in
 3961            self.selections_with_autoclose_regions(selections, &snapshot)
 3962        {
 3963            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3964                // Determine if the inserted text matches the opening or closing
 3965                // bracket of any of this language's bracket pairs.
 3966                let mut bracket_pair = None;
 3967                let mut is_bracket_pair_start = false;
 3968                let mut is_bracket_pair_end = false;
 3969                if !text.is_empty() {
 3970                    let mut bracket_pair_matching_end = None;
 3971                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3972                    //  and they are removing the character that triggered IME popup.
 3973                    for (pair, enabled) in scope.brackets() {
 3974                        if !pair.close && !pair.surround {
 3975                            continue;
 3976                        }
 3977
 3978                        if enabled && pair.start.ends_with(text.as_ref()) {
 3979                            let prefix_len = pair.start.len() - text.len();
 3980                            let preceding_text_matches_prefix = prefix_len == 0
 3981                                || (selection.start.column >= (prefix_len as u32)
 3982                                    && snapshot.contains_str_at(
 3983                                        Point::new(
 3984                                            selection.start.row,
 3985                                            selection.start.column - (prefix_len as u32),
 3986                                        ),
 3987                                        &pair.start[..prefix_len],
 3988                                    ));
 3989                            if preceding_text_matches_prefix {
 3990                                bracket_pair = Some(pair.clone());
 3991                                is_bracket_pair_start = true;
 3992                                break;
 3993                            }
 3994                        }
 3995                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3996                        {
 3997                            // take first bracket pair matching end, but don't break in case a later bracket
 3998                            // pair matches start
 3999                            bracket_pair_matching_end = Some(pair.clone());
 4000                        }
 4001                    }
 4002                    if let Some(end) = bracket_pair_matching_end
 4003                        && bracket_pair.is_none()
 4004                    {
 4005                        bracket_pair = Some(end);
 4006                        is_bracket_pair_end = true;
 4007                    }
 4008                }
 4009
 4010                if let Some(bracket_pair) = bracket_pair {
 4011                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4012                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4013                    let auto_surround =
 4014                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4015                    if selection.is_empty() {
 4016                        if is_bracket_pair_start {
 4017                            // If the inserted text is a suffix of an opening bracket and the
 4018                            // selection is preceded by the rest of the opening bracket, then
 4019                            // insert the closing bracket.
 4020                            let following_text_allows_autoclose = snapshot
 4021                                .chars_at(selection.start)
 4022                                .next()
 4023                                .is_none_or(|c| scope.should_autoclose_before(c));
 4024
 4025                            let preceding_text_allows_autoclose = selection.start.column == 0
 4026                                || snapshot
 4027                                    .reversed_chars_at(selection.start)
 4028                                    .next()
 4029                                    .is_none_or(|c| {
 4030                                        bracket_pair.start != bracket_pair.end
 4031                                            || !snapshot
 4032                                                .char_classifier_at(selection.start)
 4033                                                .is_word(c)
 4034                                    });
 4035
 4036                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4037                                && bracket_pair.start.len() == 1
 4038                            {
 4039                                let target = bracket_pair.start.chars().next().unwrap();
 4040                                let current_line_count = snapshot
 4041                                    .reversed_chars_at(selection.start)
 4042                                    .take_while(|&c| c != '\n')
 4043                                    .filter(|&c| c == target)
 4044                                    .count();
 4045                                current_line_count % 2 == 1
 4046                            } else {
 4047                                false
 4048                            };
 4049
 4050                            if autoclose
 4051                                && bracket_pair.close
 4052                                && following_text_allows_autoclose
 4053                                && preceding_text_allows_autoclose
 4054                                && !is_closing_quote
 4055                            {
 4056                                let anchor = snapshot.anchor_before(selection.end);
 4057                                new_selections.push((selection.map(|_| anchor), text.len()));
 4058                                new_autoclose_regions.push((
 4059                                    anchor,
 4060                                    text.len(),
 4061                                    selection.id,
 4062                                    bracket_pair.clone(),
 4063                                ));
 4064                                edits.push((
 4065                                    selection.range(),
 4066                                    format!("{}{}", text, bracket_pair.end).into(),
 4067                                ));
 4068                                bracket_inserted = true;
 4069                                continue;
 4070                            }
 4071                        }
 4072
 4073                        if let Some(region) = autoclose_region {
 4074                            // If the selection is followed by an auto-inserted closing bracket,
 4075                            // then don't insert that closing bracket again; just move the selection
 4076                            // past the closing bracket.
 4077                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4078                                && text.as_ref() == region.pair.end.as_str()
 4079                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4080                            if should_skip {
 4081                                let anchor = snapshot.anchor_after(selection.end);
 4082                                new_selections
 4083                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4084                                continue;
 4085                            }
 4086                        }
 4087
 4088                        let always_treat_brackets_as_autoclosed = snapshot
 4089                            .language_settings_at(selection.start, cx)
 4090                            .always_treat_brackets_as_autoclosed;
 4091                        if always_treat_brackets_as_autoclosed
 4092                            && is_bracket_pair_end
 4093                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4094                        {
 4095                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4096                            // and the inserted text is a closing bracket and the selection is followed
 4097                            // by the closing bracket then move the selection past the closing bracket.
 4098                            let anchor = snapshot.anchor_after(selection.end);
 4099                            new_selections.push((selection.map(|_| anchor), text.len()));
 4100                            continue;
 4101                        }
 4102                    }
 4103                    // If an opening bracket is 1 character long and is typed while
 4104                    // text is selected, then surround that text with the bracket pair.
 4105                    else if auto_surround
 4106                        && bracket_pair.surround
 4107                        && is_bracket_pair_start
 4108                        && bracket_pair.start.chars().count() == 1
 4109                    {
 4110                        edits.push((selection.start..selection.start, text.clone()));
 4111                        edits.push((
 4112                            selection.end..selection.end,
 4113                            bracket_pair.end.as_str().into(),
 4114                        ));
 4115                        bracket_inserted = true;
 4116                        new_selections.push((
 4117                            Selection {
 4118                                id: selection.id,
 4119                                start: snapshot.anchor_after(selection.start),
 4120                                end: snapshot.anchor_before(selection.end),
 4121                                reversed: selection.reversed,
 4122                                goal: selection.goal,
 4123                            },
 4124                            0,
 4125                        ));
 4126                        continue;
 4127                    }
 4128                }
 4129            }
 4130
 4131            if self.auto_replace_emoji_shortcode
 4132                && selection.is_empty()
 4133                && text.as_ref().ends_with(':')
 4134                && let Some(possible_emoji_short_code) =
 4135                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4136                && !possible_emoji_short_code.is_empty()
 4137                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4138            {
 4139                let emoji_shortcode_start = Point::new(
 4140                    selection.start.row,
 4141                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4142                );
 4143
 4144                // Remove shortcode from buffer
 4145                edits.push((
 4146                    emoji_shortcode_start..selection.start,
 4147                    "".to_string().into(),
 4148                ));
 4149                new_selections.push((
 4150                    Selection {
 4151                        id: selection.id,
 4152                        start: snapshot.anchor_after(emoji_shortcode_start),
 4153                        end: snapshot.anchor_before(selection.start),
 4154                        reversed: selection.reversed,
 4155                        goal: selection.goal,
 4156                    },
 4157                    0,
 4158                ));
 4159
 4160                // Insert emoji
 4161                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4162                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4163                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4164
 4165                continue;
 4166            }
 4167
 4168            // If not handling any auto-close operation, then just replace the selected
 4169            // text with the given input and move the selection to the end of the
 4170            // newly inserted text.
 4171            let anchor = snapshot.anchor_after(selection.end);
 4172            if !self.linked_edit_ranges.is_empty() {
 4173                let start_anchor = snapshot.anchor_before(selection.start);
 4174
 4175                let is_word_char = text.chars().next().is_none_or(|char| {
 4176                    let classifier = snapshot
 4177                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4178                        .ignore_punctuation(true);
 4179                    classifier.is_word(char)
 4180                });
 4181
 4182                if is_word_char {
 4183                    if let Some(ranges) = self
 4184                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4185                    {
 4186                        for (buffer, edits) in ranges {
 4187                            linked_edits
 4188                                .entry(buffer.clone())
 4189                                .or_default()
 4190                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4191                        }
 4192                    }
 4193                } else {
 4194                    clear_linked_edit_ranges = true;
 4195                }
 4196            }
 4197
 4198            new_selections.push((selection.map(|_| anchor), 0));
 4199            edits.push((selection.start..selection.end, text.clone()));
 4200        }
 4201
 4202        drop(snapshot);
 4203
 4204        self.transact(window, cx, |this, window, cx| {
 4205            if clear_linked_edit_ranges {
 4206                this.linked_edit_ranges.clear();
 4207            }
 4208            let initial_buffer_versions =
 4209                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4210
 4211            this.buffer.update(cx, |buffer, cx| {
 4212                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4213            });
 4214            for (buffer, edits) in linked_edits {
 4215                buffer.update(cx, |buffer, cx| {
 4216                    let snapshot = buffer.snapshot();
 4217                    let edits = edits
 4218                        .into_iter()
 4219                        .map(|(range, text)| {
 4220                            use text::ToPoint as TP;
 4221                            let end_point = TP::to_point(&range.end, &snapshot);
 4222                            let start_point = TP::to_point(&range.start, &snapshot);
 4223                            (start_point..end_point, text)
 4224                        })
 4225                        .sorted_by_key(|(range, _)| range.start);
 4226                    buffer.edit(edits, None, cx);
 4227                })
 4228            }
 4229            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4230            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4231            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4232            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4233                .zip(new_selection_deltas)
 4234                .map(|(selection, delta)| Selection {
 4235                    id: selection.id,
 4236                    start: selection.start + delta,
 4237                    end: selection.end + delta,
 4238                    reversed: selection.reversed,
 4239                    goal: SelectionGoal::None,
 4240                })
 4241                .collect::<Vec<_>>();
 4242
 4243            let mut i = 0;
 4244            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4245                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4246                let start = map.buffer_snapshot.anchor_before(position);
 4247                let end = map.buffer_snapshot.anchor_after(position);
 4248                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4249                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4250                        Ordering::Less => i += 1,
 4251                        Ordering::Greater => break,
 4252                        Ordering::Equal => {
 4253                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4254                                Ordering::Less => i += 1,
 4255                                Ordering::Equal => break,
 4256                                Ordering::Greater => break,
 4257                            }
 4258                        }
 4259                    }
 4260                }
 4261                this.autoclose_regions.insert(
 4262                    i,
 4263                    AutocloseRegion {
 4264                        selection_id,
 4265                        range: start..end,
 4266                        pair,
 4267                    },
 4268                );
 4269            }
 4270
 4271            let had_active_edit_prediction = this.has_active_edit_prediction();
 4272            this.change_selections(
 4273                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4274                window,
 4275                cx,
 4276                |s| s.select(new_selections),
 4277            );
 4278
 4279            if !bracket_inserted
 4280                && let Some(on_type_format_task) =
 4281                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4282            {
 4283                on_type_format_task.detach_and_log_err(cx);
 4284            }
 4285
 4286            let editor_settings = EditorSettings::get_global(cx);
 4287            if bracket_inserted
 4288                && (editor_settings.auto_signature_help
 4289                    || editor_settings.show_signature_help_after_edits)
 4290            {
 4291                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4292            }
 4293
 4294            let trigger_in_words =
 4295                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4296            if this.hard_wrap.is_some() {
 4297                let latest: Range<Point> = this.selections.newest(cx).range();
 4298                if latest.is_empty()
 4299                    && this
 4300                        .buffer()
 4301                        .read(cx)
 4302                        .snapshot(cx)
 4303                        .line_len(MultiBufferRow(latest.start.row))
 4304                        == latest.start.column
 4305                {
 4306                    this.rewrap_impl(
 4307                        RewrapOptions {
 4308                            override_language_settings: true,
 4309                            preserve_existing_whitespace: true,
 4310                        },
 4311                        cx,
 4312                    )
 4313                }
 4314            }
 4315            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4316            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4317            this.refresh_edit_prediction(true, false, window, cx);
 4318            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4319        });
 4320    }
 4321
 4322    fn find_possible_emoji_shortcode_at_position(
 4323        snapshot: &MultiBufferSnapshot,
 4324        position: Point,
 4325    ) -> Option<String> {
 4326        let mut chars = Vec::new();
 4327        let mut found_colon = false;
 4328        for char in snapshot.reversed_chars_at(position).take(100) {
 4329            // Found a possible emoji shortcode in the middle of the buffer
 4330            if found_colon {
 4331                if char.is_whitespace() {
 4332                    chars.reverse();
 4333                    return Some(chars.iter().collect());
 4334                }
 4335                // If the previous character is not a whitespace, we are in the middle of a word
 4336                // and we only want to complete the shortcode if the word is made up of other emojis
 4337                let mut containing_word = String::new();
 4338                for ch in snapshot
 4339                    .reversed_chars_at(position)
 4340                    .skip(chars.len() + 1)
 4341                    .take(100)
 4342                {
 4343                    if ch.is_whitespace() {
 4344                        break;
 4345                    }
 4346                    containing_word.push(ch);
 4347                }
 4348                let containing_word = containing_word.chars().rev().collect::<String>();
 4349                if util::word_consists_of_emojis(containing_word.as_str()) {
 4350                    chars.reverse();
 4351                    return Some(chars.iter().collect());
 4352                }
 4353            }
 4354
 4355            if char.is_whitespace() || !char.is_ascii() {
 4356                return None;
 4357            }
 4358            if char == ':' {
 4359                found_colon = true;
 4360            } else {
 4361                chars.push(char);
 4362            }
 4363        }
 4364        // Found a possible emoji shortcode at the beginning of the buffer
 4365        chars.reverse();
 4366        Some(chars.iter().collect())
 4367    }
 4368
 4369    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4370        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4371        self.transact(window, cx, |this, window, cx| {
 4372            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4373                let selections = this.selections.all::<usize>(cx);
 4374                let multi_buffer = this.buffer.read(cx);
 4375                let buffer = multi_buffer.snapshot(cx);
 4376                selections
 4377                    .iter()
 4378                    .map(|selection| {
 4379                        let start_point = selection.start.to_point(&buffer);
 4380                        let mut existing_indent =
 4381                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4382                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4383                        let start = selection.start;
 4384                        let end = selection.end;
 4385                        let selection_is_empty = start == end;
 4386                        let language_scope = buffer.language_scope_at(start);
 4387                        let (
 4388                            comment_delimiter,
 4389                            doc_delimiter,
 4390                            insert_extra_newline,
 4391                            indent_on_newline,
 4392                            indent_on_extra_newline,
 4393                        ) = if let Some(language) = &language_scope {
 4394                            let mut insert_extra_newline =
 4395                                insert_extra_newline_brackets(&buffer, start..end, language)
 4396                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4397
 4398                            // Comment extension on newline is allowed only for cursor selections
 4399                            let comment_delimiter = maybe!({
 4400                                if !selection_is_empty {
 4401                                    return None;
 4402                                }
 4403
 4404                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4405                                    return None;
 4406                                }
 4407
 4408                                let delimiters = language.line_comment_prefixes();
 4409                                let max_len_of_delimiter =
 4410                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4411                                let (snapshot, range) =
 4412                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4413
 4414                                let num_of_whitespaces = snapshot
 4415                                    .chars_for_range(range.clone())
 4416                                    .take_while(|c| c.is_whitespace())
 4417                                    .count();
 4418                                let comment_candidate = snapshot
 4419                                    .chars_for_range(range.clone())
 4420                                    .skip(num_of_whitespaces)
 4421                                    .take(max_len_of_delimiter)
 4422                                    .collect::<String>();
 4423                                let (delimiter, trimmed_len) = delimiters
 4424                                    .iter()
 4425                                    .filter_map(|delimiter| {
 4426                                        let prefix = delimiter.trim_end();
 4427                                        if comment_candidate.starts_with(prefix) {
 4428                                            Some((delimiter, prefix.len()))
 4429                                        } else {
 4430                                            None
 4431                                        }
 4432                                    })
 4433                                    .max_by_key(|(_, len)| *len)?;
 4434
 4435                                if let Some(BlockCommentConfig {
 4436                                    start: block_start, ..
 4437                                }) = language.block_comment()
 4438                                {
 4439                                    let block_start_trimmed = block_start.trim_end();
 4440                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4441                                        let line_content = snapshot
 4442                                            .chars_for_range(range)
 4443                                            .skip(num_of_whitespaces)
 4444                                            .take(block_start_trimmed.len())
 4445                                            .collect::<String>();
 4446
 4447                                        if line_content.starts_with(block_start_trimmed) {
 4448                                            return None;
 4449                                        }
 4450                                    }
 4451                                }
 4452
 4453                                let cursor_is_placed_after_comment_marker =
 4454                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4455                                if cursor_is_placed_after_comment_marker {
 4456                                    Some(delimiter.clone())
 4457                                } else {
 4458                                    None
 4459                                }
 4460                            });
 4461
 4462                            let mut indent_on_newline = IndentSize::spaces(0);
 4463                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4464
 4465                            let doc_delimiter = maybe!({
 4466                                if !selection_is_empty {
 4467                                    return None;
 4468                                }
 4469
 4470                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4471                                    return None;
 4472                                }
 4473
 4474                                let BlockCommentConfig {
 4475                                    start: start_tag,
 4476                                    end: end_tag,
 4477                                    prefix: delimiter,
 4478                                    tab_size: len,
 4479                                } = language.documentation_comment()?;
 4480                                let is_within_block_comment = buffer
 4481                                    .language_scope_at(start_point)
 4482                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4483                                if !is_within_block_comment {
 4484                                    return None;
 4485                                }
 4486
 4487                                let (snapshot, range) =
 4488                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4489
 4490                                let num_of_whitespaces = snapshot
 4491                                    .chars_for_range(range.clone())
 4492                                    .take_while(|c| c.is_whitespace())
 4493                                    .count();
 4494
 4495                                // 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.
 4496                                let column = start_point.column;
 4497                                let cursor_is_after_start_tag = {
 4498                                    let start_tag_len = start_tag.len();
 4499                                    let start_tag_line = snapshot
 4500                                        .chars_for_range(range.clone())
 4501                                        .skip(num_of_whitespaces)
 4502                                        .take(start_tag_len)
 4503                                        .collect::<String>();
 4504                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4505                                        num_of_whitespaces + start_tag_len <= column as usize
 4506                                    } else {
 4507                                        false
 4508                                    }
 4509                                };
 4510
 4511                                let cursor_is_after_delimiter = {
 4512                                    let delimiter_trim = delimiter.trim_end();
 4513                                    let delimiter_line = snapshot
 4514                                        .chars_for_range(range.clone())
 4515                                        .skip(num_of_whitespaces)
 4516                                        .take(delimiter_trim.len())
 4517                                        .collect::<String>();
 4518                                    if delimiter_line.starts_with(delimiter_trim) {
 4519                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4520                                    } else {
 4521                                        false
 4522                                    }
 4523                                };
 4524
 4525                                let cursor_is_before_end_tag_if_exists = {
 4526                                    let mut char_position = 0u32;
 4527                                    let mut end_tag_offset = None;
 4528
 4529                                    'outer: for chunk in snapshot.text_for_range(range) {
 4530                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4531                                            let chars_before_match =
 4532                                                chunk[..byte_pos].chars().count() as u32;
 4533                                            end_tag_offset =
 4534                                                Some(char_position + chars_before_match);
 4535                                            break 'outer;
 4536                                        }
 4537                                        char_position += chunk.chars().count() as u32;
 4538                                    }
 4539
 4540                                    if let Some(end_tag_offset) = end_tag_offset {
 4541                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4542                                        if cursor_is_after_start_tag {
 4543                                            if cursor_is_before_end_tag {
 4544                                                insert_extra_newline = true;
 4545                                            }
 4546                                            let cursor_is_at_start_of_end_tag =
 4547                                                column == end_tag_offset;
 4548                                            if cursor_is_at_start_of_end_tag {
 4549                                                indent_on_extra_newline.len = *len;
 4550                                            }
 4551                                        }
 4552                                        cursor_is_before_end_tag
 4553                                    } else {
 4554                                        true
 4555                                    }
 4556                                };
 4557
 4558                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4559                                    && cursor_is_before_end_tag_if_exists
 4560                                {
 4561                                    if cursor_is_after_start_tag {
 4562                                        indent_on_newline.len = *len;
 4563                                    }
 4564                                    Some(delimiter.clone())
 4565                                } else {
 4566                                    None
 4567                                }
 4568                            });
 4569
 4570                            (
 4571                                comment_delimiter,
 4572                                doc_delimiter,
 4573                                insert_extra_newline,
 4574                                indent_on_newline,
 4575                                indent_on_extra_newline,
 4576                            )
 4577                        } else {
 4578                            (
 4579                                None,
 4580                                None,
 4581                                false,
 4582                                IndentSize::default(),
 4583                                IndentSize::default(),
 4584                            )
 4585                        };
 4586
 4587                        let prevent_auto_indent = doc_delimiter.is_some();
 4588                        let delimiter = comment_delimiter.or(doc_delimiter);
 4589
 4590                        let capacity_for_delimiter =
 4591                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4592                        let mut new_text = String::with_capacity(
 4593                            1 + capacity_for_delimiter
 4594                                + existing_indent.len as usize
 4595                                + indent_on_newline.len as usize
 4596                                + indent_on_extra_newline.len as usize,
 4597                        );
 4598                        new_text.push('\n');
 4599                        new_text.extend(existing_indent.chars());
 4600                        new_text.extend(indent_on_newline.chars());
 4601
 4602                        if let Some(delimiter) = &delimiter {
 4603                            new_text.push_str(delimiter);
 4604                        }
 4605
 4606                        if insert_extra_newline {
 4607                            new_text.push('\n');
 4608                            new_text.extend(existing_indent.chars());
 4609                            new_text.extend(indent_on_extra_newline.chars());
 4610                        }
 4611
 4612                        let anchor = buffer.anchor_after(end);
 4613                        let new_selection = selection.map(|_| anchor);
 4614                        (
 4615                            ((start..end, new_text), prevent_auto_indent),
 4616                            (insert_extra_newline, new_selection),
 4617                        )
 4618                    })
 4619                    .unzip()
 4620            };
 4621
 4622            let mut auto_indent_edits = Vec::new();
 4623            let mut edits = Vec::new();
 4624            for (edit, prevent_auto_indent) in edits_with_flags {
 4625                if prevent_auto_indent {
 4626                    edits.push(edit);
 4627                } else {
 4628                    auto_indent_edits.push(edit);
 4629                }
 4630            }
 4631            if !edits.is_empty() {
 4632                this.edit(edits, cx);
 4633            }
 4634            if !auto_indent_edits.is_empty() {
 4635                this.edit_with_autoindent(auto_indent_edits, cx);
 4636            }
 4637
 4638            let buffer = this.buffer.read(cx).snapshot(cx);
 4639            let new_selections = selection_info
 4640                .into_iter()
 4641                .map(|(extra_newline_inserted, new_selection)| {
 4642                    let mut cursor = new_selection.end.to_point(&buffer);
 4643                    if extra_newline_inserted {
 4644                        cursor.row -= 1;
 4645                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4646                    }
 4647                    new_selection.map(|_| cursor)
 4648                })
 4649                .collect();
 4650
 4651            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4652            this.refresh_edit_prediction(true, false, window, cx);
 4653        });
 4654    }
 4655
 4656    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4657        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4658
 4659        let buffer = self.buffer.read(cx);
 4660        let snapshot = buffer.snapshot(cx);
 4661
 4662        let mut edits = Vec::new();
 4663        let mut rows = Vec::new();
 4664
 4665        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4666            let cursor = selection.head();
 4667            let row = cursor.row;
 4668
 4669            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4670
 4671            let newline = "\n".to_string();
 4672            edits.push((start_of_line..start_of_line, newline));
 4673
 4674            rows.push(row + rows_inserted as u32);
 4675        }
 4676
 4677        self.transact(window, cx, |editor, window, cx| {
 4678            editor.edit(edits, cx);
 4679
 4680            editor.change_selections(Default::default(), window, cx, |s| {
 4681                let mut index = 0;
 4682                s.move_cursors_with(|map, _, _| {
 4683                    let row = rows[index];
 4684                    index += 1;
 4685
 4686                    let point = Point::new(row, 0);
 4687                    let boundary = map.next_line_boundary(point).1;
 4688                    let clipped = map.clip_point(boundary, Bias::Left);
 4689
 4690                    (clipped, SelectionGoal::None)
 4691                });
 4692            });
 4693
 4694            let mut indent_edits = Vec::new();
 4695            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4696            for row in rows {
 4697                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4698                for (row, indent) in indents {
 4699                    if indent.len == 0 {
 4700                        continue;
 4701                    }
 4702
 4703                    let text = match indent.kind {
 4704                        IndentKind::Space => " ".repeat(indent.len as usize),
 4705                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4706                    };
 4707                    let point = Point::new(row.0, 0);
 4708                    indent_edits.push((point..point, text));
 4709                }
 4710            }
 4711            editor.edit(indent_edits, cx);
 4712        });
 4713    }
 4714
 4715    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4716        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4717
 4718        let buffer = self.buffer.read(cx);
 4719        let snapshot = buffer.snapshot(cx);
 4720
 4721        let mut edits = Vec::new();
 4722        let mut rows = Vec::new();
 4723        let mut rows_inserted = 0;
 4724
 4725        for selection in self.selections.all_adjusted(cx) {
 4726            let cursor = selection.head();
 4727            let row = cursor.row;
 4728
 4729            let point = Point::new(row + 1, 0);
 4730            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4731
 4732            let newline = "\n".to_string();
 4733            edits.push((start_of_line..start_of_line, newline));
 4734
 4735            rows_inserted += 1;
 4736            rows.push(row + rows_inserted);
 4737        }
 4738
 4739        self.transact(window, cx, |editor, window, cx| {
 4740            editor.edit(edits, cx);
 4741
 4742            editor.change_selections(Default::default(), window, cx, |s| {
 4743                let mut index = 0;
 4744                s.move_cursors_with(|map, _, _| {
 4745                    let row = rows[index];
 4746                    index += 1;
 4747
 4748                    let point = Point::new(row, 0);
 4749                    let boundary = map.next_line_boundary(point).1;
 4750                    let clipped = map.clip_point(boundary, Bias::Left);
 4751
 4752                    (clipped, SelectionGoal::None)
 4753                });
 4754            });
 4755
 4756            let mut indent_edits = Vec::new();
 4757            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4758            for row in rows {
 4759                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4760                for (row, indent) in indents {
 4761                    if indent.len == 0 {
 4762                        continue;
 4763                    }
 4764
 4765                    let text = match indent.kind {
 4766                        IndentKind::Space => " ".repeat(indent.len as usize),
 4767                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4768                    };
 4769                    let point = Point::new(row.0, 0);
 4770                    indent_edits.push((point..point, text));
 4771                }
 4772            }
 4773            editor.edit(indent_edits, cx);
 4774        });
 4775    }
 4776
 4777    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4778        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4779            original_indent_columns: Vec::new(),
 4780        });
 4781        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4782    }
 4783
 4784    fn insert_with_autoindent_mode(
 4785        &mut self,
 4786        text: &str,
 4787        autoindent_mode: Option<AutoindentMode>,
 4788        window: &mut Window,
 4789        cx: &mut Context<Self>,
 4790    ) {
 4791        if self.read_only(cx) {
 4792            return;
 4793        }
 4794
 4795        let text: Arc<str> = text.into();
 4796        self.transact(window, cx, |this, window, cx| {
 4797            let old_selections = this.selections.all_adjusted(cx);
 4798            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4799                let anchors = {
 4800                    let snapshot = buffer.read(cx);
 4801                    old_selections
 4802                        .iter()
 4803                        .map(|s| {
 4804                            let anchor = snapshot.anchor_after(s.head());
 4805                            s.map(|_| anchor)
 4806                        })
 4807                        .collect::<Vec<_>>()
 4808                };
 4809                buffer.edit(
 4810                    old_selections
 4811                        .iter()
 4812                        .map(|s| (s.start..s.end, text.clone())),
 4813                    autoindent_mode,
 4814                    cx,
 4815                );
 4816                anchors
 4817            });
 4818
 4819            this.change_selections(Default::default(), window, cx, |s| {
 4820                s.select_anchors(selection_anchors);
 4821            });
 4822
 4823            cx.notify();
 4824        });
 4825    }
 4826
 4827    fn trigger_completion_on_input(
 4828        &mut self,
 4829        text: &str,
 4830        trigger_in_words: bool,
 4831        window: &mut Window,
 4832        cx: &mut Context<Self>,
 4833    ) {
 4834        let completions_source = self
 4835            .context_menu
 4836            .borrow()
 4837            .as_ref()
 4838            .and_then(|menu| match menu {
 4839                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4840                CodeContextMenu::CodeActions(_) => None,
 4841            });
 4842
 4843        match completions_source {
 4844            Some(CompletionsMenuSource::Words) => {
 4845                self.show_word_completions(&ShowWordCompletions, window, cx)
 4846            }
 4847            Some(CompletionsMenuSource::Normal)
 4848            | Some(CompletionsMenuSource::SnippetChoices)
 4849            | None
 4850                if self.is_completion_trigger(
 4851                    text,
 4852                    trigger_in_words,
 4853                    completions_source.is_some(),
 4854                    cx,
 4855                ) =>
 4856            {
 4857                self.show_completions(
 4858                    &ShowCompletions {
 4859                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4860                    },
 4861                    window,
 4862                    cx,
 4863                )
 4864            }
 4865            _ => {
 4866                self.hide_context_menu(window, cx);
 4867            }
 4868        }
 4869    }
 4870
 4871    fn is_completion_trigger(
 4872        &self,
 4873        text: &str,
 4874        trigger_in_words: bool,
 4875        menu_is_open: bool,
 4876        cx: &mut Context<Self>,
 4877    ) -> bool {
 4878        let position = self.selections.newest_anchor().head();
 4879        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4880            return false;
 4881        };
 4882
 4883        if let Some(completion_provider) = &self.completion_provider {
 4884            completion_provider.is_completion_trigger(
 4885                &buffer,
 4886                position.text_anchor,
 4887                text,
 4888                trigger_in_words,
 4889                menu_is_open,
 4890                cx,
 4891            )
 4892        } else {
 4893            false
 4894        }
 4895    }
 4896
 4897    /// If any empty selections is touching the start of its innermost containing autoclose
 4898    /// region, expand it to select the brackets.
 4899    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4900        let selections = self.selections.all::<usize>(cx);
 4901        let buffer = self.buffer.read(cx).read(cx);
 4902        let new_selections = self
 4903            .selections_with_autoclose_regions(selections, &buffer)
 4904            .map(|(mut selection, region)| {
 4905                if !selection.is_empty() {
 4906                    return selection;
 4907                }
 4908
 4909                if let Some(region) = region {
 4910                    let mut range = region.range.to_offset(&buffer);
 4911                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4912                        range.start -= region.pair.start.len();
 4913                        if buffer.contains_str_at(range.start, &region.pair.start)
 4914                            && buffer.contains_str_at(range.end, &region.pair.end)
 4915                        {
 4916                            range.end += region.pair.end.len();
 4917                            selection.start = range.start;
 4918                            selection.end = range.end;
 4919
 4920                            return selection;
 4921                        }
 4922                    }
 4923                }
 4924
 4925                let always_treat_brackets_as_autoclosed = buffer
 4926                    .language_settings_at(selection.start, cx)
 4927                    .always_treat_brackets_as_autoclosed;
 4928
 4929                if !always_treat_brackets_as_autoclosed {
 4930                    return selection;
 4931                }
 4932
 4933                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4934                    for (pair, enabled) in scope.brackets() {
 4935                        if !enabled || !pair.close {
 4936                            continue;
 4937                        }
 4938
 4939                        if buffer.contains_str_at(selection.start, &pair.end) {
 4940                            let pair_start_len = pair.start.len();
 4941                            if buffer.contains_str_at(
 4942                                selection.start.saturating_sub(pair_start_len),
 4943                                &pair.start,
 4944                            ) {
 4945                                selection.start -= pair_start_len;
 4946                                selection.end += pair.end.len();
 4947
 4948                                return selection;
 4949                            }
 4950                        }
 4951                    }
 4952                }
 4953
 4954                selection
 4955            })
 4956            .collect();
 4957
 4958        drop(buffer);
 4959        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4960            selections.select(new_selections)
 4961        });
 4962    }
 4963
 4964    /// Iterate the given selections, and for each one, find the smallest surrounding
 4965    /// autoclose region. This uses the ordering of the selections and the autoclose
 4966    /// regions to avoid repeated comparisons.
 4967    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4968        &'a self,
 4969        selections: impl IntoIterator<Item = Selection<D>>,
 4970        buffer: &'a MultiBufferSnapshot,
 4971    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4972        let mut i = 0;
 4973        let mut regions = self.autoclose_regions.as_slice();
 4974        selections.into_iter().map(move |selection| {
 4975            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4976
 4977            let mut enclosing = None;
 4978            while let Some(pair_state) = regions.get(i) {
 4979                if pair_state.range.end.to_offset(buffer) < range.start {
 4980                    regions = &regions[i + 1..];
 4981                    i = 0;
 4982                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4983                    break;
 4984                } else {
 4985                    if pair_state.selection_id == selection.id {
 4986                        enclosing = Some(pair_state);
 4987                    }
 4988                    i += 1;
 4989                }
 4990            }
 4991
 4992            (selection, enclosing)
 4993        })
 4994    }
 4995
 4996    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4997    fn invalidate_autoclose_regions(
 4998        &mut self,
 4999        mut selections: &[Selection<Anchor>],
 5000        buffer: &MultiBufferSnapshot,
 5001    ) {
 5002        self.autoclose_regions.retain(|state| {
 5003            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5004                return false;
 5005            }
 5006
 5007            let mut i = 0;
 5008            while let Some(selection) = selections.get(i) {
 5009                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5010                    selections = &selections[1..];
 5011                    continue;
 5012                }
 5013                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5014                    break;
 5015                }
 5016                if selection.id == state.selection_id {
 5017                    return true;
 5018                } else {
 5019                    i += 1;
 5020                }
 5021            }
 5022            false
 5023        });
 5024    }
 5025
 5026    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5027        let offset = position.to_offset(buffer);
 5028        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5029        if offset > word_range.start && kind == Some(CharKind::Word) {
 5030            Some(
 5031                buffer
 5032                    .text_for_range(word_range.start..offset)
 5033                    .collect::<String>(),
 5034            )
 5035        } else {
 5036            None
 5037        }
 5038    }
 5039
 5040    pub fn toggle_inline_values(
 5041        &mut self,
 5042        _: &ToggleInlineValues,
 5043        _: &mut Window,
 5044        cx: &mut Context<Self>,
 5045    ) {
 5046        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5047
 5048        self.refresh_inline_values(cx);
 5049    }
 5050
 5051    pub fn toggle_inlay_hints(
 5052        &mut self,
 5053        _: &ToggleInlayHints,
 5054        _: &mut Window,
 5055        cx: &mut Context<Self>,
 5056    ) {
 5057        self.refresh_inlay_hints(
 5058            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5059            cx,
 5060        );
 5061    }
 5062
 5063    pub fn inlay_hints_enabled(&self) -> bool {
 5064        self.inlay_hint_cache.enabled
 5065    }
 5066
 5067    pub fn inline_values_enabled(&self) -> bool {
 5068        self.inline_value_cache.enabled
 5069    }
 5070
 5071    #[cfg(any(test, feature = "test-support"))]
 5072    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5073        self.display_map
 5074            .read(cx)
 5075            .current_inlays()
 5076            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5077            .cloned()
 5078            .collect()
 5079    }
 5080
 5081    #[cfg(any(test, feature = "test-support"))]
 5082    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5083        self.display_map
 5084            .read(cx)
 5085            .current_inlays()
 5086            .cloned()
 5087            .collect()
 5088    }
 5089
 5090    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5091        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5092            return;
 5093        }
 5094
 5095        let reason_description = reason.description();
 5096        let ignore_debounce = matches!(
 5097            reason,
 5098            InlayHintRefreshReason::SettingsChange(_)
 5099                | InlayHintRefreshReason::Toggle(_)
 5100                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5101                | InlayHintRefreshReason::ModifiersChanged(_)
 5102        );
 5103        let (invalidate_cache, required_languages) = match reason {
 5104            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5105                match self.inlay_hint_cache.modifiers_override(enabled) {
 5106                    Some(enabled) => {
 5107                        if enabled {
 5108                            (InvalidationStrategy::RefreshRequested, None)
 5109                        } else {
 5110                            self.splice_inlays(
 5111                                &self
 5112                                    .visible_inlay_hints(cx)
 5113                                    .iter()
 5114                                    .map(|inlay| inlay.id)
 5115                                    .collect::<Vec<InlayId>>(),
 5116                                Vec::new(),
 5117                                cx,
 5118                            );
 5119                            return;
 5120                        }
 5121                    }
 5122                    None => return,
 5123                }
 5124            }
 5125            InlayHintRefreshReason::Toggle(enabled) => {
 5126                if self.inlay_hint_cache.toggle(enabled) {
 5127                    if enabled {
 5128                        (InvalidationStrategy::RefreshRequested, None)
 5129                    } else {
 5130                        self.splice_inlays(
 5131                            &self
 5132                                .visible_inlay_hints(cx)
 5133                                .iter()
 5134                                .map(|inlay| inlay.id)
 5135                                .collect::<Vec<InlayId>>(),
 5136                            Vec::new(),
 5137                            cx,
 5138                        );
 5139                        return;
 5140                    }
 5141                } else {
 5142                    return;
 5143                }
 5144            }
 5145            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5146                match self.inlay_hint_cache.update_settings(
 5147                    &self.buffer,
 5148                    new_settings,
 5149                    self.visible_inlay_hints(cx),
 5150                    cx,
 5151                ) {
 5152                    ControlFlow::Break(Some(InlaySplice {
 5153                        to_remove,
 5154                        to_insert,
 5155                    })) => {
 5156                        self.splice_inlays(&to_remove, to_insert, cx);
 5157                        return;
 5158                    }
 5159                    ControlFlow::Break(None) => return,
 5160                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5161                }
 5162            }
 5163            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5164                if let Some(InlaySplice {
 5165                    to_remove,
 5166                    to_insert,
 5167                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5168                {
 5169                    self.splice_inlays(&to_remove, to_insert, cx);
 5170                }
 5171                self.display_map.update(cx, |display_map, _| {
 5172                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5173                });
 5174                return;
 5175            }
 5176            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5177            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5178                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5179            }
 5180            InlayHintRefreshReason::RefreshRequested => {
 5181                (InvalidationStrategy::RefreshRequested, None)
 5182            }
 5183        };
 5184
 5185        if let Some(InlaySplice {
 5186            to_remove,
 5187            to_insert,
 5188        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5189            reason_description,
 5190            self.visible_excerpts(required_languages.as_ref(), cx),
 5191            invalidate_cache,
 5192            ignore_debounce,
 5193            cx,
 5194        ) {
 5195            self.splice_inlays(&to_remove, to_insert, cx);
 5196        }
 5197    }
 5198
 5199    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5200        self.display_map
 5201            .read(cx)
 5202            .current_inlays()
 5203            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5204            .cloned()
 5205            .collect()
 5206    }
 5207
 5208    pub fn visible_excerpts(
 5209        &self,
 5210        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5211        cx: &mut Context<Editor>,
 5212    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5213        let Some(project) = self.project() else {
 5214            return HashMap::default();
 5215        };
 5216        let project = project.read(cx);
 5217        let multi_buffer = self.buffer().read(cx);
 5218        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5219        let multi_buffer_visible_start = self
 5220            .scroll_manager
 5221            .anchor()
 5222            .anchor
 5223            .to_point(&multi_buffer_snapshot);
 5224        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5225            multi_buffer_visible_start
 5226                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5227            Bias::Left,
 5228        );
 5229        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5230        multi_buffer_snapshot
 5231            .range_to_buffer_ranges(multi_buffer_visible_range)
 5232            .into_iter()
 5233            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5234            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5235                let buffer_file = project::File::from_dyn(buffer.file())?;
 5236                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5237                let worktree_entry = buffer_worktree
 5238                    .read(cx)
 5239                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5240                if worktree_entry.is_ignored {
 5241                    return None;
 5242                }
 5243
 5244                let language = buffer.language()?;
 5245                if let Some(restrict_to_languages) = restrict_to_languages
 5246                    && !restrict_to_languages.contains(language)
 5247                {
 5248                    return None;
 5249                }
 5250                Some((
 5251                    excerpt_id,
 5252                    (
 5253                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5254                        buffer.version().clone(),
 5255                        excerpt_visible_range,
 5256                    ),
 5257                ))
 5258            })
 5259            .collect()
 5260    }
 5261
 5262    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5263        TextLayoutDetails {
 5264            text_system: window.text_system().clone(),
 5265            editor_style: self.style.clone().unwrap(),
 5266            rem_size: window.rem_size(),
 5267            scroll_anchor: self.scroll_manager.anchor(),
 5268            visible_rows: self.visible_line_count(),
 5269            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5270        }
 5271    }
 5272
 5273    pub fn splice_inlays(
 5274        &self,
 5275        to_remove: &[InlayId],
 5276        to_insert: Vec<Inlay>,
 5277        cx: &mut Context<Self>,
 5278    ) {
 5279        self.display_map.update(cx, |display_map, cx| {
 5280            display_map.splice_inlays(to_remove, to_insert, cx)
 5281        });
 5282        cx.notify();
 5283    }
 5284
 5285    fn trigger_on_type_formatting(
 5286        &self,
 5287        input: String,
 5288        window: &mut Window,
 5289        cx: &mut Context<Self>,
 5290    ) -> Option<Task<Result<()>>> {
 5291        if input.len() != 1 {
 5292            return None;
 5293        }
 5294
 5295        let project = self.project()?;
 5296        let position = self.selections.newest_anchor().head();
 5297        let (buffer, buffer_position) = self
 5298            .buffer
 5299            .read(cx)
 5300            .text_anchor_for_position(position, cx)?;
 5301
 5302        let settings = language_settings::language_settings(
 5303            buffer
 5304                .read(cx)
 5305                .language_at(buffer_position)
 5306                .map(|l| l.name()),
 5307            buffer.read(cx).file(),
 5308            cx,
 5309        );
 5310        if !settings.use_on_type_format {
 5311            return None;
 5312        }
 5313
 5314        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5315        // hence we do LSP request & edit on host side only — add formats to host's history.
 5316        let push_to_lsp_host_history = true;
 5317        // If this is not the host, append its history with new edits.
 5318        let push_to_client_history = project.read(cx).is_via_collab();
 5319
 5320        let on_type_formatting = project.update(cx, |project, cx| {
 5321            project.on_type_format(
 5322                buffer.clone(),
 5323                buffer_position,
 5324                input,
 5325                push_to_lsp_host_history,
 5326                cx,
 5327            )
 5328        });
 5329        Some(cx.spawn_in(window, async move |editor, cx| {
 5330            if let Some(transaction) = on_type_formatting.await? {
 5331                if push_to_client_history {
 5332                    buffer
 5333                        .update(cx, |buffer, _| {
 5334                            buffer.push_transaction(transaction, Instant::now());
 5335                            buffer.finalize_last_transaction();
 5336                        })
 5337                        .ok();
 5338                }
 5339                editor.update(cx, |editor, cx| {
 5340                    editor.refresh_document_highlights(cx);
 5341                })?;
 5342            }
 5343            Ok(())
 5344        }))
 5345    }
 5346
 5347    pub fn show_word_completions(
 5348        &mut self,
 5349        _: &ShowWordCompletions,
 5350        window: &mut Window,
 5351        cx: &mut Context<Self>,
 5352    ) {
 5353        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5354    }
 5355
 5356    pub fn show_completions(
 5357        &mut self,
 5358        options: &ShowCompletions,
 5359        window: &mut Window,
 5360        cx: &mut Context<Self>,
 5361    ) {
 5362        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5363    }
 5364
 5365    fn open_or_update_completions_menu(
 5366        &mut self,
 5367        requested_source: Option<CompletionsMenuSource>,
 5368        trigger: Option<&str>,
 5369        window: &mut Window,
 5370        cx: &mut Context<Self>,
 5371    ) {
 5372        if self.pending_rename.is_some() {
 5373            return;
 5374        }
 5375
 5376        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5377
 5378        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5379        // inserted and selected. To handle that case, the start of the selection is used so that
 5380        // the menu starts with all choices.
 5381        let position = self
 5382            .selections
 5383            .newest_anchor()
 5384            .start
 5385            .bias_right(&multibuffer_snapshot);
 5386        if position.diff_base_anchor.is_some() {
 5387            return;
 5388        }
 5389        let (buffer, buffer_position) =
 5390            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5391                output
 5392            } else {
 5393                return;
 5394            };
 5395        let buffer_snapshot = buffer.read(cx).snapshot();
 5396
 5397        let query: Option<Arc<String>> =
 5398            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5399
 5400        drop(multibuffer_snapshot);
 5401
 5402        let provider = match requested_source {
 5403            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5404            Some(CompletionsMenuSource::Words) => None,
 5405            Some(CompletionsMenuSource::SnippetChoices) => {
 5406                log::error!("bug: SnippetChoices requested_source is not handled");
 5407                None
 5408            }
 5409        };
 5410
 5411        let sort_completions = provider
 5412            .as_ref()
 5413            .is_some_and(|provider| provider.sort_completions());
 5414
 5415        let filter_completions = provider
 5416            .as_ref()
 5417            .is_none_or(|provider| provider.filter_completions());
 5418
 5419        let trigger_kind = match trigger {
 5420            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5421                CompletionTriggerKind::TRIGGER_CHARACTER
 5422            }
 5423            _ => CompletionTriggerKind::INVOKED,
 5424        };
 5425        let completion_context = CompletionContext {
 5426            trigger_character: trigger.and_then(|trigger| {
 5427                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5428                    Some(String::from(trigger))
 5429                } else {
 5430                    None
 5431                }
 5432            }),
 5433            trigger_kind,
 5434        };
 5435
 5436        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5437        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5438        // involve trigger chars, so this is skipped in that case.
 5439        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5440        {
 5441            let menu_is_open = matches!(
 5442                self.context_menu.borrow().as_ref(),
 5443                Some(CodeContextMenu::Completions(_))
 5444            );
 5445            if menu_is_open {
 5446                self.hide_context_menu(window, cx);
 5447            }
 5448        }
 5449
 5450        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5451            if filter_completions {
 5452                menu.filter(query.clone(), provider.clone(), window, cx);
 5453            }
 5454            // When `is_incomplete` is false, no need to re-query completions when the current query
 5455            // is a suffix of the initial query.
 5456            if !menu.is_incomplete {
 5457                // If the new query is a suffix of the old query (typing more characters) and
 5458                // the previous result was complete, the existing completions can be filtered.
 5459                //
 5460                // Note that this is always true for snippet completions.
 5461                let query_matches = match (&menu.initial_query, &query) {
 5462                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5463                    (None, _) => true,
 5464                    _ => false,
 5465                };
 5466                if query_matches {
 5467                    let position_matches = if menu.initial_position == position {
 5468                        true
 5469                    } else {
 5470                        let snapshot = self.buffer.read(cx).read(cx);
 5471                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5472                    };
 5473                    if position_matches {
 5474                        return;
 5475                    }
 5476                }
 5477            }
 5478        };
 5479
 5480        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5481            buffer_snapshot.surrounding_word(buffer_position, false)
 5482        {
 5483            let word_to_exclude = buffer_snapshot
 5484                .text_for_range(word_range.clone())
 5485                .collect::<String>();
 5486            (
 5487                buffer_snapshot.anchor_before(word_range.start)
 5488                    ..buffer_snapshot.anchor_after(buffer_position),
 5489                Some(word_to_exclude),
 5490            )
 5491        } else {
 5492            (buffer_position..buffer_position, None)
 5493        };
 5494
 5495        let language = buffer_snapshot
 5496            .language_at(buffer_position)
 5497            .map(|language| language.name());
 5498
 5499        let completion_settings =
 5500            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5501
 5502        let show_completion_documentation = buffer_snapshot
 5503            .settings_at(buffer_position, cx)
 5504            .show_completion_documentation;
 5505
 5506        // The document can be large, so stay in reasonable bounds when searching for words,
 5507        // otherwise completion pop-up might be slow to appear.
 5508        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5509        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5510        let min_word_search = buffer_snapshot.clip_point(
 5511            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5512            Bias::Left,
 5513        );
 5514        let max_word_search = buffer_snapshot.clip_point(
 5515            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5516            Bias::Right,
 5517        );
 5518        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5519            ..buffer_snapshot.point_to_offset(max_word_search);
 5520
 5521        let skip_digits = query
 5522            .as_ref()
 5523            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5524
 5525        let (mut words, provider_responses) = match &provider {
 5526            Some(provider) => {
 5527                let provider_responses = provider.completions(
 5528                    position.excerpt_id,
 5529                    &buffer,
 5530                    buffer_position,
 5531                    completion_context,
 5532                    window,
 5533                    cx,
 5534                );
 5535
 5536                let words = match completion_settings.words {
 5537                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5538                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5539                        .background_spawn(async move {
 5540                            buffer_snapshot.words_in_range(WordsQuery {
 5541                                fuzzy_contents: None,
 5542                                range: word_search_range,
 5543                                skip_digits,
 5544                            })
 5545                        }),
 5546                };
 5547
 5548                (words, provider_responses)
 5549            }
 5550            None => (
 5551                cx.background_spawn(async move {
 5552                    buffer_snapshot.words_in_range(WordsQuery {
 5553                        fuzzy_contents: None,
 5554                        range: word_search_range,
 5555                        skip_digits,
 5556                    })
 5557                }),
 5558                Task::ready(Ok(Vec::new())),
 5559            ),
 5560        };
 5561
 5562        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5563
 5564        let id = post_inc(&mut self.next_completion_id);
 5565        let task = cx.spawn_in(window, async move |editor, cx| {
 5566            let Ok(()) = editor.update(cx, |this, _| {
 5567                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5568            }) else {
 5569                return;
 5570            };
 5571
 5572            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5573            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5574            let mut completions = Vec::new();
 5575            let mut is_incomplete = false;
 5576            if let Some(provider_responses) = provider_responses.await.log_err()
 5577                && !provider_responses.is_empty()
 5578            {
 5579                for response in provider_responses {
 5580                    completions.extend(response.completions);
 5581                    is_incomplete = is_incomplete || response.is_incomplete;
 5582                }
 5583                if completion_settings.words == WordsCompletionMode::Fallback {
 5584                    words = Task::ready(BTreeMap::default());
 5585                }
 5586            }
 5587
 5588            let mut words = words.await;
 5589            if let Some(word_to_exclude) = &word_to_exclude {
 5590                words.remove(word_to_exclude);
 5591            }
 5592            for lsp_completion in &completions {
 5593                words.remove(&lsp_completion.new_text);
 5594            }
 5595            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5596                replace_range: word_replace_range.clone(),
 5597                new_text: word.clone(),
 5598                label: CodeLabel::plain(word, None),
 5599                icon_path: None,
 5600                documentation: None,
 5601                source: CompletionSource::BufferWord {
 5602                    word_range,
 5603                    resolved: false,
 5604                },
 5605                insert_text_mode: Some(InsertTextMode::AS_IS),
 5606                confirm: None,
 5607            }));
 5608
 5609            let menu = if completions.is_empty() {
 5610                None
 5611            } else {
 5612                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5613                    let languages = editor
 5614                        .workspace
 5615                        .as_ref()
 5616                        .and_then(|(workspace, _)| workspace.upgrade())
 5617                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5618                    let menu = CompletionsMenu::new(
 5619                        id,
 5620                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5621                        sort_completions,
 5622                        show_completion_documentation,
 5623                        position,
 5624                        query.clone(),
 5625                        is_incomplete,
 5626                        buffer.clone(),
 5627                        completions.into(),
 5628                        snippet_sort_order,
 5629                        languages,
 5630                        language,
 5631                        cx,
 5632                    );
 5633
 5634                    let query = if filter_completions { query } else { None };
 5635                    let matches_task = if let Some(query) = query {
 5636                        menu.do_async_filtering(query, cx)
 5637                    } else {
 5638                        Task::ready(menu.unfiltered_matches())
 5639                    };
 5640                    (menu, matches_task)
 5641                }) else {
 5642                    return;
 5643                };
 5644
 5645                let matches = matches_task.await;
 5646
 5647                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5648                    // Newer menu already set, so exit.
 5649                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5650                        editor.context_menu.borrow().as_ref()
 5651                        && prev_menu.id > id
 5652                    {
 5653                        return;
 5654                    };
 5655
 5656                    // Only valid to take prev_menu because it the new menu is immediately set
 5657                    // below, or the menu is hidden.
 5658                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5659                        editor.context_menu.borrow_mut().take()
 5660                    {
 5661                        let position_matches =
 5662                            if prev_menu.initial_position == menu.initial_position {
 5663                                true
 5664                            } else {
 5665                                let snapshot = editor.buffer.read(cx).read(cx);
 5666                                prev_menu.initial_position.to_offset(&snapshot)
 5667                                    == menu.initial_position.to_offset(&snapshot)
 5668                            };
 5669                        if position_matches {
 5670                            // Preserve markdown cache before `set_filter_results` because it will
 5671                            // try to populate the documentation cache.
 5672                            menu.preserve_markdown_cache(prev_menu);
 5673                        }
 5674                    };
 5675
 5676                    menu.set_filter_results(matches, provider, window, cx);
 5677                }) else {
 5678                    return;
 5679                };
 5680
 5681                menu.visible().then_some(menu)
 5682            };
 5683
 5684            editor
 5685                .update_in(cx, |editor, window, cx| {
 5686                    if editor.focus_handle.is_focused(window)
 5687                        && let Some(menu) = menu
 5688                    {
 5689                        *editor.context_menu.borrow_mut() =
 5690                            Some(CodeContextMenu::Completions(menu));
 5691
 5692                        crate::hover_popover::hide_hover(editor, cx);
 5693                        if editor.show_edit_predictions_in_menu() {
 5694                            editor.update_visible_edit_prediction(window, cx);
 5695                        } else {
 5696                            editor.discard_edit_prediction(false, cx);
 5697                        }
 5698
 5699                        cx.notify();
 5700                        return;
 5701                    }
 5702
 5703                    if editor.completion_tasks.len() <= 1 {
 5704                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5705                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5706                        // If it was already hidden and we don't show edit predictions in the menu,
 5707                        // we should also show the edit prediction when available.
 5708                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5709                            editor.update_visible_edit_prediction(window, cx);
 5710                        }
 5711                    }
 5712                })
 5713                .ok();
 5714        });
 5715
 5716        self.completion_tasks.push((id, task));
 5717    }
 5718
 5719    #[cfg(feature = "test-support")]
 5720    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5721        let menu = self.context_menu.borrow();
 5722        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5723            let completions = menu.completions.borrow();
 5724            Some(completions.to_vec())
 5725        } else {
 5726            None
 5727        }
 5728    }
 5729
 5730    pub fn with_completions_menu_matching_id<R>(
 5731        &self,
 5732        id: CompletionId,
 5733        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5734    ) -> R {
 5735        let mut context_menu = self.context_menu.borrow_mut();
 5736        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5737            return f(None);
 5738        };
 5739        if completions_menu.id != id {
 5740            return f(None);
 5741        }
 5742        f(Some(completions_menu))
 5743    }
 5744
 5745    pub fn confirm_completion(
 5746        &mut self,
 5747        action: &ConfirmCompletion,
 5748        window: &mut Window,
 5749        cx: &mut Context<Self>,
 5750    ) -> Option<Task<Result<()>>> {
 5751        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5752        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5753    }
 5754
 5755    pub fn confirm_completion_insert(
 5756        &mut self,
 5757        _: &ConfirmCompletionInsert,
 5758        window: &mut Window,
 5759        cx: &mut Context<Self>,
 5760    ) -> Option<Task<Result<()>>> {
 5761        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5762        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5763    }
 5764
 5765    pub fn confirm_completion_replace(
 5766        &mut self,
 5767        _: &ConfirmCompletionReplace,
 5768        window: &mut Window,
 5769        cx: &mut Context<Self>,
 5770    ) -> Option<Task<Result<()>>> {
 5771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5772        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5773    }
 5774
 5775    pub fn compose_completion(
 5776        &mut self,
 5777        action: &ComposeCompletion,
 5778        window: &mut Window,
 5779        cx: &mut Context<Self>,
 5780    ) -> Option<Task<Result<()>>> {
 5781        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5782        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5783    }
 5784
 5785    fn do_completion(
 5786        &mut self,
 5787        item_ix: Option<usize>,
 5788        intent: CompletionIntent,
 5789        window: &mut Window,
 5790        cx: &mut Context<Editor>,
 5791    ) -> Option<Task<Result<()>>> {
 5792        use language::ToOffset as _;
 5793
 5794        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5795        else {
 5796            return None;
 5797        };
 5798
 5799        let candidate_id = {
 5800            let entries = completions_menu.entries.borrow();
 5801            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5802            if self.show_edit_predictions_in_menu() {
 5803                self.discard_edit_prediction(true, cx);
 5804            }
 5805            mat.candidate_id
 5806        };
 5807
 5808        let completion = completions_menu
 5809            .completions
 5810            .borrow()
 5811            .get(candidate_id)?
 5812            .clone();
 5813        cx.stop_propagation();
 5814
 5815        let buffer_handle = completions_menu.buffer.clone();
 5816
 5817        let CompletionEdit {
 5818            new_text,
 5819            snippet,
 5820            replace_range,
 5821        } = process_completion_for_edit(
 5822            &completion,
 5823            intent,
 5824            &buffer_handle,
 5825            &completions_menu.initial_position.text_anchor,
 5826            cx,
 5827        );
 5828
 5829        let buffer = buffer_handle.read(cx);
 5830        let snapshot = self.buffer.read(cx).snapshot(cx);
 5831        let newest_anchor = self.selections.newest_anchor();
 5832        let replace_range_multibuffer = {
 5833            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5834            let multibuffer_anchor = snapshot
 5835                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5836                .unwrap()
 5837                ..snapshot
 5838                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5839                    .unwrap();
 5840            multibuffer_anchor.start.to_offset(&snapshot)
 5841                ..multibuffer_anchor.end.to_offset(&snapshot)
 5842        };
 5843        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5844            return None;
 5845        }
 5846
 5847        let old_text = buffer
 5848            .text_for_range(replace_range.clone())
 5849            .collect::<String>();
 5850        let lookbehind = newest_anchor
 5851            .start
 5852            .text_anchor
 5853            .to_offset(buffer)
 5854            .saturating_sub(replace_range.start);
 5855        let lookahead = replace_range
 5856            .end
 5857            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5858        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5859        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5860
 5861        let selections = self.selections.all::<usize>(cx);
 5862        let mut ranges = Vec::new();
 5863        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5864
 5865        for selection in &selections {
 5866            let range = if selection.id == newest_anchor.id {
 5867                replace_range_multibuffer.clone()
 5868            } else {
 5869                let mut range = selection.range();
 5870
 5871                // if prefix is present, don't duplicate it
 5872                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5873                    range.start = range.start.saturating_sub(lookbehind);
 5874
 5875                    // if suffix is also present, mimic the newest cursor and replace it
 5876                    if selection.id != newest_anchor.id
 5877                        && snapshot.contains_str_at(range.end, suffix)
 5878                    {
 5879                        range.end += lookahead;
 5880                    }
 5881                }
 5882                range
 5883            };
 5884
 5885            ranges.push(range.clone());
 5886
 5887            if !self.linked_edit_ranges.is_empty() {
 5888                let start_anchor = snapshot.anchor_before(range.start);
 5889                let end_anchor = snapshot.anchor_after(range.end);
 5890                if let Some(ranges) = self
 5891                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5892                {
 5893                    for (buffer, edits) in ranges {
 5894                        linked_edits
 5895                            .entry(buffer.clone())
 5896                            .or_default()
 5897                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5898                    }
 5899                }
 5900            }
 5901        }
 5902
 5903        let common_prefix_len = old_text
 5904            .chars()
 5905            .zip(new_text.chars())
 5906            .take_while(|(a, b)| a == b)
 5907            .map(|(a, _)| a.len_utf8())
 5908            .sum::<usize>();
 5909
 5910        cx.emit(EditorEvent::InputHandled {
 5911            utf16_range_to_replace: None,
 5912            text: new_text[common_prefix_len..].into(),
 5913        });
 5914
 5915        self.transact(window, cx, |editor, window, cx| {
 5916            if let Some(mut snippet) = snippet {
 5917                snippet.text = new_text.to_string();
 5918                editor
 5919                    .insert_snippet(&ranges, snippet, window, cx)
 5920                    .log_err();
 5921            } else {
 5922                editor.buffer.update(cx, |multi_buffer, cx| {
 5923                    let auto_indent = match completion.insert_text_mode {
 5924                        Some(InsertTextMode::AS_IS) => None,
 5925                        _ => editor.autoindent_mode.clone(),
 5926                    };
 5927                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5928                    multi_buffer.edit(edits, auto_indent, cx);
 5929                });
 5930            }
 5931            for (buffer, edits) in linked_edits {
 5932                buffer.update(cx, |buffer, cx| {
 5933                    let snapshot = buffer.snapshot();
 5934                    let edits = edits
 5935                        .into_iter()
 5936                        .map(|(range, text)| {
 5937                            use text::ToPoint as TP;
 5938                            let end_point = TP::to_point(&range.end, &snapshot);
 5939                            let start_point = TP::to_point(&range.start, &snapshot);
 5940                            (start_point..end_point, text)
 5941                        })
 5942                        .sorted_by_key(|(range, _)| range.start);
 5943                    buffer.edit(edits, None, cx);
 5944                })
 5945            }
 5946
 5947            editor.refresh_edit_prediction(true, false, window, cx);
 5948        });
 5949        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5950
 5951        let show_new_completions_on_confirm = completion
 5952            .confirm
 5953            .as_ref()
 5954            .is_some_and(|confirm| confirm(intent, window, cx));
 5955        if show_new_completions_on_confirm {
 5956            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5957        }
 5958
 5959        let provider = self.completion_provider.as_ref()?;
 5960        drop(completion);
 5961        let apply_edits = provider.apply_additional_edits_for_completion(
 5962            buffer_handle,
 5963            completions_menu.completions.clone(),
 5964            candidate_id,
 5965            true,
 5966            cx,
 5967        );
 5968
 5969        let editor_settings = EditorSettings::get_global(cx);
 5970        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5971            // After the code completion is finished, users often want to know what signatures are needed.
 5972            // so we should automatically call signature_help
 5973            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5974        }
 5975
 5976        Some(cx.foreground_executor().spawn(async move {
 5977            apply_edits.await?;
 5978            Ok(())
 5979        }))
 5980    }
 5981
 5982    pub fn toggle_code_actions(
 5983        &mut self,
 5984        action: &ToggleCodeActions,
 5985        window: &mut Window,
 5986        cx: &mut Context<Self>,
 5987    ) {
 5988        let quick_launch = action.quick_launch;
 5989        let mut context_menu = self.context_menu.borrow_mut();
 5990        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5991            if code_actions.deployed_from == action.deployed_from {
 5992                // Toggle if we're selecting the same one
 5993                *context_menu = None;
 5994                cx.notify();
 5995                return;
 5996            } else {
 5997                // Otherwise, clear it and start a new one
 5998                *context_menu = None;
 5999                cx.notify();
 6000            }
 6001        }
 6002        drop(context_menu);
 6003        let snapshot = self.snapshot(window, cx);
 6004        let deployed_from = action.deployed_from.clone();
 6005        let action = action.clone();
 6006        self.completion_tasks.clear();
 6007        self.discard_edit_prediction(false, cx);
 6008
 6009        let multibuffer_point = match &action.deployed_from {
 6010            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6011                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6012            }
 6013            _ => self.selections.newest::<Point>(cx).head(),
 6014        };
 6015        let Some((buffer, buffer_row)) = snapshot
 6016            .buffer_snapshot
 6017            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6018            .and_then(|(buffer_snapshot, range)| {
 6019                self.buffer()
 6020                    .read(cx)
 6021                    .buffer(buffer_snapshot.remote_id())
 6022                    .map(|buffer| (buffer, range.start.row))
 6023            })
 6024        else {
 6025            return;
 6026        };
 6027        let buffer_id = buffer.read(cx).remote_id();
 6028        let tasks = self
 6029            .tasks
 6030            .get(&(buffer_id, buffer_row))
 6031            .map(|t| Arc::new(t.to_owned()));
 6032
 6033        if !self.focus_handle.is_focused(window) {
 6034            return;
 6035        }
 6036        let project = self.project.clone();
 6037
 6038        let code_actions_task = match deployed_from {
 6039            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6040            _ => self.code_actions(buffer_row, window, cx),
 6041        };
 6042
 6043        let runnable_task = match deployed_from {
 6044            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6045            _ => {
 6046                let mut task_context_task = Task::ready(None);
 6047                if let Some(tasks) = &tasks
 6048                    && let Some(project) = project
 6049                {
 6050                    task_context_task =
 6051                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6052                }
 6053
 6054                cx.spawn_in(window, {
 6055                    let buffer = buffer.clone();
 6056                    async move |editor, cx| {
 6057                        let task_context = task_context_task.await;
 6058
 6059                        let resolved_tasks =
 6060                            tasks
 6061                                .zip(task_context.clone())
 6062                                .map(|(tasks, task_context)| ResolvedTasks {
 6063                                    templates: tasks.resolve(&task_context).collect(),
 6064                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6065                                        multibuffer_point.row,
 6066                                        tasks.column,
 6067                                    )),
 6068                                });
 6069                        let debug_scenarios = editor
 6070                            .update(cx, |editor, cx| {
 6071                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6072                            })?
 6073                            .await;
 6074                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6075                    }
 6076                })
 6077            }
 6078        };
 6079
 6080        cx.spawn_in(window, async move |editor, cx| {
 6081            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6082            let code_actions = code_actions_task.await;
 6083            let spawn_straight_away = quick_launch
 6084                && resolved_tasks
 6085                    .as_ref()
 6086                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6087                && code_actions
 6088                    .as_ref()
 6089                    .is_none_or(|actions| actions.is_empty())
 6090                && debug_scenarios.is_empty();
 6091
 6092            editor.update_in(cx, |editor, window, cx| {
 6093                crate::hover_popover::hide_hover(editor, cx);
 6094                let actions = CodeActionContents::new(
 6095                    resolved_tasks,
 6096                    code_actions,
 6097                    debug_scenarios,
 6098                    task_context.unwrap_or_default(),
 6099                );
 6100
 6101                // Don't show the menu if there are no actions available
 6102                if actions.is_empty() {
 6103                    cx.notify();
 6104                    return Task::ready(Ok(()));
 6105                }
 6106
 6107                *editor.context_menu.borrow_mut() =
 6108                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6109                        buffer,
 6110                        actions,
 6111                        selected_item: Default::default(),
 6112                        scroll_handle: UniformListScrollHandle::default(),
 6113                        deployed_from,
 6114                    }));
 6115                cx.notify();
 6116                if spawn_straight_away
 6117                    && let Some(task) = editor.confirm_code_action(
 6118                        &ConfirmCodeAction { item_ix: Some(0) },
 6119                        window,
 6120                        cx,
 6121                    )
 6122                {
 6123                    return task;
 6124                }
 6125
 6126                Task::ready(Ok(()))
 6127            })
 6128        })
 6129        .detach_and_log_err(cx);
 6130    }
 6131
 6132    fn debug_scenarios(
 6133        &mut self,
 6134        resolved_tasks: &Option<ResolvedTasks>,
 6135        buffer: &Entity<Buffer>,
 6136        cx: &mut App,
 6137    ) -> Task<Vec<task::DebugScenario>> {
 6138        maybe!({
 6139            let project = self.project()?;
 6140            let dap_store = project.read(cx).dap_store();
 6141            let mut scenarios = vec![];
 6142            let resolved_tasks = resolved_tasks.as_ref()?;
 6143            let buffer = buffer.read(cx);
 6144            let language = buffer.language()?;
 6145            let file = buffer.file();
 6146            let debug_adapter = language_settings(language.name().into(), file, cx)
 6147                .debuggers
 6148                .first()
 6149                .map(SharedString::from)
 6150                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6151
 6152            dap_store.update(cx, |dap_store, cx| {
 6153                for (_, task) in &resolved_tasks.templates {
 6154                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6155                        task.original_task().clone(),
 6156                        debug_adapter.clone().into(),
 6157                        task.display_label().to_owned().into(),
 6158                        cx,
 6159                    );
 6160                    scenarios.push(maybe_scenario);
 6161                }
 6162            });
 6163            Some(cx.background_spawn(async move {
 6164                futures::future::join_all(scenarios)
 6165                    .await
 6166                    .into_iter()
 6167                    .flatten()
 6168                    .collect::<Vec<_>>()
 6169            }))
 6170        })
 6171        .unwrap_or_else(|| Task::ready(vec![]))
 6172    }
 6173
 6174    fn code_actions(
 6175        &mut self,
 6176        buffer_row: u32,
 6177        window: &mut Window,
 6178        cx: &mut Context<Self>,
 6179    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6180        let mut task = self.code_actions_task.take();
 6181        cx.spawn_in(window, async move |editor, cx| {
 6182            while let Some(prev_task) = task {
 6183                prev_task.await.log_err();
 6184                task = editor
 6185                    .update(cx, |this, _| this.code_actions_task.take())
 6186                    .ok()?;
 6187            }
 6188
 6189            editor
 6190                .update(cx, |editor, cx| {
 6191                    editor
 6192                        .available_code_actions
 6193                        .clone()
 6194                        .and_then(|(location, code_actions)| {
 6195                            let snapshot = location.buffer.read(cx).snapshot();
 6196                            let point_range = location.range.to_point(&snapshot);
 6197                            let point_range = point_range.start.row..=point_range.end.row;
 6198                            if point_range.contains(&buffer_row) {
 6199                                Some(code_actions)
 6200                            } else {
 6201                                None
 6202                            }
 6203                        })
 6204                })
 6205                .ok()
 6206                .flatten()
 6207        })
 6208    }
 6209
 6210    pub fn confirm_code_action(
 6211        &mut self,
 6212        action: &ConfirmCodeAction,
 6213        window: &mut Window,
 6214        cx: &mut Context<Self>,
 6215    ) -> Option<Task<Result<()>>> {
 6216        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6217
 6218        let actions_menu =
 6219            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6220                menu
 6221            } else {
 6222                return None;
 6223            };
 6224
 6225        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6226        let action = actions_menu.actions.get(action_ix)?;
 6227        let title = action.label();
 6228        let buffer = actions_menu.buffer;
 6229        let workspace = self.workspace()?;
 6230
 6231        match action {
 6232            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6233                workspace.update(cx, |workspace, cx| {
 6234                    workspace.schedule_resolved_task(
 6235                        task_source_kind,
 6236                        resolved_task,
 6237                        false,
 6238                        window,
 6239                        cx,
 6240                    );
 6241
 6242                    Some(Task::ready(Ok(())))
 6243                })
 6244            }
 6245            CodeActionsItem::CodeAction {
 6246                excerpt_id,
 6247                action,
 6248                provider,
 6249            } => {
 6250                let apply_code_action =
 6251                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6252                let workspace = workspace.downgrade();
 6253                Some(cx.spawn_in(window, async move |editor, cx| {
 6254                    let project_transaction = apply_code_action.await?;
 6255                    Self::open_project_transaction(
 6256                        &editor,
 6257                        workspace,
 6258                        project_transaction,
 6259                        title,
 6260                        cx,
 6261                    )
 6262                    .await
 6263                }))
 6264            }
 6265            CodeActionsItem::DebugScenario(scenario) => {
 6266                let context = actions_menu.actions.context;
 6267
 6268                workspace.update(cx, |workspace, cx| {
 6269                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6270                    workspace.start_debug_session(
 6271                        scenario,
 6272                        context,
 6273                        Some(buffer),
 6274                        None,
 6275                        window,
 6276                        cx,
 6277                    );
 6278                });
 6279                Some(Task::ready(Ok(())))
 6280            }
 6281        }
 6282    }
 6283
 6284    pub async fn open_project_transaction(
 6285        this: &WeakEntity<Editor>,
 6286        workspace: WeakEntity<Workspace>,
 6287        transaction: ProjectTransaction,
 6288        title: String,
 6289        cx: &mut AsyncWindowContext,
 6290    ) -> Result<()> {
 6291        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6292        cx.update(|_, cx| {
 6293            entries.sort_unstable_by_key(|(buffer, _)| {
 6294                buffer.read(cx).file().map(|f| f.path().clone())
 6295            });
 6296        })?;
 6297
 6298        // If the project transaction's edits are all contained within this editor, then
 6299        // avoid opening a new editor to display them.
 6300
 6301        if let Some((buffer, transaction)) = entries.first() {
 6302            if entries.len() == 1 {
 6303                let excerpt = this.update(cx, |editor, cx| {
 6304                    editor
 6305                        .buffer()
 6306                        .read(cx)
 6307                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6308                })?;
 6309                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6310                    && excerpted_buffer == *buffer
 6311                {
 6312                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6313                        let excerpt_range = excerpt_range.to_offset(buffer);
 6314                        buffer
 6315                            .edited_ranges_for_transaction::<usize>(transaction)
 6316                            .all(|range| {
 6317                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6318                            })
 6319                    })?;
 6320
 6321                    if all_edits_within_excerpt {
 6322                        return Ok(());
 6323                    }
 6324                }
 6325            }
 6326        } else {
 6327            return Ok(());
 6328        }
 6329
 6330        let mut ranges_to_highlight = Vec::new();
 6331        let excerpt_buffer = cx.new(|cx| {
 6332            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6333            for (buffer_handle, transaction) in &entries {
 6334                let edited_ranges = buffer_handle
 6335                    .read(cx)
 6336                    .edited_ranges_for_transaction::<Point>(transaction)
 6337                    .collect::<Vec<_>>();
 6338                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6339                    PathKey::for_buffer(buffer_handle, cx),
 6340                    buffer_handle.clone(),
 6341                    edited_ranges,
 6342                    DEFAULT_MULTIBUFFER_CONTEXT,
 6343                    cx,
 6344                );
 6345
 6346                ranges_to_highlight.extend(ranges);
 6347            }
 6348            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6349            multibuffer
 6350        })?;
 6351
 6352        workspace.update_in(cx, |workspace, window, cx| {
 6353            let project = workspace.project().clone();
 6354            let editor =
 6355                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6356            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6357            editor.update(cx, |editor, cx| {
 6358                editor.highlight_background::<Self>(
 6359                    &ranges_to_highlight,
 6360                    |theme| theme.colors().editor_highlighted_line_background,
 6361                    cx,
 6362                );
 6363            });
 6364        })?;
 6365
 6366        Ok(())
 6367    }
 6368
 6369    pub fn clear_code_action_providers(&mut self) {
 6370        self.code_action_providers.clear();
 6371        self.available_code_actions.take();
 6372    }
 6373
 6374    pub fn add_code_action_provider(
 6375        &mut self,
 6376        provider: Rc<dyn CodeActionProvider>,
 6377        window: &mut Window,
 6378        cx: &mut Context<Self>,
 6379    ) {
 6380        if self
 6381            .code_action_providers
 6382            .iter()
 6383            .any(|existing_provider| existing_provider.id() == provider.id())
 6384        {
 6385            return;
 6386        }
 6387
 6388        self.code_action_providers.push(provider);
 6389        self.refresh_code_actions(window, cx);
 6390    }
 6391
 6392    pub fn remove_code_action_provider(
 6393        &mut self,
 6394        id: Arc<str>,
 6395        window: &mut Window,
 6396        cx: &mut Context<Self>,
 6397    ) {
 6398        self.code_action_providers
 6399            .retain(|provider| provider.id() != id);
 6400        self.refresh_code_actions(window, cx);
 6401    }
 6402
 6403    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6404        !self.code_action_providers.is_empty()
 6405            && EditorSettings::get_global(cx).toolbar.code_actions
 6406    }
 6407
 6408    pub fn has_available_code_actions(&self) -> bool {
 6409        self.available_code_actions
 6410            .as_ref()
 6411            .is_some_and(|(_, actions)| !actions.is_empty())
 6412    }
 6413
 6414    fn render_inline_code_actions(
 6415        &self,
 6416        icon_size: ui::IconSize,
 6417        display_row: DisplayRow,
 6418        is_active: bool,
 6419        cx: &mut Context<Self>,
 6420    ) -> AnyElement {
 6421        let show_tooltip = !self.context_menu_visible();
 6422        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6423            .icon_size(icon_size)
 6424            .shape(ui::IconButtonShape::Square)
 6425            .icon_color(ui::Color::Hidden)
 6426            .toggle_state(is_active)
 6427            .when(show_tooltip, |this| {
 6428                this.tooltip({
 6429                    let focus_handle = self.focus_handle.clone();
 6430                    move |window, cx| {
 6431                        Tooltip::for_action_in(
 6432                            "Toggle Code Actions",
 6433                            &ToggleCodeActions {
 6434                                deployed_from: None,
 6435                                quick_launch: false,
 6436                            },
 6437                            &focus_handle,
 6438                            window,
 6439                            cx,
 6440                        )
 6441                    }
 6442                })
 6443            })
 6444            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6445                window.focus(&editor.focus_handle(cx));
 6446                editor.toggle_code_actions(
 6447                    &crate::actions::ToggleCodeActions {
 6448                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6449                            display_row,
 6450                        )),
 6451                        quick_launch: false,
 6452                    },
 6453                    window,
 6454                    cx,
 6455                );
 6456            }))
 6457            .into_any_element()
 6458    }
 6459
 6460    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6461        &self.context_menu
 6462    }
 6463
 6464    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6465        let newest_selection = self.selections.newest_anchor().clone();
 6466        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6467        let buffer = self.buffer.read(cx);
 6468        if newest_selection.head().diff_base_anchor.is_some() {
 6469            return None;
 6470        }
 6471        let (start_buffer, start) =
 6472            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6473        let (end_buffer, end) =
 6474            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6475        if start_buffer != end_buffer {
 6476            return None;
 6477        }
 6478
 6479        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6480            cx.background_executor()
 6481                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6482                .await;
 6483
 6484            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6485                let providers = this.code_action_providers.clone();
 6486                let tasks = this
 6487                    .code_action_providers
 6488                    .iter()
 6489                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6490                    .collect::<Vec<_>>();
 6491                (providers, tasks)
 6492            })?;
 6493
 6494            let mut actions = Vec::new();
 6495            for (provider, provider_actions) in
 6496                providers.into_iter().zip(future::join_all(tasks).await)
 6497            {
 6498                if let Some(provider_actions) = provider_actions.log_err() {
 6499                    actions.extend(provider_actions.into_iter().map(|action| {
 6500                        AvailableCodeAction {
 6501                            excerpt_id: newest_selection.start.excerpt_id,
 6502                            action,
 6503                            provider: provider.clone(),
 6504                        }
 6505                    }));
 6506                }
 6507            }
 6508
 6509            this.update(cx, |this, cx| {
 6510                this.available_code_actions = if actions.is_empty() {
 6511                    None
 6512                } else {
 6513                    Some((
 6514                        Location {
 6515                            buffer: start_buffer,
 6516                            range: start..end,
 6517                        },
 6518                        actions.into(),
 6519                    ))
 6520                };
 6521                cx.notify();
 6522            })
 6523        }));
 6524        None
 6525    }
 6526
 6527    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6528        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6529            self.show_git_blame_inline = false;
 6530
 6531            self.show_git_blame_inline_delay_task =
 6532                Some(cx.spawn_in(window, async move |this, cx| {
 6533                    cx.background_executor().timer(delay).await;
 6534
 6535                    this.update(cx, |this, cx| {
 6536                        this.show_git_blame_inline = true;
 6537                        cx.notify();
 6538                    })
 6539                    .log_err();
 6540                }));
 6541        }
 6542    }
 6543
 6544    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6545        let snapshot = self.snapshot(window, cx);
 6546        let cursor = self.selections.newest::<Point>(cx).head();
 6547        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6548        else {
 6549            return;
 6550        };
 6551
 6552        let Some(blame) = self.blame.as_ref() else {
 6553            return;
 6554        };
 6555
 6556        let row_info = RowInfo {
 6557            buffer_id: Some(buffer.remote_id()),
 6558            buffer_row: Some(point.row),
 6559            ..Default::default()
 6560        };
 6561        let Some(blame_entry) = blame
 6562            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6563            .flatten()
 6564        else {
 6565            return;
 6566        };
 6567
 6568        let anchor = self.selections.newest_anchor().head();
 6569        let position = self.to_pixel_point(anchor, &snapshot, window);
 6570        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6571            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6572        };
 6573    }
 6574
 6575    fn show_blame_popover(
 6576        &mut self,
 6577        blame_entry: &BlameEntry,
 6578        position: gpui::Point<Pixels>,
 6579        ignore_timeout: bool,
 6580        cx: &mut Context<Self>,
 6581    ) {
 6582        if let Some(state) = &mut self.inline_blame_popover {
 6583            state.hide_task.take();
 6584        } else {
 6585            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6586            let blame_entry = blame_entry.clone();
 6587            let show_task = cx.spawn(async move |editor, cx| {
 6588                if !ignore_timeout {
 6589                    cx.background_executor()
 6590                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6591                        .await;
 6592                }
 6593                editor
 6594                    .update(cx, |editor, cx| {
 6595                        editor.inline_blame_popover_show_task.take();
 6596                        let Some(blame) = editor.blame.as_ref() else {
 6597                            return;
 6598                        };
 6599                        let blame = blame.read(cx);
 6600                        let details = blame.details_for_entry(&blame_entry);
 6601                        let markdown = cx.new(|cx| {
 6602                            Markdown::new(
 6603                                details
 6604                                    .as_ref()
 6605                                    .map(|message| message.message.clone())
 6606                                    .unwrap_or_default(),
 6607                                None,
 6608                                None,
 6609                                cx,
 6610                            )
 6611                        });
 6612                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6613                            position,
 6614                            hide_task: None,
 6615                            popover_bounds: None,
 6616                            popover_state: InlineBlamePopoverState {
 6617                                scroll_handle: ScrollHandle::new(),
 6618                                commit_message: details,
 6619                                markdown,
 6620                            },
 6621                            keyboard_grace: ignore_timeout,
 6622                        });
 6623                        cx.notify();
 6624                    })
 6625                    .ok();
 6626            });
 6627            self.inline_blame_popover_show_task = Some(show_task);
 6628        }
 6629    }
 6630
 6631    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6632        self.inline_blame_popover_show_task.take();
 6633        if let Some(state) = &mut self.inline_blame_popover {
 6634            let hide_task = cx.spawn(async move |editor, cx| {
 6635                cx.background_executor()
 6636                    .timer(std::time::Duration::from_millis(100))
 6637                    .await;
 6638                editor
 6639                    .update(cx, |editor, cx| {
 6640                        editor.inline_blame_popover.take();
 6641                        cx.notify();
 6642                    })
 6643                    .ok();
 6644            });
 6645            state.hide_task = Some(hide_task);
 6646        }
 6647    }
 6648
 6649    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6650        if self.pending_rename.is_some() {
 6651            return None;
 6652        }
 6653
 6654        let provider = self.semantics_provider.clone()?;
 6655        let buffer = self.buffer.read(cx);
 6656        let newest_selection = self.selections.newest_anchor().clone();
 6657        let cursor_position = newest_selection.head();
 6658        let (cursor_buffer, cursor_buffer_position) =
 6659            buffer.text_anchor_for_position(cursor_position, cx)?;
 6660        let (tail_buffer, tail_buffer_position) =
 6661            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6662        if cursor_buffer != tail_buffer {
 6663            return None;
 6664        }
 6665
 6666        let snapshot = cursor_buffer.read(cx).snapshot();
 6667        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6668        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6669        if start_word_range != end_word_range {
 6670            self.document_highlights_task.take();
 6671            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6672            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6673            return None;
 6674        }
 6675
 6676        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6677        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6678            cx.background_executor()
 6679                .timer(Duration::from_millis(debounce))
 6680                .await;
 6681
 6682            let highlights = if let Some(highlights) = cx
 6683                .update(|cx| {
 6684                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6685                })
 6686                .ok()
 6687                .flatten()
 6688            {
 6689                highlights.await.log_err()
 6690            } else {
 6691                None
 6692            };
 6693
 6694            if let Some(highlights) = highlights {
 6695                this.update(cx, |this, cx| {
 6696                    if this.pending_rename.is_some() {
 6697                        return;
 6698                    }
 6699
 6700                    let buffer_id = cursor_position.buffer_id;
 6701                    let buffer = this.buffer.read(cx);
 6702                    if buffer
 6703                        .text_anchor_for_position(cursor_position, cx)
 6704                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6705                    {
 6706                        return;
 6707                    }
 6708
 6709                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6710                    let mut write_ranges = Vec::new();
 6711                    let mut read_ranges = Vec::new();
 6712                    for highlight in highlights {
 6713                        for (excerpt_id, excerpt_range) in
 6714                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6715                        {
 6716                            let start = highlight
 6717                                .range
 6718                                .start
 6719                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6720                            let end = highlight
 6721                                .range
 6722                                .end
 6723                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6724                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6725                                continue;
 6726                            }
 6727
 6728                            let range = Anchor {
 6729                                buffer_id,
 6730                                excerpt_id,
 6731                                text_anchor: start,
 6732                                diff_base_anchor: None,
 6733                            }..Anchor {
 6734                                buffer_id,
 6735                                excerpt_id,
 6736                                text_anchor: end,
 6737                                diff_base_anchor: None,
 6738                            };
 6739                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6740                                write_ranges.push(range);
 6741                            } else {
 6742                                read_ranges.push(range);
 6743                            }
 6744                        }
 6745                    }
 6746
 6747                    this.highlight_background::<DocumentHighlightRead>(
 6748                        &read_ranges,
 6749                        |theme| theme.colors().editor_document_highlight_read_background,
 6750                        cx,
 6751                    );
 6752                    this.highlight_background::<DocumentHighlightWrite>(
 6753                        &write_ranges,
 6754                        |theme| theme.colors().editor_document_highlight_write_background,
 6755                        cx,
 6756                    );
 6757                    cx.notify();
 6758                })
 6759                .log_err();
 6760            }
 6761        }));
 6762        None
 6763    }
 6764
 6765    fn prepare_highlight_query_from_selection(
 6766        &mut self,
 6767        cx: &mut Context<Editor>,
 6768    ) -> Option<(String, Range<Anchor>)> {
 6769        if matches!(self.mode, EditorMode::SingleLine) {
 6770            return None;
 6771        }
 6772        if !EditorSettings::get_global(cx).selection_highlight {
 6773            return None;
 6774        }
 6775        if self.selections.count() != 1 || self.selections.line_mode {
 6776            return None;
 6777        }
 6778        let selection = self.selections.newest::<Point>(cx);
 6779        if selection.is_empty() || selection.start.row != selection.end.row {
 6780            return None;
 6781        }
 6782        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6783        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6784        let query = multi_buffer_snapshot
 6785            .text_for_range(selection_anchor_range.clone())
 6786            .collect::<String>();
 6787        if query.trim().is_empty() {
 6788            return None;
 6789        }
 6790        Some((query, selection_anchor_range))
 6791    }
 6792
 6793    fn update_selection_occurrence_highlights(
 6794        &mut self,
 6795        query_text: String,
 6796        query_range: Range<Anchor>,
 6797        multi_buffer_range_to_query: Range<Point>,
 6798        use_debounce: bool,
 6799        window: &mut Window,
 6800        cx: &mut Context<Editor>,
 6801    ) -> Task<()> {
 6802        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6803        cx.spawn_in(window, async move |editor, cx| {
 6804            if use_debounce {
 6805                cx.background_executor()
 6806                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6807                    .await;
 6808            }
 6809            let match_task = cx.background_spawn(async move {
 6810                let buffer_ranges = multi_buffer_snapshot
 6811                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6812                    .into_iter()
 6813                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6814                let mut match_ranges = Vec::new();
 6815                let Ok(regex) = project::search::SearchQuery::text(
 6816                    query_text.clone(),
 6817                    false,
 6818                    false,
 6819                    false,
 6820                    Default::default(),
 6821                    Default::default(),
 6822                    false,
 6823                    None,
 6824                ) else {
 6825                    return Vec::default();
 6826                };
 6827                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6828                    match_ranges.extend(
 6829                        regex
 6830                            .search(buffer_snapshot, Some(search_range.clone()))
 6831                            .await
 6832                            .into_iter()
 6833                            .filter_map(|match_range| {
 6834                                let match_start = buffer_snapshot
 6835                                    .anchor_after(search_range.start + match_range.start);
 6836                                let match_end = buffer_snapshot
 6837                                    .anchor_before(search_range.start + match_range.end);
 6838                                let match_anchor_range = Anchor::range_in_buffer(
 6839                                    excerpt_id,
 6840                                    buffer_snapshot.remote_id(),
 6841                                    match_start..match_end,
 6842                                );
 6843                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6844                            }),
 6845                    );
 6846                }
 6847                match_ranges
 6848            });
 6849            let match_ranges = match_task.await;
 6850            editor
 6851                .update_in(cx, |editor, _, cx| {
 6852                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6853                    if !match_ranges.is_empty() {
 6854                        editor.highlight_background::<SelectedTextHighlight>(
 6855                            &match_ranges,
 6856                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6857                            cx,
 6858                        )
 6859                    }
 6860                })
 6861                .log_err();
 6862        })
 6863    }
 6864
 6865    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6866        struct NewlineFold;
 6867        let type_id = std::any::TypeId::of::<NewlineFold>();
 6868        if !self.mode.is_single_line() {
 6869            return;
 6870        }
 6871        let snapshot = self.snapshot(window, cx);
 6872        if snapshot.buffer_snapshot.max_point().row == 0 {
 6873            return;
 6874        }
 6875        let task = cx.background_spawn(async move {
 6876            let new_newlines = snapshot
 6877                .buffer_chars_at(0)
 6878                .filter_map(|(c, i)| {
 6879                    if c == '\n' {
 6880                        Some(
 6881                            snapshot.buffer_snapshot.anchor_after(i)
 6882                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6883                        )
 6884                    } else {
 6885                        None
 6886                    }
 6887                })
 6888                .collect::<Vec<_>>();
 6889            let existing_newlines = snapshot
 6890                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6891                .filter_map(|fold| {
 6892                    if fold.placeholder.type_tag == Some(type_id) {
 6893                        Some(fold.range.start..fold.range.end)
 6894                    } else {
 6895                        None
 6896                    }
 6897                })
 6898                .collect::<Vec<_>>();
 6899
 6900            (new_newlines, existing_newlines)
 6901        });
 6902        self.folding_newlines = cx.spawn(async move |this, cx| {
 6903            let (new_newlines, existing_newlines) = task.await;
 6904            if new_newlines == existing_newlines {
 6905                return;
 6906            }
 6907            let placeholder = FoldPlaceholder {
 6908                render: Arc::new(move |_, _, cx| {
 6909                    div()
 6910                        .bg(cx.theme().status().hint_background)
 6911                        .border_b_1()
 6912                        .size_full()
 6913                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6914                        .border_color(cx.theme().status().hint)
 6915                        .child("\\n")
 6916                        .into_any()
 6917                }),
 6918                constrain_width: false,
 6919                merge_adjacent: false,
 6920                type_tag: Some(type_id),
 6921            };
 6922            let creases = new_newlines
 6923                .into_iter()
 6924                .map(|range| Crease::simple(range, placeholder.clone()))
 6925                .collect();
 6926            this.update(cx, |this, cx| {
 6927                this.display_map.update(cx, |display_map, cx| {
 6928                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6929                    display_map.fold(creases, cx);
 6930                });
 6931            })
 6932            .ok();
 6933        });
 6934    }
 6935
 6936    fn refresh_selected_text_highlights(
 6937        &mut self,
 6938        on_buffer_edit: bool,
 6939        window: &mut Window,
 6940        cx: &mut Context<Editor>,
 6941    ) {
 6942        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6943        else {
 6944            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6945            self.quick_selection_highlight_task.take();
 6946            self.debounced_selection_highlight_task.take();
 6947            return;
 6948        };
 6949        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6950        if on_buffer_edit
 6951            || self
 6952                .quick_selection_highlight_task
 6953                .as_ref()
 6954                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6955        {
 6956            let multi_buffer_visible_start = self
 6957                .scroll_manager
 6958                .anchor()
 6959                .anchor
 6960                .to_point(&multi_buffer_snapshot);
 6961            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6962                multi_buffer_visible_start
 6963                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6964                Bias::Left,
 6965            );
 6966            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6967            self.quick_selection_highlight_task = Some((
 6968                query_range.clone(),
 6969                self.update_selection_occurrence_highlights(
 6970                    query_text.clone(),
 6971                    query_range.clone(),
 6972                    multi_buffer_visible_range,
 6973                    false,
 6974                    window,
 6975                    cx,
 6976                ),
 6977            ));
 6978        }
 6979        if on_buffer_edit
 6980            || self
 6981                .debounced_selection_highlight_task
 6982                .as_ref()
 6983                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6984        {
 6985            let multi_buffer_start = multi_buffer_snapshot
 6986                .anchor_before(0)
 6987                .to_point(&multi_buffer_snapshot);
 6988            let multi_buffer_end = multi_buffer_snapshot
 6989                .anchor_after(multi_buffer_snapshot.len())
 6990                .to_point(&multi_buffer_snapshot);
 6991            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6992            self.debounced_selection_highlight_task = Some((
 6993                query_range.clone(),
 6994                self.update_selection_occurrence_highlights(
 6995                    query_text,
 6996                    query_range,
 6997                    multi_buffer_full_range,
 6998                    true,
 6999                    window,
 7000                    cx,
 7001                ),
 7002            ));
 7003        }
 7004    }
 7005
 7006    pub fn refresh_edit_prediction(
 7007        &mut self,
 7008        debounce: bool,
 7009        user_requested: bool,
 7010        window: &mut Window,
 7011        cx: &mut Context<Self>,
 7012    ) -> Option<()> {
 7013        if DisableAiSettings::get_global(cx).disable_ai {
 7014            return None;
 7015        }
 7016
 7017        let provider = self.edit_prediction_provider()?;
 7018        let cursor = self.selections.newest_anchor().head();
 7019        let (buffer, cursor_buffer_position) =
 7020            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7021
 7022        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7023            self.discard_edit_prediction(false, cx);
 7024            return None;
 7025        }
 7026
 7027        if !user_requested
 7028            && (!self.should_show_edit_predictions()
 7029                || !self.is_focused(window)
 7030                || buffer.read(cx).is_empty())
 7031        {
 7032            self.discard_edit_prediction(false, cx);
 7033            return None;
 7034        }
 7035
 7036        self.update_visible_edit_prediction(window, cx);
 7037        provider.refresh(
 7038            self.project.clone(),
 7039            buffer,
 7040            cursor_buffer_position,
 7041            debounce,
 7042            cx,
 7043        );
 7044        Some(())
 7045    }
 7046
 7047    fn show_edit_predictions_in_menu(&self) -> bool {
 7048        match self.edit_prediction_settings {
 7049            EditPredictionSettings::Disabled => false,
 7050            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7051        }
 7052    }
 7053
 7054    pub fn edit_predictions_enabled(&self) -> bool {
 7055        match self.edit_prediction_settings {
 7056            EditPredictionSettings::Disabled => false,
 7057            EditPredictionSettings::Enabled { .. } => true,
 7058        }
 7059    }
 7060
 7061    fn edit_prediction_requires_modifier(&self) -> bool {
 7062        match self.edit_prediction_settings {
 7063            EditPredictionSettings::Disabled => false,
 7064            EditPredictionSettings::Enabled {
 7065                preview_requires_modifier,
 7066                ..
 7067            } => preview_requires_modifier,
 7068        }
 7069    }
 7070
 7071    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7072        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7073            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7074            self.discard_edit_prediction(false, cx);
 7075        } else {
 7076            let selection = self.selections.newest_anchor();
 7077            let cursor = selection.head();
 7078
 7079            if let Some((buffer, cursor_buffer_position)) =
 7080                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7081            {
 7082                self.edit_prediction_settings =
 7083                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7084            }
 7085        }
 7086    }
 7087
 7088    fn edit_prediction_settings_at_position(
 7089        &self,
 7090        buffer: &Entity<Buffer>,
 7091        buffer_position: language::Anchor,
 7092        cx: &App,
 7093    ) -> EditPredictionSettings {
 7094        if !self.mode.is_full()
 7095            || !self.show_edit_predictions_override.unwrap_or(true)
 7096            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7097        {
 7098            return EditPredictionSettings::Disabled;
 7099        }
 7100
 7101        let buffer = buffer.read(cx);
 7102
 7103        let file = buffer.file();
 7104
 7105        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7106            return EditPredictionSettings::Disabled;
 7107        };
 7108
 7109        let by_provider = matches!(
 7110            self.menu_edit_predictions_policy,
 7111            MenuEditPredictionsPolicy::ByProvider
 7112        );
 7113
 7114        let show_in_menu = by_provider
 7115            && self
 7116                .edit_prediction_provider
 7117                .as_ref()
 7118                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7119
 7120        let preview_requires_modifier =
 7121            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7122
 7123        EditPredictionSettings::Enabled {
 7124            show_in_menu,
 7125            preview_requires_modifier,
 7126        }
 7127    }
 7128
 7129    fn should_show_edit_predictions(&self) -> bool {
 7130        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7131    }
 7132
 7133    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7134        matches!(
 7135            self.edit_prediction_preview,
 7136            EditPredictionPreview::Active { .. }
 7137        )
 7138    }
 7139
 7140    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7141        let cursor = self.selections.newest_anchor().head();
 7142        if let Some((buffer, cursor_position)) =
 7143            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7144        {
 7145            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7146        } else {
 7147            false
 7148        }
 7149    }
 7150
 7151    pub fn supports_minimap(&self, cx: &App) -> bool {
 7152        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7153    }
 7154
 7155    fn edit_predictions_enabled_in_buffer(
 7156        &self,
 7157        buffer: &Entity<Buffer>,
 7158        buffer_position: language::Anchor,
 7159        cx: &App,
 7160    ) -> bool {
 7161        maybe!({
 7162            if self.read_only(cx) {
 7163                return Some(false);
 7164            }
 7165            let provider = self.edit_prediction_provider()?;
 7166            if !provider.is_enabled(buffer, buffer_position, cx) {
 7167                return Some(false);
 7168            }
 7169            let buffer = buffer.read(cx);
 7170            let Some(file) = buffer.file() else {
 7171                return Some(true);
 7172            };
 7173            let settings = all_language_settings(Some(file), cx);
 7174            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7175        })
 7176        .unwrap_or(false)
 7177    }
 7178
 7179    fn cycle_edit_prediction(
 7180        &mut self,
 7181        direction: Direction,
 7182        window: &mut Window,
 7183        cx: &mut Context<Self>,
 7184    ) -> Option<()> {
 7185        let provider = self.edit_prediction_provider()?;
 7186        let cursor = self.selections.newest_anchor().head();
 7187        let (buffer, cursor_buffer_position) =
 7188            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7189        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7190            return None;
 7191        }
 7192
 7193        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7194        self.update_visible_edit_prediction(window, cx);
 7195
 7196        Some(())
 7197    }
 7198
 7199    pub fn show_edit_prediction(
 7200        &mut self,
 7201        _: &ShowEditPrediction,
 7202        window: &mut Window,
 7203        cx: &mut Context<Self>,
 7204    ) {
 7205        if !self.has_active_edit_prediction() {
 7206            self.refresh_edit_prediction(false, true, window, cx);
 7207            return;
 7208        }
 7209
 7210        self.update_visible_edit_prediction(window, cx);
 7211    }
 7212
 7213    pub fn display_cursor_names(
 7214        &mut self,
 7215        _: &DisplayCursorNames,
 7216        window: &mut Window,
 7217        cx: &mut Context<Self>,
 7218    ) {
 7219        self.show_cursor_names(window, cx);
 7220    }
 7221
 7222    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7223        self.show_cursor_names = true;
 7224        cx.notify();
 7225        cx.spawn_in(window, async move |this, cx| {
 7226            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7227            this.update(cx, |this, cx| {
 7228                this.show_cursor_names = false;
 7229                cx.notify()
 7230            })
 7231            .ok()
 7232        })
 7233        .detach();
 7234    }
 7235
 7236    pub fn next_edit_prediction(
 7237        &mut self,
 7238        _: &NextEditPrediction,
 7239        window: &mut Window,
 7240        cx: &mut Context<Self>,
 7241    ) {
 7242        if self.has_active_edit_prediction() {
 7243            self.cycle_edit_prediction(Direction::Next, window, cx);
 7244        } else {
 7245            let is_copilot_disabled = self
 7246                .refresh_edit_prediction(false, true, window, cx)
 7247                .is_none();
 7248            if is_copilot_disabled {
 7249                cx.propagate();
 7250            }
 7251        }
 7252    }
 7253
 7254    pub fn previous_edit_prediction(
 7255        &mut self,
 7256        _: &PreviousEditPrediction,
 7257        window: &mut Window,
 7258        cx: &mut Context<Self>,
 7259    ) {
 7260        if self.has_active_edit_prediction() {
 7261            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7262        } else {
 7263            let is_copilot_disabled = self
 7264                .refresh_edit_prediction(false, true, window, cx)
 7265                .is_none();
 7266            if is_copilot_disabled {
 7267                cx.propagate();
 7268            }
 7269        }
 7270    }
 7271
 7272    pub fn accept_edit_prediction(
 7273        &mut self,
 7274        _: &AcceptEditPrediction,
 7275        window: &mut Window,
 7276        cx: &mut Context<Self>,
 7277    ) {
 7278        if self.show_edit_predictions_in_menu() {
 7279            self.hide_context_menu(window, cx);
 7280        }
 7281
 7282        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7283            return;
 7284        };
 7285
 7286        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7287
 7288        match &active_edit_prediction.completion {
 7289            EditPrediction::Move { target, .. } => {
 7290                let target = *target;
 7291
 7292                if let Some(position_map) = &self.last_position_map {
 7293                    if position_map
 7294                        .visible_row_range
 7295                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7296                        || !self.edit_prediction_requires_modifier()
 7297                    {
 7298                        self.unfold_ranges(&[target..target], true, false, cx);
 7299                        // Note that this is also done in vim's handler of the Tab action.
 7300                        self.change_selections(
 7301                            SelectionEffects::scroll(Autoscroll::newest()),
 7302                            window,
 7303                            cx,
 7304                            |selections| {
 7305                                selections.select_anchor_ranges([target..target]);
 7306                            },
 7307                        );
 7308                        self.clear_row_highlights::<EditPredictionPreview>();
 7309
 7310                        self.edit_prediction_preview
 7311                            .set_previous_scroll_position(None);
 7312                    } else {
 7313                        self.edit_prediction_preview
 7314                            .set_previous_scroll_position(Some(
 7315                                position_map.snapshot.scroll_anchor,
 7316                            ));
 7317
 7318                        self.highlight_rows::<EditPredictionPreview>(
 7319                            target..target,
 7320                            cx.theme().colors().editor_highlighted_line_background,
 7321                            RowHighlightOptions {
 7322                                autoscroll: true,
 7323                                ..Default::default()
 7324                            },
 7325                            cx,
 7326                        );
 7327                        self.request_autoscroll(Autoscroll::fit(), cx);
 7328                    }
 7329                }
 7330            }
 7331            EditPrediction::Edit { edits, .. } => {
 7332                if let Some(provider) = self.edit_prediction_provider() {
 7333                    provider.accept(cx);
 7334                }
 7335
 7336                // Store the transaction ID and selections before applying the edit
 7337                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7338
 7339                let snapshot = self.buffer.read(cx).snapshot(cx);
 7340                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7341
 7342                self.buffer.update(cx, |buffer, cx| {
 7343                    buffer.edit(edits.iter().cloned(), None, cx)
 7344                });
 7345
 7346                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7347                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7348                });
 7349
 7350                let selections = self.selections.disjoint_anchors();
 7351                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7352                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7353                    if has_new_transaction {
 7354                        self.selection_history
 7355                            .insert_transaction(transaction_id_now, selections);
 7356                    }
 7357                }
 7358
 7359                self.update_visible_edit_prediction(window, cx);
 7360                if self.active_edit_prediction.is_none() {
 7361                    self.refresh_edit_prediction(true, true, window, cx);
 7362                }
 7363
 7364                cx.notify();
 7365            }
 7366        }
 7367
 7368        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7369    }
 7370
 7371    pub fn accept_partial_edit_prediction(
 7372        &mut self,
 7373        _: &AcceptPartialEditPrediction,
 7374        window: &mut Window,
 7375        cx: &mut Context<Self>,
 7376    ) {
 7377        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7378            return;
 7379        };
 7380        if self.selections.count() != 1 {
 7381            return;
 7382        }
 7383
 7384        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7385
 7386        match &active_edit_prediction.completion {
 7387            EditPrediction::Move { target, .. } => {
 7388                let target = *target;
 7389                self.change_selections(
 7390                    SelectionEffects::scroll(Autoscroll::newest()),
 7391                    window,
 7392                    cx,
 7393                    |selections| {
 7394                        selections.select_anchor_ranges([target..target]);
 7395                    },
 7396                );
 7397            }
 7398            EditPrediction::Edit { edits, .. } => {
 7399                // Find an insertion that starts at the cursor position.
 7400                let snapshot = self.buffer.read(cx).snapshot(cx);
 7401                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7402                let insertion = edits.iter().find_map(|(range, text)| {
 7403                    let range = range.to_offset(&snapshot);
 7404                    if range.is_empty() && range.start == cursor_offset {
 7405                        Some(text)
 7406                    } else {
 7407                        None
 7408                    }
 7409                });
 7410
 7411                if let Some(text) = insertion {
 7412                    let mut partial_completion = text
 7413                        .chars()
 7414                        .by_ref()
 7415                        .take_while(|c| c.is_alphabetic())
 7416                        .collect::<String>();
 7417                    if partial_completion.is_empty() {
 7418                        partial_completion = text
 7419                            .chars()
 7420                            .by_ref()
 7421                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7422                            .collect::<String>();
 7423                    }
 7424
 7425                    cx.emit(EditorEvent::InputHandled {
 7426                        utf16_range_to_replace: None,
 7427                        text: partial_completion.clone().into(),
 7428                    });
 7429
 7430                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7431
 7432                    self.refresh_edit_prediction(true, true, window, cx);
 7433                    cx.notify();
 7434                } else {
 7435                    self.accept_edit_prediction(&Default::default(), window, cx);
 7436                }
 7437            }
 7438        }
 7439    }
 7440
 7441    fn discard_edit_prediction(
 7442        &mut self,
 7443        should_report_edit_prediction_event: bool,
 7444        cx: &mut Context<Self>,
 7445    ) -> bool {
 7446        if should_report_edit_prediction_event {
 7447            let completion_id = self
 7448                .active_edit_prediction
 7449                .as_ref()
 7450                .and_then(|active_completion| active_completion.completion_id.clone());
 7451
 7452            self.report_edit_prediction_event(completion_id, false, cx);
 7453        }
 7454
 7455        if let Some(provider) = self.edit_prediction_provider() {
 7456            provider.discard(cx);
 7457        }
 7458
 7459        self.take_active_edit_prediction(cx)
 7460    }
 7461
 7462    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7463        let Some(provider) = self.edit_prediction_provider() else {
 7464            return;
 7465        };
 7466
 7467        let Some((_, buffer, _)) = self
 7468            .buffer
 7469            .read(cx)
 7470            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7471        else {
 7472            return;
 7473        };
 7474
 7475        let extension = buffer
 7476            .read(cx)
 7477            .file()
 7478            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7479
 7480        let event_type = match accepted {
 7481            true => "Edit Prediction Accepted",
 7482            false => "Edit Prediction Discarded",
 7483        };
 7484        telemetry::event!(
 7485            event_type,
 7486            provider = provider.name(),
 7487            prediction_id = id,
 7488            suggestion_accepted = accepted,
 7489            file_extension = extension,
 7490        );
 7491    }
 7492
 7493    pub fn has_active_edit_prediction(&self) -> bool {
 7494        self.active_edit_prediction.is_some()
 7495    }
 7496
 7497    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7498        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7499            return false;
 7500        };
 7501
 7502        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7503        self.clear_highlights::<EditPredictionHighlight>(cx);
 7504        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7505        true
 7506    }
 7507
 7508    /// Returns true when we're displaying the edit prediction popover below the cursor
 7509    /// like we are not previewing and the LSP autocomplete menu is visible
 7510    /// or we are in `when_holding_modifier` mode.
 7511    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7512        if self.edit_prediction_preview_is_active()
 7513            || !self.show_edit_predictions_in_menu()
 7514            || !self.edit_predictions_enabled()
 7515        {
 7516            return false;
 7517        }
 7518
 7519        if self.has_visible_completions_menu() {
 7520            return true;
 7521        }
 7522
 7523        has_completion && self.edit_prediction_requires_modifier()
 7524    }
 7525
 7526    fn handle_modifiers_changed(
 7527        &mut self,
 7528        modifiers: Modifiers,
 7529        position_map: &PositionMap,
 7530        window: &mut Window,
 7531        cx: &mut Context<Self>,
 7532    ) {
 7533        if self.show_edit_predictions_in_menu() {
 7534            self.update_edit_prediction_preview(&modifiers, window, cx);
 7535        }
 7536
 7537        self.update_selection_mode(&modifiers, position_map, window, cx);
 7538
 7539        let mouse_position = window.mouse_position();
 7540        if !position_map.text_hitbox.is_hovered(window) {
 7541            return;
 7542        }
 7543
 7544        self.update_hovered_link(
 7545            position_map.point_for_position(mouse_position),
 7546            &position_map.snapshot,
 7547            modifiers,
 7548            window,
 7549            cx,
 7550        )
 7551    }
 7552
 7553    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7554        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7555        if invert {
 7556            match multi_cursor_setting {
 7557                MultiCursorModifier::Alt => modifiers.alt,
 7558                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7559            }
 7560        } else {
 7561            match multi_cursor_setting {
 7562                MultiCursorModifier::Alt => modifiers.secondary(),
 7563                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7564            }
 7565        }
 7566    }
 7567
 7568    fn columnar_selection_mode(
 7569        modifiers: &Modifiers,
 7570        cx: &mut Context<Self>,
 7571    ) -> Option<ColumnarMode> {
 7572        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7573            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7574                Some(ColumnarMode::FromMouse)
 7575            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7576                Some(ColumnarMode::FromSelection)
 7577            } else {
 7578                None
 7579            }
 7580        } else {
 7581            None
 7582        }
 7583    }
 7584
 7585    fn update_selection_mode(
 7586        &mut self,
 7587        modifiers: &Modifiers,
 7588        position_map: &PositionMap,
 7589        window: &mut Window,
 7590        cx: &mut Context<Self>,
 7591    ) {
 7592        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7593            return;
 7594        };
 7595        if self.selections.pending.is_none() {
 7596            return;
 7597        }
 7598
 7599        let mouse_position = window.mouse_position();
 7600        let point_for_position = position_map.point_for_position(mouse_position);
 7601        let position = point_for_position.previous_valid;
 7602
 7603        self.select(
 7604            SelectPhase::BeginColumnar {
 7605                position,
 7606                reset: false,
 7607                mode,
 7608                goal_column: point_for_position.exact_unclipped.column(),
 7609            },
 7610            window,
 7611            cx,
 7612        );
 7613    }
 7614
 7615    fn update_edit_prediction_preview(
 7616        &mut self,
 7617        modifiers: &Modifiers,
 7618        window: &mut Window,
 7619        cx: &mut Context<Self>,
 7620    ) {
 7621        let mut modifiers_held = false;
 7622        if let Some(accept_keystroke) = self
 7623            .accept_edit_prediction_keybind(false, window, cx)
 7624            .keystroke()
 7625        {
 7626            modifiers_held = modifiers_held
 7627                || (&accept_keystroke.modifiers == modifiers
 7628                    && accept_keystroke.modifiers.modified());
 7629        };
 7630        if let Some(accept_partial_keystroke) = self
 7631            .accept_edit_prediction_keybind(true, window, cx)
 7632            .keystroke()
 7633        {
 7634            modifiers_held = modifiers_held
 7635                || (&accept_partial_keystroke.modifiers == modifiers
 7636                    && accept_partial_keystroke.modifiers.modified());
 7637        }
 7638
 7639        if modifiers_held {
 7640            if matches!(
 7641                self.edit_prediction_preview,
 7642                EditPredictionPreview::Inactive { .. }
 7643            ) {
 7644                self.edit_prediction_preview = EditPredictionPreview::Active {
 7645                    previous_scroll_position: None,
 7646                    since: Instant::now(),
 7647                };
 7648
 7649                self.update_visible_edit_prediction(window, cx);
 7650                cx.notify();
 7651            }
 7652        } else if let EditPredictionPreview::Active {
 7653            previous_scroll_position,
 7654            since,
 7655        } = self.edit_prediction_preview
 7656        {
 7657            if let (Some(previous_scroll_position), Some(position_map)) =
 7658                (previous_scroll_position, self.last_position_map.as_ref())
 7659            {
 7660                self.set_scroll_position(
 7661                    previous_scroll_position
 7662                        .scroll_position(&position_map.snapshot.display_snapshot),
 7663                    window,
 7664                    cx,
 7665                );
 7666            }
 7667
 7668            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7669                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7670            };
 7671            self.clear_row_highlights::<EditPredictionPreview>();
 7672            self.update_visible_edit_prediction(window, cx);
 7673            cx.notify();
 7674        }
 7675    }
 7676
 7677    fn update_visible_edit_prediction(
 7678        &mut self,
 7679        _window: &mut Window,
 7680        cx: &mut Context<Self>,
 7681    ) -> Option<()> {
 7682        if DisableAiSettings::get_global(cx).disable_ai {
 7683            return None;
 7684        }
 7685
 7686        let selection = self.selections.newest_anchor();
 7687        let cursor = selection.head();
 7688        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7689        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7690        let excerpt_id = cursor.excerpt_id;
 7691
 7692        let show_in_menu = self.show_edit_predictions_in_menu();
 7693        let completions_menu_has_precedence = !show_in_menu
 7694            && (self.context_menu.borrow().is_some()
 7695                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7696
 7697        if completions_menu_has_precedence
 7698            || !offset_selection.is_empty()
 7699            || self
 7700                .active_edit_prediction
 7701                .as_ref()
 7702                .is_some_and(|completion| {
 7703                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7704                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7705                    !invalidation_range.contains(&offset_selection.head())
 7706                })
 7707        {
 7708            self.discard_edit_prediction(false, cx);
 7709            return None;
 7710        }
 7711
 7712        self.take_active_edit_prediction(cx);
 7713        let Some(provider) = self.edit_prediction_provider() else {
 7714            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7715            return None;
 7716        };
 7717
 7718        let (buffer, cursor_buffer_position) =
 7719            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7720
 7721        self.edit_prediction_settings =
 7722            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7723
 7724        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7725            self.discard_edit_prediction(false, cx);
 7726            return None;
 7727        };
 7728
 7729        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7730
 7731        if self.edit_prediction_indent_conflict {
 7732            let cursor_point = cursor.to_point(&multibuffer);
 7733
 7734            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7735
 7736            if let Some((_, indent)) = indents.iter().next()
 7737                && indent.len == cursor_point.column
 7738            {
 7739                self.edit_prediction_indent_conflict = false;
 7740            }
 7741        }
 7742
 7743        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7744        let edits = edit_prediction
 7745            .edits
 7746            .into_iter()
 7747            .flat_map(|(range, new_text)| {
 7748                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7749                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7750                Some((start..end, new_text))
 7751            })
 7752            .collect::<Vec<_>>();
 7753        if edits.is_empty() {
 7754            return None;
 7755        }
 7756
 7757        let first_edit_start = edits.first().unwrap().0.start;
 7758        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7759        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7760
 7761        let last_edit_end = edits.last().unwrap().0.end;
 7762        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7763        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7764
 7765        let cursor_row = cursor.to_point(&multibuffer).row;
 7766
 7767        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7768
 7769        let mut inlay_ids = Vec::new();
 7770        let invalidation_row_range;
 7771        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7772            Some(cursor_row..edit_end_row)
 7773        } else if cursor_row > edit_end_row {
 7774            Some(edit_start_row..cursor_row)
 7775        } else {
 7776            None
 7777        };
 7778        let supports_jump = self
 7779            .edit_prediction_provider
 7780            .as_ref()
 7781            .map(|provider| provider.provider.supports_jump_to_edit())
 7782            .unwrap_or(true);
 7783
 7784        let is_move = supports_jump
 7785            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7786        let completion = if is_move {
 7787            invalidation_row_range =
 7788                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7789            let target = first_edit_start;
 7790            EditPrediction::Move { target, snapshot }
 7791        } else {
 7792            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7793                && !self.edit_predictions_hidden_for_vim_mode;
 7794
 7795            if show_completions_in_buffer {
 7796                if edits
 7797                    .iter()
 7798                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7799                {
 7800                    let mut inlays = Vec::new();
 7801                    for (range, new_text) in &edits {
 7802                        let inlay = Inlay::edit_prediction(
 7803                            post_inc(&mut self.next_inlay_id),
 7804                            range.start,
 7805                            new_text.as_str(),
 7806                        );
 7807                        inlay_ids.push(inlay.id);
 7808                        inlays.push(inlay);
 7809                    }
 7810
 7811                    self.splice_inlays(&[], inlays, cx);
 7812                } else {
 7813                    let background_color = cx.theme().status().deleted_background;
 7814                    self.highlight_text::<EditPredictionHighlight>(
 7815                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7816                        HighlightStyle {
 7817                            background_color: Some(background_color),
 7818                            ..Default::default()
 7819                        },
 7820                        cx,
 7821                    );
 7822                }
 7823            }
 7824
 7825            invalidation_row_range = edit_start_row..edit_end_row;
 7826
 7827            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7828                if provider.show_tab_accept_marker() {
 7829                    EditDisplayMode::TabAccept
 7830                } else {
 7831                    EditDisplayMode::Inline
 7832                }
 7833            } else {
 7834                EditDisplayMode::DiffPopover
 7835            };
 7836
 7837            EditPrediction::Edit {
 7838                edits,
 7839                edit_preview: edit_prediction.edit_preview,
 7840                display_mode,
 7841                snapshot,
 7842            }
 7843        };
 7844
 7845        let invalidation_range = multibuffer
 7846            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7847            ..multibuffer.anchor_after(Point::new(
 7848                invalidation_row_range.end,
 7849                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7850            ));
 7851
 7852        self.stale_edit_prediction_in_menu = None;
 7853        self.active_edit_prediction = Some(EditPredictionState {
 7854            inlay_ids,
 7855            completion,
 7856            completion_id: edit_prediction.id,
 7857            invalidation_range,
 7858        });
 7859
 7860        cx.notify();
 7861
 7862        Some(())
 7863    }
 7864
 7865    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7866        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7867    }
 7868
 7869    fn clear_tasks(&mut self) {
 7870        self.tasks.clear()
 7871    }
 7872
 7873    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7874        if self.tasks.insert(key, value).is_some() {
 7875            // This case should hopefully be rare, but just in case...
 7876            log::error!(
 7877                "multiple different run targets found on a single line, only the last target will be rendered"
 7878            )
 7879        }
 7880    }
 7881
 7882    /// Get all display points of breakpoints that will be rendered within editor
 7883    ///
 7884    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7885    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7886    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7887    fn active_breakpoints(
 7888        &self,
 7889        range: Range<DisplayRow>,
 7890        window: &mut Window,
 7891        cx: &mut Context<Self>,
 7892    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7893        let mut breakpoint_display_points = HashMap::default();
 7894
 7895        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7896            return breakpoint_display_points;
 7897        };
 7898
 7899        let snapshot = self.snapshot(window, cx);
 7900
 7901        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7902        let Some(project) = self.project() else {
 7903            return breakpoint_display_points;
 7904        };
 7905
 7906        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7907            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7908
 7909        for (buffer_snapshot, range, excerpt_id) in
 7910            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7911        {
 7912            let Some(buffer) = project
 7913                .read(cx)
 7914                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7915            else {
 7916                continue;
 7917            };
 7918            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7919                &buffer,
 7920                Some(
 7921                    buffer_snapshot.anchor_before(range.start)
 7922                        ..buffer_snapshot.anchor_after(range.end),
 7923                ),
 7924                buffer_snapshot,
 7925                cx,
 7926            );
 7927            for (breakpoint, state) in breakpoints {
 7928                let multi_buffer_anchor =
 7929                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7930                let position = multi_buffer_anchor
 7931                    .to_point(multi_buffer_snapshot)
 7932                    .to_display_point(&snapshot);
 7933
 7934                breakpoint_display_points.insert(
 7935                    position.row(),
 7936                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7937                );
 7938            }
 7939        }
 7940
 7941        breakpoint_display_points
 7942    }
 7943
 7944    fn breakpoint_context_menu(
 7945        &self,
 7946        anchor: Anchor,
 7947        window: &mut Window,
 7948        cx: &mut Context<Self>,
 7949    ) -> Entity<ui::ContextMenu> {
 7950        let weak_editor = cx.weak_entity();
 7951        let focus_handle = self.focus_handle(cx);
 7952
 7953        let row = self
 7954            .buffer
 7955            .read(cx)
 7956            .snapshot(cx)
 7957            .summary_for_anchor::<Point>(&anchor)
 7958            .row;
 7959
 7960        let breakpoint = self
 7961            .breakpoint_at_row(row, window, cx)
 7962            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7963
 7964        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7965            "Edit Log Breakpoint"
 7966        } else {
 7967            "Set Log Breakpoint"
 7968        };
 7969
 7970        let condition_breakpoint_msg = if breakpoint
 7971            .as_ref()
 7972            .is_some_and(|bp| bp.1.condition.is_some())
 7973        {
 7974            "Edit Condition Breakpoint"
 7975        } else {
 7976            "Set Condition Breakpoint"
 7977        };
 7978
 7979        let hit_condition_breakpoint_msg = if breakpoint
 7980            .as_ref()
 7981            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7982        {
 7983            "Edit Hit Condition Breakpoint"
 7984        } else {
 7985            "Set Hit Condition Breakpoint"
 7986        };
 7987
 7988        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7989            "Unset Breakpoint"
 7990        } else {
 7991            "Set Breakpoint"
 7992        };
 7993
 7994        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7995
 7996        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7997            BreakpointState::Enabled => Some("Disable"),
 7998            BreakpointState::Disabled => Some("Enable"),
 7999        });
 8000
 8001        let (anchor, breakpoint) =
 8002            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8003
 8004        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8005            menu.on_blur_subscription(Subscription::new(|| {}))
 8006                .context(focus_handle)
 8007                .when(run_to_cursor, |this| {
 8008                    let weak_editor = weak_editor.clone();
 8009                    this.entry("Run to cursor", None, move |window, cx| {
 8010                        weak_editor
 8011                            .update(cx, |editor, cx| {
 8012                                editor.change_selections(
 8013                                    SelectionEffects::no_scroll(),
 8014                                    window,
 8015                                    cx,
 8016                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8017                                );
 8018                            })
 8019                            .ok();
 8020
 8021                        window.dispatch_action(Box::new(RunToCursor), cx);
 8022                    })
 8023                    .separator()
 8024                })
 8025                .when_some(toggle_state_msg, |this, msg| {
 8026                    this.entry(msg, None, {
 8027                        let weak_editor = weak_editor.clone();
 8028                        let breakpoint = breakpoint.clone();
 8029                        move |_window, cx| {
 8030                            weak_editor
 8031                                .update(cx, |this, cx| {
 8032                                    this.edit_breakpoint_at_anchor(
 8033                                        anchor,
 8034                                        breakpoint.as_ref().clone(),
 8035                                        BreakpointEditAction::InvertState,
 8036                                        cx,
 8037                                    );
 8038                                })
 8039                                .log_err();
 8040                        }
 8041                    })
 8042                })
 8043                .entry(set_breakpoint_msg, None, {
 8044                    let weak_editor = weak_editor.clone();
 8045                    let breakpoint = breakpoint.clone();
 8046                    move |_window, cx| {
 8047                        weak_editor
 8048                            .update(cx, |this, cx| {
 8049                                this.edit_breakpoint_at_anchor(
 8050                                    anchor,
 8051                                    breakpoint.as_ref().clone(),
 8052                                    BreakpointEditAction::Toggle,
 8053                                    cx,
 8054                                );
 8055                            })
 8056                            .log_err();
 8057                    }
 8058                })
 8059                .entry(log_breakpoint_msg, None, {
 8060                    let breakpoint = breakpoint.clone();
 8061                    let weak_editor = weak_editor.clone();
 8062                    move |window, cx| {
 8063                        weak_editor
 8064                            .update(cx, |this, cx| {
 8065                                this.add_edit_breakpoint_block(
 8066                                    anchor,
 8067                                    breakpoint.as_ref(),
 8068                                    BreakpointPromptEditAction::Log,
 8069                                    window,
 8070                                    cx,
 8071                                );
 8072                            })
 8073                            .log_err();
 8074                    }
 8075                })
 8076                .entry(condition_breakpoint_msg, None, {
 8077                    let breakpoint = breakpoint.clone();
 8078                    let weak_editor = weak_editor.clone();
 8079                    move |window, cx| {
 8080                        weak_editor
 8081                            .update(cx, |this, cx| {
 8082                                this.add_edit_breakpoint_block(
 8083                                    anchor,
 8084                                    breakpoint.as_ref(),
 8085                                    BreakpointPromptEditAction::Condition,
 8086                                    window,
 8087                                    cx,
 8088                                );
 8089                            })
 8090                            .log_err();
 8091                    }
 8092                })
 8093                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8094                    weak_editor
 8095                        .update(cx, |this, cx| {
 8096                            this.add_edit_breakpoint_block(
 8097                                anchor,
 8098                                breakpoint.as_ref(),
 8099                                BreakpointPromptEditAction::HitCondition,
 8100                                window,
 8101                                cx,
 8102                            );
 8103                        })
 8104                        .log_err();
 8105                })
 8106        })
 8107    }
 8108
 8109    fn render_breakpoint(
 8110        &self,
 8111        position: Anchor,
 8112        row: DisplayRow,
 8113        breakpoint: &Breakpoint,
 8114        state: Option<BreakpointSessionState>,
 8115        cx: &mut Context<Self>,
 8116    ) -> IconButton {
 8117        let is_rejected = state.is_some_and(|s| !s.verified);
 8118        // Is it a breakpoint that shows up when hovering over gutter?
 8119        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8120            (false, false),
 8121            |PhantomBreakpointIndicator {
 8122                 is_active,
 8123                 display_row,
 8124                 collides_with_existing_breakpoint,
 8125             }| {
 8126                (
 8127                    is_active && display_row == row,
 8128                    collides_with_existing_breakpoint,
 8129                )
 8130            },
 8131        );
 8132
 8133        let (color, icon) = {
 8134            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8135                (false, false) => ui::IconName::DebugBreakpoint,
 8136                (true, false) => ui::IconName::DebugLogBreakpoint,
 8137                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8138                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8139            };
 8140
 8141            let color = if is_phantom {
 8142                Color::Hint
 8143            } else if is_rejected {
 8144                Color::Disabled
 8145            } else {
 8146                Color::Debugger
 8147            };
 8148
 8149            (color, icon)
 8150        };
 8151
 8152        let breakpoint = Arc::from(breakpoint.clone());
 8153
 8154        let alt_as_text = gpui::Keystroke {
 8155            modifiers: Modifiers::secondary_key(),
 8156            ..Default::default()
 8157        };
 8158        let primary_action_text = if breakpoint.is_disabled() {
 8159            "Enable breakpoint"
 8160        } else if is_phantom && !collides_with_existing {
 8161            "Set breakpoint"
 8162        } else {
 8163            "Unset breakpoint"
 8164        };
 8165        let focus_handle = self.focus_handle.clone();
 8166
 8167        let meta = if is_rejected {
 8168            SharedString::from("No executable code is associated with this line.")
 8169        } else if collides_with_existing && !breakpoint.is_disabled() {
 8170            SharedString::from(format!(
 8171                "{alt_as_text}-click to disable,\nright-click for more options."
 8172            ))
 8173        } else {
 8174            SharedString::from("Right-click for more options.")
 8175        };
 8176        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8177            .icon_size(IconSize::XSmall)
 8178            .size(ui::ButtonSize::None)
 8179            .when(is_rejected, |this| {
 8180                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8181            })
 8182            .icon_color(color)
 8183            .style(ButtonStyle::Transparent)
 8184            .on_click(cx.listener({
 8185                move |editor, event: &ClickEvent, window, cx| {
 8186                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8187                        BreakpointEditAction::InvertState
 8188                    } else {
 8189                        BreakpointEditAction::Toggle
 8190                    };
 8191
 8192                    window.focus(&editor.focus_handle(cx));
 8193                    editor.edit_breakpoint_at_anchor(
 8194                        position,
 8195                        breakpoint.as_ref().clone(),
 8196                        edit_action,
 8197                        cx,
 8198                    );
 8199                }
 8200            }))
 8201            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8202                editor.set_breakpoint_context_menu(
 8203                    row,
 8204                    Some(position),
 8205                    event.position(),
 8206                    window,
 8207                    cx,
 8208                );
 8209            }))
 8210            .tooltip(move |window, cx| {
 8211                Tooltip::with_meta_in(
 8212                    primary_action_text,
 8213                    Some(&ToggleBreakpoint),
 8214                    meta.clone(),
 8215                    &focus_handle,
 8216                    window,
 8217                    cx,
 8218                )
 8219            })
 8220    }
 8221
 8222    fn build_tasks_context(
 8223        project: &Entity<Project>,
 8224        buffer: &Entity<Buffer>,
 8225        buffer_row: u32,
 8226        tasks: &Arc<RunnableTasks>,
 8227        cx: &mut Context<Self>,
 8228    ) -> Task<Option<task::TaskContext>> {
 8229        let position = Point::new(buffer_row, tasks.column);
 8230        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8231        let location = Location {
 8232            buffer: buffer.clone(),
 8233            range: range_start..range_start,
 8234        };
 8235        // Fill in the environmental variables from the tree-sitter captures
 8236        let mut captured_task_variables = TaskVariables::default();
 8237        for (capture_name, value) in tasks.extra_variables.clone() {
 8238            captured_task_variables.insert(
 8239                task::VariableName::Custom(capture_name.into()),
 8240                value.clone(),
 8241            );
 8242        }
 8243        project.update(cx, |project, cx| {
 8244            project.task_store().update(cx, |task_store, cx| {
 8245                task_store.task_context_for_location(captured_task_variables, location, cx)
 8246            })
 8247        })
 8248    }
 8249
 8250    pub fn spawn_nearest_task(
 8251        &mut self,
 8252        action: &SpawnNearestTask,
 8253        window: &mut Window,
 8254        cx: &mut Context<Self>,
 8255    ) {
 8256        let Some((workspace, _)) = self.workspace.clone() else {
 8257            return;
 8258        };
 8259        let Some(project) = self.project.clone() else {
 8260            return;
 8261        };
 8262
 8263        // Try to find a closest, enclosing node using tree-sitter that has a task
 8264        let Some((buffer, buffer_row, tasks)) = self
 8265            .find_enclosing_node_task(cx)
 8266            // Or find the task that's closest in row-distance.
 8267            .or_else(|| self.find_closest_task(cx))
 8268        else {
 8269            return;
 8270        };
 8271
 8272        let reveal_strategy = action.reveal;
 8273        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8274        cx.spawn_in(window, async move |_, cx| {
 8275            let context = task_context.await?;
 8276            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8277
 8278            let resolved = &mut resolved_task.resolved;
 8279            resolved.reveal = reveal_strategy;
 8280
 8281            workspace
 8282                .update_in(cx, |workspace, window, cx| {
 8283                    workspace.schedule_resolved_task(
 8284                        task_source_kind,
 8285                        resolved_task,
 8286                        false,
 8287                        window,
 8288                        cx,
 8289                    );
 8290                })
 8291                .ok()
 8292        })
 8293        .detach();
 8294    }
 8295
 8296    fn find_closest_task(
 8297        &mut self,
 8298        cx: &mut Context<Self>,
 8299    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8300        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8301
 8302        let ((buffer_id, row), tasks) = self
 8303            .tasks
 8304            .iter()
 8305            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8306
 8307        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8308        let tasks = Arc::new(tasks.to_owned());
 8309        Some((buffer, *row, tasks))
 8310    }
 8311
 8312    fn find_enclosing_node_task(
 8313        &mut self,
 8314        cx: &mut Context<Self>,
 8315    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8316        let snapshot = self.buffer.read(cx).snapshot(cx);
 8317        let offset = self.selections.newest::<usize>(cx).head();
 8318        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8319        let buffer_id = excerpt.buffer().remote_id();
 8320
 8321        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8322        let mut cursor = layer.node().walk();
 8323
 8324        while cursor.goto_first_child_for_byte(offset).is_some() {
 8325            if cursor.node().end_byte() == offset {
 8326                cursor.goto_next_sibling();
 8327            }
 8328        }
 8329
 8330        // Ascend to the smallest ancestor that contains the range and has a task.
 8331        loop {
 8332            let node = cursor.node();
 8333            let node_range = node.byte_range();
 8334            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8335
 8336            // Check if this node contains our offset
 8337            if node_range.start <= offset && node_range.end >= offset {
 8338                // If it contains offset, check for task
 8339                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8340                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8341                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8342                }
 8343            }
 8344
 8345            if !cursor.goto_parent() {
 8346                break;
 8347            }
 8348        }
 8349        None
 8350    }
 8351
 8352    fn render_run_indicator(
 8353        &self,
 8354        _style: &EditorStyle,
 8355        is_active: bool,
 8356        row: DisplayRow,
 8357        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8358        cx: &mut Context<Self>,
 8359    ) -> IconButton {
 8360        let color = Color::Muted;
 8361        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8362
 8363        IconButton::new(
 8364            ("run_indicator", row.0 as usize),
 8365            ui::IconName::PlayOutlined,
 8366        )
 8367        .shape(ui::IconButtonShape::Square)
 8368        .icon_size(IconSize::XSmall)
 8369        .icon_color(color)
 8370        .toggle_state(is_active)
 8371        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8372            let quick_launch = match e {
 8373                ClickEvent::Keyboard(_) => true,
 8374                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8375            };
 8376
 8377            window.focus(&editor.focus_handle(cx));
 8378            editor.toggle_code_actions(
 8379                &ToggleCodeActions {
 8380                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8381                    quick_launch,
 8382                },
 8383                window,
 8384                cx,
 8385            );
 8386        }))
 8387        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8388            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8389        }))
 8390    }
 8391
 8392    pub fn context_menu_visible(&self) -> bool {
 8393        !self.edit_prediction_preview_is_active()
 8394            && self
 8395                .context_menu
 8396                .borrow()
 8397                .as_ref()
 8398                .is_some_and(|menu| menu.visible())
 8399    }
 8400
 8401    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8402        self.context_menu
 8403            .borrow()
 8404            .as_ref()
 8405            .map(|menu| menu.origin())
 8406    }
 8407
 8408    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8409        self.context_menu_options = Some(options);
 8410    }
 8411
 8412    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8413    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8414
 8415    fn render_edit_prediction_popover(
 8416        &mut self,
 8417        text_bounds: &Bounds<Pixels>,
 8418        content_origin: gpui::Point<Pixels>,
 8419        right_margin: Pixels,
 8420        editor_snapshot: &EditorSnapshot,
 8421        visible_row_range: Range<DisplayRow>,
 8422        scroll_top: f32,
 8423        scroll_bottom: f32,
 8424        line_layouts: &[LineWithInvisibles],
 8425        line_height: Pixels,
 8426        scroll_pixel_position: gpui::Point<Pixels>,
 8427        newest_selection_head: Option<DisplayPoint>,
 8428        editor_width: Pixels,
 8429        style: &EditorStyle,
 8430        window: &mut Window,
 8431        cx: &mut App,
 8432    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8433        if self.mode().is_minimap() {
 8434            return None;
 8435        }
 8436        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8437
 8438        if self.edit_prediction_visible_in_cursor_popover(true) {
 8439            return None;
 8440        }
 8441
 8442        match &active_edit_prediction.completion {
 8443            EditPrediction::Move { target, .. } => {
 8444                let target_display_point = target.to_display_point(editor_snapshot);
 8445
 8446                if self.edit_prediction_requires_modifier() {
 8447                    if !self.edit_prediction_preview_is_active() {
 8448                        return None;
 8449                    }
 8450
 8451                    self.render_edit_prediction_modifier_jump_popover(
 8452                        text_bounds,
 8453                        content_origin,
 8454                        visible_row_range,
 8455                        line_layouts,
 8456                        line_height,
 8457                        scroll_pixel_position,
 8458                        newest_selection_head,
 8459                        target_display_point,
 8460                        window,
 8461                        cx,
 8462                    )
 8463                } else {
 8464                    self.render_edit_prediction_eager_jump_popover(
 8465                        text_bounds,
 8466                        content_origin,
 8467                        editor_snapshot,
 8468                        visible_row_range,
 8469                        scroll_top,
 8470                        scroll_bottom,
 8471                        line_height,
 8472                        scroll_pixel_position,
 8473                        target_display_point,
 8474                        editor_width,
 8475                        window,
 8476                        cx,
 8477                    )
 8478                }
 8479            }
 8480            EditPrediction::Edit {
 8481                display_mode: EditDisplayMode::Inline,
 8482                ..
 8483            } => None,
 8484            EditPrediction::Edit {
 8485                display_mode: EditDisplayMode::TabAccept,
 8486                edits,
 8487                ..
 8488            } => {
 8489                let range = &edits.first()?.0;
 8490                let target_display_point = range.end.to_display_point(editor_snapshot);
 8491
 8492                self.render_edit_prediction_end_of_line_popover(
 8493                    "Accept",
 8494                    editor_snapshot,
 8495                    visible_row_range,
 8496                    target_display_point,
 8497                    line_height,
 8498                    scroll_pixel_position,
 8499                    content_origin,
 8500                    editor_width,
 8501                    window,
 8502                    cx,
 8503                )
 8504            }
 8505            EditPrediction::Edit {
 8506                edits,
 8507                edit_preview,
 8508                display_mode: EditDisplayMode::DiffPopover,
 8509                snapshot,
 8510            } => self.render_edit_prediction_diff_popover(
 8511                text_bounds,
 8512                content_origin,
 8513                right_margin,
 8514                editor_snapshot,
 8515                visible_row_range,
 8516                line_layouts,
 8517                line_height,
 8518                scroll_pixel_position,
 8519                newest_selection_head,
 8520                editor_width,
 8521                style,
 8522                edits,
 8523                edit_preview,
 8524                snapshot,
 8525                window,
 8526                cx,
 8527            ),
 8528        }
 8529    }
 8530
 8531    fn render_edit_prediction_modifier_jump_popover(
 8532        &mut self,
 8533        text_bounds: &Bounds<Pixels>,
 8534        content_origin: gpui::Point<Pixels>,
 8535        visible_row_range: Range<DisplayRow>,
 8536        line_layouts: &[LineWithInvisibles],
 8537        line_height: Pixels,
 8538        scroll_pixel_position: gpui::Point<Pixels>,
 8539        newest_selection_head: Option<DisplayPoint>,
 8540        target_display_point: DisplayPoint,
 8541        window: &mut Window,
 8542        cx: &mut App,
 8543    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8544        let scrolled_content_origin =
 8545            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8546
 8547        const SCROLL_PADDING_Y: Pixels = px(12.);
 8548
 8549        if target_display_point.row() < visible_row_range.start {
 8550            return self.render_edit_prediction_scroll_popover(
 8551                |_| SCROLL_PADDING_Y,
 8552                IconName::ArrowUp,
 8553                visible_row_range,
 8554                line_layouts,
 8555                newest_selection_head,
 8556                scrolled_content_origin,
 8557                window,
 8558                cx,
 8559            );
 8560        } else if target_display_point.row() >= visible_row_range.end {
 8561            return self.render_edit_prediction_scroll_popover(
 8562                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8563                IconName::ArrowDown,
 8564                visible_row_range,
 8565                line_layouts,
 8566                newest_selection_head,
 8567                scrolled_content_origin,
 8568                window,
 8569                cx,
 8570            );
 8571        }
 8572
 8573        const POLE_WIDTH: Pixels = px(2.);
 8574
 8575        let line_layout =
 8576            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8577        let target_column = target_display_point.column() as usize;
 8578
 8579        let target_x = line_layout.x_for_index(target_column);
 8580        let target_y =
 8581            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8582
 8583        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8584
 8585        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8586        border_color.l += 0.001;
 8587
 8588        let mut element = v_flex()
 8589            .items_end()
 8590            .when(flag_on_right, |el| el.items_start())
 8591            .child(if flag_on_right {
 8592                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8593                    .rounded_bl(px(0.))
 8594                    .rounded_tl(px(0.))
 8595                    .border_l_2()
 8596                    .border_color(border_color)
 8597            } else {
 8598                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8599                    .rounded_br(px(0.))
 8600                    .rounded_tr(px(0.))
 8601                    .border_r_2()
 8602                    .border_color(border_color)
 8603            })
 8604            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8605            .into_any();
 8606
 8607        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8608
 8609        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8610            - point(
 8611                if flag_on_right {
 8612                    POLE_WIDTH
 8613                } else {
 8614                    size.width - POLE_WIDTH
 8615                },
 8616                size.height - line_height,
 8617            );
 8618
 8619        origin.x = origin.x.max(content_origin.x);
 8620
 8621        element.prepaint_at(origin, window, cx);
 8622
 8623        Some((element, origin))
 8624    }
 8625
 8626    fn render_edit_prediction_scroll_popover(
 8627        &mut self,
 8628        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8629        scroll_icon: IconName,
 8630        visible_row_range: Range<DisplayRow>,
 8631        line_layouts: &[LineWithInvisibles],
 8632        newest_selection_head: Option<DisplayPoint>,
 8633        scrolled_content_origin: gpui::Point<Pixels>,
 8634        window: &mut Window,
 8635        cx: &mut App,
 8636    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8637        let mut element = self
 8638            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8639            .into_any();
 8640
 8641        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8642
 8643        let cursor = newest_selection_head?;
 8644        let cursor_row_layout =
 8645            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8646        let cursor_column = cursor.column() as usize;
 8647
 8648        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8649
 8650        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8651
 8652        element.prepaint_at(origin, window, cx);
 8653        Some((element, origin))
 8654    }
 8655
 8656    fn render_edit_prediction_eager_jump_popover(
 8657        &mut self,
 8658        text_bounds: &Bounds<Pixels>,
 8659        content_origin: gpui::Point<Pixels>,
 8660        editor_snapshot: &EditorSnapshot,
 8661        visible_row_range: Range<DisplayRow>,
 8662        scroll_top: f32,
 8663        scroll_bottom: f32,
 8664        line_height: Pixels,
 8665        scroll_pixel_position: gpui::Point<Pixels>,
 8666        target_display_point: DisplayPoint,
 8667        editor_width: Pixels,
 8668        window: &mut Window,
 8669        cx: &mut App,
 8670    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8671        if target_display_point.row().as_f32() < scroll_top {
 8672            let mut element = self
 8673                .render_edit_prediction_line_popover(
 8674                    "Jump to Edit",
 8675                    Some(IconName::ArrowUp),
 8676                    window,
 8677                    cx,
 8678                )?
 8679                .into_any();
 8680
 8681            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8682            let offset = point(
 8683                (text_bounds.size.width - size.width) / 2.,
 8684                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8685            );
 8686
 8687            let origin = text_bounds.origin + offset;
 8688            element.prepaint_at(origin, window, cx);
 8689            Some((element, origin))
 8690        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8691            let mut element = self
 8692                .render_edit_prediction_line_popover(
 8693                    "Jump to Edit",
 8694                    Some(IconName::ArrowDown),
 8695                    window,
 8696                    cx,
 8697                )?
 8698                .into_any();
 8699
 8700            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8701            let offset = point(
 8702                (text_bounds.size.width - size.width) / 2.,
 8703                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8704            );
 8705
 8706            let origin = text_bounds.origin + offset;
 8707            element.prepaint_at(origin, window, cx);
 8708            Some((element, origin))
 8709        } else {
 8710            self.render_edit_prediction_end_of_line_popover(
 8711                "Jump to Edit",
 8712                editor_snapshot,
 8713                visible_row_range,
 8714                target_display_point,
 8715                line_height,
 8716                scroll_pixel_position,
 8717                content_origin,
 8718                editor_width,
 8719                window,
 8720                cx,
 8721            )
 8722        }
 8723    }
 8724
 8725    fn render_edit_prediction_end_of_line_popover(
 8726        self: &mut Editor,
 8727        label: &'static str,
 8728        editor_snapshot: &EditorSnapshot,
 8729        visible_row_range: Range<DisplayRow>,
 8730        target_display_point: DisplayPoint,
 8731        line_height: Pixels,
 8732        scroll_pixel_position: gpui::Point<Pixels>,
 8733        content_origin: gpui::Point<Pixels>,
 8734        editor_width: Pixels,
 8735        window: &mut Window,
 8736        cx: &mut App,
 8737    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8738        let target_line_end = DisplayPoint::new(
 8739            target_display_point.row(),
 8740            editor_snapshot.line_len(target_display_point.row()),
 8741        );
 8742
 8743        let mut element = self
 8744            .render_edit_prediction_line_popover(label, None, window, cx)?
 8745            .into_any();
 8746
 8747        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8748
 8749        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8750
 8751        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8752        let mut origin = start_point
 8753            + line_origin
 8754            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8755        origin.x = origin.x.max(content_origin.x);
 8756
 8757        let max_x = content_origin.x + editor_width - size.width;
 8758
 8759        if origin.x > max_x {
 8760            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8761
 8762            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8763                origin.y += offset;
 8764                IconName::ArrowUp
 8765            } else {
 8766                origin.y -= offset;
 8767                IconName::ArrowDown
 8768            };
 8769
 8770            element = self
 8771                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8772                .into_any();
 8773
 8774            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8775
 8776            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8777        }
 8778
 8779        element.prepaint_at(origin, window, cx);
 8780        Some((element, origin))
 8781    }
 8782
 8783    fn render_edit_prediction_diff_popover(
 8784        self: &Editor,
 8785        text_bounds: &Bounds<Pixels>,
 8786        content_origin: gpui::Point<Pixels>,
 8787        right_margin: Pixels,
 8788        editor_snapshot: &EditorSnapshot,
 8789        visible_row_range: Range<DisplayRow>,
 8790        line_layouts: &[LineWithInvisibles],
 8791        line_height: Pixels,
 8792        scroll_pixel_position: gpui::Point<Pixels>,
 8793        newest_selection_head: Option<DisplayPoint>,
 8794        editor_width: Pixels,
 8795        style: &EditorStyle,
 8796        edits: &Vec<(Range<Anchor>, String)>,
 8797        edit_preview: &Option<language::EditPreview>,
 8798        snapshot: &language::BufferSnapshot,
 8799        window: &mut Window,
 8800        cx: &mut App,
 8801    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8802        let edit_start = edits
 8803            .first()
 8804            .unwrap()
 8805            .0
 8806            .start
 8807            .to_display_point(editor_snapshot);
 8808        let edit_end = edits
 8809            .last()
 8810            .unwrap()
 8811            .0
 8812            .end
 8813            .to_display_point(editor_snapshot);
 8814
 8815        let is_visible = visible_row_range.contains(&edit_start.row())
 8816            || visible_row_range.contains(&edit_end.row());
 8817        if !is_visible {
 8818            return None;
 8819        }
 8820
 8821        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8822            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8823        } else {
 8824            // Fallback for providers without edit_preview
 8825            crate::edit_prediction_fallback_text(edits, cx)
 8826        };
 8827
 8828        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8829        let line_count = highlighted_edits.text.lines().count();
 8830
 8831        const BORDER_WIDTH: Pixels = px(1.);
 8832
 8833        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8834        let has_keybind = keybind.is_some();
 8835
 8836        let mut element = h_flex()
 8837            .items_start()
 8838            .child(
 8839                h_flex()
 8840                    .bg(cx.theme().colors().editor_background)
 8841                    .border(BORDER_WIDTH)
 8842                    .shadow_xs()
 8843                    .border_color(cx.theme().colors().border)
 8844                    .rounded_l_lg()
 8845                    .when(line_count > 1, |el| el.rounded_br_lg())
 8846                    .pr_1()
 8847                    .child(styled_text),
 8848            )
 8849            .child(
 8850                h_flex()
 8851                    .h(line_height + BORDER_WIDTH * 2.)
 8852                    .px_1p5()
 8853                    .gap_1()
 8854                    // Workaround: For some reason, there's a gap if we don't do this
 8855                    .ml(-BORDER_WIDTH)
 8856                    .shadow(vec![gpui::BoxShadow {
 8857                        color: gpui::black().opacity(0.05),
 8858                        offset: point(px(1.), px(1.)),
 8859                        blur_radius: px(2.),
 8860                        spread_radius: px(0.),
 8861                    }])
 8862                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8863                    .border(BORDER_WIDTH)
 8864                    .border_color(cx.theme().colors().border)
 8865                    .rounded_r_lg()
 8866                    .id("edit_prediction_diff_popover_keybind")
 8867                    .when(!has_keybind, |el| {
 8868                        let status_colors = cx.theme().status();
 8869
 8870                        el.bg(status_colors.error_background)
 8871                            .border_color(status_colors.error.opacity(0.6))
 8872                            .child(Icon::new(IconName::Info).color(Color::Error))
 8873                            .cursor_default()
 8874                            .hoverable_tooltip(move |_window, cx| {
 8875                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8876                            })
 8877                    })
 8878                    .children(keybind),
 8879            )
 8880            .into_any();
 8881
 8882        let longest_row =
 8883            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8884        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8885            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8886        } else {
 8887            layout_line(
 8888                longest_row,
 8889                editor_snapshot,
 8890                style,
 8891                editor_width,
 8892                |_| false,
 8893                window,
 8894                cx,
 8895            )
 8896            .width
 8897        };
 8898
 8899        let viewport_bounds =
 8900            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8901                right: -right_margin,
 8902                ..Default::default()
 8903            });
 8904
 8905        let x_after_longest =
 8906            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8907                - scroll_pixel_position.x;
 8908
 8909        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8910
 8911        // Fully visible if it can be displayed within the window (allow overlapping other
 8912        // panes). However, this is only allowed if the popover starts within text_bounds.
 8913        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8914            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8915
 8916        let mut origin = if can_position_to_the_right {
 8917            point(
 8918                x_after_longest,
 8919                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8920                    - scroll_pixel_position.y,
 8921            )
 8922        } else {
 8923            let cursor_row = newest_selection_head.map(|head| head.row());
 8924            let above_edit = edit_start
 8925                .row()
 8926                .0
 8927                .checked_sub(line_count as u32)
 8928                .map(DisplayRow);
 8929            let below_edit = Some(edit_end.row() + 1);
 8930            let above_cursor =
 8931                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8932            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8933
 8934            // Place the edit popover adjacent to the edit if there is a location
 8935            // available that is onscreen and does not obscure the cursor. Otherwise,
 8936            // place it adjacent to the cursor.
 8937            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8938                .into_iter()
 8939                .flatten()
 8940                .find(|&start_row| {
 8941                    let end_row = start_row + line_count as u32;
 8942                    visible_row_range.contains(&start_row)
 8943                        && visible_row_range.contains(&end_row)
 8944                        && cursor_row
 8945                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 8946                })?;
 8947
 8948            content_origin
 8949                + point(
 8950                    -scroll_pixel_position.x,
 8951                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8952                )
 8953        };
 8954
 8955        origin.x -= BORDER_WIDTH;
 8956
 8957        window.defer_draw(element, origin, 1);
 8958
 8959        // Do not return an element, since it will already be drawn due to defer_draw.
 8960        None
 8961    }
 8962
 8963    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8964        px(30.)
 8965    }
 8966
 8967    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8968        if self.read_only(cx) {
 8969            cx.theme().players().read_only()
 8970        } else {
 8971            self.style.as_ref().unwrap().local_player
 8972        }
 8973    }
 8974
 8975    fn render_edit_prediction_accept_keybind(
 8976        &self,
 8977        window: &mut Window,
 8978        cx: &App,
 8979    ) -> Option<AnyElement> {
 8980        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8981        let accept_keystroke = accept_binding.keystroke()?;
 8982
 8983        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8984
 8985        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8986            Color::Accent
 8987        } else {
 8988            Color::Muted
 8989        };
 8990
 8991        h_flex()
 8992            .px_0p5()
 8993            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8994            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8995            .text_size(TextSize::XSmall.rems(cx))
 8996            .child(h_flex().children(ui::render_modifiers(
 8997                &accept_keystroke.modifiers,
 8998                PlatformStyle::platform(),
 8999                Some(modifiers_color),
 9000                Some(IconSize::XSmall.rems().into()),
 9001                true,
 9002            )))
 9003            .when(is_platform_style_mac, |parent| {
 9004                parent.child(accept_keystroke.key.clone())
 9005            })
 9006            .when(!is_platform_style_mac, |parent| {
 9007                parent.child(
 9008                    Key::new(
 9009                        util::capitalize(&accept_keystroke.key),
 9010                        Some(Color::Default),
 9011                    )
 9012                    .size(Some(IconSize::XSmall.rems().into())),
 9013                )
 9014            })
 9015            .into_any()
 9016            .into()
 9017    }
 9018
 9019    fn render_edit_prediction_line_popover(
 9020        &self,
 9021        label: impl Into<SharedString>,
 9022        icon: Option<IconName>,
 9023        window: &mut Window,
 9024        cx: &App,
 9025    ) -> Option<Stateful<Div>> {
 9026        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9027
 9028        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9029        let has_keybind = keybind.is_some();
 9030
 9031        let result = h_flex()
 9032            .id("ep-line-popover")
 9033            .py_0p5()
 9034            .pl_1()
 9035            .pr(padding_right)
 9036            .gap_1()
 9037            .rounded_md()
 9038            .border_1()
 9039            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9040            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9041            .shadow_xs()
 9042            .when(!has_keybind, |el| {
 9043                let status_colors = cx.theme().status();
 9044
 9045                el.bg(status_colors.error_background)
 9046                    .border_color(status_colors.error.opacity(0.6))
 9047                    .pl_2()
 9048                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9049                    .cursor_default()
 9050                    .hoverable_tooltip(move |_window, cx| {
 9051                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9052                    })
 9053            })
 9054            .children(keybind)
 9055            .child(
 9056                Label::new(label)
 9057                    .size(LabelSize::Small)
 9058                    .when(!has_keybind, |el| {
 9059                        el.color(cx.theme().status().error.into()).strikethrough()
 9060                    }),
 9061            )
 9062            .when(!has_keybind, |el| {
 9063                el.child(
 9064                    h_flex().ml_1().child(
 9065                        Icon::new(IconName::Info)
 9066                            .size(IconSize::Small)
 9067                            .color(cx.theme().status().error.into()),
 9068                    ),
 9069                )
 9070            })
 9071            .when_some(icon, |element, icon| {
 9072                element.child(
 9073                    div()
 9074                        .mt(px(1.5))
 9075                        .child(Icon::new(icon).size(IconSize::Small)),
 9076                )
 9077            });
 9078
 9079        Some(result)
 9080    }
 9081
 9082    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9083        let accent_color = cx.theme().colors().text_accent;
 9084        let editor_bg_color = cx.theme().colors().editor_background;
 9085        editor_bg_color.blend(accent_color.opacity(0.1))
 9086    }
 9087
 9088    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9089        let accent_color = cx.theme().colors().text_accent;
 9090        let editor_bg_color = cx.theme().colors().editor_background;
 9091        editor_bg_color.blend(accent_color.opacity(0.6))
 9092    }
 9093    fn get_prediction_provider_icon_name(
 9094        provider: &Option<RegisteredEditPredictionProvider>,
 9095    ) -> IconName {
 9096        match provider {
 9097            Some(provider) => match provider.provider.name() {
 9098                "copilot" => IconName::Copilot,
 9099                "supermaven" => IconName::Supermaven,
 9100                _ => IconName::ZedPredict,
 9101            },
 9102            None => IconName::ZedPredict,
 9103        }
 9104    }
 9105
 9106    fn render_edit_prediction_cursor_popover(
 9107        &self,
 9108        min_width: Pixels,
 9109        max_width: Pixels,
 9110        cursor_point: Point,
 9111        style: &EditorStyle,
 9112        accept_keystroke: Option<&gpui::Keystroke>,
 9113        _window: &Window,
 9114        cx: &mut Context<Editor>,
 9115    ) -> Option<AnyElement> {
 9116        let provider = self.edit_prediction_provider.as_ref()?;
 9117        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9118
 9119        if provider.provider.needs_terms_acceptance(cx) {
 9120            return Some(
 9121                h_flex()
 9122                    .min_w(min_width)
 9123                    .flex_1()
 9124                    .px_2()
 9125                    .py_1()
 9126                    .gap_3()
 9127                    .elevation_2(cx)
 9128                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9129                    .id("accept-terms")
 9130                    .cursor_pointer()
 9131                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9132                    .on_click(cx.listener(|this, _event, window, cx| {
 9133                        cx.stop_propagation();
 9134                        this.report_editor_event(ReportEditorEvent::ZetaTosClicked, None, cx);
 9135                        window.dispatch_action(
 9136                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9137                            cx,
 9138                        );
 9139                    }))
 9140                    .child(
 9141                        h_flex()
 9142                            .flex_1()
 9143                            .gap_2()
 9144                            .child(Icon::new(provider_icon))
 9145                            .child(Label::new("Accept Terms of Service"))
 9146                            .child(div().w_full())
 9147                            .child(
 9148                                Icon::new(IconName::ArrowUpRight)
 9149                                    .color(Color::Muted)
 9150                                    .size(IconSize::Small),
 9151                            )
 9152                            .into_any_element(),
 9153                    )
 9154                    .into_any(),
 9155            );
 9156        }
 9157
 9158        let is_refreshing = provider.provider.is_refreshing(cx);
 9159
 9160        fn pending_completion_container(icon: IconName) -> Div {
 9161            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9162        }
 9163
 9164        let completion = match &self.active_edit_prediction {
 9165            Some(prediction) => {
 9166                if !self.has_visible_completions_menu() {
 9167                    const RADIUS: Pixels = px(6.);
 9168                    const BORDER_WIDTH: Pixels = px(1.);
 9169
 9170                    return Some(
 9171                        h_flex()
 9172                            .elevation_2(cx)
 9173                            .border(BORDER_WIDTH)
 9174                            .border_color(cx.theme().colors().border)
 9175                            .when(accept_keystroke.is_none(), |el| {
 9176                                el.border_color(cx.theme().status().error)
 9177                            })
 9178                            .rounded(RADIUS)
 9179                            .rounded_tl(px(0.))
 9180                            .overflow_hidden()
 9181                            .child(div().px_1p5().child(match &prediction.completion {
 9182                                EditPrediction::Move { target, snapshot } => {
 9183                                    use text::ToPoint as _;
 9184                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9185                                    {
 9186                                        Icon::new(IconName::ZedPredictDown)
 9187                                    } else {
 9188                                        Icon::new(IconName::ZedPredictUp)
 9189                                    }
 9190                                }
 9191                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9192                            }))
 9193                            .child(
 9194                                h_flex()
 9195                                    .gap_1()
 9196                                    .py_1()
 9197                                    .px_2()
 9198                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9199                                    .border_l_1()
 9200                                    .border_color(cx.theme().colors().border)
 9201                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9202                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9203                                        el.child(
 9204                                            Label::new("Hold")
 9205                                                .size(LabelSize::Small)
 9206                                                .when(accept_keystroke.is_none(), |el| {
 9207                                                    el.strikethrough()
 9208                                                })
 9209                                                .line_height_style(LineHeightStyle::UiLabel),
 9210                                        )
 9211                                    })
 9212                                    .id("edit_prediction_cursor_popover_keybind")
 9213                                    .when(accept_keystroke.is_none(), |el| {
 9214                                        let status_colors = cx.theme().status();
 9215
 9216                                        el.bg(status_colors.error_background)
 9217                                            .border_color(status_colors.error.opacity(0.6))
 9218                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9219                                            .cursor_default()
 9220                                            .hoverable_tooltip(move |_window, cx| {
 9221                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9222                                                    .into()
 9223                                            })
 9224                                    })
 9225                                    .when_some(
 9226                                        accept_keystroke.as_ref(),
 9227                                        |el, accept_keystroke| {
 9228                                            el.child(h_flex().children(ui::render_modifiers(
 9229                                                &accept_keystroke.modifiers,
 9230                                                PlatformStyle::platform(),
 9231                                                Some(Color::Default),
 9232                                                Some(IconSize::XSmall.rems().into()),
 9233                                                false,
 9234                                            )))
 9235                                        },
 9236                                    ),
 9237                            )
 9238                            .into_any(),
 9239                    );
 9240                }
 9241
 9242                self.render_edit_prediction_cursor_popover_preview(
 9243                    prediction,
 9244                    cursor_point,
 9245                    style,
 9246                    cx,
 9247                )?
 9248            }
 9249
 9250            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9251                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9252                    stale_completion,
 9253                    cursor_point,
 9254                    style,
 9255                    cx,
 9256                )?,
 9257
 9258                None => pending_completion_container(provider_icon)
 9259                    .child(Label::new("...").size(LabelSize::Small)),
 9260            },
 9261
 9262            None => pending_completion_container(provider_icon)
 9263                .child(Label::new("...").size(LabelSize::Small)),
 9264        };
 9265
 9266        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9267            completion
 9268                .with_animation(
 9269                    "loading-completion",
 9270                    Animation::new(Duration::from_secs(2))
 9271                        .repeat()
 9272                        .with_easing(pulsating_between(0.4, 0.8)),
 9273                    |label, delta| label.opacity(delta),
 9274                )
 9275                .into_any_element()
 9276        } else {
 9277            completion.into_any_element()
 9278        };
 9279
 9280        let has_completion = self.active_edit_prediction.is_some();
 9281
 9282        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9283        Some(
 9284            h_flex()
 9285                .min_w(min_width)
 9286                .max_w(max_width)
 9287                .flex_1()
 9288                .elevation_2(cx)
 9289                .border_color(cx.theme().colors().border)
 9290                .child(
 9291                    div()
 9292                        .flex_1()
 9293                        .py_1()
 9294                        .px_2()
 9295                        .overflow_hidden()
 9296                        .child(completion),
 9297                )
 9298                .when_some(accept_keystroke, |el, accept_keystroke| {
 9299                    if !accept_keystroke.modifiers.modified() {
 9300                        return el;
 9301                    }
 9302
 9303                    el.child(
 9304                        h_flex()
 9305                            .h_full()
 9306                            .border_l_1()
 9307                            .rounded_r_lg()
 9308                            .border_color(cx.theme().colors().border)
 9309                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9310                            .gap_1()
 9311                            .py_1()
 9312                            .px_2()
 9313                            .child(
 9314                                h_flex()
 9315                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9316                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9317                                    .child(h_flex().children(ui::render_modifiers(
 9318                                        &accept_keystroke.modifiers,
 9319                                        PlatformStyle::platform(),
 9320                                        Some(if !has_completion {
 9321                                            Color::Muted
 9322                                        } else {
 9323                                            Color::Default
 9324                                        }),
 9325                                        None,
 9326                                        false,
 9327                                    ))),
 9328                            )
 9329                            .child(Label::new("Preview").into_any_element())
 9330                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9331                    )
 9332                })
 9333                .into_any(),
 9334        )
 9335    }
 9336
 9337    fn render_edit_prediction_cursor_popover_preview(
 9338        &self,
 9339        completion: &EditPredictionState,
 9340        cursor_point: Point,
 9341        style: &EditorStyle,
 9342        cx: &mut Context<Editor>,
 9343    ) -> Option<Div> {
 9344        use text::ToPoint as _;
 9345
 9346        fn render_relative_row_jump(
 9347            prefix: impl Into<String>,
 9348            current_row: u32,
 9349            target_row: u32,
 9350        ) -> Div {
 9351            let (row_diff, arrow) = if target_row < current_row {
 9352                (current_row - target_row, IconName::ArrowUp)
 9353            } else {
 9354                (target_row - current_row, IconName::ArrowDown)
 9355            };
 9356
 9357            h_flex()
 9358                .child(
 9359                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9360                        .color(Color::Muted)
 9361                        .size(LabelSize::Small),
 9362                )
 9363                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9364        }
 9365
 9366        let supports_jump = self
 9367            .edit_prediction_provider
 9368            .as_ref()
 9369            .map(|provider| provider.provider.supports_jump_to_edit())
 9370            .unwrap_or(true);
 9371
 9372        match &completion.completion {
 9373            EditPrediction::Move {
 9374                target, snapshot, ..
 9375            } => {
 9376                if !supports_jump {
 9377                    return None;
 9378                }
 9379
 9380                Some(
 9381                    h_flex()
 9382                        .px_2()
 9383                        .gap_2()
 9384                        .flex_1()
 9385                        .child(
 9386                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9387                                Icon::new(IconName::ZedPredictDown)
 9388                            } else {
 9389                                Icon::new(IconName::ZedPredictUp)
 9390                            },
 9391                        )
 9392                        .child(Label::new("Jump to Edit")),
 9393                )
 9394            }
 9395
 9396            EditPrediction::Edit {
 9397                edits,
 9398                edit_preview,
 9399                snapshot,
 9400                display_mode: _,
 9401            } => {
 9402                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9403
 9404                let (highlighted_edits, has_more_lines) =
 9405                    if let Some(edit_preview) = edit_preview.as_ref() {
 9406                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9407                            .first_line_preview()
 9408                    } else {
 9409                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9410                    };
 9411
 9412                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9413                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9414
 9415                let preview = h_flex()
 9416                    .gap_1()
 9417                    .min_w_16()
 9418                    .child(styled_text)
 9419                    .when(has_more_lines, |parent| parent.child(""));
 9420
 9421                let left = if supports_jump && first_edit_row != cursor_point.row {
 9422                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9423                        .into_any_element()
 9424                } else {
 9425                    let icon_name =
 9426                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9427                    Icon::new(icon_name).into_any_element()
 9428                };
 9429
 9430                Some(
 9431                    h_flex()
 9432                        .h_full()
 9433                        .flex_1()
 9434                        .gap_2()
 9435                        .pr_1()
 9436                        .overflow_x_hidden()
 9437                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9438                        .child(left)
 9439                        .child(preview),
 9440                )
 9441            }
 9442        }
 9443    }
 9444
 9445    pub fn render_context_menu(
 9446        &self,
 9447        style: &EditorStyle,
 9448        max_height_in_lines: u32,
 9449        window: &mut Window,
 9450        cx: &mut Context<Editor>,
 9451    ) -> Option<AnyElement> {
 9452        let menu = self.context_menu.borrow();
 9453        let menu = menu.as_ref()?;
 9454        if !menu.visible() {
 9455            return None;
 9456        };
 9457        Some(menu.render(style, max_height_in_lines, window, cx))
 9458    }
 9459
 9460    fn render_context_menu_aside(
 9461        &mut self,
 9462        max_size: Size<Pixels>,
 9463        window: &mut Window,
 9464        cx: &mut Context<Editor>,
 9465    ) -> Option<AnyElement> {
 9466        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9467            if menu.visible() {
 9468                menu.render_aside(max_size, window, cx)
 9469            } else {
 9470                None
 9471            }
 9472        })
 9473    }
 9474
 9475    fn hide_context_menu(
 9476        &mut self,
 9477        window: &mut Window,
 9478        cx: &mut Context<Self>,
 9479    ) -> Option<CodeContextMenu> {
 9480        cx.notify();
 9481        self.completion_tasks.clear();
 9482        let context_menu = self.context_menu.borrow_mut().take();
 9483        self.stale_edit_prediction_in_menu.take();
 9484        self.update_visible_edit_prediction(window, cx);
 9485        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9486            && let Some(completion_provider) = &self.completion_provider
 9487        {
 9488            completion_provider.selection_changed(None, window, cx);
 9489        }
 9490        context_menu
 9491    }
 9492
 9493    fn show_snippet_choices(
 9494        &mut self,
 9495        choices: &Vec<String>,
 9496        selection: Range<Anchor>,
 9497        cx: &mut Context<Self>,
 9498    ) {
 9499        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9500            (Some(a), Some(b)) if a == b => a,
 9501            _ => {
 9502                log::error!("expected anchor range to have matching buffer IDs");
 9503                return;
 9504            }
 9505        };
 9506        let multi_buffer = self.buffer().read(cx);
 9507        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9508            return;
 9509        };
 9510
 9511        let id = post_inc(&mut self.next_completion_id);
 9512        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9513        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9514            CompletionsMenu::new_snippet_choices(
 9515                id,
 9516                true,
 9517                choices,
 9518                selection,
 9519                buffer,
 9520                snippet_sort_order,
 9521            ),
 9522        ));
 9523    }
 9524
 9525    pub fn insert_snippet(
 9526        &mut self,
 9527        insertion_ranges: &[Range<usize>],
 9528        snippet: Snippet,
 9529        window: &mut Window,
 9530        cx: &mut Context<Self>,
 9531    ) -> Result<()> {
 9532        struct Tabstop<T> {
 9533            is_end_tabstop: bool,
 9534            ranges: Vec<Range<T>>,
 9535            choices: Option<Vec<String>>,
 9536        }
 9537
 9538        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9539            let snippet_text: Arc<str> = snippet.text.clone().into();
 9540            let edits = insertion_ranges
 9541                .iter()
 9542                .cloned()
 9543                .map(|range| (range, snippet_text.clone()));
 9544            let autoindent_mode = AutoindentMode::Block {
 9545                original_indent_columns: Vec::new(),
 9546            };
 9547            buffer.edit(edits, Some(autoindent_mode), cx);
 9548
 9549            let snapshot = &*buffer.read(cx);
 9550            let snippet = &snippet;
 9551            snippet
 9552                .tabstops
 9553                .iter()
 9554                .map(|tabstop| {
 9555                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9556                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9557                    });
 9558                    let mut tabstop_ranges = tabstop
 9559                        .ranges
 9560                        .iter()
 9561                        .flat_map(|tabstop_range| {
 9562                            let mut delta = 0_isize;
 9563                            insertion_ranges.iter().map(move |insertion_range| {
 9564                                let insertion_start = insertion_range.start as isize + delta;
 9565                                delta +=
 9566                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9567
 9568                                let start = ((insertion_start + tabstop_range.start) as usize)
 9569                                    .min(snapshot.len());
 9570                                let end = ((insertion_start + tabstop_range.end) as usize)
 9571                                    .min(snapshot.len());
 9572                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9573                            })
 9574                        })
 9575                        .collect::<Vec<_>>();
 9576                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9577
 9578                    Tabstop {
 9579                        is_end_tabstop,
 9580                        ranges: tabstop_ranges,
 9581                        choices: tabstop.choices.clone(),
 9582                    }
 9583                })
 9584                .collect::<Vec<_>>()
 9585        });
 9586        if let Some(tabstop) = tabstops.first() {
 9587            self.change_selections(Default::default(), window, cx, |s| {
 9588                // Reverse order so that the first range is the newest created selection.
 9589                // Completions will use it and autoscroll will prioritize it.
 9590                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9591            });
 9592
 9593            if let Some(choices) = &tabstop.choices
 9594                && let Some(selection) = tabstop.ranges.first()
 9595            {
 9596                self.show_snippet_choices(choices, selection.clone(), cx)
 9597            }
 9598
 9599            // If we're already at the last tabstop and it's at the end of the snippet,
 9600            // we're done, we don't need to keep the state around.
 9601            if !tabstop.is_end_tabstop {
 9602                let choices = tabstops
 9603                    .iter()
 9604                    .map(|tabstop| tabstop.choices.clone())
 9605                    .collect();
 9606
 9607                let ranges = tabstops
 9608                    .into_iter()
 9609                    .map(|tabstop| tabstop.ranges)
 9610                    .collect::<Vec<_>>();
 9611
 9612                self.snippet_stack.push(SnippetState {
 9613                    active_index: 0,
 9614                    ranges,
 9615                    choices,
 9616                });
 9617            }
 9618
 9619            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9620            if self.autoclose_regions.is_empty() {
 9621                let snapshot = self.buffer.read(cx).snapshot(cx);
 9622                let mut all_selections = self.selections.all::<Point>(cx);
 9623                for selection in &mut all_selections {
 9624                    let selection_head = selection.head();
 9625                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9626                        continue;
 9627                    };
 9628
 9629                    let mut bracket_pair = None;
 9630                    let max_lookup_length = scope
 9631                        .brackets()
 9632                        .map(|(pair, _)| {
 9633                            pair.start
 9634                                .as_str()
 9635                                .chars()
 9636                                .count()
 9637                                .max(pair.end.as_str().chars().count())
 9638                        })
 9639                        .max();
 9640                    if let Some(max_lookup_length) = max_lookup_length {
 9641                        let next_text = snapshot
 9642                            .chars_at(selection_head)
 9643                            .take(max_lookup_length)
 9644                            .collect::<String>();
 9645                        let prev_text = snapshot
 9646                            .reversed_chars_at(selection_head)
 9647                            .take(max_lookup_length)
 9648                            .collect::<String>();
 9649
 9650                        for (pair, enabled) in scope.brackets() {
 9651                            if enabled
 9652                                && pair.close
 9653                                && prev_text.starts_with(pair.start.as_str())
 9654                                && next_text.starts_with(pair.end.as_str())
 9655                            {
 9656                                bracket_pair = Some(pair.clone());
 9657                                break;
 9658                            }
 9659                        }
 9660                    }
 9661
 9662                    if let Some(pair) = bracket_pair {
 9663                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9664                        let autoclose_enabled =
 9665                            self.use_autoclose && snapshot_settings.use_autoclose;
 9666                        if autoclose_enabled {
 9667                            let start = snapshot.anchor_after(selection_head);
 9668                            let end = snapshot.anchor_after(selection_head);
 9669                            self.autoclose_regions.push(AutocloseRegion {
 9670                                selection_id: selection.id,
 9671                                range: start..end,
 9672                                pair,
 9673                            });
 9674                        }
 9675                    }
 9676                }
 9677            }
 9678        }
 9679        Ok(())
 9680    }
 9681
 9682    pub fn move_to_next_snippet_tabstop(
 9683        &mut self,
 9684        window: &mut Window,
 9685        cx: &mut Context<Self>,
 9686    ) -> bool {
 9687        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9688    }
 9689
 9690    pub fn move_to_prev_snippet_tabstop(
 9691        &mut self,
 9692        window: &mut Window,
 9693        cx: &mut Context<Self>,
 9694    ) -> bool {
 9695        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9696    }
 9697
 9698    pub fn move_to_snippet_tabstop(
 9699        &mut self,
 9700        bias: Bias,
 9701        window: &mut Window,
 9702        cx: &mut Context<Self>,
 9703    ) -> bool {
 9704        if let Some(mut snippet) = self.snippet_stack.pop() {
 9705            match bias {
 9706                Bias::Left => {
 9707                    if snippet.active_index > 0 {
 9708                        snippet.active_index -= 1;
 9709                    } else {
 9710                        self.snippet_stack.push(snippet);
 9711                        return false;
 9712                    }
 9713                }
 9714                Bias::Right => {
 9715                    if snippet.active_index + 1 < snippet.ranges.len() {
 9716                        snippet.active_index += 1;
 9717                    } else {
 9718                        self.snippet_stack.push(snippet);
 9719                        return false;
 9720                    }
 9721                }
 9722            }
 9723            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9724                self.change_selections(Default::default(), window, cx, |s| {
 9725                    // Reverse order so that the first range is the newest created selection.
 9726                    // Completions will use it and autoscroll will prioritize it.
 9727                    s.select_ranges(current_ranges.iter().rev().cloned())
 9728                });
 9729
 9730                if let Some(choices) = &snippet.choices[snippet.active_index]
 9731                    && let Some(selection) = current_ranges.first()
 9732                {
 9733                    self.show_snippet_choices(choices, selection.clone(), cx);
 9734                }
 9735
 9736                // If snippet state is not at the last tabstop, push it back on the stack
 9737                if snippet.active_index + 1 < snippet.ranges.len() {
 9738                    self.snippet_stack.push(snippet);
 9739                }
 9740                return true;
 9741            }
 9742        }
 9743
 9744        false
 9745    }
 9746
 9747    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9748        self.transact(window, cx, |this, window, cx| {
 9749            this.select_all(&SelectAll, window, cx);
 9750            this.insert("", window, cx);
 9751        });
 9752    }
 9753
 9754    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9755        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9756        self.transact(window, cx, |this, window, cx| {
 9757            this.select_autoclose_pair(window, cx);
 9758            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9759            if !this.linked_edit_ranges.is_empty() {
 9760                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9761                let snapshot = this.buffer.read(cx).snapshot(cx);
 9762
 9763                for selection in selections.iter() {
 9764                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9765                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9766                    if selection_start.buffer_id != selection_end.buffer_id {
 9767                        continue;
 9768                    }
 9769                    if let Some(ranges) =
 9770                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9771                    {
 9772                        for (buffer, entries) in ranges {
 9773                            linked_ranges.entry(buffer).or_default().extend(entries);
 9774                        }
 9775                    }
 9776                }
 9777            }
 9778
 9779            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9780            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9781            for selection in &mut selections {
 9782                if selection.is_empty() {
 9783                    let old_head = selection.head();
 9784                    let mut new_head =
 9785                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9786                            .to_point(&display_map);
 9787                    if let Some((buffer, line_buffer_range)) = display_map
 9788                        .buffer_snapshot
 9789                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9790                    {
 9791                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9792                        let indent_len = match indent_size.kind {
 9793                            IndentKind::Space => {
 9794                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9795                            }
 9796                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9797                        };
 9798                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9799                            let indent_len = indent_len.get();
 9800                            new_head = cmp::min(
 9801                                new_head,
 9802                                MultiBufferPoint::new(
 9803                                    old_head.row,
 9804                                    ((old_head.column - 1) / indent_len) * indent_len,
 9805                                ),
 9806                            );
 9807                        }
 9808                    }
 9809
 9810                    selection.set_head(new_head, SelectionGoal::None);
 9811                }
 9812            }
 9813
 9814            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9815            this.insert("", window, cx);
 9816            let empty_str: Arc<str> = Arc::from("");
 9817            for (buffer, edits) in linked_ranges {
 9818                let snapshot = buffer.read(cx).snapshot();
 9819                use text::ToPoint as TP;
 9820
 9821                let edits = edits
 9822                    .into_iter()
 9823                    .map(|range| {
 9824                        let end_point = TP::to_point(&range.end, &snapshot);
 9825                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9826
 9827                        if end_point == start_point {
 9828                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9829                                .saturating_sub(1);
 9830                            start_point =
 9831                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9832                        };
 9833
 9834                        (start_point..end_point, empty_str.clone())
 9835                    })
 9836                    .sorted_by_key(|(range, _)| range.start)
 9837                    .collect::<Vec<_>>();
 9838                buffer.update(cx, |this, cx| {
 9839                    this.edit(edits, None, cx);
 9840                })
 9841            }
 9842            this.refresh_edit_prediction(true, false, window, cx);
 9843            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9844        });
 9845    }
 9846
 9847    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9848        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9849        self.transact(window, cx, |this, window, cx| {
 9850            this.change_selections(Default::default(), window, cx, |s| {
 9851                s.move_with(|map, selection| {
 9852                    if selection.is_empty() {
 9853                        let cursor = movement::right(map, selection.head());
 9854                        selection.end = cursor;
 9855                        selection.reversed = true;
 9856                        selection.goal = SelectionGoal::None;
 9857                    }
 9858                })
 9859            });
 9860            this.insert("", window, cx);
 9861            this.refresh_edit_prediction(true, false, window, cx);
 9862        });
 9863    }
 9864
 9865    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9866        if self.mode.is_single_line() {
 9867            cx.propagate();
 9868            return;
 9869        }
 9870
 9871        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9872        if self.move_to_prev_snippet_tabstop(window, cx) {
 9873            return;
 9874        }
 9875        self.outdent(&Outdent, window, cx);
 9876    }
 9877
 9878    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9879        if self.mode.is_single_line() {
 9880            cx.propagate();
 9881            return;
 9882        }
 9883
 9884        if self.move_to_next_snippet_tabstop(window, cx) {
 9885            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9886            return;
 9887        }
 9888        if self.read_only(cx) {
 9889            return;
 9890        }
 9891        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9892        let mut selections = self.selections.all_adjusted(cx);
 9893        let buffer = self.buffer.read(cx);
 9894        let snapshot = buffer.snapshot(cx);
 9895        let rows_iter = selections.iter().map(|s| s.head().row);
 9896        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9897
 9898        let has_some_cursor_in_whitespace = selections
 9899            .iter()
 9900            .filter(|selection| selection.is_empty())
 9901            .any(|selection| {
 9902                let cursor = selection.head();
 9903                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9904                cursor.column < current_indent.len
 9905            });
 9906
 9907        let mut edits = Vec::new();
 9908        let mut prev_edited_row = 0;
 9909        let mut row_delta = 0;
 9910        for selection in &mut selections {
 9911            if selection.start.row != prev_edited_row {
 9912                row_delta = 0;
 9913            }
 9914            prev_edited_row = selection.end.row;
 9915
 9916            // If the selection is non-empty, then increase the indentation of the selected lines.
 9917            if !selection.is_empty() {
 9918                row_delta =
 9919                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9920                continue;
 9921            }
 9922
 9923            let cursor = selection.head();
 9924            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9925            if let Some(suggested_indent) =
 9926                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9927            {
 9928                // Don't do anything if already at suggested indent
 9929                // and there is any other cursor which is not
 9930                if has_some_cursor_in_whitespace
 9931                    && cursor.column == current_indent.len
 9932                    && current_indent.len == suggested_indent.len
 9933                {
 9934                    continue;
 9935                }
 9936
 9937                // Adjust line and move cursor to suggested indent
 9938                // if cursor is not at suggested indent
 9939                if cursor.column < suggested_indent.len
 9940                    && cursor.column <= current_indent.len
 9941                    && current_indent.len <= suggested_indent.len
 9942                {
 9943                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9944                    selection.end = selection.start;
 9945                    if row_delta == 0 {
 9946                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9947                            cursor.row,
 9948                            current_indent,
 9949                            suggested_indent,
 9950                        ));
 9951                        row_delta = suggested_indent.len - current_indent.len;
 9952                    }
 9953                    continue;
 9954                }
 9955
 9956                // If current indent is more than suggested indent
 9957                // only move cursor to current indent and skip indent
 9958                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9959                    selection.start = Point::new(cursor.row, current_indent.len);
 9960                    selection.end = selection.start;
 9961                    continue;
 9962                }
 9963            }
 9964
 9965            // Otherwise, insert a hard or soft tab.
 9966            let settings = buffer.language_settings_at(cursor, cx);
 9967            let tab_size = if settings.hard_tabs {
 9968                IndentSize::tab()
 9969            } else {
 9970                let tab_size = settings.tab_size.get();
 9971                let indent_remainder = snapshot
 9972                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9973                    .flat_map(str::chars)
 9974                    .fold(row_delta % tab_size, |counter: u32, c| {
 9975                        if c == '\t' {
 9976                            0
 9977                        } else {
 9978                            (counter + 1) % tab_size
 9979                        }
 9980                    });
 9981
 9982                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9983                IndentSize::spaces(chars_to_next_tab_stop)
 9984            };
 9985            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9986            selection.end = selection.start;
 9987            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9988            row_delta += tab_size.len;
 9989        }
 9990
 9991        self.transact(window, cx, |this, window, cx| {
 9992            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9993            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9994            this.refresh_edit_prediction(true, false, window, cx);
 9995        });
 9996    }
 9997
 9998    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9999        if self.read_only(cx) {
10000            return;
10001        }
10002        if self.mode.is_single_line() {
10003            cx.propagate();
10004            return;
10005        }
10006
10007        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10008        let mut selections = self.selections.all::<Point>(cx);
10009        let mut prev_edited_row = 0;
10010        let mut row_delta = 0;
10011        let mut edits = Vec::new();
10012        let buffer = self.buffer.read(cx);
10013        let snapshot = buffer.snapshot(cx);
10014        for selection in &mut selections {
10015            if selection.start.row != prev_edited_row {
10016                row_delta = 0;
10017            }
10018            prev_edited_row = selection.end.row;
10019
10020            row_delta =
10021                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10022        }
10023
10024        self.transact(window, cx, |this, window, cx| {
10025            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10026            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10027        });
10028    }
10029
10030    fn indent_selection(
10031        buffer: &MultiBuffer,
10032        snapshot: &MultiBufferSnapshot,
10033        selection: &mut Selection<Point>,
10034        edits: &mut Vec<(Range<Point>, String)>,
10035        delta_for_start_row: u32,
10036        cx: &App,
10037    ) -> u32 {
10038        let settings = buffer.language_settings_at(selection.start, cx);
10039        let tab_size = settings.tab_size.get();
10040        let indent_kind = if settings.hard_tabs {
10041            IndentKind::Tab
10042        } else {
10043            IndentKind::Space
10044        };
10045        let mut start_row = selection.start.row;
10046        let mut end_row = selection.end.row + 1;
10047
10048        // If a selection ends at the beginning of a line, don't indent
10049        // that last line.
10050        if selection.end.column == 0 && selection.end.row > selection.start.row {
10051            end_row -= 1;
10052        }
10053
10054        // Avoid re-indenting a row that has already been indented by a
10055        // previous selection, but still update this selection's column
10056        // to reflect that indentation.
10057        if delta_for_start_row > 0 {
10058            start_row += 1;
10059            selection.start.column += delta_for_start_row;
10060            if selection.end.row == selection.start.row {
10061                selection.end.column += delta_for_start_row;
10062            }
10063        }
10064
10065        let mut delta_for_end_row = 0;
10066        let has_multiple_rows = start_row + 1 != end_row;
10067        for row in start_row..end_row {
10068            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10069            let indent_delta = match (current_indent.kind, indent_kind) {
10070                (IndentKind::Space, IndentKind::Space) => {
10071                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10072                    IndentSize::spaces(columns_to_next_tab_stop)
10073                }
10074                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10075                (_, IndentKind::Tab) => IndentSize::tab(),
10076            };
10077
10078            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10079                0
10080            } else {
10081                selection.start.column
10082            };
10083            let row_start = Point::new(row, start);
10084            edits.push((
10085                row_start..row_start,
10086                indent_delta.chars().collect::<String>(),
10087            ));
10088
10089            // Update this selection's endpoints to reflect the indentation.
10090            if row == selection.start.row {
10091                selection.start.column += indent_delta.len;
10092            }
10093            if row == selection.end.row {
10094                selection.end.column += indent_delta.len;
10095                delta_for_end_row = indent_delta.len;
10096            }
10097        }
10098
10099        if selection.start.row == selection.end.row {
10100            delta_for_start_row + delta_for_end_row
10101        } else {
10102            delta_for_end_row
10103        }
10104    }
10105
10106    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10107        if self.read_only(cx) {
10108            return;
10109        }
10110        if self.mode.is_single_line() {
10111            cx.propagate();
10112            return;
10113        }
10114
10115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10116        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10117        let selections = self.selections.all::<Point>(cx);
10118        let mut deletion_ranges = Vec::new();
10119        let mut last_outdent = None;
10120        {
10121            let buffer = self.buffer.read(cx);
10122            let snapshot = buffer.snapshot(cx);
10123            for selection in &selections {
10124                let settings = buffer.language_settings_at(selection.start, cx);
10125                let tab_size = settings.tab_size.get();
10126                let mut rows = selection.spanned_rows(false, &display_map);
10127
10128                // Avoid re-outdenting a row that has already been outdented by a
10129                // previous selection.
10130                if let Some(last_row) = last_outdent
10131                    && last_row == rows.start
10132                {
10133                    rows.start = rows.start.next_row();
10134                }
10135                let has_multiple_rows = rows.len() > 1;
10136                for row in rows.iter_rows() {
10137                    let indent_size = snapshot.indent_size_for_line(row);
10138                    if indent_size.len > 0 {
10139                        let deletion_len = match indent_size.kind {
10140                            IndentKind::Space => {
10141                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10142                                if columns_to_prev_tab_stop == 0 {
10143                                    tab_size
10144                                } else {
10145                                    columns_to_prev_tab_stop
10146                                }
10147                            }
10148                            IndentKind::Tab => 1,
10149                        };
10150                        let start = if has_multiple_rows
10151                            || deletion_len > selection.start.column
10152                            || indent_size.len < selection.start.column
10153                        {
10154                            0
10155                        } else {
10156                            selection.start.column - deletion_len
10157                        };
10158                        deletion_ranges.push(
10159                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10160                        );
10161                        last_outdent = Some(row);
10162                    }
10163                }
10164            }
10165        }
10166
10167        self.transact(window, cx, |this, window, cx| {
10168            this.buffer.update(cx, |buffer, cx| {
10169                let empty_str: Arc<str> = Arc::default();
10170                buffer.edit(
10171                    deletion_ranges
10172                        .into_iter()
10173                        .map(|range| (range, empty_str.clone())),
10174                    None,
10175                    cx,
10176                );
10177            });
10178            let selections = this.selections.all::<usize>(cx);
10179            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10180        });
10181    }
10182
10183    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10184        if self.read_only(cx) {
10185            return;
10186        }
10187        if self.mode.is_single_line() {
10188            cx.propagate();
10189            return;
10190        }
10191
10192        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10193        let selections = self
10194            .selections
10195            .all::<usize>(cx)
10196            .into_iter()
10197            .map(|s| s.range());
10198
10199        self.transact(window, cx, |this, window, cx| {
10200            this.buffer.update(cx, |buffer, cx| {
10201                buffer.autoindent_ranges(selections, cx);
10202            });
10203            let selections = this.selections.all::<usize>(cx);
10204            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10205        });
10206    }
10207
10208    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10209        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10210        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10211        let selections = self.selections.all::<Point>(cx);
10212
10213        let mut new_cursors = Vec::new();
10214        let mut edit_ranges = Vec::new();
10215        let mut selections = selections.iter().peekable();
10216        while let Some(selection) = selections.next() {
10217            let mut rows = selection.spanned_rows(false, &display_map);
10218            let goal_display_column = selection.head().to_display_point(&display_map).column();
10219
10220            // Accumulate contiguous regions of rows that we want to delete.
10221            while let Some(next_selection) = selections.peek() {
10222                let next_rows = next_selection.spanned_rows(false, &display_map);
10223                if next_rows.start <= rows.end {
10224                    rows.end = next_rows.end;
10225                    selections.next().unwrap();
10226                } else {
10227                    break;
10228                }
10229            }
10230
10231            let buffer = &display_map.buffer_snapshot;
10232            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10233            let edit_end;
10234            let cursor_buffer_row;
10235            if buffer.max_point().row >= rows.end.0 {
10236                // If there's a line after the range, delete the \n from the end of the row range
10237                // and position the cursor on the next line.
10238                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10239                cursor_buffer_row = rows.end;
10240            } else {
10241                // If there isn't a line after the range, delete the \n from the line before the
10242                // start of the row range and position the cursor there.
10243                edit_start = edit_start.saturating_sub(1);
10244                edit_end = buffer.len();
10245                cursor_buffer_row = rows.start.previous_row();
10246            }
10247
10248            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10249            *cursor.column_mut() =
10250                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10251
10252            new_cursors.push((
10253                selection.id,
10254                buffer.anchor_after(cursor.to_point(&display_map)),
10255            ));
10256            edit_ranges.push(edit_start..edit_end);
10257        }
10258
10259        self.transact(window, cx, |this, window, cx| {
10260            let buffer = this.buffer.update(cx, |buffer, cx| {
10261                let empty_str: Arc<str> = Arc::default();
10262                buffer.edit(
10263                    edit_ranges
10264                        .into_iter()
10265                        .map(|range| (range, empty_str.clone())),
10266                    None,
10267                    cx,
10268                );
10269                buffer.snapshot(cx)
10270            });
10271            let new_selections = new_cursors
10272                .into_iter()
10273                .map(|(id, cursor)| {
10274                    let cursor = cursor.to_point(&buffer);
10275                    Selection {
10276                        id,
10277                        start: cursor,
10278                        end: cursor,
10279                        reversed: false,
10280                        goal: SelectionGoal::None,
10281                    }
10282                })
10283                .collect();
10284
10285            this.change_selections(Default::default(), window, cx, |s| {
10286                s.select(new_selections);
10287            });
10288        });
10289    }
10290
10291    pub fn join_lines_impl(
10292        &mut self,
10293        insert_whitespace: bool,
10294        window: &mut Window,
10295        cx: &mut Context<Self>,
10296    ) {
10297        if self.read_only(cx) {
10298            return;
10299        }
10300        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10301        for selection in self.selections.all::<Point>(cx) {
10302            let start = MultiBufferRow(selection.start.row);
10303            // Treat single line selections as if they include the next line. Otherwise this action
10304            // would do nothing for single line selections individual cursors.
10305            let end = if selection.start.row == selection.end.row {
10306                MultiBufferRow(selection.start.row + 1)
10307            } else {
10308                MultiBufferRow(selection.end.row)
10309            };
10310
10311            if let Some(last_row_range) = row_ranges.last_mut()
10312                && start <= last_row_range.end
10313            {
10314                last_row_range.end = end;
10315                continue;
10316            }
10317            row_ranges.push(start..end);
10318        }
10319
10320        let snapshot = self.buffer.read(cx).snapshot(cx);
10321        let mut cursor_positions = Vec::new();
10322        for row_range in &row_ranges {
10323            let anchor = snapshot.anchor_before(Point::new(
10324                row_range.end.previous_row().0,
10325                snapshot.line_len(row_range.end.previous_row()),
10326            ));
10327            cursor_positions.push(anchor..anchor);
10328        }
10329
10330        self.transact(window, cx, |this, window, cx| {
10331            for row_range in row_ranges.into_iter().rev() {
10332                for row in row_range.iter_rows().rev() {
10333                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10334                    let next_line_row = row.next_row();
10335                    let indent = snapshot.indent_size_for_line(next_line_row);
10336                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10337
10338                    let replace =
10339                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10340                            " "
10341                        } else {
10342                            ""
10343                        };
10344
10345                    this.buffer.update(cx, |buffer, cx| {
10346                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10347                    });
10348                }
10349            }
10350
10351            this.change_selections(Default::default(), window, cx, |s| {
10352                s.select_anchor_ranges(cursor_positions)
10353            });
10354        });
10355    }
10356
10357    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10358        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10359        self.join_lines_impl(true, window, cx);
10360    }
10361
10362    pub fn sort_lines_case_sensitive(
10363        &mut self,
10364        _: &SortLinesCaseSensitive,
10365        window: &mut Window,
10366        cx: &mut Context<Self>,
10367    ) {
10368        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10369    }
10370
10371    pub fn sort_lines_by_length(
10372        &mut self,
10373        _: &SortLinesByLength,
10374        window: &mut Window,
10375        cx: &mut Context<Self>,
10376    ) {
10377        self.manipulate_immutable_lines(window, cx, |lines| {
10378            lines.sort_by_key(|&line| line.chars().count())
10379        })
10380    }
10381
10382    pub fn sort_lines_case_insensitive(
10383        &mut self,
10384        _: &SortLinesCaseInsensitive,
10385        window: &mut Window,
10386        cx: &mut Context<Self>,
10387    ) {
10388        self.manipulate_immutable_lines(window, cx, |lines| {
10389            lines.sort_by_key(|line| line.to_lowercase())
10390        })
10391    }
10392
10393    pub fn unique_lines_case_insensitive(
10394        &mut self,
10395        _: &UniqueLinesCaseInsensitive,
10396        window: &mut Window,
10397        cx: &mut Context<Self>,
10398    ) {
10399        self.manipulate_immutable_lines(window, cx, |lines| {
10400            let mut seen = HashSet::default();
10401            lines.retain(|line| seen.insert(line.to_lowercase()));
10402        })
10403    }
10404
10405    pub fn unique_lines_case_sensitive(
10406        &mut self,
10407        _: &UniqueLinesCaseSensitive,
10408        window: &mut Window,
10409        cx: &mut Context<Self>,
10410    ) {
10411        self.manipulate_immutable_lines(window, cx, |lines| {
10412            let mut seen = HashSet::default();
10413            lines.retain(|line| seen.insert(*line));
10414        })
10415    }
10416
10417    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10418        let Some(project) = self.project.clone() else {
10419            return;
10420        };
10421        self.reload(project, window, cx)
10422            .detach_and_notify_err(window, cx);
10423    }
10424
10425    pub fn restore_file(
10426        &mut self,
10427        _: &::git::RestoreFile,
10428        window: &mut Window,
10429        cx: &mut Context<Self>,
10430    ) {
10431        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10432        let mut buffer_ids = HashSet::default();
10433        let snapshot = self.buffer().read(cx).snapshot(cx);
10434        for selection in self.selections.all::<usize>(cx) {
10435            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10436        }
10437
10438        let buffer = self.buffer().read(cx);
10439        let ranges = buffer_ids
10440            .into_iter()
10441            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10442            .collect::<Vec<_>>();
10443
10444        self.restore_hunks_in_ranges(ranges, window, cx);
10445    }
10446
10447    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10448        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10449        let selections = self
10450            .selections
10451            .all(cx)
10452            .into_iter()
10453            .map(|s| s.range())
10454            .collect();
10455        self.restore_hunks_in_ranges(selections, window, cx);
10456    }
10457
10458    pub fn restore_hunks_in_ranges(
10459        &mut self,
10460        ranges: Vec<Range<Point>>,
10461        window: &mut Window,
10462        cx: &mut Context<Editor>,
10463    ) {
10464        let mut revert_changes = HashMap::default();
10465        let chunk_by = self
10466            .snapshot(window, cx)
10467            .hunks_for_ranges(ranges)
10468            .into_iter()
10469            .chunk_by(|hunk| hunk.buffer_id);
10470        for (buffer_id, hunks) in &chunk_by {
10471            let hunks = hunks.collect::<Vec<_>>();
10472            for hunk in &hunks {
10473                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10474            }
10475            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10476        }
10477        drop(chunk_by);
10478        if !revert_changes.is_empty() {
10479            self.transact(window, cx, |editor, window, cx| {
10480                editor.restore(revert_changes, window, cx);
10481            });
10482        }
10483    }
10484
10485    pub fn open_active_item_in_terminal(
10486        &mut self,
10487        _: &OpenInTerminal,
10488        window: &mut Window,
10489        cx: &mut Context<Self>,
10490    ) {
10491        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10492            let project_path = buffer.read(cx).project_path(cx)?;
10493            let project = self.project()?.read(cx);
10494            let entry = project.entry_for_path(&project_path, cx)?;
10495            let parent = match &entry.canonical_path {
10496                Some(canonical_path) => canonical_path.to_path_buf(),
10497                None => project.absolute_path(&project_path, cx)?,
10498            }
10499            .parent()?
10500            .to_path_buf();
10501            Some(parent)
10502        }) {
10503            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10504        }
10505    }
10506
10507    fn set_breakpoint_context_menu(
10508        &mut self,
10509        display_row: DisplayRow,
10510        position: Option<Anchor>,
10511        clicked_point: gpui::Point<Pixels>,
10512        window: &mut Window,
10513        cx: &mut Context<Self>,
10514    ) {
10515        let source = self
10516            .buffer
10517            .read(cx)
10518            .snapshot(cx)
10519            .anchor_before(Point::new(display_row.0, 0u32));
10520
10521        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10522
10523        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10524            self,
10525            source,
10526            clicked_point,
10527            context_menu,
10528            window,
10529            cx,
10530        );
10531    }
10532
10533    fn add_edit_breakpoint_block(
10534        &mut self,
10535        anchor: Anchor,
10536        breakpoint: &Breakpoint,
10537        edit_action: BreakpointPromptEditAction,
10538        window: &mut Window,
10539        cx: &mut Context<Self>,
10540    ) {
10541        let weak_editor = cx.weak_entity();
10542        let bp_prompt = cx.new(|cx| {
10543            BreakpointPromptEditor::new(
10544                weak_editor,
10545                anchor,
10546                breakpoint.clone(),
10547                edit_action,
10548                window,
10549                cx,
10550            )
10551        });
10552
10553        let height = bp_prompt.update(cx, |this, cx| {
10554            this.prompt
10555                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10556        });
10557        let cloned_prompt = bp_prompt.clone();
10558        let blocks = vec![BlockProperties {
10559            style: BlockStyle::Sticky,
10560            placement: BlockPlacement::Above(anchor),
10561            height: Some(height),
10562            render: Arc::new(move |cx| {
10563                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10564                cloned_prompt.clone().into_any_element()
10565            }),
10566            priority: 0,
10567        }];
10568
10569        let focus_handle = bp_prompt.focus_handle(cx);
10570        window.focus(&focus_handle);
10571
10572        let block_ids = self.insert_blocks(blocks, None, cx);
10573        bp_prompt.update(cx, |prompt, _| {
10574            prompt.add_block_ids(block_ids);
10575        });
10576    }
10577
10578    pub(crate) fn breakpoint_at_row(
10579        &self,
10580        row: u32,
10581        window: &mut Window,
10582        cx: &mut Context<Self>,
10583    ) -> Option<(Anchor, Breakpoint)> {
10584        let snapshot = self.snapshot(window, cx);
10585        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10586
10587        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10588    }
10589
10590    pub(crate) fn breakpoint_at_anchor(
10591        &self,
10592        breakpoint_position: Anchor,
10593        snapshot: &EditorSnapshot,
10594        cx: &mut Context<Self>,
10595    ) -> Option<(Anchor, Breakpoint)> {
10596        let project = self.project.clone()?;
10597
10598        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10599            snapshot
10600                .buffer_snapshot
10601                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10602        })?;
10603
10604        let enclosing_excerpt = breakpoint_position.excerpt_id;
10605        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10606        let buffer_snapshot = buffer.read(cx).snapshot();
10607
10608        let row = buffer_snapshot
10609            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10610            .row;
10611
10612        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10613        let anchor_end = snapshot
10614            .buffer_snapshot
10615            .anchor_after(Point::new(row, line_len));
10616
10617        self.breakpoint_store
10618            .as_ref()?
10619            .read_with(cx, |breakpoint_store, cx| {
10620                breakpoint_store
10621                    .breakpoints(
10622                        &buffer,
10623                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10624                        &buffer_snapshot,
10625                        cx,
10626                    )
10627                    .next()
10628                    .and_then(|(bp, _)| {
10629                        let breakpoint_row = buffer_snapshot
10630                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10631                            .row;
10632
10633                        if breakpoint_row == row {
10634                            snapshot
10635                                .buffer_snapshot
10636                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10637                                .map(|position| (position, bp.bp.clone()))
10638                        } else {
10639                            None
10640                        }
10641                    })
10642            })
10643    }
10644
10645    pub fn edit_log_breakpoint(
10646        &mut self,
10647        _: &EditLogBreakpoint,
10648        window: &mut Window,
10649        cx: &mut Context<Self>,
10650    ) {
10651        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10652            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10653                message: None,
10654                state: BreakpointState::Enabled,
10655                condition: None,
10656                hit_condition: None,
10657            });
10658
10659            self.add_edit_breakpoint_block(
10660                anchor,
10661                &breakpoint,
10662                BreakpointPromptEditAction::Log,
10663                window,
10664                cx,
10665            );
10666        }
10667    }
10668
10669    fn breakpoints_at_cursors(
10670        &self,
10671        window: &mut Window,
10672        cx: &mut Context<Self>,
10673    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10674        let snapshot = self.snapshot(window, cx);
10675        let cursors = self
10676            .selections
10677            .disjoint_anchors()
10678            .iter()
10679            .map(|selection| {
10680                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10681
10682                let breakpoint_position = self
10683                    .breakpoint_at_row(cursor_position.row, window, cx)
10684                    .map(|bp| bp.0)
10685                    .unwrap_or_else(|| {
10686                        snapshot
10687                            .display_snapshot
10688                            .buffer_snapshot
10689                            .anchor_after(Point::new(cursor_position.row, 0))
10690                    });
10691
10692                let breakpoint = self
10693                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10694                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10695
10696                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10697            })
10698            // 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.
10699            .collect::<HashMap<Anchor, _>>();
10700
10701        cursors.into_iter().collect()
10702    }
10703
10704    pub fn enable_breakpoint(
10705        &mut self,
10706        _: &crate::actions::EnableBreakpoint,
10707        window: &mut Window,
10708        cx: &mut Context<Self>,
10709    ) {
10710        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10711            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10712                continue;
10713            };
10714            self.edit_breakpoint_at_anchor(
10715                anchor,
10716                breakpoint,
10717                BreakpointEditAction::InvertState,
10718                cx,
10719            );
10720        }
10721    }
10722
10723    pub fn disable_breakpoint(
10724        &mut self,
10725        _: &crate::actions::DisableBreakpoint,
10726        window: &mut Window,
10727        cx: &mut Context<Self>,
10728    ) {
10729        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10730            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10731                continue;
10732            };
10733            self.edit_breakpoint_at_anchor(
10734                anchor,
10735                breakpoint,
10736                BreakpointEditAction::InvertState,
10737                cx,
10738            );
10739        }
10740    }
10741
10742    pub fn toggle_breakpoint(
10743        &mut self,
10744        _: &crate::actions::ToggleBreakpoint,
10745        window: &mut Window,
10746        cx: &mut Context<Self>,
10747    ) {
10748        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10749            if let Some(breakpoint) = breakpoint {
10750                self.edit_breakpoint_at_anchor(
10751                    anchor,
10752                    breakpoint,
10753                    BreakpointEditAction::Toggle,
10754                    cx,
10755                );
10756            } else {
10757                self.edit_breakpoint_at_anchor(
10758                    anchor,
10759                    Breakpoint::new_standard(),
10760                    BreakpointEditAction::Toggle,
10761                    cx,
10762                );
10763            }
10764        }
10765    }
10766
10767    pub fn edit_breakpoint_at_anchor(
10768        &mut self,
10769        breakpoint_position: Anchor,
10770        breakpoint: Breakpoint,
10771        edit_action: BreakpointEditAction,
10772        cx: &mut Context<Self>,
10773    ) {
10774        let Some(breakpoint_store) = &self.breakpoint_store else {
10775            return;
10776        };
10777
10778        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10779            if breakpoint_position == Anchor::min() {
10780                self.buffer()
10781                    .read(cx)
10782                    .excerpt_buffer_ids()
10783                    .into_iter()
10784                    .next()
10785            } else {
10786                None
10787            }
10788        }) else {
10789            return;
10790        };
10791
10792        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10793            return;
10794        };
10795
10796        breakpoint_store.update(cx, |breakpoint_store, cx| {
10797            breakpoint_store.toggle_breakpoint(
10798                buffer,
10799                BreakpointWithPosition {
10800                    position: breakpoint_position.text_anchor,
10801                    bp: breakpoint,
10802                },
10803                edit_action,
10804                cx,
10805            );
10806        });
10807
10808        cx.notify();
10809    }
10810
10811    #[cfg(any(test, feature = "test-support"))]
10812    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10813        self.breakpoint_store.clone()
10814    }
10815
10816    pub fn prepare_restore_change(
10817        &self,
10818        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10819        hunk: &MultiBufferDiffHunk,
10820        cx: &mut App,
10821    ) -> Option<()> {
10822        if hunk.is_created_file() {
10823            return None;
10824        }
10825        let buffer = self.buffer.read(cx);
10826        let diff = buffer.diff_for(hunk.buffer_id)?;
10827        let buffer = buffer.buffer(hunk.buffer_id)?;
10828        let buffer = buffer.read(cx);
10829        let original_text = diff
10830            .read(cx)
10831            .base_text()
10832            .as_rope()
10833            .slice(hunk.diff_base_byte_range.clone());
10834        let buffer_snapshot = buffer.snapshot();
10835        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10836        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10837            probe
10838                .0
10839                .start
10840                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10841                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10842        }) {
10843            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10844            Some(())
10845        } else {
10846            None
10847        }
10848    }
10849
10850    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10851        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10852    }
10853
10854    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10855        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10856    }
10857
10858    fn manipulate_lines<M>(
10859        &mut self,
10860        window: &mut Window,
10861        cx: &mut Context<Self>,
10862        mut manipulate: M,
10863    ) where
10864        M: FnMut(&str) -> LineManipulationResult,
10865    {
10866        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10867
10868        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10869        let buffer = self.buffer.read(cx).snapshot(cx);
10870
10871        let mut edits = Vec::new();
10872
10873        let selections = self.selections.all::<Point>(cx);
10874        let mut selections = selections.iter().peekable();
10875        let mut contiguous_row_selections = Vec::new();
10876        let mut new_selections = Vec::new();
10877        let mut added_lines = 0;
10878        let mut removed_lines = 0;
10879
10880        while let Some(selection) = selections.next() {
10881            let (start_row, end_row) = consume_contiguous_rows(
10882                &mut contiguous_row_selections,
10883                selection,
10884                &display_map,
10885                &mut selections,
10886            );
10887
10888            let start_point = Point::new(start_row.0, 0);
10889            let end_point = Point::new(
10890                end_row.previous_row().0,
10891                buffer.line_len(end_row.previous_row()),
10892            );
10893            let text = buffer
10894                .text_for_range(start_point..end_point)
10895                .collect::<String>();
10896
10897            let LineManipulationResult {
10898                new_text,
10899                line_count_before,
10900                line_count_after,
10901            } = manipulate(&text);
10902
10903            edits.push((start_point..end_point, new_text));
10904
10905            // Selections must change based on added and removed line count
10906            let start_row =
10907                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10908            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10909            new_selections.push(Selection {
10910                id: selection.id,
10911                start: start_row,
10912                end: end_row,
10913                goal: SelectionGoal::None,
10914                reversed: selection.reversed,
10915            });
10916
10917            if line_count_after > line_count_before {
10918                added_lines += line_count_after - line_count_before;
10919            } else if line_count_before > line_count_after {
10920                removed_lines += line_count_before - line_count_after;
10921            }
10922        }
10923
10924        self.transact(window, cx, |this, window, cx| {
10925            let buffer = this.buffer.update(cx, |buffer, cx| {
10926                buffer.edit(edits, None, cx);
10927                buffer.snapshot(cx)
10928            });
10929
10930            // Recalculate offsets on newly edited buffer
10931            let new_selections = new_selections
10932                .iter()
10933                .map(|s| {
10934                    let start_point = Point::new(s.start.0, 0);
10935                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10936                    Selection {
10937                        id: s.id,
10938                        start: buffer.point_to_offset(start_point),
10939                        end: buffer.point_to_offset(end_point),
10940                        goal: s.goal,
10941                        reversed: s.reversed,
10942                    }
10943                })
10944                .collect();
10945
10946            this.change_selections(Default::default(), window, cx, |s| {
10947                s.select(new_selections);
10948            });
10949
10950            this.request_autoscroll(Autoscroll::fit(), cx);
10951        });
10952    }
10953
10954    fn manipulate_immutable_lines<Fn>(
10955        &mut self,
10956        window: &mut Window,
10957        cx: &mut Context<Self>,
10958        mut callback: Fn,
10959    ) where
10960        Fn: FnMut(&mut Vec<&str>),
10961    {
10962        self.manipulate_lines(window, cx, |text| {
10963            let mut lines: Vec<&str> = text.split('\n').collect();
10964            let line_count_before = lines.len();
10965
10966            callback(&mut lines);
10967
10968            LineManipulationResult {
10969                new_text: lines.join("\n"),
10970                line_count_before,
10971                line_count_after: lines.len(),
10972            }
10973        });
10974    }
10975
10976    fn manipulate_mutable_lines<Fn>(
10977        &mut self,
10978        window: &mut Window,
10979        cx: &mut Context<Self>,
10980        mut callback: Fn,
10981    ) where
10982        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10983    {
10984        self.manipulate_lines(window, cx, |text| {
10985            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10986            let line_count_before = lines.len();
10987
10988            callback(&mut lines);
10989
10990            LineManipulationResult {
10991                new_text: lines.join("\n"),
10992                line_count_before,
10993                line_count_after: lines.len(),
10994            }
10995        });
10996    }
10997
10998    pub fn convert_indentation_to_spaces(
10999        &mut self,
11000        _: &ConvertIndentationToSpaces,
11001        window: &mut Window,
11002        cx: &mut Context<Self>,
11003    ) {
11004        let settings = self.buffer.read(cx).language_settings(cx);
11005        let tab_size = settings.tab_size.get() as usize;
11006
11007        self.manipulate_mutable_lines(window, cx, |lines| {
11008            // Allocates a reasonably sized scratch buffer once for the whole loop
11009            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11010            // Avoids recomputing spaces that could be inserted many times
11011            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11012                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11013                .collect();
11014
11015            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11016                let mut chars = line.as_ref().chars();
11017                let mut col = 0;
11018                let mut changed = false;
11019
11020                for ch in chars.by_ref() {
11021                    match ch {
11022                        ' ' => {
11023                            reindented_line.push(' ');
11024                            col += 1;
11025                        }
11026                        '\t' => {
11027                            // \t are converted to spaces depending on the current column
11028                            let spaces_len = tab_size - (col % tab_size);
11029                            reindented_line.extend(&space_cache[spaces_len - 1]);
11030                            col += spaces_len;
11031                            changed = true;
11032                        }
11033                        _ => {
11034                            // If we dont append before break, the character is consumed
11035                            reindented_line.push(ch);
11036                            break;
11037                        }
11038                    }
11039                }
11040
11041                if !changed {
11042                    reindented_line.clear();
11043                    continue;
11044                }
11045                // Append the rest of the line and replace old reference with new one
11046                reindented_line.extend(chars);
11047                *line = Cow::Owned(reindented_line.clone());
11048                reindented_line.clear();
11049            }
11050        });
11051    }
11052
11053    pub fn convert_indentation_to_tabs(
11054        &mut self,
11055        _: &ConvertIndentationToTabs,
11056        window: &mut Window,
11057        cx: &mut Context<Self>,
11058    ) {
11059        let settings = self.buffer.read(cx).language_settings(cx);
11060        let tab_size = settings.tab_size.get() as usize;
11061
11062        self.manipulate_mutable_lines(window, cx, |lines| {
11063            // Allocates a reasonably sized buffer once for the whole loop
11064            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11065            // Avoids recomputing spaces that could be inserted many times
11066            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11067                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11068                .collect();
11069
11070            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11071                let mut chars = line.chars();
11072                let mut spaces_count = 0;
11073                let mut first_non_indent_char = None;
11074                let mut changed = false;
11075
11076                for ch in chars.by_ref() {
11077                    match ch {
11078                        ' ' => {
11079                            // Keep track of spaces. Append \t when we reach tab_size
11080                            spaces_count += 1;
11081                            changed = true;
11082                            if spaces_count == tab_size {
11083                                reindented_line.push('\t');
11084                                spaces_count = 0;
11085                            }
11086                        }
11087                        '\t' => {
11088                            reindented_line.push('\t');
11089                            spaces_count = 0;
11090                        }
11091                        _ => {
11092                            // Dont append it yet, we might have remaining spaces
11093                            first_non_indent_char = Some(ch);
11094                            break;
11095                        }
11096                    }
11097                }
11098
11099                if !changed {
11100                    reindented_line.clear();
11101                    continue;
11102                }
11103                // Remaining spaces that didn't make a full tab stop
11104                if spaces_count > 0 {
11105                    reindented_line.extend(&space_cache[spaces_count - 1]);
11106                }
11107                // If we consume an extra character that was not indentation, add it back
11108                if let Some(extra_char) = first_non_indent_char {
11109                    reindented_line.push(extra_char);
11110                }
11111                // Append the rest of the line and replace old reference with new one
11112                reindented_line.extend(chars);
11113                *line = Cow::Owned(reindented_line.clone());
11114                reindented_line.clear();
11115            }
11116        });
11117    }
11118
11119    pub fn convert_to_upper_case(
11120        &mut self,
11121        _: &ConvertToUpperCase,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124    ) {
11125        self.manipulate_text(window, cx, |text| text.to_uppercase())
11126    }
11127
11128    pub fn convert_to_lower_case(
11129        &mut self,
11130        _: &ConvertToLowerCase,
11131        window: &mut Window,
11132        cx: &mut Context<Self>,
11133    ) {
11134        self.manipulate_text(window, cx, |text| text.to_lowercase())
11135    }
11136
11137    pub fn convert_to_title_case(
11138        &mut self,
11139        _: &ConvertToTitleCase,
11140        window: &mut Window,
11141        cx: &mut Context<Self>,
11142    ) {
11143        self.manipulate_text(window, cx, |text| {
11144            text.split('\n')
11145                .map(|line| line.to_case(Case::Title))
11146                .join("\n")
11147        })
11148    }
11149
11150    pub fn convert_to_snake_case(
11151        &mut self,
11152        _: &ConvertToSnakeCase,
11153        window: &mut Window,
11154        cx: &mut Context<Self>,
11155    ) {
11156        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11157    }
11158
11159    pub fn convert_to_kebab_case(
11160        &mut self,
11161        _: &ConvertToKebabCase,
11162        window: &mut Window,
11163        cx: &mut Context<Self>,
11164    ) {
11165        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11166    }
11167
11168    pub fn convert_to_upper_camel_case(
11169        &mut self,
11170        _: &ConvertToUpperCamelCase,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173    ) {
11174        self.manipulate_text(window, cx, |text| {
11175            text.split('\n')
11176                .map(|line| line.to_case(Case::UpperCamel))
11177                .join("\n")
11178        })
11179    }
11180
11181    pub fn convert_to_lower_camel_case(
11182        &mut self,
11183        _: &ConvertToLowerCamelCase,
11184        window: &mut Window,
11185        cx: &mut Context<Self>,
11186    ) {
11187        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11188    }
11189
11190    pub fn convert_to_opposite_case(
11191        &mut self,
11192        _: &ConvertToOppositeCase,
11193        window: &mut Window,
11194        cx: &mut Context<Self>,
11195    ) {
11196        self.manipulate_text(window, cx, |text| {
11197            text.chars()
11198                .fold(String::with_capacity(text.len()), |mut t, c| {
11199                    if c.is_uppercase() {
11200                        t.extend(c.to_lowercase());
11201                    } else {
11202                        t.extend(c.to_uppercase());
11203                    }
11204                    t
11205                })
11206        })
11207    }
11208
11209    pub fn convert_to_sentence_case(
11210        &mut self,
11211        _: &ConvertToSentenceCase,
11212        window: &mut Window,
11213        cx: &mut Context<Self>,
11214    ) {
11215        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11216    }
11217
11218    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11219        self.manipulate_text(window, cx, |text| {
11220            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11221            if has_upper_case_characters {
11222                text.to_lowercase()
11223            } else {
11224                text.to_uppercase()
11225            }
11226        })
11227    }
11228
11229    pub fn convert_to_rot13(
11230        &mut self,
11231        _: &ConvertToRot13,
11232        window: &mut Window,
11233        cx: &mut Context<Self>,
11234    ) {
11235        self.manipulate_text(window, cx, |text| {
11236            text.chars()
11237                .map(|c| match c {
11238                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11239                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11240                    _ => c,
11241                })
11242                .collect()
11243        })
11244    }
11245
11246    pub fn convert_to_rot47(
11247        &mut self,
11248        _: &ConvertToRot47,
11249        window: &mut Window,
11250        cx: &mut Context<Self>,
11251    ) {
11252        self.manipulate_text(window, cx, |text| {
11253            text.chars()
11254                .map(|c| {
11255                    let code_point = c as u32;
11256                    if code_point >= 33 && code_point <= 126 {
11257                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11258                    }
11259                    c
11260                })
11261                .collect()
11262        })
11263    }
11264
11265    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11266    where
11267        Fn: FnMut(&str) -> String,
11268    {
11269        let buffer = self.buffer.read(cx).snapshot(cx);
11270
11271        let mut new_selections = Vec::new();
11272        let mut edits = Vec::new();
11273        let mut selection_adjustment = 0i32;
11274
11275        for selection in self.selections.all::<usize>(cx) {
11276            let selection_is_empty = selection.is_empty();
11277
11278            let (start, end) = if selection_is_empty {
11279                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11280                (word_range.start, word_range.end)
11281            } else {
11282                (selection.start, selection.end)
11283            };
11284
11285            let text = buffer.text_for_range(start..end).collect::<String>();
11286            let old_length = text.len() as i32;
11287            let text = callback(&text);
11288
11289            new_selections.push(Selection {
11290                start: (start as i32 - selection_adjustment) as usize,
11291                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11292                goal: SelectionGoal::None,
11293                ..selection
11294            });
11295
11296            selection_adjustment += old_length - text.len() as i32;
11297
11298            edits.push((start..end, text));
11299        }
11300
11301        self.transact(window, cx, |this, window, cx| {
11302            this.buffer.update(cx, |buffer, cx| {
11303                buffer.edit(edits, None, cx);
11304            });
11305
11306            this.change_selections(Default::default(), window, cx, |s| {
11307                s.select(new_selections);
11308            });
11309
11310            this.request_autoscroll(Autoscroll::fit(), cx);
11311        });
11312    }
11313
11314    pub fn move_selection_on_drop(
11315        &mut self,
11316        selection: &Selection<Anchor>,
11317        target: DisplayPoint,
11318        is_cut: bool,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11323        let buffer = &display_map.buffer_snapshot;
11324        let mut edits = Vec::new();
11325        let insert_point = display_map
11326            .clip_point(target, Bias::Left)
11327            .to_point(&display_map);
11328        let text = buffer
11329            .text_for_range(selection.start..selection.end)
11330            .collect::<String>();
11331        if is_cut {
11332            edits.push(((selection.start..selection.end), String::new()));
11333        }
11334        let insert_anchor = buffer.anchor_before(insert_point);
11335        edits.push(((insert_anchor..insert_anchor), text));
11336        let last_edit_start = insert_anchor.bias_left(buffer);
11337        let last_edit_end = insert_anchor.bias_right(buffer);
11338        self.transact(window, cx, |this, window, cx| {
11339            this.buffer.update(cx, |buffer, cx| {
11340                buffer.edit(edits, None, cx);
11341            });
11342            this.change_selections(Default::default(), window, cx, |s| {
11343                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11344            });
11345        });
11346    }
11347
11348    pub fn clear_selection_drag_state(&mut self) {
11349        self.selection_drag_state = SelectionDragState::None;
11350    }
11351
11352    pub fn duplicate(
11353        &mut self,
11354        upwards: bool,
11355        whole_lines: bool,
11356        window: &mut Window,
11357        cx: &mut Context<Self>,
11358    ) {
11359        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11360
11361        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11362        let buffer = &display_map.buffer_snapshot;
11363        let selections = self.selections.all::<Point>(cx);
11364
11365        let mut edits = Vec::new();
11366        let mut selections_iter = selections.iter().peekable();
11367        while let Some(selection) = selections_iter.next() {
11368            let mut rows = selection.spanned_rows(false, &display_map);
11369            // duplicate line-wise
11370            if whole_lines || selection.start == selection.end {
11371                // Avoid duplicating the same lines twice.
11372                while let Some(next_selection) = selections_iter.peek() {
11373                    let next_rows = next_selection.spanned_rows(false, &display_map);
11374                    if next_rows.start < rows.end {
11375                        rows.end = next_rows.end;
11376                        selections_iter.next().unwrap();
11377                    } else {
11378                        break;
11379                    }
11380                }
11381
11382                // Copy the text from the selected row region and splice it either at the start
11383                // or end of the region.
11384                let start = Point::new(rows.start.0, 0);
11385                let end = Point::new(
11386                    rows.end.previous_row().0,
11387                    buffer.line_len(rows.end.previous_row()),
11388                );
11389                let text = buffer
11390                    .text_for_range(start..end)
11391                    .chain(Some("\n"))
11392                    .collect::<String>();
11393                let insert_location = if upwards {
11394                    Point::new(rows.end.0, 0)
11395                } else {
11396                    start
11397                };
11398                edits.push((insert_location..insert_location, text));
11399            } else {
11400                // duplicate character-wise
11401                let start = selection.start;
11402                let end = selection.end;
11403                let text = buffer.text_for_range(start..end).collect::<String>();
11404                edits.push((selection.end..selection.end, text));
11405            }
11406        }
11407
11408        self.transact(window, cx, |this, _, cx| {
11409            this.buffer.update(cx, |buffer, cx| {
11410                buffer.edit(edits, None, cx);
11411            });
11412
11413            this.request_autoscroll(Autoscroll::fit(), cx);
11414        });
11415    }
11416
11417    pub fn duplicate_line_up(
11418        &mut self,
11419        _: &DuplicateLineUp,
11420        window: &mut Window,
11421        cx: &mut Context<Self>,
11422    ) {
11423        self.duplicate(true, true, window, cx);
11424    }
11425
11426    pub fn duplicate_line_down(
11427        &mut self,
11428        _: &DuplicateLineDown,
11429        window: &mut Window,
11430        cx: &mut Context<Self>,
11431    ) {
11432        self.duplicate(false, true, window, cx);
11433    }
11434
11435    pub fn duplicate_selection(
11436        &mut self,
11437        _: &DuplicateSelection,
11438        window: &mut Window,
11439        cx: &mut Context<Self>,
11440    ) {
11441        self.duplicate(false, false, window, cx);
11442    }
11443
11444    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11445        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11446        if self.mode.is_single_line() {
11447            cx.propagate();
11448            return;
11449        }
11450
11451        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11452        let buffer = self.buffer.read(cx).snapshot(cx);
11453
11454        let mut edits = Vec::new();
11455        let mut unfold_ranges = Vec::new();
11456        let mut refold_creases = Vec::new();
11457
11458        let selections = self.selections.all::<Point>(cx);
11459        let mut selections = selections.iter().peekable();
11460        let mut contiguous_row_selections = Vec::new();
11461        let mut new_selections = Vec::new();
11462
11463        while let Some(selection) = selections.next() {
11464            // Find all the selections that span a contiguous row range
11465            let (start_row, end_row) = consume_contiguous_rows(
11466                &mut contiguous_row_selections,
11467                selection,
11468                &display_map,
11469                &mut selections,
11470            );
11471
11472            // Move the text spanned by the row range to be before the line preceding the row range
11473            if start_row.0 > 0 {
11474                let range_to_move = Point::new(
11475                    start_row.previous_row().0,
11476                    buffer.line_len(start_row.previous_row()),
11477                )
11478                    ..Point::new(
11479                        end_row.previous_row().0,
11480                        buffer.line_len(end_row.previous_row()),
11481                    );
11482                let insertion_point = display_map
11483                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11484                    .0;
11485
11486                // Don't move lines across excerpts
11487                if buffer
11488                    .excerpt_containing(insertion_point..range_to_move.end)
11489                    .is_some()
11490                {
11491                    let text = buffer
11492                        .text_for_range(range_to_move.clone())
11493                        .flat_map(|s| s.chars())
11494                        .skip(1)
11495                        .chain(['\n'])
11496                        .collect::<String>();
11497
11498                    edits.push((
11499                        buffer.anchor_after(range_to_move.start)
11500                            ..buffer.anchor_before(range_to_move.end),
11501                        String::new(),
11502                    ));
11503                    let insertion_anchor = buffer.anchor_after(insertion_point);
11504                    edits.push((insertion_anchor..insertion_anchor, text));
11505
11506                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11507
11508                    // Move selections up
11509                    new_selections.extend(contiguous_row_selections.drain(..).map(
11510                        |mut selection| {
11511                            selection.start.row -= row_delta;
11512                            selection.end.row -= row_delta;
11513                            selection
11514                        },
11515                    ));
11516
11517                    // Move folds up
11518                    unfold_ranges.push(range_to_move.clone());
11519                    for fold in display_map.folds_in_range(
11520                        buffer.anchor_before(range_to_move.start)
11521                            ..buffer.anchor_after(range_to_move.end),
11522                    ) {
11523                        let mut start = fold.range.start.to_point(&buffer);
11524                        let mut end = fold.range.end.to_point(&buffer);
11525                        start.row -= row_delta;
11526                        end.row -= row_delta;
11527                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11528                    }
11529                }
11530            }
11531
11532            // If we didn't move line(s), preserve the existing selections
11533            new_selections.append(&mut contiguous_row_selections);
11534        }
11535
11536        self.transact(window, cx, |this, window, cx| {
11537            this.unfold_ranges(&unfold_ranges, true, true, cx);
11538            this.buffer.update(cx, |buffer, cx| {
11539                for (range, text) in edits {
11540                    buffer.edit([(range, text)], None, cx);
11541                }
11542            });
11543            this.fold_creases(refold_creases, true, window, cx);
11544            this.change_selections(Default::default(), window, cx, |s| {
11545                s.select(new_selections);
11546            })
11547        });
11548    }
11549
11550    pub fn move_line_down(
11551        &mut self,
11552        _: &MoveLineDown,
11553        window: &mut Window,
11554        cx: &mut Context<Self>,
11555    ) {
11556        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11557        if self.mode.is_single_line() {
11558            cx.propagate();
11559            return;
11560        }
11561
11562        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11563        let buffer = self.buffer.read(cx).snapshot(cx);
11564
11565        let mut edits = Vec::new();
11566        let mut unfold_ranges = Vec::new();
11567        let mut refold_creases = Vec::new();
11568
11569        let selections = self.selections.all::<Point>(cx);
11570        let mut selections = selections.iter().peekable();
11571        let mut contiguous_row_selections = Vec::new();
11572        let mut new_selections = Vec::new();
11573
11574        while let Some(selection) = selections.next() {
11575            // Find all the selections that span a contiguous row range
11576            let (start_row, end_row) = consume_contiguous_rows(
11577                &mut contiguous_row_selections,
11578                selection,
11579                &display_map,
11580                &mut selections,
11581            );
11582
11583            // Move the text spanned by the row range to be after the last line of the row range
11584            if end_row.0 <= buffer.max_point().row {
11585                let range_to_move =
11586                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11587                let insertion_point = display_map
11588                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11589                    .0;
11590
11591                // Don't move lines across excerpt boundaries
11592                if buffer
11593                    .excerpt_containing(range_to_move.start..insertion_point)
11594                    .is_some()
11595                {
11596                    let mut text = String::from("\n");
11597                    text.extend(buffer.text_for_range(range_to_move.clone()));
11598                    text.pop(); // Drop trailing newline
11599                    edits.push((
11600                        buffer.anchor_after(range_to_move.start)
11601                            ..buffer.anchor_before(range_to_move.end),
11602                        String::new(),
11603                    ));
11604                    let insertion_anchor = buffer.anchor_after(insertion_point);
11605                    edits.push((insertion_anchor..insertion_anchor, text));
11606
11607                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11608
11609                    // Move selections down
11610                    new_selections.extend(contiguous_row_selections.drain(..).map(
11611                        |mut selection| {
11612                            selection.start.row += row_delta;
11613                            selection.end.row += row_delta;
11614                            selection
11615                        },
11616                    ));
11617
11618                    // Move folds down
11619                    unfold_ranges.push(range_to_move.clone());
11620                    for fold in display_map.folds_in_range(
11621                        buffer.anchor_before(range_to_move.start)
11622                            ..buffer.anchor_after(range_to_move.end),
11623                    ) {
11624                        let mut start = fold.range.start.to_point(&buffer);
11625                        let mut end = fold.range.end.to_point(&buffer);
11626                        start.row += row_delta;
11627                        end.row += row_delta;
11628                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11629                    }
11630                }
11631            }
11632
11633            // If we didn't move line(s), preserve the existing selections
11634            new_selections.append(&mut contiguous_row_selections);
11635        }
11636
11637        self.transact(window, cx, |this, window, cx| {
11638            this.unfold_ranges(&unfold_ranges, true, true, cx);
11639            this.buffer.update(cx, |buffer, cx| {
11640                for (range, text) in edits {
11641                    buffer.edit([(range, text)], None, cx);
11642                }
11643            });
11644            this.fold_creases(refold_creases, true, window, cx);
11645            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11646        });
11647    }
11648
11649    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11650        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11651        let text_layout_details = &self.text_layout_details(window);
11652        self.transact(window, cx, |this, window, cx| {
11653            let edits = this.change_selections(Default::default(), window, cx, |s| {
11654                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11655                s.move_with(|display_map, selection| {
11656                    if !selection.is_empty() {
11657                        return;
11658                    }
11659
11660                    let mut head = selection.head();
11661                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11662                    if head.column() == display_map.line_len(head.row()) {
11663                        transpose_offset = display_map
11664                            .buffer_snapshot
11665                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11666                    }
11667
11668                    if transpose_offset == 0 {
11669                        return;
11670                    }
11671
11672                    *head.column_mut() += 1;
11673                    head = display_map.clip_point(head, Bias::Right);
11674                    let goal = SelectionGoal::HorizontalPosition(
11675                        display_map
11676                            .x_for_display_point(head, text_layout_details)
11677                            .into(),
11678                    );
11679                    selection.collapse_to(head, goal);
11680
11681                    let transpose_start = display_map
11682                        .buffer_snapshot
11683                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11684                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11685                        let transpose_end = display_map
11686                            .buffer_snapshot
11687                            .clip_offset(transpose_offset + 1, Bias::Right);
11688                        if let Some(ch) =
11689                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11690                        {
11691                            edits.push((transpose_start..transpose_offset, String::new()));
11692                            edits.push((transpose_end..transpose_end, ch.to_string()));
11693                        }
11694                    }
11695                });
11696                edits
11697            });
11698            this.buffer
11699                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11700            let selections = this.selections.all::<usize>(cx);
11701            this.change_selections(Default::default(), window, cx, |s| {
11702                s.select(selections);
11703            });
11704        });
11705    }
11706
11707    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11709        if self.mode.is_single_line() {
11710            cx.propagate();
11711            return;
11712        }
11713
11714        self.rewrap_impl(RewrapOptions::default(), cx)
11715    }
11716
11717    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11718        let buffer = self.buffer.read(cx).snapshot(cx);
11719        let selections = self.selections.all::<Point>(cx);
11720
11721        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11722        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11723            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11724                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11725                .peekable();
11726
11727            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11728                row
11729            } else {
11730                return Vec::new();
11731            };
11732
11733            let language_settings = buffer.language_settings_at(selection.head(), cx);
11734            let language_scope = buffer.language_scope_at(selection.head());
11735
11736            let indent_and_prefix_for_row =
11737                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11738                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11739                    let (comment_prefix, rewrap_prefix) =
11740                        if let Some(language_scope) = &language_scope {
11741                            let indent_end = Point::new(row, indent.len);
11742                            let comment_prefix = language_scope
11743                                .line_comment_prefixes()
11744                                .iter()
11745                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11746                                .map(|prefix| prefix.to_string());
11747                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11748                            let line_text_after_indent = buffer
11749                                .text_for_range(indent_end..line_end)
11750                                .collect::<String>();
11751                            let rewrap_prefix = language_scope
11752                                .rewrap_prefixes()
11753                                .iter()
11754                                .find_map(|prefix_regex| {
11755                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11756                                        if mat.start() == 0 {
11757                                            Some(mat.as_str().to_string())
11758                                        } else {
11759                                            None
11760                                        }
11761                                    })
11762                                })
11763                                .flatten();
11764                            (comment_prefix, rewrap_prefix)
11765                        } else {
11766                            (None, None)
11767                        };
11768                    (indent, comment_prefix, rewrap_prefix)
11769                };
11770
11771            let mut ranges = Vec::new();
11772            let from_empty_selection = selection.is_empty();
11773
11774            let mut current_range_start = first_row;
11775            let mut prev_row = first_row;
11776            let (
11777                mut current_range_indent,
11778                mut current_range_comment_prefix,
11779                mut current_range_rewrap_prefix,
11780            ) = indent_and_prefix_for_row(first_row);
11781
11782            for row in non_blank_rows_iter.skip(1) {
11783                let has_paragraph_break = row > prev_row + 1;
11784
11785                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11786                    indent_and_prefix_for_row(row);
11787
11788                let has_indent_change = row_indent != current_range_indent;
11789                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11790
11791                let has_boundary_change = has_comment_change
11792                    || row_rewrap_prefix.is_some()
11793                    || (has_indent_change && current_range_comment_prefix.is_some());
11794
11795                if has_paragraph_break || has_boundary_change {
11796                    ranges.push((
11797                        language_settings.clone(),
11798                        Point::new(current_range_start, 0)
11799                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11800                        current_range_indent,
11801                        current_range_comment_prefix.clone(),
11802                        current_range_rewrap_prefix.clone(),
11803                        from_empty_selection,
11804                    ));
11805                    current_range_start = row;
11806                    current_range_indent = row_indent;
11807                    current_range_comment_prefix = row_comment_prefix;
11808                    current_range_rewrap_prefix = row_rewrap_prefix;
11809                }
11810                prev_row = row;
11811            }
11812
11813            ranges.push((
11814                language_settings.clone(),
11815                Point::new(current_range_start, 0)
11816                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11817                current_range_indent,
11818                current_range_comment_prefix,
11819                current_range_rewrap_prefix,
11820                from_empty_selection,
11821            ));
11822
11823            ranges
11824        });
11825
11826        let mut edits = Vec::new();
11827        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11828
11829        for (
11830            language_settings,
11831            wrap_range,
11832            indent_size,
11833            comment_prefix,
11834            rewrap_prefix,
11835            from_empty_selection,
11836        ) in wrap_ranges
11837        {
11838            let mut start_row = wrap_range.start.row;
11839            let mut end_row = wrap_range.end.row;
11840
11841            // Skip selections that overlap with a range that has already been rewrapped.
11842            let selection_range = start_row..end_row;
11843            if rewrapped_row_ranges
11844                .iter()
11845                .any(|range| range.overlaps(&selection_range))
11846            {
11847                continue;
11848            }
11849
11850            let tab_size = language_settings.tab_size;
11851
11852            let indent_prefix = indent_size.chars().collect::<String>();
11853            let mut line_prefix = indent_prefix.clone();
11854            let mut inside_comment = false;
11855            if let Some(prefix) = &comment_prefix {
11856                line_prefix.push_str(prefix);
11857                inside_comment = true;
11858            }
11859            if let Some(prefix) = &rewrap_prefix {
11860                line_prefix.push_str(prefix);
11861            }
11862
11863            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11864                RewrapBehavior::InComments => inside_comment,
11865                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11866                RewrapBehavior::Anywhere => true,
11867            };
11868
11869            let should_rewrap = options.override_language_settings
11870                || allow_rewrap_based_on_language
11871                || self.hard_wrap.is_some();
11872            if !should_rewrap {
11873                continue;
11874            }
11875
11876            if from_empty_selection {
11877                'expand_upwards: while start_row > 0 {
11878                    let prev_row = start_row - 1;
11879                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11880                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11881                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11882                    {
11883                        start_row = prev_row;
11884                    } else {
11885                        break 'expand_upwards;
11886                    }
11887                }
11888
11889                'expand_downwards: while end_row < buffer.max_point().row {
11890                    let next_row = end_row + 1;
11891                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11892                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11893                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11894                    {
11895                        end_row = next_row;
11896                    } else {
11897                        break 'expand_downwards;
11898                    }
11899                }
11900            }
11901
11902            let start = Point::new(start_row, 0);
11903            let start_offset = start.to_offset(&buffer);
11904            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11905            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11906            let Some(lines_without_prefixes) = selection_text
11907                .lines()
11908                .enumerate()
11909                .map(|(ix, line)| {
11910                    let line_trimmed = line.trim_start();
11911                    if rewrap_prefix.is_some() && ix > 0 {
11912                        Ok(line_trimmed)
11913                    } else {
11914                        line_trimmed
11915                            .strip_prefix(&line_prefix.trim_start())
11916                            .with_context(|| {
11917                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11918                            })
11919                    }
11920                })
11921                .collect::<Result<Vec<_>, _>>()
11922                .log_err()
11923            else {
11924                continue;
11925            };
11926
11927            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11928                buffer
11929                    .language_settings_at(Point::new(start_row, 0), cx)
11930                    .preferred_line_length as usize
11931            });
11932
11933            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11934                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11935            } else {
11936                line_prefix.clone()
11937            };
11938
11939            let wrapped_text = wrap_with_prefix(
11940                line_prefix,
11941                subsequent_lines_prefix,
11942                lines_without_prefixes.join("\n"),
11943                wrap_column,
11944                tab_size,
11945                options.preserve_existing_whitespace,
11946            );
11947
11948            // TODO: should always use char-based diff while still supporting cursor behavior that
11949            // matches vim.
11950            let mut diff_options = DiffOptions::default();
11951            if options.override_language_settings {
11952                diff_options.max_word_diff_len = 0;
11953                diff_options.max_word_diff_line_count = 0;
11954            } else {
11955                diff_options.max_word_diff_len = usize::MAX;
11956                diff_options.max_word_diff_line_count = usize::MAX;
11957            }
11958
11959            for (old_range, new_text) in
11960                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11961            {
11962                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11963                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11964                edits.push((edit_start..edit_end, new_text));
11965            }
11966
11967            rewrapped_row_ranges.push(start_row..=end_row);
11968        }
11969
11970        self.buffer
11971            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11972    }
11973
11974    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11975        let mut text = String::new();
11976        let buffer = self.buffer.read(cx).snapshot(cx);
11977        let mut selections = self.selections.all::<Point>(cx);
11978        let mut clipboard_selections = Vec::with_capacity(selections.len());
11979        {
11980            let max_point = buffer.max_point();
11981            let mut is_first = true;
11982            for selection in &mut selections {
11983                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11984                if is_entire_line {
11985                    selection.start = Point::new(selection.start.row, 0);
11986                    if !selection.is_empty() && selection.end.column == 0 {
11987                        selection.end = cmp::min(max_point, selection.end);
11988                    } else {
11989                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11990                    }
11991                    selection.goal = SelectionGoal::None;
11992                }
11993                if is_first {
11994                    is_first = false;
11995                } else {
11996                    text += "\n";
11997                }
11998                let mut len = 0;
11999                for chunk in buffer.text_for_range(selection.start..selection.end) {
12000                    text.push_str(chunk);
12001                    len += chunk.len();
12002                }
12003                clipboard_selections.push(ClipboardSelection {
12004                    len,
12005                    is_entire_line,
12006                    first_line_indent: buffer
12007                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12008                        .len,
12009                });
12010            }
12011        }
12012
12013        self.transact(window, cx, |this, window, cx| {
12014            this.change_selections(Default::default(), window, cx, |s| {
12015                s.select(selections);
12016            });
12017            this.insert("", window, cx);
12018        });
12019        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12020    }
12021
12022    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12023        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12024        let item = self.cut_common(window, cx);
12025        cx.write_to_clipboard(item);
12026    }
12027
12028    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12029        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12030        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12031            s.move_with(|snapshot, sel| {
12032                if sel.is_empty() {
12033                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12034                }
12035            });
12036        });
12037        let item = self.cut_common(window, cx);
12038        cx.set_global(KillRing(item))
12039    }
12040
12041    pub fn kill_ring_yank(
12042        &mut self,
12043        _: &KillRingYank,
12044        window: &mut Window,
12045        cx: &mut Context<Self>,
12046    ) {
12047        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12048        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12049            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12050                (kill_ring.text().to_string(), kill_ring.metadata_json())
12051            } else {
12052                return;
12053            }
12054        } else {
12055            return;
12056        };
12057        self.do_paste(&text, metadata, false, window, cx);
12058    }
12059
12060    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12061        self.do_copy(true, cx);
12062    }
12063
12064    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12065        self.do_copy(false, cx);
12066    }
12067
12068    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12069        let selections = self.selections.all::<Point>(cx);
12070        let buffer = self.buffer.read(cx).read(cx);
12071        let mut text = String::new();
12072
12073        let mut clipboard_selections = Vec::with_capacity(selections.len());
12074        {
12075            let max_point = buffer.max_point();
12076            let mut is_first = true;
12077            for selection in &selections {
12078                let mut start = selection.start;
12079                let mut end = selection.end;
12080                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12081                if is_entire_line {
12082                    start = Point::new(start.row, 0);
12083                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12084                }
12085
12086                let mut trimmed_selections = Vec::new();
12087                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12088                    let row = MultiBufferRow(start.row);
12089                    let first_indent = buffer.indent_size_for_line(row);
12090                    if first_indent.len == 0 || start.column > first_indent.len {
12091                        trimmed_selections.push(start..end);
12092                    } else {
12093                        trimmed_selections.push(
12094                            Point::new(row.0, first_indent.len)
12095                                ..Point::new(row.0, buffer.line_len(row)),
12096                        );
12097                        for row in start.row + 1..=end.row {
12098                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12099                            if row == end.row {
12100                                line_len = end.column;
12101                            }
12102                            if line_len == 0 {
12103                                trimmed_selections
12104                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12105                                continue;
12106                            }
12107                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12108                            if row_indent_size.len >= first_indent.len {
12109                                trimmed_selections.push(
12110                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12111                                );
12112                            } else {
12113                                trimmed_selections.clear();
12114                                trimmed_selections.push(start..end);
12115                                break;
12116                            }
12117                        }
12118                    }
12119                } else {
12120                    trimmed_selections.push(start..end);
12121                }
12122
12123                for trimmed_range in trimmed_selections {
12124                    if is_first {
12125                        is_first = false;
12126                    } else {
12127                        text += "\n";
12128                    }
12129                    let mut len = 0;
12130                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12131                        text.push_str(chunk);
12132                        len += chunk.len();
12133                    }
12134                    clipboard_selections.push(ClipboardSelection {
12135                        len,
12136                        is_entire_line,
12137                        first_line_indent: buffer
12138                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12139                            .len,
12140                    });
12141                }
12142            }
12143        }
12144
12145        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12146            text,
12147            clipboard_selections,
12148        ));
12149    }
12150
12151    pub fn do_paste(
12152        &mut self,
12153        text: &String,
12154        clipboard_selections: Option<Vec<ClipboardSelection>>,
12155        handle_entire_lines: bool,
12156        window: &mut Window,
12157        cx: &mut Context<Self>,
12158    ) {
12159        if self.read_only(cx) {
12160            return;
12161        }
12162
12163        let clipboard_text = Cow::Borrowed(text);
12164
12165        self.transact(window, cx, |this, window, cx| {
12166            let had_active_edit_prediction = this.has_active_edit_prediction();
12167
12168            if let Some(mut clipboard_selections) = clipboard_selections {
12169                let old_selections = this.selections.all::<usize>(cx);
12170                let all_selections_were_entire_line =
12171                    clipboard_selections.iter().all(|s| s.is_entire_line);
12172                let first_selection_indent_column =
12173                    clipboard_selections.first().map(|s| s.first_line_indent);
12174                if clipboard_selections.len() != old_selections.len() {
12175                    clipboard_selections.drain(..);
12176                }
12177                let cursor_offset = this.selections.last::<usize>(cx).head();
12178                let mut auto_indent_on_paste = true;
12179
12180                this.buffer.update(cx, |buffer, cx| {
12181                    let snapshot = buffer.read(cx);
12182                    auto_indent_on_paste = snapshot
12183                        .language_settings_at(cursor_offset, cx)
12184                        .auto_indent_on_paste;
12185
12186                    let mut start_offset = 0;
12187                    let mut edits = Vec::new();
12188                    let mut original_indent_columns = Vec::new();
12189                    for (ix, selection) in old_selections.iter().enumerate() {
12190                        let to_insert;
12191                        let entire_line;
12192                        let original_indent_column;
12193                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12194                            let end_offset = start_offset + clipboard_selection.len;
12195                            to_insert = &clipboard_text[start_offset..end_offset];
12196                            entire_line = clipboard_selection.is_entire_line;
12197                            start_offset = end_offset + 1;
12198                            original_indent_column = Some(clipboard_selection.first_line_indent);
12199                        } else {
12200                            to_insert = clipboard_text.as_str();
12201                            entire_line = all_selections_were_entire_line;
12202                            original_indent_column = first_selection_indent_column
12203                        }
12204
12205                        // If the corresponding selection was empty when this slice of the
12206                        // clipboard text was written, then the entire line containing the
12207                        // selection was copied. If this selection is also currently empty,
12208                        // then paste the line before the current line of the buffer.
12209                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12210                            let column = selection.start.to_point(&snapshot).column as usize;
12211                            let line_start = selection.start - column;
12212                            line_start..line_start
12213                        } else {
12214                            selection.range()
12215                        };
12216
12217                        edits.push((range, to_insert));
12218                        original_indent_columns.push(original_indent_column);
12219                    }
12220                    drop(snapshot);
12221
12222                    buffer.edit(
12223                        edits,
12224                        if auto_indent_on_paste {
12225                            Some(AutoindentMode::Block {
12226                                original_indent_columns,
12227                            })
12228                        } else {
12229                            None
12230                        },
12231                        cx,
12232                    );
12233                });
12234
12235                let selections = this.selections.all::<usize>(cx);
12236                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12237            } else {
12238                this.insert(&clipboard_text, window, cx);
12239            }
12240
12241            let trigger_in_words =
12242                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12243
12244            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12245        });
12246    }
12247
12248    pub fn diff_clipboard_with_selection(
12249        &mut self,
12250        _: &DiffClipboardWithSelection,
12251        window: &mut Window,
12252        cx: &mut Context<Self>,
12253    ) {
12254        let selections = self.selections.all::<usize>(cx);
12255
12256        if selections.is_empty() {
12257            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12258            return;
12259        };
12260
12261        let clipboard_text = match cx.read_from_clipboard() {
12262            Some(item) => match item.entries().first() {
12263                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12264                _ => None,
12265            },
12266            None => None,
12267        };
12268
12269        let Some(clipboard_text) = clipboard_text else {
12270            log::warn!("Clipboard doesn't contain text.");
12271            return;
12272        };
12273
12274        window.dispatch_action(
12275            Box::new(DiffClipboardWithSelectionData {
12276                clipboard_text,
12277                editor: cx.entity(),
12278            }),
12279            cx,
12280        );
12281    }
12282
12283    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12284        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12285        if let Some(item) = cx.read_from_clipboard() {
12286            let entries = item.entries();
12287
12288            match entries.first() {
12289                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12290                // of all the pasted entries.
12291                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12292                    .do_paste(
12293                        clipboard_string.text(),
12294                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12295                        true,
12296                        window,
12297                        cx,
12298                    ),
12299                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12300            }
12301        }
12302    }
12303
12304    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12305        if self.read_only(cx) {
12306            return;
12307        }
12308
12309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12310
12311        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12312            if let Some((selections, _)) =
12313                self.selection_history.transaction(transaction_id).cloned()
12314            {
12315                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12316                    s.select_anchors(selections.to_vec());
12317                });
12318            } else {
12319                log::error!(
12320                    "No entry in selection_history found for undo. \
12321                     This may correspond to a bug where undo does not update the selection. \
12322                     If this is occurring, please add details to \
12323                     https://github.com/zed-industries/zed/issues/22692"
12324                );
12325            }
12326            self.request_autoscroll(Autoscroll::fit(), cx);
12327            self.unmark_text(window, cx);
12328            self.refresh_edit_prediction(true, false, window, cx);
12329            cx.emit(EditorEvent::Edited { transaction_id });
12330            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12331        }
12332    }
12333
12334    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12335        if self.read_only(cx) {
12336            return;
12337        }
12338
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12340
12341        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12342            if let Some((_, Some(selections))) =
12343                self.selection_history.transaction(transaction_id).cloned()
12344            {
12345                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12346                    s.select_anchors(selections.to_vec());
12347                });
12348            } else {
12349                log::error!(
12350                    "No entry in selection_history found for redo. \
12351                     This may correspond to a bug where undo does not update the selection. \
12352                     If this is occurring, please add details to \
12353                     https://github.com/zed-industries/zed/issues/22692"
12354                );
12355            }
12356            self.request_autoscroll(Autoscroll::fit(), cx);
12357            self.unmark_text(window, cx);
12358            self.refresh_edit_prediction(true, false, window, cx);
12359            cx.emit(EditorEvent::Edited { transaction_id });
12360        }
12361    }
12362
12363    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12364        self.buffer
12365            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12366    }
12367
12368    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12369        self.buffer
12370            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12371    }
12372
12373    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12374        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12375        self.change_selections(Default::default(), window, cx, |s| {
12376            s.move_with(|map, selection| {
12377                let cursor = if selection.is_empty() {
12378                    movement::left(map, selection.start)
12379                } else {
12380                    selection.start
12381                };
12382                selection.collapse_to(cursor, SelectionGoal::None);
12383            });
12384        })
12385    }
12386
12387    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12389        self.change_selections(Default::default(), window, cx, |s| {
12390            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12391        })
12392    }
12393
12394    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12395        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12396        self.change_selections(Default::default(), window, cx, |s| {
12397            s.move_with(|map, selection| {
12398                let cursor = if selection.is_empty() {
12399                    movement::right(map, selection.end)
12400                } else {
12401                    selection.end
12402                };
12403                selection.collapse_to(cursor, SelectionGoal::None)
12404            });
12405        })
12406    }
12407
12408    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12410        self.change_selections(Default::default(), window, cx, |s| {
12411            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12412        })
12413    }
12414
12415    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12416        if self.take_rename(true, window, cx).is_some() {
12417            return;
12418        }
12419
12420        if self.mode.is_single_line() {
12421            cx.propagate();
12422            return;
12423        }
12424
12425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12426
12427        let text_layout_details = &self.text_layout_details(window);
12428        let selection_count = self.selections.count();
12429        let first_selection = self.selections.first_anchor();
12430
12431        self.change_selections(Default::default(), window, cx, |s| {
12432            s.move_with(|map, selection| {
12433                if !selection.is_empty() {
12434                    selection.goal = SelectionGoal::None;
12435                }
12436                let (cursor, goal) = movement::up(
12437                    map,
12438                    selection.start,
12439                    selection.goal,
12440                    false,
12441                    text_layout_details,
12442                );
12443                selection.collapse_to(cursor, goal);
12444            });
12445        });
12446
12447        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12448        {
12449            cx.propagate();
12450        }
12451    }
12452
12453    pub fn move_up_by_lines(
12454        &mut self,
12455        action: &MoveUpByLines,
12456        window: &mut Window,
12457        cx: &mut Context<Self>,
12458    ) {
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
12472        self.change_selections(Default::default(), window, cx, |s| {
12473            s.move_with(|map, selection| {
12474                if !selection.is_empty() {
12475                    selection.goal = SelectionGoal::None;
12476                }
12477                let (cursor, goal) = movement::up_by_rows(
12478                    map,
12479                    selection.start,
12480                    action.lines,
12481                    selection.goal,
12482                    false,
12483                    text_layout_details,
12484                );
12485                selection.collapse_to(cursor, goal);
12486            });
12487        })
12488    }
12489
12490    pub fn move_down_by_lines(
12491        &mut self,
12492        action: &MoveDownByLines,
12493        window: &mut Window,
12494        cx: &mut Context<Self>,
12495    ) {
12496        if self.take_rename(true, window, cx).is_some() {
12497            return;
12498        }
12499
12500        if self.mode.is_single_line() {
12501            cx.propagate();
12502            return;
12503        }
12504
12505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12506
12507        let text_layout_details = &self.text_layout_details(window);
12508
12509        self.change_selections(Default::default(), window, cx, |s| {
12510            s.move_with(|map, selection| {
12511                if !selection.is_empty() {
12512                    selection.goal = SelectionGoal::None;
12513                }
12514                let (cursor, goal) = movement::down_by_rows(
12515                    map,
12516                    selection.start,
12517                    action.lines,
12518                    selection.goal,
12519                    false,
12520                    text_layout_details,
12521                );
12522                selection.collapse_to(cursor, goal);
12523            });
12524        })
12525    }
12526
12527    pub fn select_down_by_lines(
12528        &mut self,
12529        action: &SelectDownByLines,
12530        window: &mut Window,
12531        cx: &mut Context<Self>,
12532    ) {
12533        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12534        let text_layout_details = &self.text_layout_details(window);
12535        self.change_selections(Default::default(), window, cx, |s| {
12536            s.move_heads_with(|map, head, goal| {
12537                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12538            })
12539        })
12540    }
12541
12542    pub fn select_up_by_lines(
12543        &mut self,
12544        action: &SelectUpByLines,
12545        window: &mut Window,
12546        cx: &mut Context<Self>,
12547    ) {
12548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12549        let text_layout_details = &self.text_layout_details(window);
12550        self.change_selections(Default::default(), window, cx, |s| {
12551            s.move_heads_with(|map, head, goal| {
12552                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12553            })
12554        })
12555    }
12556
12557    pub fn select_page_up(
12558        &mut self,
12559        _: &SelectPageUp,
12560        window: &mut Window,
12561        cx: &mut Context<Self>,
12562    ) {
12563        let Some(row_count) = self.visible_row_count() else {
12564            return;
12565        };
12566
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12568
12569        let text_layout_details = &self.text_layout_details(window);
12570
12571        self.change_selections(Default::default(), window, cx, |s| {
12572            s.move_heads_with(|map, head, goal| {
12573                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12574            })
12575        })
12576    }
12577
12578    pub fn move_page_up(
12579        &mut self,
12580        action: &MovePageUp,
12581        window: &mut Window,
12582        cx: &mut Context<Self>,
12583    ) {
12584        if self.take_rename(true, window, cx).is_some() {
12585            return;
12586        }
12587
12588        if self
12589            .context_menu
12590            .borrow_mut()
12591            .as_mut()
12592            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12593            .unwrap_or(false)
12594        {
12595            return;
12596        }
12597
12598        if matches!(self.mode, EditorMode::SingleLine) {
12599            cx.propagate();
12600            return;
12601        }
12602
12603        let Some(row_count) = self.visible_row_count() else {
12604            return;
12605        };
12606
12607        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12608
12609        let effects = if action.center_cursor {
12610            SelectionEffects::scroll(Autoscroll::center())
12611        } else {
12612            SelectionEffects::default()
12613        };
12614
12615        let text_layout_details = &self.text_layout_details(window);
12616
12617        self.change_selections(effects, window, cx, |s| {
12618            s.move_with(|map, selection| {
12619                if !selection.is_empty() {
12620                    selection.goal = SelectionGoal::None;
12621                }
12622                let (cursor, goal) = movement::up_by_rows(
12623                    map,
12624                    selection.end,
12625                    row_count,
12626                    selection.goal,
12627                    false,
12628                    text_layout_details,
12629                );
12630                selection.collapse_to(cursor, goal);
12631            });
12632        });
12633    }
12634
12635    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12637        let text_layout_details = &self.text_layout_details(window);
12638        self.change_selections(Default::default(), window, cx, |s| {
12639            s.move_heads_with(|map, head, goal| {
12640                movement::up(map, head, goal, false, text_layout_details)
12641            })
12642        })
12643    }
12644
12645    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12646        self.take_rename(true, window, cx);
12647
12648        if self.mode.is_single_line() {
12649            cx.propagate();
12650            return;
12651        }
12652
12653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12654
12655        let text_layout_details = &self.text_layout_details(window);
12656        let selection_count = self.selections.count();
12657        let first_selection = self.selections.first_anchor();
12658
12659        self.change_selections(Default::default(), window, cx, |s| {
12660            s.move_with(|map, selection| {
12661                if !selection.is_empty() {
12662                    selection.goal = SelectionGoal::None;
12663                }
12664                let (cursor, goal) = movement::down(
12665                    map,
12666                    selection.end,
12667                    selection.goal,
12668                    false,
12669                    text_layout_details,
12670                );
12671                selection.collapse_to(cursor, goal);
12672            });
12673        });
12674
12675        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12676        {
12677            cx.propagate();
12678        }
12679    }
12680
12681    pub fn select_page_down(
12682        &mut self,
12683        _: &SelectPageDown,
12684        window: &mut Window,
12685        cx: &mut Context<Self>,
12686    ) {
12687        let Some(row_count) = self.visible_row_count() else {
12688            return;
12689        };
12690
12691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12692
12693        let text_layout_details = &self.text_layout_details(window);
12694
12695        self.change_selections(Default::default(), window, cx, |s| {
12696            s.move_heads_with(|map, head, goal| {
12697                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12698            })
12699        })
12700    }
12701
12702    pub fn move_page_down(
12703        &mut self,
12704        action: &MovePageDown,
12705        window: &mut Window,
12706        cx: &mut Context<Self>,
12707    ) {
12708        if self.take_rename(true, window, cx).is_some() {
12709            return;
12710        }
12711
12712        if self
12713            .context_menu
12714            .borrow_mut()
12715            .as_mut()
12716            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12717            .unwrap_or(false)
12718        {
12719            return;
12720        }
12721
12722        if matches!(self.mode, EditorMode::SingleLine) {
12723            cx.propagate();
12724            return;
12725        }
12726
12727        let Some(row_count) = self.visible_row_count() else {
12728            return;
12729        };
12730
12731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12732
12733        let effects = if action.center_cursor {
12734            SelectionEffects::scroll(Autoscroll::center())
12735        } else {
12736            SelectionEffects::default()
12737        };
12738
12739        let text_layout_details = &self.text_layout_details(window);
12740        self.change_selections(effects, window, cx, |s| {
12741            s.move_with(|map, selection| {
12742                if !selection.is_empty() {
12743                    selection.goal = SelectionGoal::None;
12744                }
12745                let (cursor, goal) = movement::down_by_rows(
12746                    map,
12747                    selection.end,
12748                    row_count,
12749                    selection.goal,
12750                    false,
12751                    text_layout_details,
12752                );
12753                selection.collapse_to(cursor, goal);
12754            });
12755        });
12756    }
12757
12758    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12759        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12760        let text_layout_details = &self.text_layout_details(window);
12761        self.change_selections(Default::default(), window, cx, |s| {
12762            s.move_heads_with(|map, head, goal| {
12763                movement::down(map, head, goal, false, text_layout_details)
12764            })
12765        });
12766    }
12767
12768    pub fn context_menu_first(
12769        &mut self,
12770        _: &ContextMenuFirst,
12771        window: &mut Window,
12772        cx: &mut Context<Self>,
12773    ) {
12774        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12775            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12776        }
12777    }
12778
12779    pub fn context_menu_prev(
12780        &mut self,
12781        _: &ContextMenuPrevious,
12782        window: &mut Window,
12783        cx: &mut Context<Self>,
12784    ) {
12785        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12786            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12787        }
12788    }
12789
12790    pub fn context_menu_next(
12791        &mut self,
12792        _: &ContextMenuNext,
12793        window: &mut Window,
12794        cx: &mut Context<Self>,
12795    ) {
12796        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12797            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12798        }
12799    }
12800
12801    pub fn context_menu_last(
12802        &mut self,
12803        _: &ContextMenuLast,
12804        window: &mut Window,
12805        cx: &mut Context<Self>,
12806    ) {
12807        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12808            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12809        }
12810    }
12811
12812    pub fn signature_help_prev(
12813        &mut self,
12814        _: &SignatureHelpPrevious,
12815        _: &mut Window,
12816        cx: &mut Context<Self>,
12817    ) {
12818        if let Some(popover) = self.signature_help_state.popover_mut() {
12819            if popover.current_signature == 0 {
12820                popover.current_signature = popover.signatures.len() - 1;
12821            } else {
12822                popover.current_signature -= 1;
12823            }
12824            cx.notify();
12825        }
12826    }
12827
12828    pub fn signature_help_next(
12829        &mut self,
12830        _: &SignatureHelpNext,
12831        _: &mut Window,
12832        cx: &mut Context<Self>,
12833    ) {
12834        if let Some(popover) = self.signature_help_state.popover_mut() {
12835            if popover.current_signature + 1 == popover.signatures.len() {
12836                popover.current_signature = 0;
12837            } else {
12838                popover.current_signature += 1;
12839            }
12840            cx.notify();
12841        }
12842    }
12843
12844    pub fn move_to_previous_word_start(
12845        &mut self,
12846        _: &MoveToPreviousWordStart,
12847        window: &mut Window,
12848        cx: &mut Context<Self>,
12849    ) {
12850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12851        self.change_selections(Default::default(), window, cx, |s| {
12852            s.move_cursors_with(|map, head, _| {
12853                (
12854                    movement::previous_word_start(map, head),
12855                    SelectionGoal::None,
12856                )
12857            });
12858        })
12859    }
12860
12861    pub fn move_to_previous_subword_start(
12862        &mut self,
12863        _: &MoveToPreviousSubwordStart,
12864        window: &mut Window,
12865        cx: &mut Context<Self>,
12866    ) {
12867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12868        self.change_selections(Default::default(), window, cx, |s| {
12869            s.move_cursors_with(|map, head, _| {
12870                (
12871                    movement::previous_subword_start(map, head),
12872                    SelectionGoal::None,
12873                )
12874            });
12875        })
12876    }
12877
12878    pub fn select_to_previous_word_start(
12879        &mut self,
12880        _: &SelectToPreviousWordStart,
12881        window: &mut Window,
12882        cx: &mut Context<Self>,
12883    ) {
12884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12885        self.change_selections(Default::default(), window, cx, |s| {
12886            s.move_heads_with(|map, head, _| {
12887                (
12888                    movement::previous_word_start(map, head),
12889                    SelectionGoal::None,
12890                )
12891            });
12892        })
12893    }
12894
12895    pub fn select_to_previous_subword_start(
12896        &mut self,
12897        _: &SelectToPreviousSubwordStart,
12898        window: &mut Window,
12899        cx: &mut Context<Self>,
12900    ) {
12901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12902        self.change_selections(Default::default(), window, cx, |s| {
12903            s.move_heads_with(|map, head, _| {
12904                (
12905                    movement::previous_subword_start(map, head),
12906                    SelectionGoal::None,
12907                )
12908            });
12909        })
12910    }
12911
12912    pub fn delete_to_previous_word_start(
12913        &mut self,
12914        action: &DeleteToPreviousWordStart,
12915        window: &mut Window,
12916        cx: &mut Context<Self>,
12917    ) {
12918        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12919        self.transact(window, cx, |this, window, cx| {
12920            this.select_autoclose_pair(window, cx);
12921            this.change_selections(Default::default(), window, cx, |s| {
12922                s.move_with(|map, selection| {
12923                    if selection.is_empty() {
12924                        let cursor = if action.ignore_newlines {
12925                            movement::previous_word_start(map, selection.head())
12926                        } else {
12927                            movement::previous_word_start_or_newline(map, selection.head())
12928                        };
12929                        selection.set_head(cursor, SelectionGoal::None);
12930                    }
12931                });
12932            });
12933            this.insert("", window, cx);
12934        });
12935    }
12936
12937    pub fn delete_to_previous_subword_start(
12938        &mut self,
12939        _: &DeleteToPreviousSubwordStart,
12940        window: &mut Window,
12941        cx: &mut Context<Self>,
12942    ) {
12943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12944        self.transact(window, cx, |this, window, cx| {
12945            this.select_autoclose_pair(window, cx);
12946            this.change_selections(Default::default(), window, cx, |s| {
12947                s.move_with(|map, selection| {
12948                    if selection.is_empty() {
12949                        let cursor = movement::previous_subword_start(map, selection.head());
12950                        selection.set_head(cursor, SelectionGoal::None);
12951                    }
12952                });
12953            });
12954            this.insert("", window, cx);
12955        });
12956    }
12957
12958    pub fn move_to_next_word_end(
12959        &mut self,
12960        _: &MoveToNextWordEnd,
12961        window: &mut Window,
12962        cx: &mut Context<Self>,
12963    ) {
12964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12965        self.change_selections(Default::default(), window, cx, |s| {
12966            s.move_cursors_with(|map, head, _| {
12967                (movement::next_word_end(map, head), SelectionGoal::None)
12968            });
12969        })
12970    }
12971
12972    pub fn move_to_next_subword_end(
12973        &mut self,
12974        _: &MoveToNextSubwordEnd,
12975        window: &mut Window,
12976        cx: &mut Context<Self>,
12977    ) {
12978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12979        self.change_selections(Default::default(), window, cx, |s| {
12980            s.move_cursors_with(|map, head, _| {
12981                (movement::next_subword_end(map, head), SelectionGoal::None)
12982            });
12983        })
12984    }
12985
12986    pub fn select_to_next_word_end(
12987        &mut self,
12988        _: &SelectToNextWordEnd,
12989        window: &mut Window,
12990        cx: &mut Context<Self>,
12991    ) {
12992        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12993        self.change_selections(Default::default(), window, cx, |s| {
12994            s.move_heads_with(|map, head, _| {
12995                (movement::next_word_end(map, head), SelectionGoal::None)
12996            });
12997        })
12998    }
12999
13000    pub fn select_to_next_subword_end(
13001        &mut self,
13002        _: &SelectToNextSubwordEnd,
13003        window: &mut Window,
13004        cx: &mut Context<Self>,
13005    ) {
13006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13007        self.change_selections(Default::default(), window, cx, |s| {
13008            s.move_heads_with(|map, head, _| {
13009                (movement::next_subword_end(map, head), SelectionGoal::None)
13010            });
13011        })
13012    }
13013
13014    pub fn delete_to_next_word_end(
13015        &mut self,
13016        action: &DeleteToNextWordEnd,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13021        self.transact(window, cx, |this, window, cx| {
13022            this.change_selections(Default::default(), window, cx, |s| {
13023                s.move_with(|map, selection| {
13024                    if selection.is_empty() {
13025                        let cursor = if action.ignore_newlines {
13026                            movement::next_word_end(map, selection.head())
13027                        } else {
13028                            movement::next_word_end_or_newline(map, selection.head())
13029                        };
13030                        selection.set_head(cursor, SelectionGoal::None);
13031                    }
13032                });
13033            });
13034            this.insert("", window, cx);
13035        });
13036    }
13037
13038    pub fn delete_to_next_subword_end(
13039        &mut self,
13040        _: &DeleteToNextSubwordEnd,
13041        window: &mut Window,
13042        cx: &mut Context<Self>,
13043    ) {
13044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13045        self.transact(window, cx, |this, window, cx| {
13046            this.change_selections(Default::default(), window, cx, |s| {
13047                s.move_with(|map, selection| {
13048                    if selection.is_empty() {
13049                        let cursor = movement::next_subword_end(map, selection.head());
13050                        selection.set_head(cursor, SelectionGoal::None);
13051                    }
13052                });
13053            });
13054            this.insert("", window, cx);
13055        });
13056    }
13057
13058    pub fn move_to_beginning_of_line(
13059        &mut self,
13060        action: &MoveToBeginningOfLine,
13061        window: &mut Window,
13062        cx: &mut Context<Self>,
13063    ) {
13064        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13065        self.change_selections(Default::default(), window, cx, |s| {
13066            s.move_cursors_with(|map, head, _| {
13067                (
13068                    movement::indented_line_beginning(
13069                        map,
13070                        head,
13071                        action.stop_at_soft_wraps,
13072                        action.stop_at_indent,
13073                    ),
13074                    SelectionGoal::None,
13075                )
13076            });
13077        })
13078    }
13079
13080    pub fn select_to_beginning_of_line(
13081        &mut self,
13082        action: &SelectToBeginningOfLine,
13083        window: &mut Window,
13084        cx: &mut Context<Self>,
13085    ) {
13086        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13087        self.change_selections(Default::default(), window, cx, |s| {
13088            s.move_heads_with(|map, head, _| {
13089                (
13090                    movement::indented_line_beginning(
13091                        map,
13092                        head,
13093                        action.stop_at_soft_wraps,
13094                        action.stop_at_indent,
13095                    ),
13096                    SelectionGoal::None,
13097                )
13098            });
13099        });
13100    }
13101
13102    pub fn delete_to_beginning_of_line(
13103        &mut self,
13104        action: &DeleteToBeginningOfLine,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) {
13108        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13109        self.transact(window, cx, |this, window, cx| {
13110            this.change_selections(Default::default(), window, cx, |s| {
13111                s.move_with(|_, selection| {
13112                    selection.reversed = true;
13113                });
13114            });
13115
13116            this.select_to_beginning_of_line(
13117                &SelectToBeginningOfLine {
13118                    stop_at_soft_wraps: false,
13119                    stop_at_indent: action.stop_at_indent,
13120                },
13121                window,
13122                cx,
13123            );
13124            this.backspace(&Backspace, window, cx);
13125        });
13126    }
13127
13128    pub fn move_to_end_of_line(
13129        &mut self,
13130        action: &MoveToEndOfLine,
13131        window: &mut Window,
13132        cx: &mut Context<Self>,
13133    ) {
13134        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13135        self.change_selections(Default::default(), window, cx, |s| {
13136            s.move_cursors_with(|map, head, _| {
13137                (
13138                    movement::line_end(map, head, action.stop_at_soft_wraps),
13139                    SelectionGoal::None,
13140                )
13141            });
13142        })
13143    }
13144
13145    pub fn select_to_end_of_line(
13146        &mut self,
13147        action: &SelectToEndOfLine,
13148        window: &mut Window,
13149        cx: &mut Context<Self>,
13150    ) {
13151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13152        self.change_selections(Default::default(), window, cx, |s| {
13153            s.move_heads_with(|map, head, _| {
13154                (
13155                    movement::line_end(map, head, action.stop_at_soft_wraps),
13156                    SelectionGoal::None,
13157                )
13158            });
13159        })
13160    }
13161
13162    pub fn delete_to_end_of_line(
13163        &mut self,
13164        _: &DeleteToEndOfLine,
13165        window: &mut Window,
13166        cx: &mut Context<Self>,
13167    ) {
13168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13169        self.transact(window, cx, |this, window, cx| {
13170            this.select_to_end_of_line(
13171                &SelectToEndOfLine {
13172                    stop_at_soft_wraps: false,
13173                },
13174                window,
13175                cx,
13176            );
13177            this.delete(&Delete, window, cx);
13178        });
13179    }
13180
13181    pub fn cut_to_end_of_line(
13182        &mut self,
13183        _: &CutToEndOfLine,
13184        window: &mut Window,
13185        cx: &mut Context<Self>,
13186    ) {
13187        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13188        self.transact(window, cx, |this, window, cx| {
13189            this.select_to_end_of_line(
13190                &SelectToEndOfLine {
13191                    stop_at_soft_wraps: false,
13192                },
13193                window,
13194                cx,
13195            );
13196            this.cut(&Cut, window, cx);
13197        });
13198    }
13199
13200    pub fn move_to_start_of_paragraph(
13201        &mut self,
13202        _: &MoveToStartOfParagraph,
13203        window: &mut Window,
13204        cx: &mut Context<Self>,
13205    ) {
13206        if matches!(self.mode, EditorMode::SingleLine) {
13207            cx.propagate();
13208            return;
13209        }
13210        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13211        self.change_selections(Default::default(), window, cx, |s| {
13212            s.move_with(|map, selection| {
13213                selection.collapse_to(
13214                    movement::start_of_paragraph(map, selection.head(), 1),
13215                    SelectionGoal::None,
13216                )
13217            });
13218        })
13219    }
13220
13221    pub fn move_to_end_of_paragraph(
13222        &mut self,
13223        _: &MoveToEndOfParagraph,
13224        window: &mut Window,
13225        cx: &mut Context<Self>,
13226    ) {
13227        if matches!(self.mode, EditorMode::SingleLine) {
13228            cx.propagate();
13229            return;
13230        }
13231        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13232        self.change_selections(Default::default(), window, cx, |s| {
13233            s.move_with(|map, selection| {
13234                selection.collapse_to(
13235                    movement::end_of_paragraph(map, selection.head(), 1),
13236                    SelectionGoal::None,
13237                )
13238            });
13239        })
13240    }
13241
13242    pub fn select_to_start_of_paragraph(
13243        &mut self,
13244        _: &SelectToStartOfParagraph,
13245        window: &mut Window,
13246        cx: &mut Context<Self>,
13247    ) {
13248        if matches!(self.mode, EditorMode::SingleLine) {
13249            cx.propagate();
13250            return;
13251        }
13252        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13253        self.change_selections(Default::default(), window, cx, |s| {
13254            s.move_heads_with(|map, head, _| {
13255                (
13256                    movement::start_of_paragraph(map, head, 1),
13257                    SelectionGoal::None,
13258                )
13259            });
13260        })
13261    }
13262
13263    pub fn select_to_end_of_paragraph(
13264        &mut self,
13265        _: &SelectToEndOfParagraph,
13266        window: &mut Window,
13267        cx: &mut Context<Self>,
13268    ) {
13269        if matches!(self.mode, EditorMode::SingleLine) {
13270            cx.propagate();
13271            return;
13272        }
13273        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13274        self.change_selections(Default::default(), window, cx, |s| {
13275            s.move_heads_with(|map, head, _| {
13276                (
13277                    movement::end_of_paragraph(map, head, 1),
13278                    SelectionGoal::None,
13279                )
13280            });
13281        })
13282    }
13283
13284    pub fn move_to_start_of_excerpt(
13285        &mut self,
13286        _: &MoveToStartOfExcerpt,
13287        window: &mut Window,
13288        cx: &mut Context<Self>,
13289    ) {
13290        if matches!(self.mode, EditorMode::SingleLine) {
13291            cx.propagate();
13292            return;
13293        }
13294        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13295        self.change_selections(Default::default(), window, cx, |s| {
13296            s.move_with(|map, selection| {
13297                selection.collapse_to(
13298                    movement::start_of_excerpt(
13299                        map,
13300                        selection.head(),
13301                        workspace::searchable::Direction::Prev,
13302                    ),
13303                    SelectionGoal::None,
13304                )
13305            });
13306        })
13307    }
13308
13309    pub fn move_to_start_of_next_excerpt(
13310        &mut self,
13311        _: &MoveToStartOfNextExcerpt,
13312        window: &mut Window,
13313        cx: &mut Context<Self>,
13314    ) {
13315        if matches!(self.mode, EditorMode::SingleLine) {
13316            cx.propagate();
13317            return;
13318        }
13319
13320        self.change_selections(Default::default(), window, cx, |s| {
13321            s.move_with(|map, selection| {
13322                selection.collapse_to(
13323                    movement::start_of_excerpt(
13324                        map,
13325                        selection.head(),
13326                        workspace::searchable::Direction::Next,
13327                    ),
13328                    SelectionGoal::None,
13329                )
13330            });
13331        })
13332    }
13333
13334    pub fn move_to_end_of_excerpt(
13335        &mut self,
13336        _: &MoveToEndOfExcerpt,
13337        window: &mut Window,
13338        cx: &mut Context<Self>,
13339    ) {
13340        if matches!(self.mode, EditorMode::SingleLine) {
13341            cx.propagate();
13342            return;
13343        }
13344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13345        self.change_selections(Default::default(), window, cx, |s| {
13346            s.move_with(|map, selection| {
13347                selection.collapse_to(
13348                    movement::end_of_excerpt(
13349                        map,
13350                        selection.head(),
13351                        workspace::searchable::Direction::Next,
13352                    ),
13353                    SelectionGoal::None,
13354                )
13355            });
13356        })
13357    }
13358
13359    pub fn move_to_end_of_previous_excerpt(
13360        &mut self,
13361        _: &MoveToEndOfPreviousExcerpt,
13362        window: &mut Window,
13363        cx: &mut Context<Self>,
13364    ) {
13365        if matches!(self.mode, EditorMode::SingleLine) {
13366            cx.propagate();
13367            return;
13368        }
13369        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13370        self.change_selections(Default::default(), window, cx, |s| {
13371            s.move_with(|map, selection| {
13372                selection.collapse_to(
13373                    movement::end_of_excerpt(
13374                        map,
13375                        selection.head(),
13376                        workspace::searchable::Direction::Prev,
13377                    ),
13378                    SelectionGoal::None,
13379                )
13380            });
13381        })
13382    }
13383
13384    pub fn select_to_start_of_excerpt(
13385        &mut self,
13386        _: &SelectToStartOfExcerpt,
13387        window: &mut Window,
13388        cx: &mut Context<Self>,
13389    ) {
13390        if matches!(self.mode, EditorMode::SingleLine) {
13391            cx.propagate();
13392            return;
13393        }
13394        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13395        self.change_selections(Default::default(), window, cx, |s| {
13396            s.move_heads_with(|map, head, _| {
13397                (
13398                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13399                    SelectionGoal::None,
13400                )
13401            });
13402        })
13403    }
13404
13405    pub fn select_to_start_of_next_excerpt(
13406        &mut self,
13407        _: &SelectToStartOfNextExcerpt,
13408        window: &mut Window,
13409        cx: &mut Context<Self>,
13410    ) {
13411        if matches!(self.mode, EditorMode::SingleLine) {
13412            cx.propagate();
13413            return;
13414        }
13415        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13416        self.change_selections(Default::default(), window, cx, |s| {
13417            s.move_heads_with(|map, head, _| {
13418                (
13419                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13420                    SelectionGoal::None,
13421                )
13422            });
13423        })
13424    }
13425
13426    pub fn select_to_end_of_excerpt(
13427        &mut self,
13428        _: &SelectToEndOfExcerpt,
13429        window: &mut Window,
13430        cx: &mut Context<Self>,
13431    ) {
13432        if matches!(self.mode, EditorMode::SingleLine) {
13433            cx.propagate();
13434            return;
13435        }
13436        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13437        self.change_selections(Default::default(), window, cx, |s| {
13438            s.move_heads_with(|map, head, _| {
13439                (
13440                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13441                    SelectionGoal::None,
13442                )
13443            });
13444        })
13445    }
13446
13447    pub fn select_to_end_of_previous_excerpt(
13448        &mut self,
13449        _: &SelectToEndOfPreviousExcerpt,
13450        window: &mut Window,
13451        cx: &mut Context<Self>,
13452    ) {
13453        if matches!(self.mode, EditorMode::SingleLine) {
13454            cx.propagate();
13455            return;
13456        }
13457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13458        self.change_selections(Default::default(), window, cx, |s| {
13459            s.move_heads_with(|map, head, _| {
13460                (
13461                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13462                    SelectionGoal::None,
13463                )
13464            });
13465        })
13466    }
13467
13468    pub fn move_to_beginning(
13469        &mut self,
13470        _: &MoveToBeginning,
13471        window: &mut Window,
13472        cx: &mut Context<Self>,
13473    ) {
13474        if matches!(self.mode, EditorMode::SingleLine) {
13475            cx.propagate();
13476            return;
13477        }
13478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13479        self.change_selections(Default::default(), window, cx, |s| {
13480            s.select_ranges(vec![0..0]);
13481        });
13482    }
13483
13484    pub fn select_to_beginning(
13485        &mut self,
13486        _: &SelectToBeginning,
13487        window: &mut Window,
13488        cx: &mut Context<Self>,
13489    ) {
13490        let mut selection = self.selections.last::<Point>(cx);
13491        selection.set_head(Point::zero(), SelectionGoal::None);
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13493        self.change_selections(Default::default(), window, cx, |s| {
13494            s.select(vec![selection]);
13495        });
13496    }
13497
13498    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13499        if matches!(self.mode, EditorMode::SingleLine) {
13500            cx.propagate();
13501            return;
13502        }
13503        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13504        let cursor = self.buffer.read(cx).read(cx).len();
13505        self.change_selections(Default::default(), window, cx, |s| {
13506            s.select_ranges(vec![cursor..cursor])
13507        });
13508    }
13509
13510    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13511        self.nav_history = nav_history;
13512    }
13513
13514    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13515        self.nav_history.as_ref()
13516    }
13517
13518    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13519        self.push_to_nav_history(
13520            self.selections.newest_anchor().head(),
13521            None,
13522            false,
13523            true,
13524            cx,
13525        );
13526    }
13527
13528    fn push_to_nav_history(
13529        &mut self,
13530        cursor_anchor: Anchor,
13531        new_position: Option<Point>,
13532        is_deactivate: bool,
13533        always: bool,
13534        cx: &mut Context<Self>,
13535    ) {
13536        if let Some(nav_history) = self.nav_history.as_mut() {
13537            let buffer = self.buffer.read(cx).read(cx);
13538            let cursor_position = cursor_anchor.to_point(&buffer);
13539            let scroll_state = self.scroll_manager.anchor();
13540            let scroll_top_row = scroll_state.top_row(&buffer);
13541            drop(buffer);
13542
13543            if let Some(new_position) = new_position {
13544                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13545                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13546                    return;
13547                }
13548            }
13549
13550            nav_history.push(
13551                Some(NavigationData {
13552                    cursor_anchor,
13553                    cursor_position,
13554                    scroll_anchor: scroll_state,
13555                    scroll_top_row,
13556                }),
13557                cx,
13558            );
13559            cx.emit(EditorEvent::PushedToNavHistory {
13560                anchor: cursor_anchor,
13561                is_deactivate,
13562            })
13563        }
13564    }
13565
13566    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13568        let buffer = self.buffer.read(cx).snapshot(cx);
13569        let mut selection = self.selections.first::<usize>(cx);
13570        selection.set_head(buffer.len(), SelectionGoal::None);
13571        self.change_selections(Default::default(), window, cx, |s| {
13572            s.select(vec![selection]);
13573        });
13574    }
13575
13576    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13578        let end = self.buffer.read(cx).read(cx).len();
13579        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13580            s.select_ranges(vec![0..end]);
13581        });
13582    }
13583
13584    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13586        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13587        let mut selections = self.selections.all::<Point>(cx);
13588        let max_point = display_map.buffer_snapshot.max_point();
13589        for selection in &mut selections {
13590            let rows = selection.spanned_rows(true, &display_map);
13591            selection.start = Point::new(rows.start.0, 0);
13592            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13593            selection.reversed = false;
13594        }
13595        self.change_selections(Default::default(), window, cx, |s| {
13596            s.select(selections);
13597        });
13598    }
13599
13600    pub fn split_selection_into_lines(
13601        &mut self,
13602        action: &SplitSelectionIntoLines,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        let selections = self
13607            .selections
13608            .all::<Point>(cx)
13609            .into_iter()
13610            .map(|selection| selection.start..selection.end)
13611            .collect::<Vec<_>>();
13612        self.unfold_ranges(&selections, true, true, cx);
13613
13614        let mut new_selection_ranges = Vec::new();
13615        {
13616            let buffer = self.buffer.read(cx).read(cx);
13617            for selection in selections {
13618                for row in selection.start.row..selection.end.row {
13619                    let line_start = Point::new(row, 0);
13620                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13621
13622                    if action.keep_selections {
13623                        // Keep the selection range for each line
13624                        let selection_start = if row == selection.start.row {
13625                            selection.start
13626                        } else {
13627                            line_start
13628                        };
13629                        new_selection_ranges.push(selection_start..line_end);
13630                    } else {
13631                        // Collapse to cursor at end of line
13632                        new_selection_ranges.push(line_end..line_end);
13633                    }
13634                }
13635
13636                let is_multiline_selection = selection.start.row != selection.end.row;
13637                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13638                // so this action feels more ergonomic when paired with other selection operations
13639                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13640                if !should_skip_last {
13641                    if action.keep_selections {
13642                        if is_multiline_selection {
13643                            let line_start = Point::new(selection.end.row, 0);
13644                            new_selection_ranges.push(line_start..selection.end);
13645                        } else {
13646                            new_selection_ranges.push(selection.start..selection.end);
13647                        }
13648                    } else {
13649                        new_selection_ranges.push(selection.end..selection.end);
13650                    }
13651                }
13652            }
13653        }
13654        self.change_selections(Default::default(), window, cx, |s| {
13655            s.select_ranges(new_selection_ranges);
13656        });
13657    }
13658
13659    pub fn add_selection_above(
13660        &mut self,
13661        _: &AddSelectionAbove,
13662        window: &mut Window,
13663        cx: &mut Context<Self>,
13664    ) {
13665        self.add_selection(true, window, cx);
13666    }
13667
13668    pub fn add_selection_below(
13669        &mut self,
13670        _: &AddSelectionBelow,
13671        window: &mut Window,
13672        cx: &mut Context<Self>,
13673    ) {
13674        self.add_selection(false, window, cx);
13675    }
13676
13677    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13679
13680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13681        let all_selections = self.selections.all::<Point>(cx);
13682        let text_layout_details = self.text_layout_details(window);
13683
13684        let (mut columnar_selections, new_selections_to_columnarize) = {
13685            if let Some(state) = self.add_selections_state.as_ref() {
13686                let columnar_selection_ids: HashSet<_> = state
13687                    .groups
13688                    .iter()
13689                    .flat_map(|group| group.stack.iter())
13690                    .copied()
13691                    .collect();
13692
13693                all_selections
13694                    .into_iter()
13695                    .partition(|s| columnar_selection_ids.contains(&s.id))
13696            } else {
13697                (Vec::new(), all_selections)
13698            }
13699        };
13700
13701        let mut state = self
13702            .add_selections_state
13703            .take()
13704            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13705
13706        for selection in new_selections_to_columnarize {
13707            let range = selection.display_range(&display_map).sorted();
13708            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13709            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13710            let positions = start_x.min(end_x)..start_x.max(end_x);
13711            let mut stack = Vec::new();
13712            for row in range.start.row().0..=range.end.row().0 {
13713                if let Some(selection) = self.selections.build_columnar_selection(
13714                    &display_map,
13715                    DisplayRow(row),
13716                    &positions,
13717                    selection.reversed,
13718                    &text_layout_details,
13719                ) {
13720                    stack.push(selection.id);
13721                    columnar_selections.push(selection);
13722                }
13723            }
13724            if !stack.is_empty() {
13725                if above {
13726                    stack.reverse();
13727                }
13728                state.groups.push(AddSelectionsGroup { above, stack });
13729            }
13730        }
13731
13732        let mut final_selections = Vec::new();
13733        let end_row = if above {
13734            DisplayRow(0)
13735        } else {
13736            display_map.max_point().row()
13737        };
13738
13739        let mut last_added_item_per_group = HashMap::default();
13740        for group in state.groups.iter_mut() {
13741            if let Some(last_id) = group.stack.last() {
13742                last_added_item_per_group.insert(*last_id, group);
13743            }
13744        }
13745
13746        for selection in columnar_selections {
13747            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13748                if above == group.above {
13749                    let range = selection.display_range(&display_map).sorted();
13750                    debug_assert_eq!(range.start.row(), range.end.row());
13751                    let mut row = range.start.row();
13752                    let positions =
13753                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13754                            px(start)..px(end)
13755                        } else {
13756                            let start_x =
13757                                display_map.x_for_display_point(range.start, &text_layout_details);
13758                            let end_x =
13759                                display_map.x_for_display_point(range.end, &text_layout_details);
13760                            start_x.min(end_x)..start_x.max(end_x)
13761                        };
13762
13763                    let mut maybe_new_selection = None;
13764                    while row != end_row {
13765                        if above {
13766                            row.0 -= 1;
13767                        } else {
13768                            row.0 += 1;
13769                        }
13770                        if let Some(new_selection) = self.selections.build_columnar_selection(
13771                            &display_map,
13772                            row,
13773                            &positions,
13774                            selection.reversed,
13775                            &text_layout_details,
13776                        ) {
13777                            maybe_new_selection = Some(new_selection);
13778                            break;
13779                        }
13780                    }
13781
13782                    if let Some(new_selection) = maybe_new_selection {
13783                        group.stack.push(new_selection.id);
13784                        if above {
13785                            final_selections.push(new_selection);
13786                            final_selections.push(selection);
13787                        } else {
13788                            final_selections.push(selection);
13789                            final_selections.push(new_selection);
13790                        }
13791                    } else {
13792                        final_selections.push(selection);
13793                    }
13794                } else {
13795                    group.stack.pop();
13796                }
13797            } else {
13798                final_selections.push(selection);
13799            }
13800        }
13801
13802        self.change_selections(Default::default(), window, cx, |s| {
13803            s.select(final_selections);
13804        });
13805
13806        let final_selection_ids: HashSet<_> = self
13807            .selections
13808            .all::<Point>(cx)
13809            .iter()
13810            .map(|s| s.id)
13811            .collect();
13812        state.groups.retain_mut(|group| {
13813            // selections might get merged above so we remove invalid items from stacks
13814            group.stack.retain(|id| final_selection_ids.contains(id));
13815
13816            // single selection in stack can be treated as initial state
13817            group.stack.len() > 1
13818        });
13819
13820        if !state.groups.is_empty() {
13821            self.add_selections_state = Some(state);
13822        }
13823    }
13824
13825    fn select_match_ranges(
13826        &mut self,
13827        range: Range<usize>,
13828        reversed: bool,
13829        replace_newest: bool,
13830        auto_scroll: Option<Autoscroll>,
13831        window: &mut Window,
13832        cx: &mut Context<Editor>,
13833    ) {
13834        self.unfold_ranges(
13835            std::slice::from_ref(&range),
13836            false,
13837            auto_scroll.is_some(),
13838            cx,
13839        );
13840        let effects = if let Some(scroll) = auto_scroll {
13841            SelectionEffects::scroll(scroll)
13842        } else {
13843            SelectionEffects::no_scroll()
13844        };
13845        self.change_selections(effects, window, cx, |s| {
13846            if replace_newest {
13847                s.delete(s.newest_anchor().id);
13848            }
13849            if reversed {
13850                s.insert_range(range.end..range.start);
13851            } else {
13852                s.insert_range(range);
13853            }
13854        });
13855    }
13856
13857    pub fn select_next_match_internal(
13858        &mut self,
13859        display_map: &DisplaySnapshot,
13860        replace_newest: bool,
13861        autoscroll: Option<Autoscroll>,
13862        window: &mut Window,
13863        cx: &mut Context<Self>,
13864    ) -> Result<()> {
13865        let buffer = &display_map.buffer_snapshot;
13866        let mut selections = self.selections.all::<usize>(cx);
13867        if let Some(mut select_next_state) = self.select_next_state.take() {
13868            let query = &select_next_state.query;
13869            if !select_next_state.done {
13870                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13871                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13872                let mut next_selected_range = None;
13873
13874                let bytes_after_last_selection =
13875                    buffer.bytes_in_range(last_selection.end..buffer.len());
13876                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13877                let query_matches = query
13878                    .stream_find_iter(bytes_after_last_selection)
13879                    .map(|result| (last_selection.end, result))
13880                    .chain(
13881                        query
13882                            .stream_find_iter(bytes_before_first_selection)
13883                            .map(|result| (0, result)),
13884                    );
13885
13886                for (start_offset, query_match) in query_matches {
13887                    let query_match = query_match.unwrap(); // can only fail due to I/O
13888                    let offset_range =
13889                        start_offset + query_match.start()..start_offset + query_match.end();
13890
13891                    if !select_next_state.wordwise
13892                        || (!buffer.is_inside_word(offset_range.start, false)
13893                            && !buffer.is_inside_word(offset_range.end, false))
13894                    {
13895                        // TODO: This is n^2, because we might check all the selections
13896                        if !selections
13897                            .iter()
13898                            .any(|selection| selection.range().overlaps(&offset_range))
13899                        {
13900                            next_selected_range = Some(offset_range);
13901                            break;
13902                        }
13903                    }
13904                }
13905
13906                if let Some(next_selected_range) = next_selected_range {
13907                    self.select_match_ranges(
13908                        next_selected_range,
13909                        last_selection.reversed,
13910                        replace_newest,
13911                        autoscroll,
13912                        window,
13913                        cx,
13914                    );
13915                } else {
13916                    select_next_state.done = true;
13917                }
13918            }
13919
13920            self.select_next_state = Some(select_next_state);
13921        } else {
13922            let mut only_carets = true;
13923            let mut same_text_selected = true;
13924            let mut selected_text = None;
13925
13926            let mut selections_iter = selections.iter().peekable();
13927            while let Some(selection) = selections_iter.next() {
13928                if selection.start != selection.end {
13929                    only_carets = false;
13930                }
13931
13932                if same_text_selected {
13933                    if selected_text.is_none() {
13934                        selected_text =
13935                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13936                    }
13937
13938                    if let Some(next_selection) = selections_iter.peek() {
13939                        if next_selection.range().len() == selection.range().len() {
13940                            let next_selected_text = buffer
13941                                .text_for_range(next_selection.range())
13942                                .collect::<String>();
13943                            if Some(next_selected_text) != selected_text {
13944                                same_text_selected = false;
13945                                selected_text = None;
13946                            }
13947                        } else {
13948                            same_text_selected = false;
13949                            selected_text = None;
13950                        }
13951                    }
13952                }
13953            }
13954
13955            if only_carets {
13956                for selection in &mut selections {
13957                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13958                    selection.start = word_range.start;
13959                    selection.end = word_range.end;
13960                    selection.goal = SelectionGoal::None;
13961                    selection.reversed = false;
13962                    self.select_match_ranges(
13963                        selection.start..selection.end,
13964                        selection.reversed,
13965                        replace_newest,
13966                        autoscroll,
13967                        window,
13968                        cx,
13969                    );
13970                }
13971
13972                if selections.len() == 1 {
13973                    let selection = selections
13974                        .last()
13975                        .expect("ensured that there's only one selection");
13976                    let query = buffer
13977                        .text_for_range(selection.start..selection.end)
13978                        .collect::<String>();
13979                    let is_empty = query.is_empty();
13980                    let select_state = SelectNextState {
13981                        query: AhoCorasick::new(&[query])?,
13982                        wordwise: true,
13983                        done: is_empty,
13984                    };
13985                    self.select_next_state = Some(select_state);
13986                } else {
13987                    self.select_next_state = None;
13988                }
13989            } else if let Some(selected_text) = selected_text {
13990                self.select_next_state = Some(SelectNextState {
13991                    query: AhoCorasick::new(&[selected_text])?,
13992                    wordwise: false,
13993                    done: false,
13994                });
13995                self.select_next_match_internal(
13996                    display_map,
13997                    replace_newest,
13998                    autoscroll,
13999                    window,
14000                    cx,
14001                )?;
14002            }
14003        }
14004        Ok(())
14005    }
14006
14007    pub fn select_all_matches(
14008        &mut self,
14009        _action: &SelectAllMatches,
14010        window: &mut Window,
14011        cx: &mut Context<Self>,
14012    ) -> Result<()> {
14013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14014
14015        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14016
14017        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14018        let Some(select_next_state) = self.select_next_state.as_mut() else {
14019            return Ok(());
14020        };
14021        if select_next_state.done {
14022            return Ok(());
14023        }
14024
14025        let mut new_selections = Vec::new();
14026
14027        let reversed = self.selections.oldest::<usize>(cx).reversed;
14028        let buffer = &display_map.buffer_snapshot;
14029        let query_matches = select_next_state
14030            .query
14031            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14032
14033        for query_match in query_matches.into_iter() {
14034            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14035            let offset_range = if reversed {
14036                query_match.end()..query_match.start()
14037            } else {
14038                query_match.start()..query_match.end()
14039            };
14040
14041            if !select_next_state.wordwise
14042                || (!buffer.is_inside_word(offset_range.start, false)
14043                    && !buffer.is_inside_word(offset_range.end, false))
14044            {
14045                new_selections.push(offset_range.start..offset_range.end);
14046            }
14047        }
14048
14049        select_next_state.done = true;
14050
14051        if new_selections.is_empty() {
14052            log::error!("bug: new_selections is empty in select_all_matches");
14053            return Ok(());
14054        }
14055
14056        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14057        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14058            selections.select_ranges(new_selections)
14059        });
14060
14061        Ok(())
14062    }
14063
14064    pub fn select_next(
14065        &mut self,
14066        action: &SelectNext,
14067        window: &mut Window,
14068        cx: &mut Context<Self>,
14069    ) -> Result<()> {
14070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14071        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14072        self.select_next_match_internal(
14073            &display_map,
14074            action.replace_newest,
14075            Some(Autoscroll::newest()),
14076            window,
14077            cx,
14078        )?;
14079        Ok(())
14080    }
14081
14082    pub fn select_previous(
14083        &mut self,
14084        action: &SelectPrevious,
14085        window: &mut Window,
14086        cx: &mut Context<Self>,
14087    ) -> Result<()> {
14088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14089        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14090        let buffer = &display_map.buffer_snapshot;
14091        let mut selections = self.selections.all::<usize>(cx);
14092        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14093            let query = &select_prev_state.query;
14094            if !select_prev_state.done {
14095                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14096                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14097                let mut next_selected_range = None;
14098                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14099                let bytes_before_last_selection =
14100                    buffer.reversed_bytes_in_range(0..last_selection.start);
14101                let bytes_after_first_selection =
14102                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14103                let query_matches = query
14104                    .stream_find_iter(bytes_before_last_selection)
14105                    .map(|result| (last_selection.start, result))
14106                    .chain(
14107                        query
14108                            .stream_find_iter(bytes_after_first_selection)
14109                            .map(|result| (buffer.len(), result)),
14110                    );
14111                for (end_offset, query_match) in query_matches {
14112                    let query_match = query_match.unwrap(); // can only fail due to I/O
14113                    let offset_range =
14114                        end_offset - query_match.end()..end_offset - query_match.start();
14115
14116                    if !select_prev_state.wordwise
14117                        || (!buffer.is_inside_word(offset_range.start, false)
14118                            && !buffer.is_inside_word(offset_range.end, false))
14119                    {
14120                        next_selected_range = Some(offset_range);
14121                        break;
14122                    }
14123                }
14124
14125                if let Some(next_selected_range) = next_selected_range {
14126                    self.select_match_ranges(
14127                        next_selected_range,
14128                        last_selection.reversed,
14129                        action.replace_newest,
14130                        Some(Autoscroll::newest()),
14131                        window,
14132                        cx,
14133                    );
14134                } else {
14135                    select_prev_state.done = true;
14136                }
14137            }
14138
14139            self.select_prev_state = Some(select_prev_state);
14140        } else {
14141            let mut only_carets = true;
14142            let mut same_text_selected = true;
14143            let mut selected_text = None;
14144
14145            let mut selections_iter = selections.iter().peekable();
14146            while let Some(selection) = selections_iter.next() {
14147                if selection.start != selection.end {
14148                    only_carets = false;
14149                }
14150
14151                if same_text_selected {
14152                    if selected_text.is_none() {
14153                        selected_text =
14154                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14155                    }
14156
14157                    if let Some(next_selection) = selections_iter.peek() {
14158                        if next_selection.range().len() == selection.range().len() {
14159                            let next_selected_text = buffer
14160                                .text_for_range(next_selection.range())
14161                                .collect::<String>();
14162                            if Some(next_selected_text) != selected_text {
14163                                same_text_selected = false;
14164                                selected_text = None;
14165                            }
14166                        } else {
14167                            same_text_selected = false;
14168                            selected_text = None;
14169                        }
14170                    }
14171                }
14172            }
14173
14174            if only_carets {
14175                for selection in &mut selections {
14176                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14177                    selection.start = word_range.start;
14178                    selection.end = word_range.end;
14179                    selection.goal = SelectionGoal::None;
14180                    selection.reversed = false;
14181                    self.select_match_ranges(
14182                        selection.start..selection.end,
14183                        selection.reversed,
14184                        action.replace_newest,
14185                        Some(Autoscroll::newest()),
14186                        window,
14187                        cx,
14188                    );
14189                }
14190                if selections.len() == 1 {
14191                    let selection = selections
14192                        .last()
14193                        .expect("ensured that there's only one selection");
14194                    let query = buffer
14195                        .text_for_range(selection.start..selection.end)
14196                        .collect::<String>();
14197                    let is_empty = query.is_empty();
14198                    let select_state = SelectNextState {
14199                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14200                        wordwise: true,
14201                        done: is_empty,
14202                    };
14203                    self.select_prev_state = Some(select_state);
14204                } else {
14205                    self.select_prev_state = None;
14206                }
14207            } else if let Some(selected_text) = selected_text {
14208                self.select_prev_state = Some(SelectNextState {
14209                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14210                    wordwise: false,
14211                    done: false,
14212                });
14213                self.select_previous(action, window, cx)?;
14214            }
14215        }
14216        Ok(())
14217    }
14218
14219    pub fn find_next_match(
14220        &mut self,
14221        _: &FindNextMatch,
14222        window: &mut Window,
14223        cx: &mut Context<Self>,
14224    ) -> Result<()> {
14225        let selections = self.selections.disjoint_anchors();
14226        match selections.first() {
14227            Some(first) if selections.len() >= 2 => {
14228                self.change_selections(Default::default(), window, cx, |s| {
14229                    s.select_ranges([first.range()]);
14230                });
14231            }
14232            _ => self.select_next(
14233                &SelectNext {
14234                    replace_newest: true,
14235                },
14236                window,
14237                cx,
14238            )?,
14239        }
14240        Ok(())
14241    }
14242
14243    pub fn find_previous_match(
14244        &mut self,
14245        _: &FindPreviousMatch,
14246        window: &mut Window,
14247        cx: &mut Context<Self>,
14248    ) -> Result<()> {
14249        let selections = self.selections.disjoint_anchors();
14250        match selections.last() {
14251            Some(last) if selections.len() >= 2 => {
14252                self.change_selections(Default::default(), window, cx, |s| {
14253                    s.select_ranges([last.range()]);
14254                });
14255            }
14256            _ => self.select_previous(
14257                &SelectPrevious {
14258                    replace_newest: true,
14259                },
14260                window,
14261                cx,
14262            )?,
14263        }
14264        Ok(())
14265    }
14266
14267    pub fn toggle_comments(
14268        &mut self,
14269        action: &ToggleComments,
14270        window: &mut Window,
14271        cx: &mut Context<Self>,
14272    ) {
14273        if self.read_only(cx) {
14274            return;
14275        }
14276        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14277        let text_layout_details = &self.text_layout_details(window);
14278        self.transact(window, cx, |this, window, cx| {
14279            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14280            let mut edits = Vec::new();
14281            let mut selection_edit_ranges = Vec::new();
14282            let mut last_toggled_row = None;
14283            let snapshot = this.buffer.read(cx).read(cx);
14284            let empty_str: Arc<str> = Arc::default();
14285            let mut suffixes_inserted = Vec::new();
14286            let ignore_indent = action.ignore_indent;
14287
14288            fn comment_prefix_range(
14289                snapshot: &MultiBufferSnapshot,
14290                row: MultiBufferRow,
14291                comment_prefix: &str,
14292                comment_prefix_whitespace: &str,
14293                ignore_indent: bool,
14294            ) -> Range<Point> {
14295                let indent_size = if ignore_indent {
14296                    0
14297                } else {
14298                    snapshot.indent_size_for_line(row).len
14299                };
14300
14301                let start = Point::new(row.0, indent_size);
14302
14303                let mut line_bytes = snapshot
14304                    .bytes_in_range(start..snapshot.max_point())
14305                    .flatten()
14306                    .copied();
14307
14308                // If this line currently begins with the line comment prefix, then record
14309                // the range containing the prefix.
14310                if line_bytes
14311                    .by_ref()
14312                    .take(comment_prefix.len())
14313                    .eq(comment_prefix.bytes())
14314                {
14315                    // Include any whitespace that matches the comment prefix.
14316                    let matching_whitespace_len = line_bytes
14317                        .zip(comment_prefix_whitespace.bytes())
14318                        .take_while(|(a, b)| a == b)
14319                        .count() as u32;
14320                    let end = Point::new(
14321                        start.row,
14322                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14323                    );
14324                    start..end
14325                } else {
14326                    start..start
14327                }
14328            }
14329
14330            fn comment_suffix_range(
14331                snapshot: &MultiBufferSnapshot,
14332                row: MultiBufferRow,
14333                comment_suffix: &str,
14334                comment_suffix_has_leading_space: bool,
14335            ) -> Range<Point> {
14336                let end = Point::new(row.0, snapshot.line_len(row));
14337                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14338
14339                let mut line_end_bytes = snapshot
14340                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14341                    .flatten()
14342                    .copied();
14343
14344                let leading_space_len = if suffix_start_column > 0
14345                    && line_end_bytes.next() == Some(b' ')
14346                    && comment_suffix_has_leading_space
14347                {
14348                    1
14349                } else {
14350                    0
14351                };
14352
14353                // If this line currently begins with the line comment prefix, then record
14354                // the range containing the prefix.
14355                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14356                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14357                    start..end
14358                } else {
14359                    end..end
14360                }
14361            }
14362
14363            // TODO: Handle selections that cross excerpts
14364            for selection in &mut selections {
14365                let start_column = snapshot
14366                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14367                    .len;
14368                let language = if let Some(language) =
14369                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14370                {
14371                    language
14372                } else {
14373                    continue;
14374                };
14375
14376                selection_edit_ranges.clear();
14377
14378                // If multiple selections contain a given row, avoid processing that
14379                // row more than once.
14380                let mut start_row = MultiBufferRow(selection.start.row);
14381                if last_toggled_row == Some(start_row) {
14382                    start_row = start_row.next_row();
14383                }
14384                let end_row =
14385                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14386                        MultiBufferRow(selection.end.row - 1)
14387                    } else {
14388                        MultiBufferRow(selection.end.row)
14389                    };
14390                last_toggled_row = Some(end_row);
14391
14392                if start_row > end_row {
14393                    continue;
14394                }
14395
14396                // If the language has line comments, toggle those.
14397                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14398
14399                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14400                if ignore_indent {
14401                    full_comment_prefixes = full_comment_prefixes
14402                        .into_iter()
14403                        .map(|s| Arc::from(s.trim_end()))
14404                        .collect();
14405                }
14406
14407                if !full_comment_prefixes.is_empty() {
14408                    let first_prefix = full_comment_prefixes
14409                        .first()
14410                        .expect("prefixes is non-empty");
14411                    let prefix_trimmed_lengths = full_comment_prefixes
14412                        .iter()
14413                        .map(|p| p.trim_end_matches(' ').len())
14414                        .collect::<SmallVec<[usize; 4]>>();
14415
14416                    let mut all_selection_lines_are_comments = true;
14417
14418                    for row in start_row.0..=end_row.0 {
14419                        let row = MultiBufferRow(row);
14420                        if start_row < end_row && snapshot.is_line_blank(row) {
14421                            continue;
14422                        }
14423
14424                        let prefix_range = full_comment_prefixes
14425                            .iter()
14426                            .zip(prefix_trimmed_lengths.iter().copied())
14427                            .map(|(prefix, trimmed_prefix_len)| {
14428                                comment_prefix_range(
14429                                    snapshot.deref(),
14430                                    row,
14431                                    &prefix[..trimmed_prefix_len],
14432                                    &prefix[trimmed_prefix_len..],
14433                                    ignore_indent,
14434                                )
14435                            })
14436                            .max_by_key(|range| range.end.column - range.start.column)
14437                            .expect("prefixes is non-empty");
14438
14439                        if prefix_range.is_empty() {
14440                            all_selection_lines_are_comments = false;
14441                        }
14442
14443                        selection_edit_ranges.push(prefix_range);
14444                    }
14445
14446                    if all_selection_lines_are_comments {
14447                        edits.extend(
14448                            selection_edit_ranges
14449                                .iter()
14450                                .cloned()
14451                                .map(|range| (range, empty_str.clone())),
14452                        );
14453                    } else {
14454                        let min_column = selection_edit_ranges
14455                            .iter()
14456                            .map(|range| range.start.column)
14457                            .min()
14458                            .unwrap_or(0);
14459                        edits.extend(selection_edit_ranges.iter().map(|range| {
14460                            let position = Point::new(range.start.row, min_column);
14461                            (position..position, first_prefix.clone())
14462                        }));
14463                    }
14464                } else if let Some(BlockCommentConfig {
14465                    start: full_comment_prefix,
14466                    end: comment_suffix,
14467                    ..
14468                }) = language.block_comment()
14469                {
14470                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14471                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14472                    let prefix_range = comment_prefix_range(
14473                        snapshot.deref(),
14474                        start_row,
14475                        comment_prefix,
14476                        comment_prefix_whitespace,
14477                        ignore_indent,
14478                    );
14479                    let suffix_range = comment_suffix_range(
14480                        snapshot.deref(),
14481                        end_row,
14482                        comment_suffix.trim_start_matches(' '),
14483                        comment_suffix.starts_with(' '),
14484                    );
14485
14486                    if prefix_range.is_empty() || suffix_range.is_empty() {
14487                        edits.push((
14488                            prefix_range.start..prefix_range.start,
14489                            full_comment_prefix.clone(),
14490                        ));
14491                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14492                        suffixes_inserted.push((end_row, comment_suffix.len()));
14493                    } else {
14494                        edits.push((prefix_range, empty_str.clone()));
14495                        edits.push((suffix_range, empty_str.clone()));
14496                    }
14497                } else {
14498                    continue;
14499                }
14500            }
14501
14502            drop(snapshot);
14503            this.buffer.update(cx, |buffer, cx| {
14504                buffer.edit(edits, None, cx);
14505            });
14506
14507            // Adjust selections so that they end before any comment suffixes that
14508            // were inserted.
14509            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14510            let mut selections = this.selections.all::<Point>(cx);
14511            let snapshot = this.buffer.read(cx).read(cx);
14512            for selection in &mut selections {
14513                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14514                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14515                        Ordering::Less => {
14516                            suffixes_inserted.next();
14517                            continue;
14518                        }
14519                        Ordering::Greater => break,
14520                        Ordering::Equal => {
14521                            if selection.end.column == snapshot.line_len(row) {
14522                                if selection.is_empty() {
14523                                    selection.start.column -= suffix_len as u32;
14524                                }
14525                                selection.end.column -= suffix_len as u32;
14526                            }
14527                            break;
14528                        }
14529                    }
14530                }
14531            }
14532
14533            drop(snapshot);
14534            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14535
14536            let selections = this.selections.all::<Point>(cx);
14537            let selections_on_single_row = selections.windows(2).all(|selections| {
14538                selections[0].start.row == selections[1].start.row
14539                    && selections[0].end.row == selections[1].end.row
14540                    && selections[0].start.row == selections[0].end.row
14541            });
14542            let selections_selecting = selections
14543                .iter()
14544                .any(|selection| selection.start != selection.end);
14545            let advance_downwards = action.advance_downwards
14546                && selections_on_single_row
14547                && !selections_selecting
14548                && !matches!(this.mode, EditorMode::SingleLine);
14549
14550            if advance_downwards {
14551                let snapshot = this.buffer.read(cx).snapshot(cx);
14552
14553                this.change_selections(Default::default(), window, cx, |s| {
14554                    s.move_cursors_with(|display_snapshot, display_point, _| {
14555                        let mut point = display_point.to_point(display_snapshot);
14556                        point.row += 1;
14557                        point = snapshot.clip_point(point, Bias::Left);
14558                        let display_point = point.to_display_point(display_snapshot);
14559                        let goal = SelectionGoal::HorizontalPosition(
14560                            display_snapshot
14561                                .x_for_display_point(display_point, text_layout_details)
14562                                .into(),
14563                        );
14564                        (display_point, goal)
14565                    })
14566                });
14567            }
14568        });
14569    }
14570
14571    pub fn select_enclosing_symbol(
14572        &mut self,
14573        _: &SelectEnclosingSymbol,
14574        window: &mut Window,
14575        cx: &mut Context<Self>,
14576    ) {
14577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14578
14579        let buffer = self.buffer.read(cx).snapshot(cx);
14580        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14581
14582        fn update_selection(
14583            selection: &Selection<usize>,
14584            buffer_snap: &MultiBufferSnapshot,
14585        ) -> Option<Selection<usize>> {
14586            let cursor = selection.head();
14587            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14588            for symbol in symbols.iter().rev() {
14589                let start = symbol.range.start.to_offset(buffer_snap);
14590                let end = symbol.range.end.to_offset(buffer_snap);
14591                let new_range = start..end;
14592                if start < selection.start || end > selection.end {
14593                    return Some(Selection {
14594                        id: selection.id,
14595                        start: new_range.start,
14596                        end: new_range.end,
14597                        goal: SelectionGoal::None,
14598                        reversed: selection.reversed,
14599                    });
14600                }
14601            }
14602            None
14603        }
14604
14605        let mut selected_larger_symbol = false;
14606        let new_selections = old_selections
14607            .iter()
14608            .map(|selection| match update_selection(selection, &buffer) {
14609                Some(new_selection) => {
14610                    if new_selection.range() != selection.range() {
14611                        selected_larger_symbol = true;
14612                    }
14613                    new_selection
14614                }
14615                None => selection.clone(),
14616            })
14617            .collect::<Vec<_>>();
14618
14619        if selected_larger_symbol {
14620            self.change_selections(Default::default(), window, cx, |s| {
14621                s.select(new_selections);
14622            });
14623        }
14624    }
14625
14626    pub fn select_larger_syntax_node(
14627        &mut self,
14628        _: &SelectLargerSyntaxNode,
14629        window: &mut Window,
14630        cx: &mut Context<Self>,
14631    ) {
14632        let Some(visible_row_count) = self.visible_row_count() else {
14633            return;
14634        };
14635        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14636        if old_selections.is_empty() {
14637            return;
14638        }
14639
14640        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14641
14642        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14643        let buffer = self.buffer.read(cx).snapshot(cx);
14644
14645        let mut selected_larger_node = false;
14646        let mut new_selections = old_selections
14647            .iter()
14648            .map(|selection| {
14649                let old_range = selection.start..selection.end;
14650
14651                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14652                    // manually select word at selection
14653                    if ["string_content", "inline"].contains(&node.kind()) {
14654                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14655                        // ignore if word is already selected
14656                        if !word_range.is_empty() && old_range != word_range {
14657                            let (last_word_range, _) =
14658                                buffer.surrounding_word(old_range.end, false);
14659                            // only select word if start and end point belongs to same word
14660                            if word_range == last_word_range {
14661                                selected_larger_node = true;
14662                                return Selection {
14663                                    id: selection.id,
14664                                    start: word_range.start,
14665                                    end: word_range.end,
14666                                    goal: SelectionGoal::None,
14667                                    reversed: selection.reversed,
14668                                };
14669                            }
14670                        }
14671                    }
14672                }
14673
14674                let mut new_range = old_range.clone();
14675                while let Some((_node, containing_range)) =
14676                    buffer.syntax_ancestor(new_range.clone())
14677                {
14678                    new_range = match containing_range {
14679                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14680                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14681                    };
14682                    if !display_map.intersects_fold(new_range.start)
14683                        && !display_map.intersects_fold(new_range.end)
14684                    {
14685                        break;
14686                    }
14687                }
14688
14689                selected_larger_node |= new_range != old_range;
14690                Selection {
14691                    id: selection.id,
14692                    start: new_range.start,
14693                    end: new_range.end,
14694                    goal: SelectionGoal::None,
14695                    reversed: selection.reversed,
14696                }
14697            })
14698            .collect::<Vec<_>>();
14699
14700        if !selected_larger_node {
14701            return; // don't put this call in the history
14702        }
14703
14704        // scroll based on transformation done to the last selection created by the user
14705        let (last_old, last_new) = old_selections
14706            .last()
14707            .zip(new_selections.last().cloned())
14708            .expect("old_selections isn't empty");
14709
14710        // revert selection
14711        let is_selection_reversed = {
14712            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14713            new_selections.last_mut().expect("checked above").reversed =
14714                should_newest_selection_be_reversed;
14715            should_newest_selection_be_reversed
14716        };
14717
14718        if selected_larger_node {
14719            self.select_syntax_node_history.disable_clearing = true;
14720            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14721                s.select(new_selections.clone());
14722            });
14723            self.select_syntax_node_history.disable_clearing = false;
14724        }
14725
14726        let start_row = last_new.start.to_display_point(&display_map).row().0;
14727        let end_row = last_new.end.to_display_point(&display_map).row().0;
14728        let selection_height = end_row - start_row + 1;
14729        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14730
14731        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14732        let scroll_behavior = if fits_on_the_screen {
14733            self.request_autoscroll(Autoscroll::fit(), cx);
14734            SelectSyntaxNodeScrollBehavior::FitSelection
14735        } else if is_selection_reversed {
14736            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14737            SelectSyntaxNodeScrollBehavior::CursorTop
14738        } else {
14739            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14740            SelectSyntaxNodeScrollBehavior::CursorBottom
14741        };
14742
14743        self.select_syntax_node_history.push((
14744            old_selections,
14745            scroll_behavior,
14746            is_selection_reversed,
14747        ));
14748    }
14749
14750    pub fn select_smaller_syntax_node(
14751        &mut self,
14752        _: &SelectSmallerSyntaxNode,
14753        window: &mut Window,
14754        cx: &mut Context<Self>,
14755    ) {
14756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14757
14758        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14759            self.select_syntax_node_history.pop()
14760        {
14761            if let Some(selection) = selections.last_mut() {
14762                selection.reversed = is_selection_reversed;
14763            }
14764
14765            self.select_syntax_node_history.disable_clearing = true;
14766            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14767                s.select(selections.to_vec());
14768            });
14769            self.select_syntax_node_history.disable_clearing = false;
14770
14771            match scroll_behavior {
14772                SelectSyntaxNodeScrollBehavior::CursorTop => {
14773                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14774                }
14775                SelectSyntaxNodeScrollBehavior::FitSelection => {
14776                    self.request_autoscroll(Autoscroll::fit(), cx);
14777                }
14778                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14779                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14780                }
14781            }
14782        }
14783    }
14784
14785    pub fn unwrap_syntax_node(
14786        &mut self,
14787        _: &UnwrapSyntaxNode,
14788        window: &mut Window,
14789        cx: &mut Context<Self>,
14790    ) {
14791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14792
14793        let buffer = self.buffer.read(cx).snapshot(cx);
14794        let selections = self
14795            .selections
14796            .all::<usize>(cx)
14797            .into_iter()
14798            // subtracting the offset requires sorting
14799            .sorted_by_key(|i| i.start);
14800
14801        let full_edits = selections
14802            .into_iter()
14803            .filter_map(|selection| {
14804                // Only requires two branches once if-let-chains stabilize (#53667)
14805                let child = if !selection.is_empty() {
14806                    selection.range()
14807                } else if let Some((_, ancestor_range)) =
14808                    buffer.syntax_ancestor(selection.start..selection.end)
14809                {
14810                    match ancestor_range {
14811                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14812                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14813                    }
14814                } else {
14815                    selection.range()
14816                };
14817
14818                let mut parent = child.clone();
14819                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14820                    parent = match ancestor_range {
14821                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14822                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14823                    };
14824                    if parent.start < child.start || parent.end > child.end {
14825                        break;
14826                    }
14827                }
14828
14829                if parent == child {
14830                    return None;
14831                }
14832                let text = buffer.text_for_range(child).collect::<String>();
14833                Some((selection.id, parent, text))
14834            })
14835            .collect::<Vec<_>>();
14836
14837        self.transact(window, cx, |this, window, cx| {
14838            this.buffer.update(cx, |buffer, cx| {
14839                buffer.edit(
14840                    full_edits
14841                        .iter()
14842                        .map(|(_, p, t)| (p.clone(), t.clone()))
14843                        .collect::<Vec<_>>(),
14844                    None,
14845                    cx,
14846                );
14847            });
14848            this.change_selections(Default::default(), window, cx, |s| {
14849                let mut offset = 0;
14850                let mut selections = vec![];
14851                for (id, parent, text) in full_edits {
14852                    let start = parent.start - offset;
14853                    offset += parent.len() - text.len();
14854                    selections.push(Selection {
14855                        id,
14856                        start,
14857                        end: start + text.len(),
14858                        reversed: false,
14859                        goal: Default::default(),
14860                    });
14861                }
14862                s.select(selections);
14863            });
14864        });
14865    }
14866
14867    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14868        if !EditorSettings::get_global(cx).gutter.runnables {
14869            self.clear_tasks();
14870            return Task::ready(());
14871        }
14872        let project = self.project().map(Entity::downgrade);
14873        let task_sources = self.lsp_task_sources(cx);
14874        let multi_buffer = self.buffer.downgrade();
14875        cx.spawn_in(window, async move |editor, cx| {
14876            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14877            let Some(project) = project.and_then(|p| p.upgrade()) else {
14878                return;
14879            };
14880            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14881                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14882            }) else {
14883                return;
14884            };
14885
14886            let hide_runnables = project
14887                .update(cx, |project, _| project.is_via_collab())
14888                .unwrap_or(true);
14889            if hide_runnables {
14890                return;
14891            }
14892            let new_rows =
14893                cx.background_spawn({
14894                    let snapshot = display_snapshot.clone();
14895                    async move {
14896                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14897                    }
14898                })
14899                    .await;
14900            let Ok(lsp_tasks) =
14901                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14902            else {
14903                return;
14904            };
14905            let lsp_tasks = lsp_tasks.await;
14906
14907            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14908                lsp_tasks
14909                    .into_iter()
14910                    .flat_map(|(kind, tasks)| {
14911                        tasks.into_iter().filter_map(move |(location, task)| {
14912                            Some((kind.clone(), location?, task))
14913                        })
14914                    })
14915                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14916                        let buffer = location.target.buffer;
14917                        let buffer_snapshot = buffer.read(cx).snapshot();
14918                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14919                            |(excerpt_id, snapshot, _)| {
14920                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14921                                    display_snapshot
14922                                        .buffer_snapshot
14923                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14924                                } else {
14925                                    None
14926                                }
14927                            },
14928                        );
14929                        if let Some(offset) = offset {
14930                            let task_buffer_range =
14931                                location.target.range.to_point(&buffer_snapshot);
14932                            let context_buffer_range =
14933                                task_buffer_range.to_offset(&buffer_snapshot);
14934                            let context_range = BufferOffset(context_buffer_range.start)
14935                                ..BufferOffset(context_buffer_range.end);
14936
14937                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14938                                .or_insert_with(|| RunnableTasks {
14939                                    templates: Vec::new(),
14940                                    offset,
14941                                    column: task_buffer_range.start.column,
14942                                    extra_variables: HashMap::default(),
14943                                    context_range,
14944                                })
14945                                .templates
14946                                .push((kind, task.original_task().clone()));
14947                        }
14948
14949                        acc
14950                    })
14951            }) else {
14952                return;
14953            };
14954
14955            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14956                buffer.language_settings(cx).tasks.prefer_lsp
14957            }) else {
14958                return;
14959            };
14960
14961            let rows = Self::runnable_rows(
14962                project,
14963                display_snapshot,
14964                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14965                new_rows,
14966                cx.clone(),
14967            )
14968            .await;
14969            editor
14970                .update(cx, |editor, _| {
14971                    editor.clear_tasks();
14972                    for (key, mut value) in rows {
14973                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14974                            value.templates.extend(lsp_tasks.templates);
14975                        }
14976
14977                        editor.insert_tasks(key, value);
14978                    }
14979                    for (key, value) in lsp_tasks_by_rows {
14980                        editor.insert_tasks(key, value);
14981                    }
14982                })
14983                .ok();
14984        })
14985    }
14986    fn fetch_runnable_ranges(
14987        snapshot: &DisplaySnapshot,
14988        range: Range<Anchor>,
14989    ) -> Vec<language::RunnableRange> {
14990        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14991    }
14992
14993    fn runnable_rows(
14994        project: Entity<Project>,
14995        snapshot: DisplaySnapshot,
14996        prefer_lsp: bool,
14997        runnable_ranges: Vec<RunnableRange>,
14998        cx: AsyncWindowContext,
14999    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15000        cx.spawn(async move |cx| {
15001            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15002            for mut runnable in runnable_ranges {
15003                let Some(tasks) = cx
15004                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15005                    .ok()
15006                else {
15007                    continue;
15008                };
15009                let mut tasks = tasks.await;
15010
15011                if prefer_lsp {
15012                    tasks.retain(|(task_kind, _)| {
15013                        !matches!(task_kind, TaskSourceKind::Language { .. })
15014                    });
15015                }
15016                if tasks.is_empty() {
15017                    continue;
15018                }
15019
15020                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15021                let Some(row) = snapshot
15022                    .buffer_snapshot
15023                    .buffer_line_for_row(MultiBufferRow(point.row))
15024                    .map(|(_, range)| range.start.row)
15025                else {
15026                    continue;
15027                };
15028
15029                let context_range =
15030                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15031                runnable_rows.push((
15032                    (runnable.buffer_id, row),
15033                    RunnableTasks {
15034                        templates: tasks,
15035                        offset: snapshot
15036                            .buffer_snapshot
15037                            .anchor_before(runnable.run_range.start),
15038                        context_range,
15039                        column: point.column,
15040                        extra_variables: runnable.extra_captures,
15041                    },
15042                ));
15043            }
15044            runnable_rows
15045        })
15046    }
15047
15048    fn templates_with_tags(
15049        project: &Entity<Project>,
15050        runnable: &mut Runnable,
15051        cx: &mut App,
15052    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15053        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15054            let (worktree_id, file) = project
15055                .buffer_for_id(runnable.buffer, cx)
15056                .and_then(|buffer| buffer.read(cx).file())
15057                .map(|file| (file.worktree_id(cx), file.clone()))
15058                .unzip();
15059
15060            (
15061                project.task_store().read(cx).task_inventory().cloned(),
15062                worktree_id,
15063                file,
15064            )
15065        });
15066
15067        let tags = mem::take(&mut runnable.tags);
15068        let language = runnable.language.clone();
15069        cx.spawn(async move |cx| {
15070            let mut templates_with_tags = Vec::new();
15071            if let Some(inventory) = inventory {
15072                for RunnableTag(tag) in tags {
15073                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15074                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15075                    }) else {
15076                        return templates_with_tags;
15077                    };
15078                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15079                        move |(_, template)| {
15080                            template.tags.iter().any(|source_tag| source_tag == &tag)
15081                        },
15082                    ));
15083                }
15084            }
15085            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15086
15087            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15088                // Strongest source wins; if we have worktree tag binding, prefer that to
15089                // global and language bindings;
15090                // if we have a global binding, prefer that to language binding.
15091                let first_mismatch = templates_with_tags
15092                    .iter()
15093                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15094                if let Some(index) = first_mismatch {
15095                    templates_with_tags.truncate(index);
15096                }
15097            }
15098
15099            templates_with_tags
15100        })
15101    }
15102
15103    pub fn move_to_enclosing_bracket(
15104        &mut self,
15105        _: &MoveToEnclosingBracket,
15106        window: &mut Window,
15107        cx: &mut Context<Self>,
15108    ) {
15109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15110        self.change_selections(Default::default(), window, cx, |s| {
15111            s.move_offsets_with(|snapshot, selection| {
15112                let Some(enclosing_bracket_ranges) =
15113                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15114                else {
15115                    return;
15116                };
15117
15118                let mut best_length = usize::MAX;
15119                let mut best_inside = false;
15120                let mut best_in_bracket_range = false;
15121                let mut best_destination = None;
15122                for (open, close) in enclosing_bracket_ranges {
15123                    let close = close.to_inclusive();
15124                    let length = close.end() - open.start;
15125                    let inside = selection.start >= open.end && selection.end <= *close.start();
15126                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15127                        || close.contains(&selection.head());
15128
15129                    // If best is next to a bracket and current isn't, skip
15130                    if !in_bracket_range && best_in_bracket_range {
15131                        continue;
15132                    }
15133
15134                    // Prefer smaller lengths unless best is inside and current isn't
15135                    if length > best_length && (best_inside || !inside) {
15136                        continue;
15137                    }
15138
15139                    best_length = length;
15140                    best_inside = inside;
15141                    best_in_bracket_range = in_bracket_range;
15142                    best_destination = Some(
15143                        if close.contains(&selection.start) && close.contains(&selection.end) {
15144                            if inside { open.end } else { open.start }
15145                        } else if inside {
15146                            *close.start()
15147                        } else {
15148                            *close.end()
15149                        },
15150                    );
15151                }
15152
15153                if let Some(destination) = best_destination {
15154                    selection.collapse_to(destination, SelectionGoal::None);
15155                }
15156            })
15157        });
15158    }
15159
15160    pub fn undo_selection(
15161        &mut self,
15162        _: &UndoSelection,
15163        window: &mut Window,
15164        cx: &mut Context<Self>,
15165    ) {
15166        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15167        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15168            self.selection_history.mode = SelectionHistoryMode::Undoing;
15169            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15170                this.end_selection(window, cx);
15171                this.change_selections(
15172                    SelectionEffects::scroll(Autoscroll::newest()),
15173                    window,
15174                    cx,
15175                    |s| s.select_anchors(entry.selections.to_vec()),
15176                );
15177            });
15178            self.selection_history.mode = SelectionHistoryMode::Normal;
15179
15180            self.select_next_state = entry.select_next_state;
15181            self.select_prev_state = entry.select_prev_state;
15182            self.add_selections_state = entry.add_selections_state;
15183        }
15184    }
15185
15186    pub fn redo_selection(
15187        &mut self,
15188        _: &RedoSelection,
15189        window: &mut Window,
15190        cx: &mut Context<Self>,
15191    ) {
15192        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15193        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15194            self.selection_history.mode = SelectionHistoryMode::Redoing;
15195            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15196                this.end_selection(window, cx);
15197                this.change_selections(
15198                    SelectionEffects::scroll(Autoscroll::newest()),
15199                    window,
15200                    cx,
15201                    |s| s.select_anchors(entry.selections.to_vec()),
15202                );
15203            });
15204            self.selection_history.mode = SelectionHistoryMode::Normal;
15205
15206            self.select_next_state = entry.select_next_state;
15207            self.select_prev_state = entry.select_prev_state;
15208            self.add_selections_state = entry.add_selections_state;
15209        }
15210    }
15211
15212    pub fn expand_excerpts(
15213        &mut self,
15214        action: &ExpandExcerpts,
15215        _: &mut Window,
15216        cx: &mut Context<Self>,
15217    ) {
15218        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15219    }
15220
15221    pub fn expand_excerpts_down(
15222        &mut self,
15223        action: &ExpandExcerptsDown,
15224        _: &mut Window,
15225        cx: &mut Context<Self>,
15226    ) {
15227        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15228    }
15229
15230    pub fn expand_excerpts_up(
15231        &mut self,
15232        action: &ExpandExcerptsUp,
15233        _: &mut Window,
15234        cx: &mut Context<Self>,
15235    ) {
15236        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15237    }
15238
15239    pub fn expand_excerpts_for_direction(
15240        &mut self,
15241        lines: u32,
15242        direction: ExpandExcerptDirection,
15243
15244        cx: &mut Context<Self>,
15245    ) {
15246        let selections = self.selections.disjoint_anchors();
15247
15248        let lines = if lines == 0 {
15249            EditorSettings::get_global(cx).expand_excerpt_lines
15250        } else {
15251            lines
15252        };
15253
15254        self.buffer.update(cx, |buffer, cx| {
15255            let snapshot = buffer.snapshot(cx);
15256            let mut excerpt_ids = selections
15257                .iter()
15258                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15259                .collect::<Vec<_>>();
15260            excerpt_ids.sort();
15261            excerpt_ids.dedup();
15262            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15263        })
15264    }
15265
15266    pub fn expand_excerpt(
15267        &mut self,
15268        excerpt: ExcerptId,
15269        direction: ExpandExcerptDirection,
15270        window: &mut Window,
15271        cx: &mut Context<Self>,
15272    ) {
15273        let current_scroll_position = self.scroll_position(cx);
15274        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15275        let mut should_scroll_up = false;
15276
15277        if direction == ExpandExcerptDirection::Down {
15278            let multi_buffer = self.buffer.read(cx);
15279            let snapshot = multi_buffer.snapshot(cx);
15280            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15281                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15282                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15283            {
15284                let buffer_snapshot = buffer.read(cx).snapshot();
15285                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15286                let last_row = buffer_snapshot.max_point().row;
15287                let lines_below = last_row.saturating_sub(excerpt_end_row);
15288                should_scroll_up = lines_below >= lines_to_expand;
15289            }
15290        }
15291
15292        self.buffer.update(cx, |buffer, cx| {
15293            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15294        });
15295
15296        if should_scroll_up {
15297            let new_scroll_position =
15298                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15299            self.set_scroll_position(new_scroll_position, window, cx);
15300        }
15301    }
15302
15303    pub fn go_to_singleton_buffer_point(
15304        &mut self,
15305        point: Point,
15306        window: &mut Window,
15307        cx: &mut Context<Self>,
15308    ) {
15309        self.go_to_singleton_buffer_range(point..point, window, cx);
15310    }
15311
15312    pub fn go_to_singleton_buffer_range(
15313        &mut self,
15314        range: Range<Point>,
15315        window: &mut Window,
15316        cx: &mut Context<Self>,
15317    ) {
15318        let multibuffer = self.buffer().read(cx);
15319        let Some(buffer) = multibuffer.as_singleton() else {
15320            return;
15321        };
15322        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15323            return;
15324        };
15325        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15326            return;
15327        };
15328        self.change_selections(
15329            SelectionEffects::default().nav_history(true),
15330            window,
15331            cx,
15332            |s| s.select_anchor_ranges([start..end]),
15333        );
15334    }
15335
15336    pub fn go_to_diagnostic(
15337        &mut self,
15338        action: &GoToDiagnostic,
15339        window: &mut Window,
15340        cx: &mut Context<Self>,
15341    ) {
15342        if !self.diagnostics_enabled() {
15343            return;
15344        }
15345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15346        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15347    }
15348
15349    pub fn go_to_prev_diagnostic(
15350        &mut self,
15351        action: &GoToPreviousDiagnostic,
15352        window: &mut Window,
15353        cx: &mut Context<Self>,
15354    ) {
15355        if !self.diagnostics_enabled() {
15356            return;
15357        }
15358        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15359        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15360    }
15361
15362    pub fn go_to_diagnostic_impl(
15363        &mut self,
15364        direction: Direction,
15365        severity: GoToDiagnosticSeverityFilter,
15366        window: &mut Window,
15367        cx: &mut Context<Self>,
15368    ) {
15369        let buffer = self.buffer.read(cx).snapshot(cx);
15370        let selection = self.selections.newest::<usize>(cx);
15371
15372        let mut active_group_id = None;
15373        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15374            && active_group.active_range.start.to_offset(&buffer) == selection.start
15375        {
15376            active_group_id = Some(active_group.group_id);
15377        }
15378
15379        fn filtered(
15380            snapshot: EditorSnapshot,
15381            severity: GoToDiagnosticSeverityFilter,
15382            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15383        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15384            diagnostics
15385                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15386                .filter(|entry| entry.range.start != entry.range.end)
15387                .filter(|entry| !entry.diagnostic.is_unnecessary)
15388                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15389        }
15390
15391        let snapshot = self.snapshot(window, cx);
15392        let before = filtered(
15393            snapshot.clone(),
15394            severity,
15395            buffer
15396                .diagnostics_in_range(0..selection.start)
15397                .filter(|entry| entry.range.start <= selection.start),
15398        );
15399        let after = filtered(
15400            snapshot,
15401            severity,
15402            buffer
15403                .diagnostics_in_range(selection.start..buffer.len())
15404                .filter(|entry| entry.range.start >= selection.start),
15405        );
15406
15407        let mut found: Option<DiagnosticEntry<usize>> = None;
15408        if direction == Direction::Prev {
15409            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15410            {
15411                for diagnostic in prev_diagnostics.into_iter().rev() {
15412                    if diagnostic.range.start != selection.start
15413                        || active_group_id
15414                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15415                    {
15416                        found = Some(diagnostic);
15417                        break 'outer;
15418                    }
15419                }
15420            }
15421        } else {
15422            for diagnostic in after.chain(before) {
15423                if diagnostic.range.start != selection.start
15424                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15425                {
15426                    found = Some(diagnostic);
15427                    break;
15428                }
15429            }
15430        }
15431        let Some(next_diagnostic) = found else {
15432            return;
15433        };
15434
15435        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15436            return;
15437        };
15438        self.change_selections(Default::default(), window, cx, |s| {
15439            s.select_ranges(vec![
15440                next_diagnostic.range.start..next_diagnostic.range.start,
15441            ])
15442        });
15443        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15444        self.refresh_edit_prediction(false, true, window, cx);
15445    }
15446
15447    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15449        let snapshot = self.snapshot(window, cx);
15450        let selection = self.selections.newest::<Point>(cx);
15451        self.go_to_hunk_before_or_after_position(
15452            &snapshot,
15453            selection.head(),
15454            Direction::Next,
15455            window,
15456            cx,
15457        );
15458    }
15459
15460    pub fn go_to_hunk_before_or_after_position(
15461        &mut self,
15462        snapshot: &EditorSnapshot,
15463        position: Point,
15464        direction: Direction,
15465        window: &mut Window,
15466        cx: &mut Context<Editor>,
15467    ) {
15468        let row = if direction == Direction::Next {
15469            self.hunk_after_position(snapshot, position)
15470                .map(|hunk| hunk.row_range.start)
15471        } else {
15472            self.hunk_before_position(snapshot, position)
15473        };
15474
15475        if let Some(row) = row {
15476            let destination = Point::new(row.0, 0);
15477            let autoscroll = Autoscroll::center();
15478
15479            self.unfold_ranges(&[destination..destination], false, false, cx);
15480            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15481                s.select_ranges([destination..destination]);
15482            });
15483        }
15484    }
15485
15486    fn hunk_after_position(
15487        &mut self,
15488        snapshot: &EditorSnapshot,
15489        position: Point,
15490    ) -> Option<MultiBufferDiffHunk> {
15491        snapshot
15492            .buffer_snapshot
15493            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15494            .find(|hunk| hunk.row_range.start.0 > position.row)
15495            .or_else(|| {
15496                snapshot
15497                    .buffer_snapshot
15498                    .diff_hunks_in_range(Point::zero()..position)
15499                    .find(|hunk| hunk.row_range.end.0 < position.row)
15500            })
15501    }
15502
15503    fn go_to_prev_hunk(
15504        &mut self,
15505        _: &GoToPreviousHunk,
15506        window: &mut Window,
15507        cx: &mut Context<Self>,
15508    ) {
15509        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15510        let snapshot = self.snapshot(window, cx);
15511        let selection = self.selections.newest::<Point>(cx);
15512        self.go_to_hunk_before_or_after_position(
15513            &snapshot,
15514            selection.head(),
15515            Direction::Prev,
15516            window,
15517            cx,
15518        );
15519    }
15520
15521    fn hunk_before_position(
15522        &mut self,
15523        snapshot: &EditorSnapshot,
15524        position: Point,
15525    ) -> Option<MultiBufferRow> {
15526        snapshot
15527            .buffer_snapshot
15528            .diff_hunk_before(position)
15529            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15530    }
15531
15532    fn go_to_next_change(
15533        &mut self,
15534        _: &GoToNextChange,
15535        window: &mut Window,
15536        cx: &mut Context<Self>,
15537    ) {
15538        if let Some(selections) = self
15539            .change_list
15540            .next_change(1, Direction::Next)
15541            .map(|s| s.to_vec())
15542        {
15543            self.change_selections(Default::default(), window, cx, |s| {
15544                let map = s.display_map();
15545                s.select_display_ranges(selections.iter().map(|a| {
15546                    let point = a.to_display_point(&map);
15547                    point..point
15548                }))
15549            })
15550        }
15551    }
15552
15553    fn go_to_previous_change(
15554        &mut self,
15555        _: &GoToPreviousChange,
15556        window: &mut Window,
15557        cx: &mut Context<Self>,
15558    ) {
15559        if let Some(selections) = self
15560            .change_list
15561            .next_change(1, Direction::Prev)
15562            .map(|s| s.to_vec())
15563        {
15564            self.change_selections(Default::default(), window, cx, |s| {
15565                let map = s.display_map();
15566                s.select_display_ranges(selections.iter().map(|a| {
15567                    let point = a.to_display_point(&map);
15568                    point..point
15569                }))
15570            })
15571        }
15572    }
15573
15574    fn go_to_line<T: 'static>(
15575        &mut self,
15576        position: Anchor,
15577        highlight_color: Option<Hsla>,
15578        window: &mut Window,
15579        cx: &mut Context<Self>,
15580    ) {
15581        let snapshot = self.snapshot(window, cx).display_snapshot;
15582        let position = position.to_point(&snapshot.buffer_snapshot);
15583        let start = snapshot
15584            .buffer_snapshot
15585            .clip_point(Point::new(position.row, 0), Bias::Left);
15586        let end = start + Point::new(1, 0);
15587        let start = snapshot.buffer_snapshot.anchor_before(start);
15588        let end = snapshot.buffer_snapshot.anchor_before(end);
15589
15590        self.highlight_rows::<T>(
15591            start..end,
15592            highlight_color
15593                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15594            Default::default(),
15595            cx,
15596        );
15597
15598        if self.buffer.read(cx).is_singleton() {
15599            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15600        }
15601    }
15602
15603    pub fn go_to_definition(
15604        &mut self,
15605        _: &GoToDefinition,
15606        window: &mut Window,
15607        cx: &mut Context<Self>,
15608    ) -> Task<Result<Navigated>> {
15609        let definition =
15610            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15611        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15612        cx.spawn_in(window, async move |editor, cx| {
15613            if definition.await? == Navigated::Yes {
15614                return Ok(Navigated::Yes);
15615            }
15616            match fallback_strategy {
15617                GoToDefinitionFallback::None => Ok(Navigated::No),
15618                GoToDefinitionFallback::FindAllReferences => {
15619                    match editor.update_in(cx, |editor, window, cx| {
15620                        editor.find_all_references(&FindAllReferences, window, cx)
15621                    })? {
15622                        Some(references) => references.await,
15623                        None => Ok(Navigated::No),
15624                    }
15625                }
15626            }
15627        })
15628    }
15629
15630    pub fn go_to_declaration(
15631        &mut self,
15632        _: &GoToDeclaration,
15633        window: &mut Window,
15634        cx: &mut Context<Self>,
15635    ) -> Task<Result<Navigated>> {
15636        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15637    }
15638
15639    pub fn go_to_declaration_split(
15640        &mut self,
15641        _: &GoToDeclaration,
15642        window: &mut Window,
15643        cx: &mut Context<Self>,
15644    ) -> Task<Result<Navigated>> {
15645        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15646    }
15647
15648    pub fn go_to_implementation(
15649        &mut self,
15650        _: &GoToImplementation,
15651        window: &mut Window,
15652        cx: &mut Context<Self>,
15653    ) -> Task<Result<Navigated>> {
15654        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15655    }
15656
15657    pub fn go_to_implementation_split(
15658        &mut self,
15659        _: &GoToImplementationSplit,
15660        window: &mut Window,
15661        cx: &mut Context<Self>,
15662    ) -> Task<Result<Navigated>> {
15663        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15664    }
15665
15666    pub fn go_to_type_definition(
15667        &mut self,
15668        _: &GoToTypeDefinition,
15669        window: &mut Window,
15670        cx: &mut Context<Self>,
15671    ) -> Task<Result<Navigated>> {
15672        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15673    }
15674
15675    pub fn go_to_definition_split(
15676        &mut self,
15677        _: &GoToDefinitionSplit,
15678        window: &mut Window,
15679        cx: &mut Context<Self>,
15680    ) -> Task<Result<Navigated>> {
15681        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15682    }
15683
15684    pub fn go_to_type_definition_split(
15685        &mut self,
15686        _: &GoToTypeDefinitionSplit,
15687        window: &mut Window,
15688        cx: &mut Context<Self>,
15689    ) -> Task<Result<Navigated>> {
15690        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15691    }
15692
15693    fn go_to_definition_of_kind(
15694        &mut self,
15695        kind: GotoDefinitionKind,
15696        split: bool,
15697        window: &mut Window,
15698        cx: &mut Context<Self>,
15699    ) -> Task<Result<Navigated>> {
15700        let Some(provider) = self.semantics_provider.clone() else {
15701            return Task::ready(Ok(Navigated::No));
15702        };
15703        let head = self.selections.newest::<usize>(cx).head();
15704        let buffer = self.buffer.read(cx);
15705        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15706            return Task::ready(Ok(Navigated::No));
15707        };
15708        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15709            return Task::ready(Ok(Navigated::No));
15710        };
15711
15712        cx.spawn_in(window, async move |editor, cx| {
15713            let Some(definitions) = definitions.await? else {
15714                return Ok(Navigated::No);
15715            };
15716            let navigated = editor
15717                .update_in(cx, |editor, window, cx| {
15718                    editor.navigate_to_hover_links(
15719                        Some(kind),
15720                        definitions
15721                            .into_iter()
15722                            .filter(|location| {
15723                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15724                            })
15725                            .map(HoverLink::Text)
15726                            .collect::<Vec<_>>(),
15727                        split,
15728                        window,
15729                        cx,
15730                    )
15731                })?
15732                .await?;
15733            anyhow::Ok(navigated)
15734        })
15735    }
15736
15737    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15738        let selection = self.selections.newest_anchor();
15739        let head = selection.head();
15740        let tail = selection.tail();
15741
15742        let Some((buffer, start_position)) =
15743            self.buffer.read(cx).text_anchor_for_position(head, cx)
15744        else {
15745            return;
15746        };
15747
15748        let end_position = if head != tail {
15749            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15750                return;
15751            };
15752            Some(pos)
15753        } else {
15754            None
15755        };
15756
15757        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15758            let url = if let Some(end_pos) = end_position {
15759                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15760            } else {
15761                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15762            };
15763
15764            if let Some(url) = url {
15765                editor.update(cx, |_, cx| {
15766                    cx.open_url(&url);
15767                })
15768            } else {
15769                Ok(())
15770            }
15771        });
15772
15773        url_finder.detach();
15774    }
15775
15776    pub fn open_selected_filename(
15777        &mut self,
15778        _: &OpenSelectedFilename,
15779        window: &mut Window,
15780        cx: &mut Context<Self>,
15781    ) {
15782        let Some(workspace) = self.workspace() else {
15783            return;
15784        };
15785
15786        let position = self.selections.newest_anchor().head();
15787
15788        let Some((buffer, buffer_position)) =
15789            self.buffer.read(cx).text_anchor_for_position(position, cx)
15790        else {
15791            return;
15792        };
15793
15794        let project = self.project.clone();
15795
15796        cx.spawn_in(window, async move |_, cx| {
15797            let result = find_file(&buffer, project, buffer_position, cx).await;
15798
15799            if let Some((_, path)) = result {
15800                workspace
15801                    .update_in(cx, |workspace, window, cx| {
15802                        workspace.open_resolved_path(path, window, cx)
15803                    })?
15804                    .await?;
15805            }
15806            anyhow::Ok(())
15807        })
15808        .detach();
15809    }
15810
15811    pub(crate) fn navigate_to_hover_links(
15812        &mut self,
15813        kind: Option<GotoDefinitionKind>,
15814        definitions: Vec<HoverLink>,
15815        split: bool,
15816        window: &mut Window,
15817        cx: &mut Context<Editor>,
15818    ) -> Task<Result<Navigated>> {
15819        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15820        let mut first_url_or_file = None;
15821        let definitions: Vec<_> = definitions
15822            .into_iter()
15823            .filter_map(|def| match def {
15824                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15825                HoverLink::InlayHint(lsp_location, server_id) => {
15826                    let computation =
15827                        self.compute_target_location(lsp_location, server_id, window, cx);
15828                    Some(cx.background_spawn(computation))
15829                }
15830                HoverLink::Url(url) => {
15831                    first_url_or_file = Some(Either::Left(url));
15832                    None
15833                }
15834                HoverLink::File(path) => {
15835                    first_url_or_file = Some(Either::Right(path));
15836                    None
15837                }
15838            })
15839            .collect();
15840
15841        let workspace = self.workspace();
15842
15843        cx.spawn_in(window, async move |editor, acx| {
15844            let mut locations: Vec<Location> = future::join_all(definitions)
15845                .await
15846                .into_iter()
15847                .filter_map(|location| location.transpose())
15848                .collect::<Result<_>>()
15849                .context("location tasks")?;
15850
15851            if locations.len() > 1 {
15852                let Some(workspace) = workspace else {
15853                    return Ok(Navigated::No);
15854                };
15855
15856                let tab_kind = match kind {
15857                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15858                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15859                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15860                    Some(GotoDefinitionKind::Type) => "Types",
15861                };
15862                let title = editor
15863                    .update_in(acx, |_, _, cx| {
15864                        let target = locations
15865                            .iter()
15866                            .map(|location| {
15867                                location
15868                                    .buffer
15869                                    .read(cx)
15870                                    .text_for_range(location.range.clone())
15871                                    .collect::<String>()
15872                            })
15873                            .filter(|text| !text.contains('\n'))
15874                            .unique()
15875                            .take(3)
15876                            .join(", ");
15877                        if target.is_empty() {
15878                            tab_kind.to_owned()
15879                        } else {
15880                            format!("{tab_kind} for {target}")
15881                        }
15882                    })
15883                    .context("buffer title")?;
15884
15885                let opened = workspace
15886                    .update_in(acx, |workspace, window, cx| {
15887                        Self::open_locations_in_multibuffer(
15888                            workspace,
15889                            locations,
15890                            title,
15891                            split,
15892                            MultibufferSelectionMode::First,
15893                            window,
15894                            cx,
15895                        )
15896                    })
15897                    .is_ok();
15898
15899                anyhow::Ok(Navigated::from_bool(opened))
15900            } else if locations.is_empty() {
15901                // If there is one definition, just open it directly
15902                match first_url_or_file {
15903                    Some(Either::Left(url)) => {
15904                        acx.update(|_, cx| cx.open_url(&url))?;
15905                        Ok(Navigated::Yes)
15906                    }
15907                    Some(Either::Right(path)) => {
15908                        let Some(workspace) = workspace else {
15909                            return Ok(Navigated::No);
15910                        };
15911
15912                        workspace
15913                            .update_in(acx, |workspace, window, cx| {
15914                                workspace.open_resolved_path(path, window, cx)
15915                            })?
15916                            .await?;
15917                        Ok(Navigated::Yes)
15918                    }
15919                    None => Ok(Navigated::No),
15920                }
15921            } else {
15922                let Some(workspace) = workspace else {
15923                    return Ok(Navigated::No);
15924                };
15925
15926                let target = locations.pop().unwrap();
15927                editor.update_in(acx, |editor, window, cx| {
15928                    let pane = workspace.read(cx).active_pane().clone();
15929
15930                    let range = target.range.to_point(target.buffer.read(cx));
15931                    let range = editor.range_for_match(&range);
15932                    let range = collapse_multiline_range(range);
15933
15934                    if !split
15935                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15936                    {
15937                        editor.go_to_singleton_buffer_range(range, window, cx);
15938                    } else {
15939                        window.defer(cx, move |window, cx| {
15940                            let target_editor: Entity<Self> =
15941                                workspace.update(cx, |workspace, cx| {
15942                                    let pane = if split {
15943                                        workspace.adjacent_pane(window, cx)
15944                                    } else {
15945                                        workspace.active_pane().clone()
15946                                    };
15947
15948                                    workspace.open_project_item(
15949                                        pane,
15950                                        target.buffer.clone(),
15951                                        true,
15952                                        true,
15953                                        window,
15954                                        cx,
15955                                    )
15956                                });
15957                            target_editor.update(cx, |target_editor, cx| {
15958                                // When selecting a definition in a different buffer, disable the nav history
15959                                // to avoid creating a history entry at the previous cursor location.
15960                                pane.update(cx, |pane, _| pane.disable_history());
15961                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15962                                pane.update(cx, |pane, _| pane.enable_history());
15963                            });
15964                        });
15965                    }
15966                    Navigated::Yes
15967                })
15968            }
15969        })
15970    }
15971
15972    fn compute_target_location(
15973        &self,
15974        lsp_location: lsp::Location,
15975        server_id: LanguageServerId,
15976        window: &mut Window,
15977        cx: &mut Context<Self>,
15978    ) -> Task<anyhow::Result<Option<Location>>> {
15979        let Some(project) = self.project.clone() else {
15980            return Task::ready(Ok(None));
15981        };
15982
15983        cx.spawn_in(window, async move |editor, cx| {
15984            let location_task = editor.update(cx, |_, cx| {
15985                project.update(cx, |project, cx| {
15986                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
15987                })
15988            })?;
15989            let location = Some({
15990                let target_buffer_handle = location_task.await.context("open local buffer")?;
15991                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15992                    let target_start = target_buffer
15993                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15994                    let target_end = target_buffer
15995                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15996                    target_buffer.anchor_after(target_start)
15997                        ..target_buffer.anchor_before(target_end)
15998                })?;
15999                Location {
16000                    buffer: target_buffer_handle,
16001                    range,
16002                }
16003            });
16004            Ok(location)
16005        })
16006    }
16007
16008    pub fn find_all_references(
16009        &mut self,
16010        _: &FindAllReferences,
16011        window: &mut Window,
16012        cx: &mut Context<Self>,
16013    ) -> Option<Task<Result<Navigated>>> {
16014        let selection = self.selections.newest::<usize>(cx);
16015        let multi_buffer = self.buffer.read(cx);
16016        let head = selection.head();
16017
16018        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16019        let head_anchor = multi_buffer_snapshot.anchor_at(
16020            head,
16021            if head < selection.tail() {
16022                Bias::Right
16023            } else {
16024                Bias::Left
16025            },
16026        );
16027
16028        match self
16029            .find_all_references_task_sources
16030            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16031        {
16032            Ok(_) => {
16033                log::info!(
16034                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16035                );
16036                return None;
16037            }
16038            Err(i) => {
16039                self.find_all_references_task_sources.insert(i, head_anchor);
16040            }
16041        }
16042
16043        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16044        let workspace = self.workspace()?;
16045        let project = workspace.read(cx).project().clone();
16046        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16047        Some(cx.spawn_in(window, async move |editor, cx| {
16048            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16049                if let Ok(i) = editor
16050                    .find_all_references_task_sources
16051                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16052                {
16053                    editor.find_all_references_task_sources.remove(i);
16054                }
16055            });
16056
16057            let Some(locations) = references.await? else {
16058                return anyhow::Ok(Navigated::No);
16059            };
16060            if locations.is_empty() {
16061                return anyhow::Ok(Navigated::No);
16062            }
16063
16064            workspace.update_in(cx, |workspace, window, cx| {
16065                let target = locations
16066                    .iter()
16067                    .map(|location| {
16068                        location
16069                            .buffer
16070                            .read(cx)
16071                            .text_for_range(location.range.clone())
16072                            .collect::<String>()
16073                    })
16074                    .filter(|text| !text.contains('\n'))
16075                    .unique()
16076                    .take(3)
16077                    .join(", ");
16078                let title = if target.is_empty() {
16079                    "References".to_owned()
16080                } else {
16081                    format!("References to {target}")
16082                };
16083                Self::open_locations_in_multibuffer(
16084                    workspace,
16085                    locations,
16086                    title,
16087                    false,
16088                    MultibufferSelectionMode::First,
16089                    window,
16090                    cx,
16091                );
16092                Navigated::Yes
16093            })
16094        }))
16095    }
16096
16097    /// Opens a multibuffer with the given project locations in it
16098    pub fn open_locations_in_multibuffer(
16099        workspace: &mut Workspace,
16100        mut locations: Vec<Location>,
16101        title: String,
16102        split: bool,
16103        multibuffer_selection_mode: MultibufferSelectionMode,
16104        window: &mut Window,
16105        cx: &mut Context<Workspace>,
16106    ) {
16107        if locations.is_empty() {
16108            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16109            return;
16110        }
16111
16112        // If there are multiple definitions, open them in a multibuffer
16113        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16114        let mut locations = locations.into_iter().peekable();
16115        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16116        let capability = workspace.project().read(cx).capability();
16117
16118        let excerpt_buffer = cx.new(|cx| {
16119            let mut multibuffer = MultiBuffer::new(capability);
16120            while let Some(location) = locations.next() {
16121                let buffer = location.buffer.read(cx);
16122                let mut ranges_for_buffer = Vec::new();
16123                let range = location.range.to_point(buffer);
16124                ranges_for_buffer.push(range.clone());
16125
16126                while let Some(next_location) = locations.peek() {
16127                    if next_location.buffer == location.buffer {
16128                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16129                        locations.next();
16130                    } else {
16131                        break;
16132                    }
16133                }
16134
16135                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16136                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16137                    PathKey::for_buffer(&location.buffer, cx),
16138                    location.buffer.clone(),
16139                    ranges_for_buffer,
16140                    DEFAULT_MULTIBUFFER_CONTEXT,
16141                    cx,
16142                );
16143                ranges.extend(new_ranges)
16144            }
16145
16146            multibuffer.with_title(title)
16147        });
16148
16149        let editor = cx.new(|cx| {
16150            Editor::for_multibuffer(
16151                excerpt_buffer,
16152                Some(workspace.project().clone()),
16153                window,
16154                cx,
16155            )
16156        });
16157        editor.update(cx, |editor, cx| {
16158            match multibuffer_selection_mode {
16159                MultibufferSelectionMode::First => {
16160                    if let Some(first_range) = ranges.first() {
16161                        editor.change_selections(
16162                            SelectionEffects::no_scroll(),
16163                            window,
16164                            cx,
16165                            |selections| {
16166                                selections.clear_disjoint();
16167                                selections
16168                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16169                            },
16170                        );
16171                    }
16172                    editor.highlight_background::<Self>(
16173                        &ranges,
16174                        |theme| theme.colors().editor_highlighted_line_background,
16175                        cx,
16176                    );
16177                }
16178                MultibufferSelectionMode::All => {
16179                    editor.change_selections(
16180                        SelectionEffects::no_scroll(),
16181                        window,
16182                        cx,
16183                        |selections| {
16184                            selections.clear_disjoint();
16185                            selections.select_anchor_ranges(ranges);
16186                        },
16187                    );
16188                }
16189            }
16190            editor.register_buffers_with_language_servers(cx);
16191        });
16192
16193        let item = Box::new(editor);
16194        let item_id = item.item_id();
16195
16196        if split {
16197            workspace.split_item(SplitDirection::Right, item, window, cx);
16198        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16199            let (preview_item_id, preview_item_idx) =
16200                workspace.active_pane().read_with(cx, |pane, _| {
16201                    (pane.preview_item_id(), pane.preview_item_idx())
16202                });
16203
16204            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16205
16206            if let Some(preview_item_id) = preview_item_id {
16207                workspace.active_pane().update(cx, |pane, cx| {
16208                    pane.remove_item(preview_item_id, false, false, window, cx);
16209                });
16210            }
16211        } else {
16212            workspace.add_item_to_active_pane(item, None, true, window, cx);
16213        }
16214        workspace.active_pane().update(cx, |pane, cx| {
16215            pane.set_preview_item_id(Some(item_id), cx);
16216        });
16217    }
16218
16219    pub fn rename(
16220        &mut self,
16221        _: &Rename,
16222        window: &mut Window,
16223        cx: &mut Context<Self>,
16224    ) -> Option<Task<Result<()>>> {
16225        use language::ToOffset as _;
16226
16227        let provider = self.semantics_provider.clone()?;
16228        let selection = self.selections.newest_anchor().clone();
16229        let (cursor_buffer, cursor_buffer_position) = self
16230            .buffer
16231            .read(cx)
16232            .text_anchor_for_position(selection.head(), cx)?;
16233        let (tail_buffer, cursor_buffer_position_end) = self
16234            .buffer
16235            .read(cx)
16236            .text_anchor_for_position(selection.tail(), cx)?;
16237        if tail_buffer != cursor_buffer {
16238            return None;
16239        }
16240
16241        let snapshot = cursor_buffer.read(cx).snapshot();
16242        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16243        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16244        let prepare_rename = provider
16245            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16246            .unwrap_or_else(|| Task::ready(Ok(None)));
16247        drop(snapshot);
16248
16249        Some(cx.spawn_in(window, async move |this, cx| {
16250            let rename_range = if let Some(range) = prepare_rename.await? {
16251                Some(range)
16252            } else {
16253                this.update(cx, |this, cx| {
16254                    let buffer = this.buffer.read(cx).snapshot(cx);
16255                    let mut buffer_highlights = this
16256                        .document_highlights_for_position(selection.head(), &buffer)
16257                        .filter(|highlight| {
16258                            highlight.start.excerpt_id == selection.head().excerpt_id
16259                                && highlight.end.excerpt_id == selection.head().excerpt_id
16260                        });
16261                    buffer_highlights
16262                        .next()
16263                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16264                })?
16265            };
16266            if let Some(rename_range) = rename_range {
16267                this.update_in(cx, |this, window, cx| {
16268                    let snapshot = cursor_buffer.read(cx).snapshot();
16269                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16270                    let cursor_offset_in_rename_range =
16271                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16272                    let cursor_offset_in_rename_range_end =
16273                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16274
16275                    this.take_rename(false, window, cx);
16276                    let buffer = this.buffer.read(cx).read(cx);
16277                    let cursor_offset = selection.head().to_offset(&buffer);
16278                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16279                    let rename_end = rename_start + rename_buffer_range.len();
16280                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16281                    let mut old_highlight_id = None;
16282                    let old_name: Arc<str> = buffer
16283                        .chunks(rename_start..rename_end, true)
16284                        .map(|chunk| {
16285                            if old_highlight_id.is_none() {
16286                                old_highlight_id = chunk.syntax_highlight_id;
16287                            }
16288                            chunk.text
16289                        })
16290                        .collect::<String>()
16291                        .into();
16292
16293                    drop(buffer);
16294
16295                    // Position the selection in the rename editor so that it matches the current selection.
16296                    this.show_local_selections = false;
16297                    let rename_editor = cx.new(|cx| {
16298                        let mut editor = Editor::single_line(window, cx);
16299                        editor.buffer.update(cx, |buffer, cx| {
16300                            buffer.edit([(0..0, old_name.clone())], None, cx)
16301                        });
16302                        let rename_selection_range = match cursor_offset_in_rename_range
16303                            .cmp(&cursor_offset_in_rename_range_end)
16304                        {
16305                            Ordering::Equal => {
16306                                editor.select_all(&SelectAll, window, cx);
16307                                return editor;
16308                            }
16309                            Ordering::Less => {
16310                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16311                            }
16312                            Ordering::Greater => {
16313                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16314                            }
16315                        };
16316                        if rename_selection_range.end > old_name.len() {
16317                            editor.select_all(&SelectAll, window, cx);
16318                        } else {
16319                            editor.change_selections(Default::default(), window, cx, |s| {
16320                                s.select_ranges([rename_selection_range]);
16321                            });
16322                        }
16323                        editor
16324                    });
16325                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16326                        if e == &EditorEvent::Focused {
16327                            cx.emit(EditorEvent::FocusedIn)
16328                        }
16329                    })
16330                    .detach();
16331
16332                    let write_highlights =
16333                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16334                    let read_highlights =
16335                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16336                    let ranges = write_highlights
16337                        .iter()
16338                        .flat_map(|(_, ranges)| ranges.iter())
16339                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16340                        .cloned()
16341                        .collect();
16342
16343                    this.highlight_text::<Rename>(
16344                        ranges,
16345                        HighlightStyle {
16346                            fade_out: Some(0.6),
16347                            ..Default::default()
16348                        },
16349                        cx,
16350                    );
16351                    let rename_focus_handle = rename_editor.focus_handle(cx);
16352                    window.focus(&rename_focus_handle);
16353                    let block_id = this.insert_blocks(
16354                        [BlockProperties {
16355                            style: BlockStyle::Flex,
16356                            placement: BlockPlacement::Below(range.start),
16357                            height: Some(1),
16358                            render: Arc::new({
16359                                let rename_editor = rename_editor.clone();
16360                                move |cx: &mut BlockContext| {
16361                                    let mut text_style = cx.editor_style.text.clone();
16362                                    if let Some(highlight_style) = old_highlight_id
16363                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16364                                    {
16365                                        text_style = text_style.highlight(highlight_style);
16366                                    }
16367                                    div()
16368                                        .block_mouse_except_scroll()
16369                                        .pl(cx.anchor_x)
16370                                        .child(EditorElement::new(
16371                                            &rename_editor,
16372                                            EditorStyle {
16373                                                background: cx.theme().system().transparent,
16374                                                local_player: cx.editor_style.local_player,
16375                                                text: text_style,
16376                                                scrollbar_width: cx.editor_style.scrollbar_width,
16377                                                syntax: cx.editor_style.syntax.clone(),
16378                                                status: cx.editor_style.status.clone(),
16379                                                inlay_hints_style: HighlightStyle {
16380                                                    font_weight: Some(FontWeight::BOLD),
16381                                                    ..make_inlay_hints_style(cx.app)
16382                                                },
16383                                                edit_prediction_styles: make_suggestion_styles(
16384                                                    cx.app,
16385                                                ),
16386                                                ..EditorStyle::default()
16387                                            },
16388                                        ))
16389                                        .into_any_element()
16390                                }
16391                            }),
16392                            priority: 0,
16393                        }],
16394                        Some(Autoscroll::fit()),
16395                        cx,
16396                    )[0];
16397                    this.pending_rename = Some(RenameState {
16398                        range,
16399                        old_name,
16400                        editor: rename_editor,
16401                        block_id,
16402                    });
16403                })?;
16404            }
16405
16406            Ok(())
16407        }))
16408    }
16409
16410    pub fn confirm_rename(
16411        &mut self,
16412        _: &ConfirmRename,
16413        window: &mut Window,
16414        cx: &mut Context<Self>,
16415    ) -> Option<Task<Result<()>>> {
16416        let rename = self.take_rename(false, window, cx)?;
16417        let workspace = self.workspace()?.downgrade();
16418        let (buffer, start) = self
16419            .buffer
16420            .read(cx)
16421            .text_anchor_for_position(rename.range.start, cx)?;
16422        let (end_buffer, _) = self
16423            .buffer
16424            .read(cx)
16425            .text_anchor_for_position(rename.range.end, cx)?;
16426        if buffer != end_buffer {
16427            return None;
16428        }
16429
16430        let old_name = rename.old_name;
16431        let new_name = rename.editor.read(cx).text(cx);
16432
16433        let rename = self.semantics_provider.as_ref()?.perform_rename(
16434            &buffer,
16435            start,
16436            new_name.clone(),
16437            cx,
16438        )?;
16439
16440        Some(cx.spawn_in(window, async move |editor, cx| {
16441            let project_transaction = rename.await?;
16442            Self::open_project_transaction(
16443                &editor,
16444                workspace,
16445                project_transaction,
16446                format!("Rename: {}{}", old_name, new_name),
16447                cx,
16448            )
16449            .await?;
16450
16451            editor.update(cx, |editor, cx| {
16452                editor.refresh_document_highlights(cx);
16453            })?;
16454            Ok(())
16455        }))
16456    }
16457
16458    fn take_rename(
16459        &mut self,
16460        moving_cursor: bool,
16461        window: &mut Window,
16462        cx: &mut Context<Self>,
16463    ) -> Option<RenameState> {
16464        let rename = self.pending_rename.take()?;
16465        if rename.editor.focus_handle(cx).is_focused(window) {
16466            window.focus(&self.focus_handle);
16467        }
16468
16469        self.remove_blocks(
16470            [rename.block_id].into_iter().collect(),
16471            Some(Autoscroll::fit()),
16472            cx,
16473        );
16474        self.clear_highlights::<Rename>(cx);
16475        self.show_local_selections = true;
16476
16477        if moving_cursor {
16478            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16479                editor.selections.newest::<usize>(cx).head()
16480            });
16481
16482            // Update the selection to match the position of the selection inside
16483            // the rename editor.
16484            let snapshot = self.buffer.read(cx).read(cx);
16485            let rename_range = rename.range.to_offset(&snapshot);
16486            let cursor_in_editor = snapshot
16487                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16488                .min(rename_range.end);
16489            drop(snapshot);
16490
16491            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16492                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16493            });
16494        } else {
16495            self.refresh_document_highlights(cx);
16496        }
16497
16498        Some(rename)
16499    }
16500
16501    pub fn pending_rename(&self) -> Option<&RenameState> {
16502        self.pending_rename.as_ref()
16503    }
16504
16505    fn format(
16506        &mut self,
16507        _: &Format,
16508        window: &mut Window,
16509        cx: &mut Context<Self>,
16510    ) -> Option<Task<Result<()>>> {
16511        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16512
16513        let project = match &self.project {
16514            Some(project) => project.clone(),
16515            None => return None,
16516        };
16517
16518        Some(self.perform_format(
16519            project,
16520            FormatTrigger::Manual,
16521            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16522            window,
16523            cx,
16524        ))
16525    }
16526
16527    fn format_selections(
16528        &mut self,
16529        _: &FormatSelections,
16530        window: &mut Window,
16531        cx: &mut Context<Self>,
16532    ) -> Option<Task<Result<()>>> {
16533        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16534
16535        let project = match &self.project {
16536            Some(project) => project.clone(),
16537            None => return None,
16538        };
16539
16540        let ranges = self
16541            .selections
16542            .all_adjusted(cx)
16543            .into_iter()
16544            .map(|selection| selection.range())
16545            .collect_vec();
16546
16547        Some(self.perform_format(
16548            project,
16549            FormatTrigger::Manual,
16550            FormatTarget::Ranges(ranges),
16551            window,
16552            cx,
16553        ))
16554    }
16555
16556    fn perform_format(
16557        &mut self,
16558        project: Entity<Project>,
16559        trigger: FormatTrigger,
16560        target: FormatTarget,
16561        window: &mut Window,
16562        cx: &mut Context<Self>,
16563    ) -> Task<Result<()>> {
16564        let buffer = self.buffer.clone();
16565        let (buffers, target) = match target {
16566            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16567            FormatTarget::Ranges(selection_ranges) => {
16568                let multi_buffer = buffer.read(cx);
16569                let snapshot = multi_buffer.read(cx);
16570                let mut buffers = HashSet::default();
16571                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16572                    BTreeMap::new();
16573                for selection_range in selection_ranges {
16574                    for (buffer, buffer_range, _) in
16575                        snapshot.range_to_buffer_ranges(selection_range)
16576                    {
16577                        let buffer_id = buffer.remote_id();
16578                        let start = buffer.anchor_before(buffer_range.start);
16579                        let end = buffer.anchor_after(buffer_range.end);
16580                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16581                        buffer_id_to_ranges
16582                            .entry(buffer_id)
16583                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16584                            .or_insert_with(|| vec![start..end]);
16585                    }
16586                }
16587                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16588            }
16589        };
16590
16591        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16592        let selections_prev = transaction_id_prev
16593            .and_then(|transaction_id_prev| {
16594                // default to selections as they were after the last edit, if we have them,
16595                // instead of how they are now.
16596                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16597                // will take you back to where you made the last edit, instead of staying where you scrolled
16598                self.selection_history
16599                    .transaction(transaction_id_prev)
16600                    .map(|t| t.0.clone())
16601            })
16602            .unwrap_or_else(|| self.selections.disjoint_anchors());
16603
16604        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16605        let format = project.update(cx, |project, cx| {
16606            project.format(buffers, target, true, trigger, cx)
16607        });
16608
16609        cx.spawn_in(window, async move |editor, cx| {
16610            let transaction = futures::select_biased! {
16611                transaction = format.log_err().fuse() => transaction,
16612                () = timeout => {
16613                    log::warn!("timed out waiting for formatting");
16614                    None
16615                }
16616            };
16617
16618            buffer
16619                .update(cx, |buffer, cx| {
16620                    if let Some(transaction) = transaction
16621                        && !buffer.is_singleton()
16622                    {
16623                        buffer.push_transaction(&transaction.0, cx);
16624                    }
16625                    cx.notify();
16626                })
16627                .ok();
16628
16629            if let Some(transaction_id_now) =
16630                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16631            {
16632                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16633                if has_new_transaction {
16634                    _ = editor.update(cx, |editor, _| {
16635                        editor
16636                            .selection_history
16637                            .insert_transaction(transaction_id_now, selections_prev);
16638                    });
16639                }
16640            }
16641
16642            Ok(())
16643        })
16644    }
16645
16646    fn organize_imports(
16647        &mut self,
16648        _: &OrganizeImports,
16649        window: &mut Window,
16650        cx: &mut Context<Self>,
16651    ) -> Option<Task<Result<()>>> {
16652        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16653        let project = match &self.project {
16654            Some(project) => project.clone(),
16655            None => return None,
16656        };
16657        Some(self.perform_code_action_kind(
16658            project,
16659            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16660            window,
16661            cx,
16662        ))
16663    }
16664
16665    fn perform_code_action_kind(
16666        &mut self,
16667        project: Entity<Project>,
16668        kind: CodeActionKind,
16669        window: &mut Window,
16670        cx: &mut Context<Self>,
16671    ) -> Task<Result<()>> {
16672        let buffer = self.buffer.clone();
16673        let buffers = buffer.read(cx).all_buffers();
16674        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16675        let apply_action = project.update(cx, |project, cx| {
16676            project.apply_code_action_kind(buffers, kind, true, cx)
16677        });
16678        cx.spawn_in(window, async move |_, cx| {
16679            let transaction = futures::select_biased! {
16680                () = timeout => {
16681                    log::warn!("timed out waiting for executing code action");
16682                    None
16683                }
16684                transaction = apply_action.log_err().fuse() => transaction,
16685            };
16686            buffer
16687                .update(cx, |buffer, cx| {
16688                    // check if we need this
16689                    if let Some(transaction) = transaction
16690                        && !buffer.is_singleton()
16691                    {
16692                        buffer.push_transaction(&transaction.0, cx);
16693                    }
16694                    cx.notify();
16695                })
16696                .ok();
16697            Ok(())
16698        })
16699    }
16700
16701    pub fn restart_language_server(
16702        &mut self,
16703        _: &RestartLanguageServer,
16704        _: &mut Window,
16705        cx: &mut Context<Self>,
16706    ) {
16707        if let Some(project) = self.project.clone() {
16708            self.buffer.update(cx, |multi_buffer, cx| {
16709                project.update(cx, |project, cx| {
16710                    project.restart_language_servers_for_buffers(
16711                        multi_buffer.all_buffers().into_iter().collect(),
16712                        HashSet::default(),
16713                        cx,
16714                    );
16715                });
16716            })
16717        }
16718    }
16719
16720    pub fn stop_language_server(
16721        &mut self,
16722        _: &StopLanguageServer,
16723        _: &mut Window,
16724        cx: &mut Context<Self>,
16725    ) {
16726        if let Some(project) = self.project.clone() {
16727            self.buffer.update(cx, |multi_buffer, cx| {
16728                project.update(cx, |project, cx| {
16729                    project.stop_language_servers_for_buffers(
16730                        multi_buffer.all_buffers().into_iter().collect(),
16731                        HashSet::default(),
16732                        cx,
16733                    );
16734                    cx.emit(project::Event::RefreshInlayHints);
16735                });
16736            });
16737        }
16738    }
16739
16740    fn cancel_language_server_work(
16741        workspace: &mut Workspace,
16742        _: &actions::CancelLanguageServerWork,
16743        _: &mut Window,
16744        cx: &mut Context<Workspace>,
16745    ) {
16746        let project = workspace.project();
16747        let buffers = workspace
16748            .active_item(cx)
16749            .and_then(|item| item.act_as::<Editor>(cx))
16750            .map_or(HashSet::default(), |editor| {
16751                editor.read(cx).buffer.read(cx).all_buffers()
16752            });
16753        project.update(cx, |project, cx| {
16754            project.cancel_language_server_work_for_buffers(buffers, cx);
16755        });
16756    }
16757
16758    fn show_character_palette(
16759        &mut self,
16760        _: &ShowCharacterPalette,
16761        window: &mut Window,
16762        _: &mut Context<Self>,
16763    ) {
16764        window.show_character_palette();
16765    }
16766
16767    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16768        if !self.diagnostics_enabled() {
16769            return;
16770        }
16771
16772        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16773            let buffer = self.buffer.read(cx).snapshot(cx);
16774            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16775            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16776            let is_valid = buffer
16777                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16778                .any(|entry| {
16779                    entry.diagnostic.is_primary
16780                        && !entry.range.is_empty()
16781                        && entry.range.start == primary_range_start
16782                        && entry.diagnostic.message == active_diagnostics.active_message
16783                });
16784
16785            if !is_valid {
16786                self.dismiss_diagnostics(cx);
16787            }
16788        }
16789    }
16790
16791    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16792        match &self.active_diagnostics {
16793            ActiveDiagnostic::Group(group) => Some(group),
16794            _ => None,
16795        }
16796    }
16797
16798    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16799        if !self.diagnostics_enabled() {
16800            return;
16801        }
16802        self.dismiss_diagnostics(cx);
16803        self.active_diagnostics = ActiveDiagnostic::All;
16804    }
16805
16806    fn activate_diagnostics(
16807        &mut self,
16808        buffer_id: BufferId,
16809        diagnostic: DiagnosticEntry<usize>,
16810        window: &mut Window,
16811        cx: &mut Context<Self>,
16812    ) {
16813        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16814            return;
16815        }
16816        self.dismiss_diagnostics(cx);
16817        let snapshot = self.snapshot(window, cx);
16818        let buffer = self.buffer.read(cx).snapshot(cx);
16819        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16820            return;
16821        };
16822
16823        let diagnostic_group = buffer
16824            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16825            .collect::<Vec<_>>();
16826
16827        let blocks =
16828            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16829
16830        let blocks = self.display_map.update(cx, |display_map, cx| {
16831            display_map.insert_blocks(blocks, cx).into_iter().collect()
16832        });
16833        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16834            active_range: buffer.anchor_before(diagnostic.range.start)
16835                ..buffer.anchor_after(diagnostic.range.end),
16836            active_message: diagnostic.diagnostic.message.clone(),
16837            group_id: diagnostic.diagnostic.group_id,
16838            blocks,
16839        });
16840        cx.notify();
16841    }
16842
16843    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16844        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16845            return;
16846        };
16847
16848        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16849        if let ActiveDiagnostic::Group(group) = prev {
16850            self.display_map.update(cx, |display_map, cx| {
16851                display_map.remove_blocks(group.blocks, cx);
16852            });
16853            cx.notify();
16854        }
16855    }
16856
16857    /// Disable inline diagnostics rendering for this editor.
16858    pub fn disable_inline_diagnostics(&mut self) {
16859        self.inline_diagnostics_enabled = false;
16860        self.inline_diagnostics_update = Task::ready(());
16861        self.inline_diagnostics.clear();
16862    }
16863
16864    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16865        self.diagnostics_enabled = false;
16866        self.dismiss_diagnostics(cx);
16867        self.inline_diagnostics_update = Task::ready(());
16868        self.inline_diagnostics.clear();
16869    }
16870
16871    pub fn diagnostics_enabled(&self) -> bool {
16872        self.diagnostics_enabled && self.mode.is_full()
16873    }
16874
16875    pub fn inline_diagnostics_enabled(&self) -> bool {
16876        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16877    }
16878
16879    pub fn show_inline_diagnostics(&self) -> bool {
16880        self.show_inline_diagnostics
16881    }
16882
16883    pub fn toggle_inline_diagnostics(
16884        &mut self,
16885        _: &ToggleInlineDiagnostics,
16886        window: &mut Window,
16887        cx: &mut Context<Editor>,
16888    ) {
16889        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16890        self.refresh_inline_diagnostics(false, window, cx);
16891    }
16892
16893    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16894        self.diagnostics_max_severity = severity;
16895        self.display_map.update(cx, |display_map, _| {
16896            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16897        });
16898    }
16899
16900    pub fn toggle_diagnostics(
16901        &mut self,
16902        _: &ToggleDiagnostics,
16903        window: &mut Window,
16904        cx: &mut Context<Editor>,
16905    ) {
16906        if !self.diagnostics_enabled() {
16907            return;
16908        }
16909
16910        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16911            EditorSettings::get_global(cx)
16912                .diagnostics_max_severity
16913                .filter(|severity| severity != &DiagnosticSeverity::Off)
16914                .unwrap_or(DiagnosticSeverity::Hint)
16915        } else {
16916            DiagnosticSeverity::Off
16917        };
16918        self.set_max_diagnostics_severity(new_severity, cx);
16919        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16920            self.active_diagnostics = ActiveDiagnostic::None;
16921            self.inline_diagnostics_update = Task::ready(());
16922            self.inline_diagnostics.clear();
16923        } else {
16924            self.refresh_inline_diagnostics(false, window, cx);
16925        }
16926
16927        cx.notify();
16928    }
16929
16930    pub fn toggle_minimap(
16931        &mut self,
16932        _: &ToggleMinimap,
16933        window: &mut Window,
16934        cx: &mut Context<Editor>,
16935    ) {
16936        if self.supports_minimap(cx) {
16937            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16938        }
16939    }
16940
16941    fn refresh_inline_diagnostics(
16942        &mut self,
16943        debounce: bool,
16944        window: &mut Window,
16945        cx: &mut Context<Self>,
16946    ) {
16947        let max_severity = ProjectSettings::get_global(cx)
16948            .diagnostics
16949            .inline
16950            .max_severity
16951            .unwrap_or(self.diagnostics_max_severity);
16952
16953        if !self.inline_diagnostics_enabled()
16954            || !self.show_inline_diagnostics
16955            || max_severity == DiagnosticSeverity::Off
16956        {
16957            self.inline_diagnostics_update = Task::ready(());
16958            self.inline_diagnostics.clear();
16959            return;
16960        }
16961
16962        let debounce_ms = ProjectSettings::get_global(cx)
16963            .diagnostics
16964            .inline
16965            .update_debounce_ms;
16966        let debounce = if debounce && debounce_ms > 0 {
16967            Some(Duration::from_millis(debounce_ms))
16968        } else {
16969            None
16970        };
16971        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16972            if let Some(debounce) = debounce {
16973                cx.background_executor().timer(debounce).await;
16974            }
16975            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16976                editor
16977                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16978                    .ok()
16979            }) else {
16980                return;
16981            };
16982
16983            let new_inline_diagnostics = cx
16984                .background_spawn(async move {
16985                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16986                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16987                        let message = diagnostic_entry
16988                            .diagnostic
16989                            .message
16990                            .split_once('\n')
16991                            .map(|(line, _)| line)
16992                            .map(SharedString::new)
16993                            .unwrap_or_else(|| {
16994                                SharedString::from(diagnostic_entry.diagnostic.message)
16995                            });
16996                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16997                        let (Ok(i) | Err(i)) = inline_diagnostics
16998                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16999                        inline_diagnostics.insert(
17000                            i,
17001                            (
17002                                start_anchor,
17003                                InlineDiagnostic {
17004                                    message,
17005                                    group_id: diagnostic_entry.diagnostic.group_id,
17006                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17007                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17008                                    severity: diagnostic_entry.diagnostic.severity,
17009                                },
17010                            ),
17011                        );
17012                    }
17013                    inline_diagnostics
17014                })
17015                .await;
17016
17017            editor
17018                .update(cx, |editor, cx| {
17019                    editor.inline_diagnostics = new_inline_diagnostics;
17020                    cx.notify();
17021                })
17022                .ok();
17023        });
17024    }
17025
17026    fn pull_diagnostics(
17027        &mut self,
17028        buffer_id: Option<BufferId>,
17029        window: &Window,
17030        cx: &mut Context<Self>,
17031    ) -> Option<()> {
17032        if !self.mode().is_full() {
17033            return None;
17034        }
17035        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17036            .diagnostics
17037            .lsp_pull_diagnostics;
17038        if !pull_diagnostics_settings.enabled {
17039            return None;
17040        }
17041        let project = self.project()?.downgrade();
17042        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17043        let mut buffers = self.buffer.read(cx).all_buffers();
17044        if let Some(buffer_id) = buffer_id {
17045            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17046        }
17047
17048        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17049            cx.background_executor().timer(debounce).await;
17050
17051            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17052                buffers
17053                    .into_iter()
17054                    .filter_map(|buffer| {
17055                        project
17056                            .update(cx, |project, cx| {
17057                                project.lsp_store().update(cx, |lsp_store, cx| {
17058                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17059                                })
17060                            })
17061                            .ok()
17062                    })
17063                    .collect::<FuturesUnordered<_>>()
17064            }) else {
17065                return;
17066            };
17067
17068            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17069                match pull_task {
17070                    Ok(()) => {
17071                        if editor
17072                            .update_in(cx, |editor, window, cx| {
17073                                editor.update_diagnostics_state(window, cx);
17074                            })
17075                            .is_err()
17076                        {
17077                            return;
17078                        }
17079                    }
17080                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17081                }
17082            }
17083        });
17084
17085        Some(())
17086    }
17087
17088    pub fn set_selections_from_remote(
17089        &mut self,
17090        selections: Vec<Selection<Anchor>>,
17091        pending_selection: Option<Selection<Anchor>>,
17092        window: &mut Window,
17093        cx: &mut Context<Self>,
17094    ) {
17095        let old_cursor_position = self.selections.newest_anchor().head();
17096        self.selections.change_with(cx, |s| {
17097            s.select_anchors(selections);
17098            if let Some(pending_selection) = pending_selection {
17099                s.set_pending(pending_selection, SelectMode::Character);
17100            } else {
17101                s.clear_pending();
17102            }
17103        });
17104        self.selections_did_change(
17105            false,
17106            &old_cursor_position,
17107            SelectionEffects::default(),
17108            window,
17109            cx,
17110        );
17111    }
17112
17113    pub fn transact(
17114        &mut self,
17115        window: &mut Window,
17116        cx: &mut Context<Self>,
17117        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17118    ) -> Option<TransactionId> {
17119        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17120            this.start_transaction_at(Instant::now(), window, cx);
17121            update(this, window, cx);
17122            this.end_transaction_at(Instant::now(), cx)
17123        })
17124    }
17125
17126    pub fn start_transaction_at(
17127        &mut self,
17128        now: Instant,
17129        window: &mut Window,
17130        cx: &mut Context<Self>,
17131    ) -> Option<TransactionId> {
17132        self.end_selection(window, cx);
17133        if let Some(tx_id) = self
17134            .buffer
17135            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17136        {
17137            self.selection_history
17138                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17139            cx.emit(EditorEvent::TransactionBegun {
17140                transaction_id: tx_id,
17141            });
17142            Some(tx_id)
17143        } else {
17144            None
17145        }
17146    }
17147
17148    pub fn end_transaction_at(
17149        &mut self,
17150        now: Instant,
17151        cx: &mut Context<Self>,
17152    ) -> Option<TransactionId> {
17153        if let Some(transaction_id) = self
17154            .buffer
17155            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17156        {
17157            if let Some((_, end_selections)) =
17158                self.selection_history.transaction_mut(transaction_id)
17159            {
17160                *end_selections = Some(self.selections.disjoint_anchors());
17161            } else {
17162                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17163            }
17164
17165            cx.emit(EditorEvent::Edited { transaction_id });
17166            Some(transaction_id)
17167        } else {
17168            None
17169        }
17170    }
17171
17172    pub fn modify_transaction_selection_history(
17173        &mut self,
17174        transaction_id: TransactionId,
17175        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17176    ) -> bool {
17177        self.selection_history
17178            .transaction_mut(transaction_id)
17179            .map(modify)
17180            .is_some()
17181    }
17182
17183    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17184        if self.selection_mark_mode {
17185            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17186                s.move_with(|_, sel| {
17187                    sel.collapse_to(sel.head(), SelectionGoal::None);
17188                });
17189            })
17190        }
17191        self.selection_mark_mode = true;
17192        cx.notify();
17193    }
17194
17195    pub fn swap_selection_ends(
17196        &mut self,
17197        _: &actions::SwapSelectionEnds,
17198        window: &mut Window,
17199        cx: &mut Context<Self>,
17200    ) {
17201        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17202            s.move_with(|_, sel| {
17203                if sel.start != sel.end {
17204                    sel.reversed = !sel.reversed
17205                }
17206            });
17207        });
17208        self.request_autoscroll(Autoscroll::newest(), cx);
17209        cx.notify();
17210    }
17211
17212    pub fn toggle_focus(
17213        workspace: &mut Workspace,
17214        _: &actions::ToggleFocus,
17215        window: &mut Window,
17216        cx: &mut Context<Workspace>,
17217    ) {
17218        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17219            return;
17220        };
17221        workspace.activate_item(&item, true, true, window, cx);
17222    }
17223
17224    pub fn toggle_fold(
17225        &mut self,
17226        _: &actions::ToggleFold,
17227        window: &mut Window,
17228        cx: &mut Context<Self>,
17229    ) {
17230        if self.is_singleton(cx) {
17231            let selection = self.selections.newest::<Point>(cx);
17232
17233            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17234            let range = if selection.is_empty() {
17235                let point = selection.head().to_display_point(&display_map);
17236                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17237                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17238                    .to_point(&display_map);
17239                start..end
17240            } else {
17241                selection.range()
17242            };
17243            if display_map.folds_in_range(range).next().is_some() {
17244                self.unfold_lines(&Default::default(), window, cx)
17245            } else {
17246                self.fold(&Default::default(), window, cx)
17247            }
17248        } else {
17249            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17250            let buffer_ids: HashSet<_> = self
17251                .selections
17252                .disjoint_anchor_ranges()
17253                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17254                .collect();
17255
17256            let should_unfold = buffer_ids
17257                .iter()
17258                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17259
17260            for buffer_id in buffer_ids {
17261                if should_unfold {
17262                    self.unfold_buffer(buffer_id, cx);
17263                } else {
17264                    self.fold_buffer(buffer_id, cx);
17265                }
17266            }
17267        }
17268    }
17269
17270    pub fn toggle_fold_recursive(
17271        &mut self,
17272        _: &actions::ToggleFoldRecursive,
17273        window: &mut Window,
17274        cx: &mut Context<Self>,
17275    ) {
17276        let selection = self.selections.newest::<Point>(cx);
17277
17278        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17279        let range = if selection.is_empty() {
17280            let point = selection.head().to_display_point(&display_map);
17281            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17282            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17283                .to_point(&display_map);
17284            start..end
17285        } else {
17286            selection.range()
17287        };
17288        if display_map.folds_in_range(range).next().is_some() {
17289            self.unfold_recursive(&Default::default(), window, cx)
17290        } else {
17291            self.fold_recursive(&Default::default(), window, cx)
17292        }
17293    }
17294
17295    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17296        if self.is_singleton(cx) {
17297            let mut to_fold = Vec::new();
17298            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17299            let selections = self.selections.all_adjusted(cx);
17300
17301            for selection in selections {
17302                let range = selection.range().sorted();
17303                let buffer_start_row = range.start.row;
17304
17305                if range.start.row != range.end.row {
17306                    let mut found = false;
17307                    let mut row = range.start.row;
17308                    while row <= range.end.row {
17309                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17310                        {
17311                            found = true;
17312                            row = crease.range().end.row + 1;
17313                            to_fold.push(crease);
17314                        } else {
17315                            row += 1
17316                        }
17317                    }
17318                    if found {
17319                        continue;
17320                    }
17321                }
17322
17323                for row in (0..=range.start.row).rev() {
17324                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17325                        && crease.range().end.row >= buffer_start_row
17326                    {
17327                        to_fold.push(crease);
17328                        if row <= range.start.row {
17329                            break;
17330                        }
17331                    }
17332                }
17333            }
17334
17335            self.fold_creases(to_fold, true, window, cx);
17336        } else {
17337            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17338            let buffer_ids = self
17339                .selections
17340                .disjoint_anchor_ranges()
17341                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17342                .collect::<HashSet<_>>();
17343            for buffer_id in buffer_ids {
17344                self.fold_buffer(buffer_id, cx);
17345            }
17346        }
17347    }
17348
17349    pub fn toggle_fold_all(
17350        &mut self,
17351        _: &actions::ToggleFoldAll,
17352        window: &mut Window,
17353        cx: &mut Context<Self>,
17354    ) {
17355        if self.buffer.read(cx).is_singleton() {
17356            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17357            let has_folds = display_map
17358                .folds_in_range(0..display_map.buffer_snapshot.len())
17359                .next()
17360                .is_some();
17361
17362            if has_folds {
17363                self.unfold_all(&actions::UnfoldAll, window, cx);
17364            } else {
17365                self.fold_all(&actions::FoldAll, window, cx);
17366            }
17367        } else {
17368            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17369            let should_unfold = buffer_ids
17370                .iter()
17371                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17372
17373            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17374                editor
17375                    .update_in(cx, |editor, _, cx| {
17376                        for buffer_id in buffer_ids {
17377                            if should_unfold {
17378                                editor.unfold_buffer(buffer_id, cx);
17379                            } else {
17380                                editor.fold_buffer(buffer_id, cx);
17381                            }
17382                        }
17383                    })
17384                    .ok();
17385            });
17386        }
17387    }
17388
17389    fn fold_at_level(
17390        &mut self,
17391        fold_at: &FoldAtLevel,
17392        window: &mut Window,
17393        cx: &mut Context<Self>,
17394    ) {
17395        if !self.buffer.read(cx).is_singleton() {
17396            return;
17397        }
17398
17399        let fold_at_level = fold_at.0;
17400        let snapshot = self.buffer.read(cx).snapshot(cx);
17401        let mut to_fold = Vec::new();
17402        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17403
17404        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17405            while start_row < end_row {
17406                match self
17407                    .snapshot(window, cx)
17408                    .crease_for_buffer_row(MultiBufferRow(start_row))
17409                {
17410                    Some(crease) => {
17411                        let nested_start_row = crease.range().start.row + 1;
17412                        let nested_end_row = crease.range().end.row;
17413
17414                        if current_level < fold_at_level {
17415                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17416                        } else if current_level == fold_at_level {
17417                            to_fold.push(crease);
17418                        }
17419
17420                        start_row = nested_end_row + 1;
17421                    }
17422                    None => start_row += 1,
17423                }
17424            }
17425        }
17426
17427        self.fold_creases(to_fold, true, window, cx);
17428    }
17429
17430    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17431        if self.buffer.read(cx).is_singleton() {
17432            let mut fold_ranges = Vec::new();
17433            let snapshot = self.buffer.read(cx).snapshot(cx);
17434
17435            for row in 0..snapshot.max_row().0 {
17436                if let Some(foldable_range) = self
17437                    .snapshot(window, cx)
17438                    .crease_for_buffer_row(MultiBufferRow(row))
17439                {
17440                    fold_ranges.push(foldable_range);
17441                }
17442            }
17443
17444            self.fold_creases(fold_ranges, true, window, cx);
17445        } else {
17446            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17447                editor
17448                    .update_in(cx, |editor, _, cx| {
17449                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17450                            editor.fold_buffer(buffer_id, cx);
17451                        }
17452                    })
17453                    .ok();
17454            });
17455        }
17456    }
17457
17458    pub fn fold_function_bodies(
17459        &mut self,
17460        _: &actions::FoldFunctionBodies,
17461        window: &mut Window,
17462        cx: &mut Context<Self>,
17463    ) {
17464        let snapshot = self.buffer.read(cx).snapshot(cx);
17465
17466        let ranges = snapshot
17467            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17468            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17469            .collect::<Vec<_>>();
17470
17471        let creases = ranges
17472            .into_iter()
17473            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17474            .collect();
17475
17476        self.fold_creases(creases, true, window, cx);
17477    }
17478
17479    pub fn fold_recursive(
17480        &mut self,
17481        _: &actions::FoldRecursive,
17482        window: &mut Window,
17483        cx: &mut Context<Self>,
17484    ) {
17485        let mut to_fold = Vec::new();
17486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17487        let selections = self.selections.all_adjusted(cx);
17488
17489        for selection in selections {
17490            let range = selection.range().sorted();
17491            let buffer_start_row = range.start.row;
17492
17493            if range.start.row != range.end.row {
17494                let mut found = false;
17495                for row in range.start.row..=range.end.row {
17496                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17497                        found = true;
17498                        to_fold.push(crease);
17499                    }
17500                }
17501                if found {
17502                    continue;
17503                }
17504            }
17505
17506            for row in (0..=range.start.row).rev() {
17507                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17508                    if crease.range().end.row >= buffer_start_row {
17509                        to_fold.push(crease);
17510                    } else {
17511                        break;
17512                    }
17513                }
17514            }
17515        }
17516
17517        self.fold_creases(to_fold, true, window, cx);
17518    }
17519
17520    pub fn fold_at(
17521        &mut self,
17522        buffer_row: MultiBufferRow,
17523        window: &mut Window,
17524        cx: &mut Context<Self>,
17525    ) {
17526        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17527
17528        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17529            let autoscroll = self
17530                .selections
17531                .all::<Point>(cx)
17532                .iter()
17533                .any(|selection| crease.range().overlaps(&selection.range()));
17534
17535            self.fold_creases(vec![crease], autoscroll, window, cx);
17536        }
17537    }
17538
17539    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17540        if self.is_singleton(cx) {
17541            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17542            let buffer = &display_map.buffer_snapshot;
17543            let selections = self.selections.all::<Point>(cx);
17544            let ranges = selections
17545                .iter()
17546                .map(|s| {
17547                    let range = s.display_range(&display_map).sorted();
17548                    let mut start = range.start.to_point(&display_map);
17549                    let mut end = range.end.to_point(&display_map);
17550                    start.column = 0;
17551                    end.column = buffer.line_len(MultiBufferRow(end.row));
17552                    start..end
17553                })
17554                .collect::<Vec<_>>();
17555
17556            self.unfold_ranges(&ranges, true, true, cx);
17557        } else {
17558            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17559            let buffer_ids = self
17560                .selections
17561                .disjoint_anchor_ranges()
17562                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17563                .collect::<HashSet<_>>();
17564            for buffer_id in buffer_ids {
17565                self.unfold_buffer(buffer_id, cx);
17566            }
17567        }
17568    }
17569
17570    pub fn unfold_recursive(
17571        &mut self,
17572        _: &UnfoldRecursive,
17573        _window: &mut Window,
17574        cx: &mut Context<Self>,
17575    ) {
17576        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17577        let selections = self.selections.all::<Point>(cx);
17578        let ranges = selections
17579            .iter()
17580            .map(|s| {
17581                let mut range = s.display_range(&display_map).sorted();
17582                *range.start.column_mut() = 0;
17583                *range.end.column_mut() = display_map.line_len(range.end.row());
17584                let start = range.start.to_point(&display_map);
17585                let end = range.end.to_point(&display_map);
17586                start..end
17587            })
17588            .collect::<Vec<_>>();
17589
17590        self.unfold_ranges(&ranges, true, true, cx);
17591    }
17592
17593    pub fn unfold_at(
17594        &mut self,
17595        buffer_row: MultiBufferRow,
17596        _window: &mut Window,
17597        cx: &mut Context<Self>,
17598    ) {
17599        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17600
17601        let intersection_range = Point::new(buffer_row.0, 0)
17602            ..Point::new(
17603                buffer_row.0,
17604                display_map.buffer_snapshot.line_len(buffer_row),
17605            );
17606
17607        let autoscroll = self
17608            .selections
17609            .all::<Point>(cx)
17610            .iter()
17611            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17612
17613        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17614    }
17615
17616    pub fn unfold_all(
17617        &mut self,
17618        _: &actions::UnfoldAll,
17619        _window: &mut Window,
17620        cx: &mut Context<Self>,
17621    ) {
17622        if self.buffer.read(cx).is_singleton() {
17623            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17624            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17625        } else {
17626            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17627                editor
17628                    .update(cx, |editor, cx| {
17629                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17630                            editor.unfold_buffer(buffer_id, cx);
17631                        }
17632                    })
17633                    .ok();
17634            });
17635        }
17636    }
17637
17638    pub fn fold_selected_ranges(
17639        &mut self,
17640        _: &FoldSelectedRanges,
17641        window: &mut Window,
17642        cx: &mut Context<Self>,
17643    ) {
17644        let selections = self.selections.all_adjusted(cx);
17645        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17646        let ranges = selections
17647            .into_iter()
17648            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17649            .collect::<Vec<_>>();
17650        self.fold_creases(ranges, true, window, cx);
17651    }
17652
17653    pub fn fold_ranges<T: ToOffset + Clone>(
17654        &mut self,
17655        ranges: Vec<Range<T>>,
17656        auto_scroll: bool,
17657        window: &mut Window,
17658        cx: &mut Context<Self>,
17659    ) {
17660        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17661        let ranges = ranges
17662            .into_iter()
17663            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17664            .collect::<Vec<_>>();
17665        self.fold_creases(ranges, auto_scroll, window, cx);
17666    }
17667
17668    pub fn fold_creases<T: ToOffset + Clone>(
17669        &mut self,
17670        creases: Vec<Crease<T>>,
17671        auto_scroll: bool,
17672        _window: &mut Window,
17673        cx: &mut Context<Self>,
17674    ) {
17675        if creases.is_empty() {
17676            return;
17677        }
17678
17679        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17680
17681        if auto_scroll {
17682            self.request_autoscroll(Autoscroll::fit(), cx);
17683        }
17684
17685        cx.notify();
17686
17687        self.scrollbar_marker_state.dirty = true;
17688        self.folds_did_change(cx);
17689    }
17690
17691    /// Removes any folds whose ranges intersect any of the given ranges.
17692    pub fn unfold_ranges<T: ToOffset + Clone>(
17693        &mut self,
17694        ranges: &[Range<T>],
17695        inclusive: bool,
17696        auto_scroll: bool,
17697        cx: &mut Context<Self>,
17698    ) {
17699        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17700            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17701        });
17702        self.folds_did_change(cx);
17703    }
17704
17705    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17706        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17707            return;
17708        }
17709        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17710        self.display_map.update(cx, |display_map, cx| {
17711            display_map.fold_buffers([buffer_id], cx)
17712        });
17713        cx.emit(EditorEvent::BufferFoldToggled {
17714            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17715            folded: true,
17716        });
17717        cx.notify();
17718    }
17719
17720    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17721        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17722            return;
17723        }
17724        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17725        self.display_map.update(cx, |display_map, cx| {
17726            display_map.unfold_buffers([buffer_id], cx);
17727        });
17728        cx.emit(EditorEvent::BufferFoldToggled {
17729            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17730            folded: false,
17731        });
17732        cx.notify();
17733    }
17734
17735    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17736        self.display_map.read(cx).is_buffer_folded(buffer)
17737    }
17738
17739    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17740        self.display_map.read(cx).folded_buffers()
17741    }
17742
17743    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17744        self.display_map.update(cx, |display_map, cx| {
17745            display_map.disable_header_for_buffer(buffer_id, cx);
17746        });
17747        cx.notify();
17748    }
17749
17750    /// Removes any folds with the given ranges.
17751    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17752        &mut self,
17753        ranges: &[Range<T>],
17754        type_id: TypeId,
17755        auto_scroll: bool,
17756        cx: &mut Context<Self>,
17757    ) {
17758        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17759            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17760        });
17761        self.folds_did_change(cx);
17762    }
17763
17764    fn remove_folds_with<T: ToOffset + Clone>(
17765        &mut self,
17766        ranges: &[Range<T>],
17767        auto_scroll: bool,
17768        cx: &mut Context<Self>,
17769        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17770    ) {
17771        if ranges.is_empty() {
17772            return;
17773        }
17774
17775        let mut buffers_affected = HashSet::default();
17776        let multi_buffer = self.buffer().read(cx);
17777        for range in ranges {
17778            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17779                buffers_affected.insert(buffer.read(cx).remote_id());
17780            };
17781        }
17782
17783        self.display_map.update(cx, update);
17784
17785        if auto_scroll {
17786            self.request_autoscroll(Autoscroll::fit(), cx);
17787        }
17788
17789        cx.notify();
17790        self.scrollbar_marker_state.dirty = true;
17791        self.active_indent_guides_state.dirty = true;
17792    }
17793
17794    pub fn update_renderer_widths(
17795        &mut self,
17796        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17797        cx: &mut Context<Self>,
17798    ) -> bool {
17799        self.display_map
17800            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17801    }
17802
17803    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17804        self.display_map.read(cx).fold_placeholder.clone()
17805    }
17806
17807    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17808        self.buffer.update(cx, |buffer, cx| {
17809            buffer.set_all_diff_hunks_expanded(cx);
17810        });
17811    }
17812
17813    pub fn expand_all_diff_hunks(
17814        &mut self,
17815        _: &ExpandAllDiffHunks,
17816        _window: &mut Window,
17817        cx: &mut Context<Self>,
17818    ) {
17819        self.buffer.update(cx, |buffer, cx| {
17820            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17821        });
17822    }
17823
17824    pub fn toggle_selected_diff_hunks(
17825        &mut self,
17826        _: &ToggleSelectedDiffHunks,
17827        _window: &mut Window,
17828        cx: &mut Context<Self>,
17829    ) {
17830        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17831        self.toggle_diff_hunks_in_ranges(ranges, cx);
17832    }
17833
17834    pub fn diff_hunks_in_ranges<'a>(
17835        &'a self,
17836        ranges: &'a [Range<Anchor>],
17837        buffer: &'a MultiBufferSnapshot,
17838    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17839        ranges.iter().flat_map(move |range| {
17840            let end_excerpt_id = range.end.excerpt_id;
17841            let range = range.to_point(buffer);
17842            let mut peek_end = range.end;
17843            if range.end.row < buffer.max_row().0 {
17844                peek_end = Point::new(range.end.row + 1, 0);
17845            }
17846            buffer
17847                .diff_hunks_in_range(range.start..peek_end)
17848                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17849        })
17850    }
17851
17852    pub fn has_stageable_diff_hunks_in_ranges(
17853        &self,
17854        ranges: &[Range<Anchor>],
17855        snapshot: &MultiBufferSnapshot,
17856    ) -> bool {
17857        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17858        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17859    }
17860
17861    pub fn toggle_staged_selected_diff_hunks(
17862        &mut self,
17863        _: &::git::ToggleStaged,
17864        _: &mut Window,
17865        cx: &mut Context<Self>,
17866    ) {
17867        let snapshot = self.buffer.read(cx).snapshot(cx);
17868        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17869        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17870        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17871    }
17872
17873    pub fn set_render_diff_hunk_controls(
17874        &mut self,
17875        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17876        cx: &mut Context<Self>,
17877    ) {
17878        self.render_diff_hunk_controls = render_diff_hunk_controls;
17879        cx.notify();
17880    }
17881
17882    pub fn stage_and_next(
17883        &mut self,
17884        _: &::git::StageAndNext,
17885        window: &mut Window,
17886        cx: &mut Context<Self>,
17887    ) {
17888        self.do_stage_or_unstage_and_next(true, window, cx);
17889    }
17890
17891    pub fn unstage_and_next(
17892        &mut self,
17893        _: &::git::UnstageAndNext,
17894        window: &mut Window,
17895        cx: &mut Context<Self>,
17896    ) {
17897        self.do_stage_or_unstage_and_next(false, window, cx);
17898    }
17899
17900    pub fn stage_or_unstage_diff_hunks(
17901        &mut self,
17902        stage: bool,
17903        ranges: Vec<Range<Anchor>>,
17904        cx: &mut Context<Self>,
17905    ) {
17906        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17907        cx.spawn(async move |this, cx| {
17908            task.await?;
17909            this.update(cx, |this, cx| {
17910                let snapshot = this.buffer.read(cx).snapshot(cx);
17911                let chunk_by = this
17912                    .diff_hunks_in_ranges(&ranges, &snapshot)
17913                    .chunk_by(|hunk| hunk.buffer_id);
17914                for (buffer_id, hunks) in &chunk_by {
17915                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17916                }
17917            })
17918        })
17919        .detach_and_log_err(cx);
17920    }
17921
17922    fn save_buffers_for_ranges_if_needed(
17923        &mut self,
17924        ranges: &[Range<Anchor>],
17925        cx: &mut Context<Editor>,
17926    ) -> Task<Result<()>> {
17927        let multibuffer = self.buffer.read(cx);
17928        let snapshot = multibuffer.read(cx);
17929        let buffer_ids: HashSet<_> = ranges
17930            .iter()
17931            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17932            .collect();
17933        drop(snapshot);
17934
17935        let mut buffers = HashSet::default();
17936        for buffer_id in buffer_ids {
17937            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17938                let buffer = buffer_entity.read(cx);
17939                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17940                {
17941                    buffers.insert(buffer_entity);
17942                }
17943            }
17944        }
17945
17946        if let Some(project) = &self.project {
17947            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17948        } else {
17949            Task::ready(Ok(()))
17950        }
17951    }
17952
17953    fn do_stage_or_unstage_and_next(
17954        &mut self,
17955        stage: bool,
17956        window: &mut Window,
17957        cx: &mut Context<Self>,
17958    ) {
17959        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17960
17961        if ranges.iter().any(|range| range.start != range.end) {
17962            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17963            return;
17964        }
17965
17966        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17967        let snapshot = self.snapshot(window, cx);
17968        let position = self.selections.newest::<Point>(cx).head();
17969        let mut row = snapshot
17970            .buffer_snapshot
17971            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17972            .find(|hunk| hunk.row_range.start.0 > position.row)
17973            .map(|hunk| hunk.row_range.start);
17974
17975        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17976        // Outside of the project diff editor, wrap around to the beginning.
17977        if !all_diff_hunks_expanded {
17978            row = row.or_else(|| {
17979                snapshot
17980                    .buffer_snapshot
17981                    .diff_hunks_in_range(Point::zero()..position)
17982                    .find(|hunk| hunk.row_range.end.0 < position.row)
17983                    .map(|hunk| hunk.row_range.start)
17984            });
17985        }
17986
17987        if let Some(row) = row {
17988            let destination = Point::new(row.0, 0);
17989            let autoscroll = Autoscroll::center();
17990
17991            self.unfold_ranges(&[destination..destination], false, false, cx);
17992            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17993                s.select_ranges([destination..destination]);
17994            });
17995        }
17996    }
17997
17998    fn do_stage_or_unstage(
17999        &self,
18000        stage: bool,
18001        buffer_id: BufferId,
18002        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18003        cx: &mut App,
18004    ) -> Option<()> {
18005        let project = self.project()?;
18006        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18007        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18008        let buffer_snapshot = buffer.read(cx).snapshot();
18009        let file_exists = buffer_snapshot
18010            .file()
18011            .is_some_and(|file| file.disk_state().exists());
18012        diff.update(cx, |diff, cx| {
18013            diff.stage_or_unstage_hunks(
18014                stage,
18015                &hunks
18016                    .map(|hunk| buffer_diff::DiffHunk {
18017                        buffer_range: hunk.buffer_range,
18018                        diff_base_byte_range: hunk.diff_base_byte_range,
18019                        secondary_status: hunk.secondary_status,
18020                        range: Point::zero()..Point::zero(), // unused
18021                    })
18022                    .collect::<Vec<_>>(),
18023                &buffer_snapshot,
18024                file_exists,
18025                cx,
18026            )
18027        });
18028        None
18029    }
18030
18031    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18032        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18033        self.buffer
18034            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18035    }
18036
18037    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18038        self.buffer.update(cx, |buffer, cx| {
18039            let ranges = vec![Anchor::min()..Anchor::max()];
18040            if !buffer.all_diff_hunks_expanded()
18041                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18042            {
18043                buffer.collapse_diff_hunks(ranges, cx);
18044                true
18045            } else {
18046                false
18047            }
18048        })
18049    }
18050
18051    fn toggle_diff_hunks_in_ranges(
18052        &mut self,
18053        ranges: Vec<Range<Anchor>>,
18054        cx: &mut Context<Editor>,
18055    ) {
18056        self.buffer.update(cx, |buffer, cx| {
18057            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18058            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18059        })
18060    }
18061
18062    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18063        self.buffer.update(cx, |buffer, cx| {
18064            let snapshot = buffer.snapshot(cx);
18065            let excerpt_id = range.end.excerpt_id;
18066            let point_range = range.to_point(&snapshot);
18067            let expand = !buffer.single_hunk_is_expanded(range, cx);
18068            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18069        })
18070    }
18071
18072    pub(crate) fn apply_all_diff_hunks(
18073        &mut self,
18074        _: &ApplyAllDiffHunks,
18075        window: &mut Window,
18076        cx: &mut Context<Self>,
18077    ) {
18078        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18079
18080        let buffers = self.buffer.read(cx).all_buffers();
18081        for branch_buffer in buffers {
18082            branch_buffer.update(cx, |branch_buffer, cx| {
18083                branch_buffer.merge_into_base(Vec::new(), cx);
18084            });
18085        }
18086
18087        if let Some(project) = self.project.clone() {
18088            self.save(
18089                SaveOptions {
18090                    format: true,
18091                    autosave: false,
18092                },
18093                project,
18094                window,
18095                cx,
18096            )
18097            .detach_and_log_err(cx);
18098        }
18099    }
18100
18101    pub(crate) fn apply_selected_diff_hunks(
18102        &mut self,
18103        _: &ApplyDiffHunk,
18104        window: &mut Window,
18105        cx: &mut Context<Self>,
18106    ) {
18107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18108        let snapshot = self.snapshot(window, cx);
18109        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18110        let mut ranges_by_buffer = HashMap::default();
18111        self.transact(window, cx, |editor, _window, cx| {
18112            for hunk in hunks {
18113                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18114                    ranges_by_buffer
18115                        .entry(buffer.clone())
18116                        .or_insert_with(Vec::new)
18117                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18118                }
18119            }
18120
18121            for (buffer, ranges) in ranges_by_buffer {
18122                buffer.update(cx, |buffer, cx| {
18123                    buffer.merge_into_base(ranges, cx);
18124                });
18125            }
18126        });
18127
18128        if let Some(project) = self.project.clone() {
18129            self.save(
18130                SaveOptions {
18131                    format: true,
18132                    autosave: false,
18133                },
18134                project,
18135                window,
18136                cx,
18137            )
18138            .detach_and_log_err(cx);
18139        }
18140    }
18141
18142    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18143        if hovered != self.gutter_hovered {
18144            self.gutter_hovered = hovered;
18145            cx.notify();
18146        }
18147    }
18148
18149    pub fn insert_blocks(
18150        &mut self,
18151        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18152        autoscroll: Option<Autoscroll>,
18153        cx: &mut Context<Self>,
18154    ) -> Vec<CustomBlockId> {
18155        let blocks = self
18156            .display_map
18157            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18158        if let Some(autoscroll) = autoscroll {
18159            self.request_autoscroll(autoscroll, cx);
18160        }
18161        cx.notify();
18162        blocks
18163    }
18164
18165    pub fn resize_blocks(
18166        &mut self,
18167        heights: HashMap<CustomBlockId, u32>,
18168        autoscroll: Option<Autoscroll>,
18169        cx: &mut Context<Self>,
18170    ) {
18171        self.display_map
18172            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18173        if let Some(autoscroll) = autoscroll {
18174            self.request_autoscroll(autoscroll, cx);
18175        }
18176        cx.notify();
18177    }
18178
18179    pub fn replace_blocks(
18180        &mut self,
18181        renderers: HashMap<CustomBlockId, RenderBlock>,
18182        autoscroll: Option<Autoscroll>,
18183        cx: &mut Context<Self>,
18184    ) {
18185        self.display_map
18186            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18187        if let Some(autoscroll) = autoscroll {
18188            self.request_autoscroll(autoscroll, cx);
18189        }
18190        cx.notify();
18191    }
18192
18193    pub fn remove_blocks(
18194        &mut self,
18195        block_ids: HashSet<CustomBlockId>,
18196        autoscroll: Option<Autoscroll>,
18197        cx: &mut Context<Self>,
18198    ) {
18199        self.display_map.update(cx, |display_map, cx| {
18200            display_map.remove_blocks(block_ids, cx)
18201        });
18202        if let Some(autoscroll) = autoscroll {
18203            self.request_autoscroll(autoscroll, cx);
18204        }
18205        cx.notify();
18206    }
18207
18208    pub fn row_for_block(
18209        &self,
18210        block_id: CustomBlockId,
18211        cx: &mut Context<Self>,
18212    ) -> Option<DisplayRow> {
18213        self.display_map
18214            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18215    }
18216
18217    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18218        self.focused_block = Some(focused_block);
18219    }
18220
18221    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18222        self.focused_block.take()
18223    }
18224
18225    pub fn insert_creases(
18226        &mut self,
18227        creases: impl IntoIterator<Item = Crease<Anchor>>,
18228        cx: &mut Context<Self>,
18229    ) -> Vec<CreaseId> {
18230        self.display_map
18231            .update(cx, |map, cx| map.insert_creases(creases, cx))
18232    }
18233
18234    pub fn remove_creases(
18235        &mut self,
18236        ids: impl IntoIterator<Item = CreaseId>,
18237        cx: &mut Context<Self>,
18238    ) -> Vec<(CreaseId, Range<Anchor>)> {
18239        self.display_map
18240            .update(cx, |map, cx| map.remove_creases(ids, cx))
18241    }
18242
18243    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18244        self.display_map
18245            .update(cx, |map, cx| map.snapshot(cx))
18246            .longest_row()
18247    }
18248
18249    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18250        self.display_map
18251            .update(cx, |map, cx| map.snapshot(cx))
18252            .max_point()
18253    }
18254
18255    pub fn text(&self, cx: &App) -> String {
18256        self.buffer.read(cx).read(cx).text()
18257    }
18258
18259    pub fn is_empty(&self, cx: &App) -> bool {
18260        self.buffer.read(cx).read(cx).is_empty()
18261    }
18262
18263    pub fn text_option(&self, cx: &App) -> Option<String> {
18264        let text = self.text(cx);
18265        let text = text.trim();
18266
18267        if text.is_empty() {
18268            return None;
18269        }
18270
18271        Some(text.to_string())
18272    }
18273
18274    pub fn set_text(
18275        &mut self,
18276        text: impl Into<Arc<str>>,
18277        window: &mut Window,
18278        cx: &mut Context<Self>,
18279    ) {
18280        self.transact(window, cx, |this, _, cx| {
18281            this.buffer
18282                .read(cx)
18283                .as_singleton()
18284                .expect("you can only call set_text on editors for singleton buffers")
18285                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18286        });
18287    }
18288
18289    pub fn display_text(&self, cx: &mut App) -> String {
18290        self.display_map
18291            .update(cx, |map, cx| map.snapshot(cx))
18292            .text()
18293    }
18294
18295    fn create_minimap(
18296        &self,
18297        minimap_settings: MinimapSettings,
18298        window: &mut Window,
18299        cx: &mut Context<Self>,
18300    ) -> Option<Entity<Self>> {
18301        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18302            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18303    }
18304
18305    fn initialize_new_minimap(
18306        &self,
18307        minimap_settings: MinimapSettings,
18308        window: &mut Window,
18309        cx: &mut Context<Self>,
18310    ) -> Entity<Self> {
18311        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18312
18313        let mut minimap = Editor::new_internal(
18314            EditorMode::Minimap {
18315                parent: cx.weak_entity(),
18316            },
18317            self.buffer.clone(),
18318            None,
18319            Some(self.display_map.clone()),
18320            window,
18321            cx,
18322        );
18323        minimap.scroll_manager.clone_state(&self.scroll_manager);
18324        minimap.set_text_style_refinement(TextStyleRefinement {
18325            font_size: Some(MINIMAP_FONT_SIZE),
18326            font_weight: Some(MINIMAP_FONT_WEIGHT),
18327            ..Default::default()
18328        });
18329        minimap.update_minimap_configuration(minimap_settings, cx);
18330        cx.new(|_| minimap)
18331    }
18332
18333    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18334        let current_line_highlight = minimap_settings
18335            .current_line_highlight
18336            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18337        self.set_current_line_highlight(Some(current_line_highlight));
18338    }
18339
18340    pub fn minimap(&self) -> Option<&Entity<Self>> {
18341        self.minimap
18342            .as_ref()
18343            .filter(|_| self.minimap_visibility.visible())
18344    }
18345
18346    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18347        let mut wrap_guides = smallvec![];
18348
18349        if self.show_wrap_guides == Some(false) {
18350            return wrap_guides;
18351        }
18352
18353        let settings = self.buffer.read(cx).language_settings(cx);
18354        if settings.show_wrap_guides {
18355            match self.soft_wrap_mode(cx) {
18356                SoftWrap::Column(soft_wrap) => {
18357                    wrap_guides.push((soft_wrap as usize, true));
18358                }
18359                SoftWrap::Bounded(soft_wrap) => {
18360                    wrap_guides.push((soft_wrap as usize, true));
18361                }
18362                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18363            }
18364            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18365        }
18366
18367        wrap_guides
18368    }
18369
18370    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18371        let settings = self.buffer.read(cx).language_settings(cx);
18372        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18373        match mode {
18374            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18375                SoftWrap::None
18376            }
18377            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18378            language_settings::SoftWrap::PreferredLineLength => {
18379                SoftWrap::Column(settings.preferred_line_length)
18380            }
18381            language_settings::SoftWrap::Bounded => {
18382                SoftWrap::Bounded(settings.preferred_line_length)
18383            }
18384        }
18385    }
18386
18387    pub fn set_soft_wrap_mode(
18388        &mut self,
18389        mode: language_settings::SoftWrap,
18390
18391        cx: &mut Context<Self>,
18392    ) {
18393        self.soft_wrap_mode_override = Some(mode);
18394        cx.notify();
18395    }
18396
18397    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18398        self.hard_wrap = hard_wrap;
18399        cx.notify();
18400    }
18401
18402    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18403        self.text_style_refinement = Some(style);
18404    }
18405
18406    /// called by the Element so we know what style we were most recently rendered with.
18407    pub(crate) fn set_style(
18408        &mut self,
18409        style: EditorStyle,
18410        window: &mut Window,
18411        cx: &mut Context<Self>,
18412    ) {
18413        // We intentionally do not inform the display map about the minimap style
18414        // so that wrapping is not recalculated and stays consistent for the editor
18415        // and its linked minimap.
18416        if !self.mode.is_minimap() {
18417            let rem_size = window.rem_size();
18418            self.display_map.update(cx, |map, cx| {
18419                map.set_font(
18420                    style.text.font(),
18421                    style.text.font_size.to_pixels(rem_size),
18422                    cx,
18423                )
18424            });
18425        }
18426        self.style = Some(style);
18427    }
18428
18429    pub fn style(&self) -> Option<&EditorStyle> {
18430        self.style.as_ref()
18431    }
18432
18433    // Called by the element. This method is not designed to be called outside of the editor
18434    // element's layout code because it does not notify when rewrapping is computed synchronously.
18435    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18436        self.display_map
18437            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18438    }
18439
18440    pub fn set_soft_wrap(&mut self) {
18441        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18442    }
18443
18444    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18445        if self.soft_wrap_mode_override.is_some() {
18446            self.soft_wrap_mode_override.take();
18447        } else {
18448            let soft_wrap = match self.soft_wrap_mode(cx) {
18449                SoftWrap::GitDiff => return,
18450                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18451                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18452                    language_settings::SoftWrap::None
18453                }
18454            };
18455            self.soft_wrap_mode_override = Some(soft_wrap);
18456        }
18457        cx.notify();
18458    }
18459
18460    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18461        let Some(workspace) = self.workspace() else {
18462            return;
18463        };
18464        let fs = workspace.read(cx).app_state().fs.clone();
18465        let current_show = TabBarSettings::get_global(cx).show;
18466        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18467            setting.show = Some(!current_show);
18468        });
18469    }
18470
18471    pub fn toggle_indent_guides(
18472        &mut self,
18473        _: &ToggleIndentGuides,
18474        _: &mut Window,
18475        cx: &mut Context<Self>,
18476    ) {
18477        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18478            self.buffer
18479                .read(cx)
18480                .language_settings(cx)
18481                .indent_guides
18482                .enabled
18483        });
18484        self.show_indent_guides = Some(!currently_enabled);
18485        cx.notify();
18486    }
18487
18488    fn should_show_indent_guides(&self) -> Option<bool> {
18489        self.show_indent_guides
18490    }
18491
18492    pub fn toggle_line_numbers(
18493        &mut self,
18494        _: &ToggleLineNumbers,
18495        _: &mut Window,
18496        cx: &mut Context<Self>,
18497    ) {
18498        let mut editor_settings = EditorSettings::get_global(cx).clone();
18499        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18500        EditorSettings::override_global(editor_settings, cx);
18501    }
18502
18503    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18504        if let Some(show_line_numbers) = self.show_line_numbers {
18505            return show_line_numbers;
18506        }
18507        EditorSettings::get_global(cx).gutter.line_numbers
18508    }
18509
18510    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18511        self.use_relative_line_numbers
18512            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18513    }
18514
18515    pub fn toggle_relative_line_numbers(
18516        &mut self,
18517        _: &ToggleRelativeLineNumbers,
18518        _: &mut Window,
18519        cx: &mut Context<Self>,
18520    ) {
18521        let is_relative = self.should_use_relative_line_numbers(cx);
18522        self.set_relative_line_number(Some(!is_relative), cx)
18523    }
18524
18525    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18526        self.use_relative_line_numbers = is_relative;
18527        cx.notify();
18528    }
18529
18530    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18531        self.show_gutter = show_gutter;
18532        cx.notify();
18533    }
18534
18535    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18536        self.show_scrollbars = ScrollbarAxes {
18537            horizontal: show,
18538            vertical: show,
18539        };
18540        cx.notify();
18541    }
18542
18543    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18544        self.show_scrollbars.vertical = show;
18545        cx.notify();
18546    }
18547
18548    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18549        self.show_scrollbars.horizontal = show;
18550        cx.notify();
18551    }
18552
18553    pub fn set_minimap_visibility(
18554        &mut self,
18555        minimap_visibility: MinimapVisibility,
18556        window: &mut Window,
18557        cx: &mut Context<Self>,
18558    ) {
18559        if self.minimap_visibility != minimap_visibility {
18560            if minimap_visibility.visible() && self.minimap.is_none() {
18561                let minimap_settings = EditorSettings::get_global(cx).minimap;
18562                self.minimap =
18563                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18564            }
18565            self.minimap_visibility = minimap_visibility;
18566            cx.notify();
18567        }
18568    }
18569
18570    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18571        self.set_show_scrollbars(false, cx);
18572        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18573    }
18574
18575    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18576        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18577    }
18578
18579    /// Normally the text in full mode and auto height editors is padded on the
18580    /// left side by roughly half a character width for improved hit testing.
18581    ///
18582    /// Use this method to disable this for cases where this is not wanted (e.g.
18583    /// if you want to align the editor text with some other text above or below)
18584    /// or if you want to add this padding to single-line editors.
18585    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18586        self.offset_content = offset_content;
18587        cx.notify();
18588    }
18589
18590    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18591        self.show_line_numbers = Some(show_line_numbers);
18592        cx.notify();
18593    }
18594
18595    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18596        self.disable_expand_excerpt_buttons = true;
18597        cx.notify();
18598    }
18599
18600    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18601        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18602        cx.notify();
18603    }
18604
18605    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18606        self.show_code_actions = Some(show_code_actions);
18607        cx.notify();
18608    }
18609
18610    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18611        self.show_runnables = Some(show_runnables);
18612        cx.notify();
18613    }
18614
18615    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18616        self.show_breakpoints = Some(show_breakpoints);
18617        cx.notify();
18618    }
18619
18620    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18621        if self.display_map.read(cx).masked != masked {
18622            self.display_map.update(cx, |map, _| map.masked = masked);
18623        }
18624        cx.notify()
18625    }
18626
18627    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18628        self.show_wrap_guides = Some(show_wrap_guides);
18629        cx.notify();
18630    }
18631
18632    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18633        self.show_indent_guides = Some(show_indent_guides);
18634        cx.notify();
18635    }
18636
18637    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18638        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18639            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18640                && let Some(dir) = file.abs_path(cx).parent()
18641            {
18642                return Some(dir.to_owned());
18643            }
18644
18645            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18646                return Some(project_path.path.to_path_buf());
18647            }
18648        }
18649
18650        None
18651    }
18652
18653    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18654        self.active_excerpt(cx)?
18655            .1
18656            .read(cx)
18657            .file()
18658            .and_then(|f| f.as_local())
18659    }
18660
18661    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18662        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18663            let buffer = buffer.read(cx);
18664            if let Some(project_path) = buffer.project_path(cx) {
18665                let project = self.project()?.read(cx);
18666                project.absolute_path(&project_path, cx)
18667            } else {
18668                buffer
18669                    .file()
18670                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18671            }
18672        })
18673    }
18674
18675    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18676        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18677            let project_path = buffer.read(cx).project_path(cx)?;
18678            let project = self.project()?.read(cx);
18679            let entry = project.entry_for_path(&project_path, cx)?;
18680            let path = entry.path.to_path_buf();
18681            Some(path)
18682        })
18683    }
18684
18685    pub fn reveal_in_finder(
18686        &mut self,
18687        _: &RevealInFileManager,
18688        _window: &mut Window,
18689        cx: &mut Context<Self>,
18690    ) {
18691        if let Some(target) = self.target_file(cx) {
18692            cx.reveal_path(&target.abs_path(cx));
18693        }
18694    }
18695
18696    pub fn copy_path(
18697        &mut self,
18698        _: &zed_actions::workspace::CopyPath,
18699        _window: &mut Window,
18700        cx: &mut Context<Self>,
18701    ) {
18702        if let Some(path) = self.target_file_abs_path(cx)
18703            && let Some(path) = path.to_str()
18704        {
18705            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18706        }
18707    }
18708
18709    pub fn copy_relative_path(
18710        &mut self,
18711        _: &zed_actions::workspace::CopyRelativePath,
18712        _window: &mut Window,
18713        cx: &mut Context<Self>,
18714    ) {
18715        if let Some(path) = self.target_file_path(cx)
18716            && let Some(path) = path.to_str()
18717        {
18718            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18719        }
18720    }
18721
18722    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18723        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18724            buffer.read(cx).project_path(cx)
18725        } else {
18726            None
18727        }
18728    }
18729
18730    // Returns true if the editor handled a go-to-line request
18731    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18732        maybe!({
18733            let breakpoint_store = self.breakpoint_store.as_ref()?;
18734
18735            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18736            else {
18737                self.clear_row_highlights::<ActiveDebugLine>();
18738                return None;
18739            };
18740
18741            let position = active_stack_frame.position;
18742            let buffer_id = position.buffer_id?;
18743            let snapshot = self
18744                .project
18745                .as_ref()?
18746                .read(cx)
18747                .buffer_for_id(buffer_id, cx)?
18748                .read(cx)
18749                .snapshot();
18750
18751            let mut handled = false;
18752            for (id, ExcerptRange { context, .. }) in
18753                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18754            {
18755                if context.start.cmp(&position, &snapshot).is_ge()
18756                    || context.end.cmp(&position, &snapshot).is_lt()
18757                {
18758                    continue;
18759                }
18760                let snapshot = self.buffer.read(cx).snapshot(cx);
18761                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18762
18763                handled = true;
18764                self.clear_row_highlights::<ActiveDebugLine>();
18765
18766                self.go_to_line::<ActiveDebugLine>(
18767                    multibuffer_anchor,
18768                    Some(cx.theme().colors().editor_debugger_active_line_background),
18769                    window,
18770                    cx,
18771                );
18772
18773                cx.notify();
18774            }
18775
18776            handled.then_some(())
18777        })
18778        .is_some()
18779    }
18780
18781    pub fn copy_file_name_without_extension(
18782        &mut self,
18783        _: &CopyFileNameWithoutExtension,
18784        _: &mut Window,
18785        cx: &mut Context<Self>,
18786    ) {
18787        if let Some(file) = self.target_file(cx)
18788            && let Some(file_stem) = file.path().file_stem()
18789            && let Some(name) = file_stem.to_str()
18790        {
18791            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18792        }
18793    }
18794
18795    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18796        if let Some(file) = self.target_file(cx)
18797            && let Some(file_name) = file.path().file_name()
18798            && let Some(name) = file_name.to_str()
18799        {
18800            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18801        }
18802    }
18803
18804    pub fn toggle_git_blame(
18805        &mut self,
18806        _: &::git::Blame,
18807        window: &mut Window,
18808        cx: &mut Context<Self>,
18809    ) {
18810        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18811
18812        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18813            self.start_git_blame(true, window, cx);
18814        }
18815
18816        cx.notify();
18817    }
18818
18819    pub fn toggle_git_blame_inline(
18820        &mut self,
18821        _: &ToggleGitBlameInline,
18822        window: &mut Window,
18823        cx: &mut Context<Self>,
18824    ) {
18825        self.toggle_git_blame_inline_internal(true, window, cx);
18826        cx.notify();
18827    }
18828
18829    pub fn open_git_blame_commit(
18830        &mut self,
18831        _: &OpenGitBlameCommit,
18832        window: &mut Window,
18833        cx: &mut Context<Self>,
18834    ) {
18835        self.open_git_blame_commit_internal(window, cx);
18836    }
18837
18838    fn open_git_blame_commit_internal(
18839        &mut self,
18840        window: &mut Window,
18841        cx: &mut Context<Self>,
18842    ) -> Option<()> {
18843        let blame = self.blame.as_ref()?;
18844        let snapshot = self.snapshot(window, cx);
18845        let cursor = self.selections.newest::<Point>(cx).head();
18846        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18847        let blame_entry = blame
18848            .update(cx, |blame, cx| {
18849                blame
18850                    .blame_for_rows(
18851                        &[RowInfo {
18852                            buffer_id: Some(buffer.remote_id()),
18853                            buffer_row: Some(point.row),
18854                            ..Default::default()
18855                        }],
18856                        cx,
18857                    )
18858                    .next()
18859            })
18860            .flatten()?;
18861        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18862        let repo = blame.read(cx).repository(cx)?;
18863        let workspace = self.workspace()?.downgrade();
18864        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18865        None
18866    }
18867
18868    pub fn git_blame_inline_enabled(&self) -> bool {
18869        self.git_blame_inline_enabled
18870    }
18871
18872    pub fn toggle_selection_menu(
18873        &mut self,
18874        _: &ToggleSelectionMenu,
18875        _: &mut Window,
18876        cx: &mut Context<Self>,
18877    ) {
18878        self.show_selection_menu = self
18879            .show_selection_menu
18880            .map(|show_selections_menu| !show_selections_menu)
18881            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18882
18883        cx.notify();
18884    }
18885
18886    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18887        self.show_selection_menu
18888            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18889    }
18890
18891    fn start_git_blame(
18892        &mut self,
18893        user_triggered: bool,
18894        window: &mut Window,
18895        cx: &mut Context<Self>,
18896    ) {
18897        if let Some(project) = self.project() {
18898            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18899                return;
18900            };
18901
18902            if buffer.read(cx).file().is_none() {
18903                return;
18904            }
18905
18906            let focused = self.focus_handle(cx).contains_focused(window, cx);
18907
18908            let project = project.clone();
18909            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18910            self.blame_subscription =
18911                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18912            self.blame = Some(blame);
18913        }
18914    }
18915
18916    fn toggle_git_blame_inline_internal(
18917        &mut self,
18918        user_triggered: bool,
18919        window: &mut Window,
18920        cx: &mut Context<Self>,
18921    ) {
18922        if self.git_blame_inline_enabled {
18923            self.git_blame_inline_enabled = false;
18924            self.show_git_blame_inline = false;
18925            self.show_git_blame_inline_delay_task.take();
18926        } else {
18927            self.git_blame_inline_enabled = true;
18928            self.start_git_blame_inline(user_triggered, window, cx);
18929        }
18930
18931        cx.notify();
18932    }
18933
18934    fn start_git_blame_inline(
18935        &mut self,
18936        user_triggered: bool,
18937        window: &mut Window,
18938        cx: &mut Context<Self>,
18939    ) {
18940        self.start_git_blame(user_triggered, window, cx);
18941
18942        if ProjectSettings::get_global(cx)
18943            .git
18944            .inline_blame_delay()
18945            .is_some()
18946        {
18947            self.start_inline_blame_timer(window, cx);
18948        } else {
18949            self.show_git_blame_inline = true
18950        }
18951    }
18952
18953    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18954        self.blame.as_ref()
18955    }
18956
18957    pub fn show_git_blame_gutter(&self) -> bool {
18958        self.show_git_blame_gutter
18959    }
18960
18961    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18962        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18963    }
18964
18965    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18966        self.show_git_blame_inline
18967            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18968            && !self.newest_selection_head_on_empty_line(cx)
18969            && self.has_blame_entries(cx)
18970    }
18971
18972    fn has_blame_entries(&self, cx: &App) -> bool {
18973        self.blame()
18974            .is_some_and(|blame| blame.read(cx).has_generated_entries())
18975    }
18976
18977    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18978        let cursor_anchor = self.selections.newest_anchor().head();
18979
18980        let snapshot = self.buffer.read(cx).snapshot(cx);
18981        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18982
18983        snapshot.line_len(buffer_row) == 0
18984    }
18985
18986    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18987        let buffer_and_selection = maybe!({
18988            let selection = self.selections.newest::<Point>(cx);
18989            let selection_range = selection.range();
18990
18991            let multi_buffer = self.buffer().read(cx);
18992            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18993            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18994
18995            let (buffer, range, _) = if selection.reversed {
18996                buffer_ranges.first()
18997            } else {
18998                buffer_ranges.last()
18999            }?;
19000
19001            let selection = text::ToPoint::to_point(&range.start, buffer).row
19002                ..text::ToPoint::to_point(&range.end, buffer).row;
19003            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19004        });
19005
19006        let Some((buffer, selection)) = buffer_and_selection else {
19007            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19008        };
19009
19010        let Some(project) = self.project() else {
19011            return Task::ready(Err(anyhow!("editor does not have project")));
19012        };
19013
19014        project.update(cx, |project, cx| {
19015            project.get_permalink_to_line(&buffer, selection, cx)
19016        })
19017    }
19018
19019    pub fn copy_permalink_to_line(
19020        &mut self,
19021        _: &CopyPermalinkToLine,
19022        window: &mut Window,
19023        cx: &mut Context<Self>,
19024    ) {
19025        let permalink_task = self.get_permalink_to_line(cx);
19026        let workspace = self.workspace();
19027
19028        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19029            Ok(permalink) => {
19030                cx.update(|_, cx| {
19031                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19032                })
19033                .ok();
19034            }
19035            Err(err) => {
19036                let message = format!("Failed to copy permalink: {err}");
19037
19038                anyhow::Result::<()>::Err(err).log_err();
19039
19040                if let Some(workspace) = workspace {
19041                    workspace
19042                        .update_in(cx, |workspace, _, cx| {
19043                            struct CopyPermalinkToLine;
19044
19045                            workspace.show_toast(
19046                                Toast::new(
19047                                    NotificationId::unique::<CopyPermalinkToLine>(),
19048                                    message,
19049                                ),
19050                                cx,
19051                            )
19052                        })
19053                        .ok();
19054                }
19055            }
19056        })
19057        .detach();
19058    }
19059
19060    pub fn copy_file_location(
19061        &mut self,
19062        _: &CopyFileLocation,
19063        _: &mut Window,
19064        cx: &mut Context<Self>,
19065    ) {
19066        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19067        if let Some(file) = self.target_file(cx)
19068            && let Some(path) = file.path().to_str()
19069        {
19070            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19071        }
19072    }
19073
19074    pub fn open_permalink_to_line(
19075        &mut self,
19076        _: &OpenPermalinkToLine,
19077        window: &mut Window,
19078        cx: &mut Context<Self>,
19079    ) {
19080        let permalink_task = self.get_permalink_to_line(cx);
19081        let workspace = self.workspace();
19082
19083        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19084            Ok(permalink) => {
19085                cx.update(|_, cx| {
19086                    cx.open_url(permalink.as_ref());
19087                })
19088                .ok();
19089            }
19090            Err(err) => {
19091                let message = format!("Failed to open permalink: {err}");
19092
19093                anyhow::Result::<()>::Err(err).log_err();
19094
19095                if let Some(workspace) = workspace {
19096                    workspace
19097                        .update(cx, |workspace, cx| {
19098                            struct OpenPermalinkToLine;
19099
19100                            workspace.show_toast(
19101                                Toast::new(
19102                                    NotificationId::unique::<OpenPermalinkToLine>(),
19103                                    message,
19104                                ),
19105                                cx,
19106                            )
19107                        })
19108                        .ok();
19109                }
19110            }
19111        })
19112        .detach();
19113    }
19114
19115    pub fn insert_uuid_v4(
19116        &mut self,
19117        _: &InsertUuidV4,
19118        window: &mut Window,
19119        cx: &mut Context<Self>,
19120    ) {
19121        self.insert_uuid(UuidVersion::V4, window, cx);
19122    }
19123
19124    pub fn insert_uuid_v7(
19125        &mut self,
19126        _: &InsertUuidV7,
19127        window: &mut Window,
19128        cx: &mut Context<Self>,
19129    ) {
19130        self.insert_uuid(UuidVersion::V7, window, cx);
19131    }
19132
19133    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19134        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19135        self.transact(window, cx, |this, window, cx| {
19136            let edits = this
19137                .selections
19138                .all::<Point>(cx)
19139                .into_iter()
19140                .map(|selection| {
19141                    let uuid = match version {
19142                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19143                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19144                    };
19145
19146                    (selection.range(), uuid.to_string())
19147                });
19148            this.edit(edits, cx);
19149            this.refresh_edit_prediction(true, false, window, cx);
19150        });
19151    }
19152
19153    pub fn open_selections_in_multibuffer(
19154        &mut self,
19155        _: &OpenSelectionsInMultibuffer,
19156        window: &mut Window,
19157        cx: &mut Context<Self>,
19158    ) {
19159        let multibuffer = self.buffer.read(cx);
19160
19161        let Some(buffer) = multibuffer.as_singleton() else {
19162            return;
19163        };
19164
19165        let Some(workspace) = self.workspace() else {
19166            return;
19167        };
19168
19169        let title = multibuffer.title(cx).to_string();
19170
19171        let locations = self
19172            .selections
19173            .all_anchors(cx)
19174            .iter()
19175            .map(|selection| Location {
19176                buffer: buffer.clone(),
19177                range: selection.start.text_anchor..selection.end.text_anchor,
19178            })
19179            .collect::<Vec<_>>();
19180
19181        cx.spawn_in(window, async move |_, cx| {
19182            workspace.update_in(cx, |workspace, window, cx| {
19183                Self::open_locations_in_multibuffer(
19184                    workspace,
19185                    locations,
19186                    format!("Selections for '{title}'"),
19187                    false,
19188                    MultibufferSelectionMode::All,
19189                    window,
19190                    cx,
19191                );
19192            })
19193        })
19194        .detach();
19195    }
19196
19197    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19198    /// last highlight added will be used.
19199    ///
19200    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19201    pub fn highlight_rows<T: 'static>(
19202        &mut self,
19203        range: Range<Anchor>,
19204        color: Hsla,
19205        options: RowHighlightOptions,
19206        cx: &mut Context<Self>,
19207    ) {
19208        let snapshot = self.buffer().read(cx).snapshot(cx);
19209        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19210        let ix = row_highlights.binary_search_by(|highlight| {
19211            Ordering::Equal
19212                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19213                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19214        });
19215
19216        if let Err(mut ix) = ix {
19217            let index = post_inc(&mut self.highlight_order);
19218
19219            // If this range intersects with the preceding highlight, then merge it with
19220            // the preceding highlight. Otherwise insert a new highlight.
19221            let mut merged = false;
19222            if ix > 0 {
19223                let prev_highlight = &mut row_highlights[ix - 1];
19224                if prev_highlight
19225                    .range
19226                    .end
19227                    .cmp(&range.start, &snapshot)
19228                    .is_ge()
19229                {
19230                    ix -= 1;
19231                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19232                        prev_highlight.range.end = range.end;
19233                    }
19234                    merged = true;
19235                    prev_highlight.index = index;
19236                    prev_highlight.color = color;
19237                    prev_highlight.options = options;
19238                }
19239            }
19240
19241            if !merged {
19242                row_highlights.insert(
19243                    ix,
19244                    RowHighlight {
19245                        range,
19246                        index,
19247                        color,
19248                        options,
19249                        type_id: TypeId::of::<T>(),
19250                    },
19251                );
19252            }
19253
19254            // If any of the following highlights intersect with this one, merge them.
19255            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19256                let highlight = &row_highlights[ix];
19257                if next_highlight
19258                    .range
19259                    .start
19260                    .cmp(&highlight.range.end, &snapshot)
19261                    .is_le()
19262                {
19263                    if next_highlight
19264                        .range
19265                        .end
19266                        .cmp(&highlight.range.end, &snapshot)
19267                        .is_gt()
19268                    {
19269                        row_highlights[ix].range.end = next_highlight.range.end;
19270                    }
19271                    row_highlights.remove(ix + 1);
19272                } else {
19273                    break;
19274                }
19275            }
19276        }
19277    }
19278
19279    /// Remove any highlighted row ranges of the given type that intersect the
19280    /// given ranges.
19281    pub fn remove_highlighted_rows<T: 'static>(
19282        &mut self,
19283        ranges_to_remove: Vec<Range<Anchor>>,
19284        cx: &mut Context<Self>,
19285    ) {
19286        let snapshot = self.buffer().read(cx).snapshot(cx);
19287        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19288        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19289        row_highlights.retain(|highlight| {
19290            while let Some(range_to_remove) = ranges_to_remove.peek() {
19291                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19292                    Ordering::Less | Ordering::Equal => {
19293                        ranges_to_remove.next();
19294                    }
19295                    Ordering::Greater => {
19296                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19297                            Ordering::Less | Ordering::Equal => {
19298                                return false;
19299                            }
19300                            Ordering::Greater => break,
19301                        }
19302                    }
19303                }
19304            }
19305
19306            true
19307        })
19308    }
19309
19310    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19311    pub fn clear_row_highlights<T: 'static>(&mut self) {
19312        self.highlighted_rows.remove(&TypeId::of::<T>());
19313    }
19314
19315    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19316    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19317        self.highlighted_rows
19318            .get(&TypeId::of::<T>())
19319            .map_or(&[] as &[_], |vec| vec.as_slice())
19320            .iter()
19321            .map(|highlight| (highlight.range.clone(), highlight.color))
19322    }
19323
19324    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19325    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19326    /// Allows to ignore certain kinds of highlights.
19327    pub fn highlighted_display_rows(
19328        &self,
19329        window: &mut Window,
19330        cx: &mut App,
19331    ) -> BTreeMap<DisplayRow, LineHighlight> {
19332        let snapshot = self.snapshot(window, cx);
19333        let mut used_highlight_orders = HashMap::default();
19334        self.highlighted_rows
19335            .iter()
19336            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19337            .fold(
19338                BTreeMap::<DisplayRow, LineHighlight>::new(),
19339                |mut unique_rows, highlight| {
19340                    let start = highlight.range.start.to_display_point(&snapshot);
19341                    let end = highlight.range.end.to_display_point(&snapshot);
19342                    let start_row = start.row().0;
19343                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19344                        && end.column() == 0
19345                    {
19346                        end.row().0.saturating_sub(1)
19347                    } else {
19348                        end.row().0
19349                    };
19350                    for row in start_row..=end_row {
19351                        let used_index =
19352                            used_highlight_orders.entry(row).or_insert(highlight.index);
19353                        if highlight.index >= *used_index {
19354                            *used_index = highlight.index;
19355                            unique_rows.insert(
19356                                DisplayRow(row),
19357                                LineHighlight {
19358                                    include_gutter: highlight.options.include_gutter,
19359                                    border: None,
19360                                    background: highlight.color.into(),
19361                                    type_id: Some(highlight.type_id),
19362                                },
19363                            );
19364                        }
19365                    }
19366                    unique_rows
19367                },
19368            )
19369    }
19370
19371    pub fn highlighted_display_row_for_autoscroll(
19372        &self,
19373        snapshot: &DisplaySnapshot,
19374    ) -> Option<DisplayRow> {
19375        self.highlighted_rows
19376            .values()
19377            .flat_map(|highlighted_rows| highlighted_rows.iter())
19378            .filter_map(|highlight| {
19379                if highlight.options.autoscroll {
19380                    Some(highlight.range.start.to_display_point(snapshot).row())
19381                } else {
19382                    None
19383                }
19384            })
19385            .min()
19386    }
19387
19388    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19389        self.highlight_background::<SearchWithinRange>(
19390            ranges,
19391            |colors| colors.colors().editor_document_highlight_read_background,
19392            cx,
19393        )
19394    }
19395
19396    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19397        self.breadcrumb_header = Some(new_header);
19398    }
19399
19400    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19401        self.clear_background_highlights::<SearchWithinRange>(cx);
19402    }
19403
19404    pub fn highlight_background<T: 'static>(
19405        &mut self,
19406        ranges: &[Range<Anchor>],
19407        color_fetcher: fn(&Theme) -> Hsla,
19408        cx: &mut Context<Self>,
19409    ) {
19410        self.background_highlights.insert(
19411            HighlightKey::Type(TypeId::of::<T>()),
19412            (color_fetcher, Arc::from(ranges)),
19413        );
19414        self.scrollbar_marker_state.dirty = true;
19415        cx.notify();
19416    }
19417
19418    pub fn highlight_background_key<T: 'static>(
19419        &mut self,
19420        key: usize,
19421        ranges: &[Range<Anchor>],
19422        color_fetcher: fn(&Theme) -> Hsla,
19423        cx: &mut Context<Self>,
19424    ) {
19425        self.background_highlights.insert(
19426            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19427            (color_fetcher, Arc::from(ranges)),
19428        );
19429        self.scrollbar_marker_state.dirty = true;
19430        cx.notify();
19431    }
19432
19433    pub fn clear_background_highlights<T: 'static>(
19434        &mut self,
19435        cx: &mut Context<Self>,
19436    ) -> Option<BackgroundHighlight> {
19437        let text_highlights = self
19438            .background_highlights
19439            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19440        if !text_highlights.1.is_empty() {
19441            self.scrollbar_marker_state.dirty = true;
19442            cx.notify();
19443        }
19444        Some(text_highlights)
19445    }
19446
19447    pub fn highlight_gutter<T: 'static>(
19448        &mut self,
19449        ranges: impl Into<Vec<Range<Anchor>>>,
19450        color_fetcher: fn(&App) -> Hsla,
19451        cx: &mut Context<Self>,
19452    ) {
19453        self.gutter_highlights
19454            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19455        cx.notify();
19456    }
19457
19458    pub fn clear_gutter_highlights<T: 'static>(
19459        &mut self,
19460        cx: &mut Context<Self>,
19461    ) -> Option<GutterHighlight> {
19462        cx.notify();
19463        self.gutter_highlights.remove(&TypeId::of::<T>())
19464    }
19465
19466    pub fn insert_gutter_highlight<T: 'static>(
19467        &mut self,
19468        range: Range<Anchor>,
19469        color_fetcher: fn(&App) -> Hsla,
19470        cx: &mut Context<Self>,
19471    ) {
19472        let snapshot = self.buffer().read(cx).snapshot(cx);
19473        let mut highlights = self
19474            .gutter_highlights
19475            .remove(&TypeId::of::<T>())
19476            .map(|(_, highlights)| highlights)
19477            .unwrap_or_default();
19478        let ix = highlights.binary_search_by(|highlight| {
19479            Ordering::Equal
19480                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19481                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19482        });
19483        if let Err(ix) = ix {
19484            highlights.insert(ix, range);
19485        }
19486        self.gutter_highlights
19487            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19488    }
19489
19490    pub fn remove_gutter_highlights<T: 'static>(
19491        &mut self,
19492        ranges_to_remove: Vec<Range<Anchor>>,
19493        cx: &mut Context<Self>,
19494    ) {
19495        let snapshot = self.buffer().read(cx).snapshot(cx);
19496        let Some((color_fetcher, mut gutter_highlights)) =
19497            self.gutter_highlights.remove(&TypeId::of::<T>())
19498        else {
19499            return;
19500        };
19501        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19502        gutter_highlights.retain(|highlight| {
19503            while let Some(range_to_remove) = ranges_to_remove.peek() {
19504                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19505                    Ordering::Less | Ordering::Equal => {
19506                        ranges_to_remove.next();
19507                    }
19508                    Ordering::Greater => {
19509                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19510                            Ordering::Less | Ordering::Equal => {
19511                                return false;
19512                            }
19513                            Ordering::Greater => break,
19514                        }
19515                    }
19516                }
19517            }
19518
19519            true
19520        });
19521        self.gutter_highlights
19522            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19523    }
19524
19525    #[cfg(feature = "test-support")]
19526    pub fn all_text_highlights(
19527        &self,
19528        window: &mut Window,
19529        cx: &mut Context<Self>,
19530    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19531        let snapshot = self.snapshot(window, cx);
19532        self.display_map.update(cx, |display_map, _| {
19533            display_map
19534                .all_text_highlights()
19535                .map(|highlight| {
19536                    let (style, ranges) = highlight.as_ref();
19537                    (
19538                        *style,
19539                        ranges
19540                            .iter()
19541                            .map(|range| range.clone().to_display_points(&snapshot))
19542                            .collect(),
19543                    )
19544                })
19545                .collect()
19546        })
19547    }
19548
19549    #[cfg(feature = "test-support")]
19550    pub fn all_text_background_highlights(
19551        &self,
19552        window: &mut Window,
19553        cx: &mut Context<Self>,
19554    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19555        let snapshot = self.snapshot(window, cx);
19556        let buffer = &snapshot.buffer_snapshot;
19557        let start = buffer.anchor_before(0);
19558        let end = buffer.anchor_after(buffer.len());
19559        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19560    }
19561
19562    #[cfg(feature = "test-support")]
19563    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19564        let snapshot = self.buffer().read(cx).snapshot(cx);
19565
19566        let highlights = self
19567            .background_highlights
19568            .get(&HighlightKey::Type(TypeId::of::<
19569                items::BufferSearchHighlights,
19570            >()));
19571
19572        if let Some((_color, ranges)) = highlights {
19573            ranges
19574                .iter()
19575                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19576                .collect_vec()
19577        } else {
19578            vec![]
19579        }
19580    }
19581
19582    fn document_highlights_for_position<'a>(
19583        &'a self,
19584        position: Anchor,
19585        buffer: &'a MultiBufferSnapshot,
19586    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19587        let read_highlights = self
19588            .background_highlights
19589            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19590            .map(|h| &h.1);
19591        let write_highlights = self
19592            .background_highlights
19593            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19594            .map(|h| &h.1);
19595        let left_position = position.bias_left(buffer);
19596        let right_position = position.bias_right(buffer);
19597        read_highlights
19598            .into_iter()
19599            .chain(write_highlights)
19600            .flat_map(move |ranges| {
19601                let start_ix = match ranges.binary_search_by(|probe| {
19602                    let cmp = probe.end.cmp(&left_position, buffer);
19603                    if cmp.is_ge() {
19604                        Ordering::Greater
19605                    } else {
19606                        Ordering::Less
19607                    }
19608                }) {
19609                    Ok(i) | Err(i) => i,
19610                };
19611
19612                ranges[start_ix..]
19613                    .iter()
19614                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19615            })
19616    }
19617
19618    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19619        self.background_highlights
19620            .get(&HighlightKey::Type(TypeId::of::<T>()))
19621            .is_some_and(|(_, highlights)| !highlights.is_empty())
19622    }
19623
19624    pub fn background_highlights_in_range(
19625        &self,
19626        search_range: Range<Anchor>,
19627        display_snapshot: &DisplaySnapshot,
19628        theme: &Theme,
19629    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19630        let mut results = Vec::new();
19631        for (color_fetcher, ranges) in self.background_highlights.values() {
19632            let color = color_fetcher(theme);
19633            let start_ix = match ranges.binary_search_by(|probe| {
19634                let cmp = probe
19635                    .end
19636                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19637                if cmp.is_gt() {
19638                    Ordering::Greater
19639                } else {
19640                    Ordering::Less
19641                }
19642            }) {
19643                Ok(i) | Err(i) => i,
19644            };
19645            for range in &ranges[start_ix..] {
19646                if range
19647                    .start
19648                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19649                    .is_ge()
19650                {
19651                    break;
19652                }
19653
19654                let start = range.start.to_display_point(display_snapshot);
19655                let end = range.end.to_display_point(display_snapshot);
19656                results.push((start..end, color))
19657            }
19658        }
19659        results
19660    }
19661
19662    pub fn background_highlight_row_ranges<T: 'static>(
19663        &self,
19664        search_range: Range<Anchor>,
19665        display_snapshot: &DisplaySnapshot,
19666        count: usize,
19667    ) -> Vec<RangeInclusive<DisplayPoint>> {
19668        let mut results = Vec::new();
19669        let Some((_, ranges)) = self
19670            .background_highlights
19671            .get(&HighlightKey::Type(TypeId::of::<T>()))
19672        else {
19673            return vec![];
19674        };
19675
19676        let start_ix = match ranges.binary_search_by(|probe| {
19677            let cmp = probe
19678                .end
19679                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19680            if cmp.is_gt() {
19681                Ordering::Greater
19682            } else {
19683                Ordering::Less
19684            }
19685        }) {
19686            Ok(i) | Err(i) => i,
19687        };
19688        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19689            if let (Some(start_display), Some(end_display)) = (start, end) {
19690                results.push(
19691                    start_display.to_display_point(display_snapshot)
19692                        ..=end_display.to_display_point(display_snapshot),
19693                );
19694            }
19695        };
19696        let mut start_row: Option<Point> = None;
19697        let mut end_row: Option<Point> = None;
19698        if ranges.len() > count {
19699            return Vec::new();
19700        }
19701        for range in &ranges[start_ix..] {
19702            if range
19703                .start
19704                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19705                .is_ge()
19706            {
19707                break;
19708            }
19709            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19710            if let Some(current_row) = &end_row
19711                && end.row == current_row.row
19712            {
19713                continue;
19714            }
19715            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19716            if start_row.is_none() {
19717                assert_eq!(end_row, None);
19718                start_row = Some(start);
19719                end_row = Some(end);
19720                continue;
19721            }
19722            if let Some(current_end) = end_row.as_mut() {
19723                if start.row > current_end.row + 1 {
19724                    push_region(start_row, end_row);
19725                    start_row = Some(start);
19726                    end_row = Some(end);
19727                } else {
19728                    // Merge two hunks.
19729                    *current_end = end;
19730                }
19731            } else {
19732                unreachable!();
19733            }
19734        }
19735        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19736        push_region(start_row, end_row);
19737        results
19738    }
19739
19740    pub fn gutter_highlights_in_range(
19741        &self,
19742        search_range: Range<Anchor>,
19743        display_snapshot: &DisplaySnapshot,
19744        cx: &App,
19745    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19746        let mut results = Vec::new();
19747        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19748            let color = color_fetcher(cx);
19749            let start_ix = match ranges.binary_search_by(|probe| {
19750                let cmp = probe
19751                    .end
19752                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19753                if cmp.is_gt() {
19754                    Ordering::Greater
19755                } else {
19756                    Ordering::Less
19757                }
19758            }) {
19759                Ok(i) | Err(i) => i,
19760            };
19761            for range in &ranges[start_ix..] {
19762                if range
19763                    .start
19764                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19765                    .is_ge()
19766                {
19767                    break;
19768                }
19769
19770                let start = range.start.to_display_point(display_snapshot);
19771                let end = range.end.to_display_point(display_snapshot);
19772                results.push((start..end, color))
19773            }
19774        }
19775        results
19776    }
19777
19778    /// Get the text ranges corresponding to the redaction query
19779    pub fn redacted_ranges(
19780        &self,
19781        search_range: Range<Anchor>,
19782        display_snapshot: &DisplaySnapshot,
19783        cx: &App,
19784    ) -> Vec<Range<DisplayPoint>> {
19785        display_snapshot
19786            .buffer_snapshot
19787            .redacted_ranges(search_range, |file| {
19788                if let Some(file) = file {
19789                    file.is_private()
19790                        && EditorSettings::get(
19791                            Some(SettingsLocation {
19792                                worktree_id: file.worktree_id(cx),
19793                                path: file.path().as_ref(),
19794                            }),
19795                            cx,
19796                        )
19797                        .redact_private_values
19798                } else {
19799                    false
19800                }
19801            })
19802            .map(|range| {
19803                range.start.to_display_point(display_snapshot)
19804                    ..range.end.to_display_point(display_snapshot)
19805            })
19806            .collect()
19807    }
19808
19809    pub fn highlight_text_key<T: 'static>(
19810        &mut self,
19811        key: usize,
19812        ranges: Vec<Range<Anchor>>,
19813        style: HighlightStyle,
19814        cx: &mut Context<Self>,
19815    ) {
19816        self.display_map.update(cx, |map, _| {
19817            map.highlight_text(
19818                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19819                ranges,
19820                style,
19821            );
19822        });
19823        cx.notify();
19824    }
19825
19826    pub fn highlight_text<T: 'static>(
19827        &mut self,
19828        ranges: Vec<Range<Anchor>>,
19829        style: HighlightStyle,
19830        cx: &mut Context<Self>,
19831    ) {
19832        self.display_map.update(cx, |map, _| {
19833            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19834        });
19835        cx.notify();
19836    }
19837
19838    pub(crate) fn highlight_inlays<T: 'static>(
19839        &mut self,
19840        highlights: Vec<InlayHighlight>,
19841        style: HighlightStyle,
19842        cx: &mut Context<Self>,
19843    ) {
19844        self.display_map.update(cx, |map, _| {
19845            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19846        });
19847        cx.notify();
19848    }
19849
19850    pub fn text_highlights<'a, T: 'static>(
19851        &'a self,
19852        cx: &'a App,
19853    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19854        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19855    }
19856
19857    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19858        let cleared = self
19859            .display_map
19860            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19861        if cleared {
19862            cx.notify();
19863        }
19864    }
19865
19866    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19867        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19868            && self.focus_handle.is_focused(window)
19869    }
19870
19871    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19872        self.show_cursor_when_unfocused = is_enabled;
19873        cx.notify();
19874    }
19875
19876    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19877        cx.notify();
19878    }
19879
19880    fn on_debug_session_event(
19881        &mut self,
19882        _session: Entity<Session>,
19883        event: &SessionEvent,
19884        cx: &mut Context<Self>,
19885    ) {
19886        if let SessionEvent::InvalidateInlineValue = event {
19887            self.refresh_inline_values(cx);
19888        }
19889    }
19890
19891    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19892        let Some(project) = self.project.clone() else {
19893            return;
19894        };
19895
19896        if !self.inline_value_cache.enabled {
19897            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19898            self.splice_inlays(&inlays, Vec::new(), cx);
19899            return;
19900        }
19901
19902        let current_execution_position = self
19903            .highlighted_rows
19904            .get(&TypeId::of::<ActiveDebugLine>())
19905            .and_then(|lines| lines.last().map(|line| line.range.end));
19906
19907        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19908            let inline_values = editor
19909                .update(cx, |editor, cx| {
19910                    let Some(current_execution_position) = current_execution_position else {
19911                        return Some(Task::ready(Ok(Vec::new())));
19912                    };
19913
19914                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19915                        let snapshot = buffer.snapshot(cx);
19916
19917                        let excerpt = snapshot.excerpt_containing(
19918                            current_execution_position..current_execution_position,
19919                        )?;
19920
19921                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19922                    })?;
19923
19924                    let range =
19925                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19926
19927                    project.inline_values(buffer, range, cx)
19928                })
19929                .ok()
19930                .flatten()?
19931                .await
19932                .context("refreshing debugger inlays")
19933                .log_err()?;
19934
19935            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19936
19937            for (buffer_id, inline_value) in inline_values
19938                .into_iter()
19939                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19940            {
19941                buffer_inline_values
19942                    .entry(buffer_id)
19943                    .or_default()
19944                    .push(inline_value);
19945            }
19946
19947            editor
19948                .update(cx, |editor, cx| {
19949                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19950                    let mut new_inlays = Vec::default();
19951
19952                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19953                        let buffer_id = buffer_snapshot.remote_id();
19954                        buffer_inline_values
19955                            .get(&buffer_id)
19956                            .into_iter()
19957                            .flatten()
19958                            .for_each(|hint| {
19959                                let inlay = Inlay::debugger(
19960                                    post_inc(&mut editor.next_inlay_id),
19961                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19962                                    hint.text(),
19963                                );
19964                                if !inlay.text.chars().contains(&'\n') {
19965                                    new_inlays.push(inlay);
19966                                }
19967                            });
19968                    }
19969
19970                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19971                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19972
19973                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19974                })
19975                .ok()?;
19976            Some(())
19977        });
19978    }
19979
19980    fn on_buffer_event(
19981        &mut self,
19982        multibuffer: &Entity<MultiBuffer>,
19983        event: &multi_buffer::Event,
19984        window: &mut Window,
19985        cx: &mut Context<Self>,
19986    ) {
19987        match event {
19988            multi_buffer::Event::Edited {
19989                singleton_buffer_edited,
19990                edited_buffer,
19991            } => {
19992                self.scrollbar_marker_state.dirty = true;
19993                self.active_indent_guides_state.dirty = true;
19994                self.refresh_active_diagnostics(cx);
19995                self.refresh_code_actions(window, cx);
19996                self.refresh_selected_text_highlights(true, window, cx);
19997                self.refresh_single_line_folds(window, cx);
19998                refresh_matching_bracket_highlights(self, window, cx);
19999                if self.has_active_edit_prediction() {
20000                    self.update_visible_edit_prediction(window, cx);
20001                }
20002                if let Some(project) = self.project.as_ref()
20003                    && let Some(edited_buffer) = edited_buffer
20004                {
20005                    project.update(cx, |project, cx| {
20006                        self.registered_buffers
20007                            .entry(edited_buffer.read(cx).remote_id())
20008                            .or_insert_with(|| {
20009                                project.register_buffer_with_language_servers(edited_buffer, cx)
20010                            });
20011                    });
20012                }
20013                cx.emit(EditorEvent::BufferEdited);
20014                cx.emit(SearchEvent::MatchesInvalidated);
20015
20016                if let Some(buffer) = edited_buffer {
20017                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20018                }
20019
20020                if *singleton_buffer_edited {
20021                    if let Some(buffer) = edited_buffer
20022                        && buffer.read(cx).file().is_none()
20023                    {
20024                        cx.emit(EditorEvent::TitleChanged);
20025                    }
20026                    if let Some(project) = &self.project {
20027                        #[allow(clippy::mutable_key_type)]
20028                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20029                            multibuffer
20030                                .all_buffers()
20031                                .into_iter()
20032                                .filter_map(|buffer| {
20033                                    buffer.update(cx, |buffer, cx| {
20034                                        let language = buffer.language()?;
20035                                        let should_discard = project.update(cx, |project, cx| {
20036                                            project.is_local()
20037                                                && !project.has_language_servers_for(buffer, cx)
20038                                        });
20039                                        should_discard.not().then_some(language.clone())
20040                                    })
20041                                })
20042                                .collect::<HashSet<_>>()
20043                        });
20044                        if !languages_affected.is_empty() {
20045                            self.refresh_inlay_hints(
20046                                InlayHintRefreshReason::BufferEdited(languages_affected),
20047                                cx,
20048                            );
20049                        }
20050                    }
20051                }
20052
20053                let Some(project) = &self.project else { return };
20054                let (telemetry, is_via_ssh) = {
20055                    let project = project.read(cx);
20056                    let telemetry = project.client().telemetry().clone();
20057                    let is_via_ssh = project.is_via_ssh();
20058                    (telemetry, is_via_ssh)
20059                };
20060                refresh_linked_ranges(self, window, cx);
20061                telemetry.log_edit_event("editor", is_via_ssh);
20062            }
20063            multi_buffer::Event::ExcerptsAdded {
20064                buffer,
20065                predecessor,
20066                excerpts,
20067            } => {
20068                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20069                let buffer_id = buffer.read(cx).remote_id();
20070                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20071                    && let Some(project) = &self.project
20072                {
20073                    update_uncommitted_diff_for_buffer(
20074                        cx.entity(),
20075                        project,
20076                        [buffer.clone()],
20077                        self.buffer.clone(),
20078                        cx,
20079                    )
20080                    .detach();
20081                }
20082                self.update_lsp_data(false, Some(buffer_id), window, cx);
20083                cx.emit(EditorEvent::ExcerptsAdded {
20084                    buffer: buffer.clone(),
20085                    predecessor: *predecessor,
20086                    excerpts: excerpts.clone(),
20087                });
20088                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20089            }
20090            multi_buffer::Event::ExcerptsRemoved {
20091                ids,
20092                removed_buffer_ids,
20093            } => {
20094                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20095                let buffer = self.buffer.read(cx);
20096                self.registered_buffers
20097                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20098                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20099                cx.emit(EditorEvent::ExcerptsRemoved {
20100                    ids: ids.clone(),
20101                    removed_buffer_ids: removed_buffer_ids.clone(),
20102                });
20103            }
20104            multi_buffer::Event::ExcerptsEdited {
20105                excerpt_ids,
20106                buffer_ids,
20107            } => {
20108                self.display_map.update(cx, |map, cx| {
20109                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20110                });
20111                cx.emit(EditorEvent::ExcerptsEdited {
20112                    ids: excerpt_ids.clone(),
20113                });
20114            }
20115            multi_buffer::Event::ExcerptsExpanded { ids } => {
20116                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20117                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20118            }
20119            multi_buffer::Event::Reparsed(buffer_id) => {
20120                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20121                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20122
20123                cx.emit(EditorEvent::Reparsed(*buffer_id));
20124            }
20125            multi_buffer::Event::DiffHunksToggled => {
20126                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20127            }
20128            multi_buffer::Event::LanguageChanged(buffer_id) => {
20129                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20130                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20131                cx.emit(EditorEvent::Reparsed(*buffer_id));
20132                cx.notify();
20133            }
20134            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20135            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20136            multi_buffer::Event::FileHandleChanged
20137            | multi_buffer::Event::Reloaded
20138            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20139            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20140            multi_buffer::Event::DiagnosticsUpdated => {
20141                self.update_diagnostics_state(window, cx);
20142            }
20143            _ => {}
20144        };
20145    }
20146
20147    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20148        if !self.diagnostics_enabled() {
20149            return;
20150        }
20151        self.refresh_active_diagnostics(cx);
20152        self.refresh_inline_diagnostics(true, window, cx);
20153        self.scrollbar_marker_state.dirty = true;
20154        cx.notify();
20155    }
20156
20157    pub fn start_temporary_diff_override(&mut self) {
20158        self.load_diff_task.take();
20159        self.temporary_diff_override = true;
20160    }
20161
20162    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20163        self.temporary_diff_override = false;
20164        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20165        self.buffer.update(cx, |buffer, cx| {
20166            buffer.set_all_diff_hunks_collapsed(cx);
20167        });
20168
20169        if let Some(project) = self.project.clone() {
20170            self.load_diff_task = Some(
20171                update_uncommitted_diff_for_buffer(
20172                    cx.entity(),
20173                    &project,
20174                    self.buffer.read(cx).all_buffers(),
20175                    self.buffer.clone(),
20176                    cx,
20177                )
20178                .shared(),
20179            );
20180        }
20181    }
20182
20183    fn on_display_map_changed(
20184        &mut self,
20185        _: Entity<DisplayMap>,
20186        _: &mut Window,
20187        cx: &mut Context<Self>,
20188    ) {
20189        cx.notify();
20190    }
20191
20192    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20193        if self.diagnostics_enabled() {
20194            let new_severity = EditorSettings::get_global(cx)
20195                .diagnostics_max_severity
20196                .unwrap_or(DiagnosticSeverity::Hint);
20197            self.set_max_diagnostics_severity(new_severity, cx);
20198        }
20199        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20200        self.update_edit_prediction_settings(cx);
20201        self.refresh_edit_prediction(true, false, window, cx);
20202        self.refresh_inline_values(cx);
20203        self.refresh_inlay_hints(
20204            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20205                self.selections.newest_anchor().head(),
20206                &self.buffer.read(cx).snapshot(cx),
20207                cx,
20208            )),
20209            cx,
20210        );
20211
20212        let old_cursor_shape = self.cursor_shape;
20213        let old_show_breadcrumbs = self.show_breadcrumbs;
20214
20215        {
20216            let editor_settings = EditorSettings::get_global(cx);
20217            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20218            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20219            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20220            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20221        }
20222
20223        if old_cursor_shape != self.cursor_shape {
20224            cx.emit(EditorEvent::CursorShapeChanged);
20225        }
20226
20227        if old_show_breadcrumbs != self.show_breadcrumbs {
20228            cx.emit(EditorEvent::BreadcrumbsChanged);
20229        }
20230
20231        let project_settings = ProjectSettings::get_global(cx);
20232        self.serialize_dirty_buffers =
20233            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20234
20235        if self.mode.is_full() {
20236            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20237            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20238            if self.show_inline_diagnostics != show_inline_diagnostics {
20239                self.show_inline_diagnostics = show_inline_diagnostics;
20240                self.refresh_inline_diagnostics(false, window, cx);
20241            }
20242
20243            if self.git_blame_inline_enabled != inline_blame_enabled {
20244                self.toggle_git_blame_inline_internal(false, window, cx);
20245            }
20246
20247            let minimap_settings = EditorSettings::get_global(cx).minimap;
20248            if self.minimap_visibility != MinimapVisibility::Disabled {
20249                if self.minimap_visibility.settings_visibility()
20250                    != minimap_settings.minimap_enabled()
20251                {
20252                    self.set_minimap_visibility(
20253                        MinimapVisibility::for_mode(self.mode(), cx),
20254                        window,
20255                        cx,
20256                    );
20257                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20258                    minimap_entity.update(cx, |minimap_editor, cx| {
20259                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20260                    })
20261                }
20262            }
20263        }
20264
20265        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20266            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20267        }) {
20268            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20269                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20270            }
20271            self.refresh_colors(false, None, window, cx);
20272        }
20273
20274        cx.notify();
20275    }
20276
20277    pub fn set_searchable(&mut self, searchable: bool) {
20278        self.searchable = searchable;
20279    }
20280
20281    pub fn searchable(&self) -> bool {
20282        self.searchable
20283    }
20284
20285    fn open_proposed_changes_editor(
20286        &mut self,
20287        _: &OpenProposedChangesEditor,
20288        window: &mut Window,
20289        cx: &mut Context<Self>,
20290    ) {
20291        let Some(workspace) = self.workspace() else {
20292            cx.propagate();
20293            return;
20294        };
20295
20296        let selections = self.selections.all::<usize>(cx);
20297        let multi_buffer = self.buffer.read(cx);
20298        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20299        let mut new_selections_by_buffer = HashMap::default();
20300        for selection in selections {
20301            for (buffer, range, _) in
20302                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20303            {
20304                let mut range = range.to_point(buffer);
20305                range.start.column = 0;
20306                range.end.column = buffer.line_len(range.end.row);
20307                new_selections_by_buffer
20308                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20309                    .or_insert(Vec::new())
20310                    .push(range)
20311            }
20312        }
20313
20314        let proposed_changes_buffers = new_selections_by_buffer
20315            .into_iter()
20316            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20317            .collect::<Vec<_>>();
20318        let proposed_changes_editor = cx.new(|cx| {
20319            ProposedChangesEditor::new(
20320                "Proposed changes",
20321                proposed_changes_buffers,
20322                self.project.clone(),
20323                window,
20324                cx,
20325            )
20326        });
20327
20328        window.defer(cx, move |window, cx| {
20329            workspace.update(cx, |workspace, cx| {
20330                workspace.active_pane().update(cx, |pane, cx| {
20331                    pane.add_item(
20332                        Box::new(proposed_changes_editor),
20333                        true,
20334                        true,
20335                        None,
20336                        window,
20337                        cx,
20338                    );
20339                });
20340            });
20341        });
20342    }
20343
20344    pub fn open_excerpts_in_split(
20345        &mut self,
20346        _: &OpenExcerptsSplit,
20347        window: &mut Window,
20348        cx: &mut Context<Self>,
20349    ) {
20350        self.open_excerpts_common(None, true, window, cx)
20351    }
20352
20353    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20354        self.open_excerpts_common(None, false, window, cx)
20355    }
20356
20357    fn open_excerpts_common(
20358        &mut self,
20359        jump_data: Option<JumpData>,
20360        split: bool,
20361        window: &mut Window,
20362        cx: &mut Context<Self>,
20363    ) {
20364        let Some(workspace) = self.workspace() else {
20365            cx.propagate();
20366            return;
20367        };
20368
20369        if self.buffer.read(cx).is_singleton() {
20370            cx.propagate();
20371            return;
20372        }
20373
20374        let mut new_selections_by_buffer = HashMap::default();
20375        match &jump_data {
20376            Some(JumpData::MultiBufferPoint {
20377                excerpt_id,
20378                position,
20379                anchor,
20380                line_offset_from_top,
20381            }) => {
20382                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20383                if let Some(buffer) = multi_buffer_snapshot
20384                    .buffer_id_for_excerpt(*excerpt_id)
20385                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20386                {
20387                    let buffer_snapshot = buffer.read(cx).snapshot();
20388                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20389                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20390                    } else {
20391                        buffer_snapshot.clip_point(*position, Bias::Left)
20392                    };
20393                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20394                    new_selections_by_buffer.insert(
20395                        buffer,
20396                        (
20397                            vec![jump_to_offset..jump_to_offset],
20398                            Some(*line_offset_from_top),
20399                        ),
20400                    );
20401                }
20402            }
20403            Some(JumpData::MultiBufferRow {
20404                row,
20405                line_offset_from_top,
20406            }) => {
20407                let point = MultiBufferPoint::new(row.0, 0);
20408                if let Some((buffer, buffer_point, _)) =
20409                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20410                {
20411                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20412                    new_selections_by_buffer
20413                        .entry(buffer)
20414                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20415                        .0
20416                        .push(buffer_offset..buffer_offset)
20417                }
20418            }
20419            None => {
20420                let selections = self.selections.all::<usize>(cx);
20421                let multi_buffer = self.buffer.read(cx);
20422                for selection in selections {
20423                    for (snapshot, range, _, anchor) in multi_buffer
20424                        .snapshot(cx)
20425                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20426                    {
20427                        if let Some(anchor) = anchor {
20428                            // selection is in a deleted hunk
20429                            let Some(buffer_id) = anchor.buffer_id else {
20430                                continue;
20431                            };
20432                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20433                                continue;
20434                            };
20435                            let offset = text::ToOffset::to_offset(
20436                                &anchor.text_anchor,
20437                                &buffer_handle.read(cx).snapshot(),
20438                            );
20439                            let range = offset..offset;
20440                            new_selections_by_buffer
20441                                .entry(buffer_handle)
20442                                .or_insert((Vec::new(), None))
20443                                .0
20444                                .push(range)
20445                        } else {
20446                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20447                            else {
20448                                continue;
20449                            };
20450                            new_selections_by_buffer
20451                                .entry(buffer_handle)
20452                                .or_insert((Vec::new(), None))
20453                                .0
20454                                .push(range)
20455                        }
20456                    }
20457                }
20458            }
20459        }
20460
20461        new_selections_by_buffer
20462            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20463
20464        if new_selections_by_buffer.is_empty() {
20465            return;
20466        }
20467
20468        // We defer the pane interaction because we ourselves are a workspace item
20469        // and activating a new item causes the pane to call a method on us reentrantly,
20470        // which panics if we're on the stack.
20471        window.defer(cx, move |window, cx| {
20472            workspace.update(cx, |workspace, cx| {
20473                let pane = if split {
20474                    workspace.adjacent_pane(window, cx)
20475                } else {
20476                    workspace.active_pane().clone()
20477                };
20478
20479                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20480                    let editor = buffer
20481                        .read(cx)
20482                        .file()
20483                        .is_none()
20484                        .then(|| {
20485                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20486                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20487                            // Instead, we try to activate the existing editor in the pane first.
20488                            let (editor, pane_item_index) =
20489                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20490                                    let editor = item.downcast::<Editor>()?;
20491                                    let singleton_buffer =
20492                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20493                                    if singleton_buffer == buffer {
20494                                        Some((editor, i))
20495                                    } else {
20496                                        None
20497                                    }
20498                                })?;
20499                            pane.update(cx, |pane, cx| {
20500                                pane.activate_item(pane_item_index, true, true, window, cx)
20501                            });
20502                            Some(editor)
20503                        })
20504                        .flatten()
20505                        .unwrap_or_else(|| {
20506                            workspace.open_project_item::<Self>(
20507                                pane.clone(),
20508                                buffer,
20509                                true,
20510                                true,
20511                                window,
20512                                cx,
20513                            )
20514                        });
20515
20516                    editor.update(cx, |editor, cx| {
20517                        let autoscroll = match scroll_offset {
20518                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20519                            None => Autoscroll::newest(),
20520                        };
20521                        let nav_history = editor.nav_history.take();
20522                        editor.change_selections(
20523                            SelectionEffects::scroll(autoscroll),
20524                            window,
20525                            cx,
20526                            |s| {
20527                                s.select_ranges(ranges);
20528                            },
20529                        );
20530                        editor.nav_history = nav_history;
20531                    });
20532                }
20533            })
20534        });
20535    }
20536
20537    // For now, don't allow opening excerpts in buffers that aren't backed by
20538    // regular project files.
20539    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20540        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20541    }
20542
20543    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20544        let snapshot = self.buffer.read(cx).read(cx);
20545        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20546        Some(
20547            ranges
20548                .iter()
20549                .map(move |range| {
20550                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20551                })
20552                .collect(),
20553        )
20554    }
20555
20556    fn selection_replacement_ranges(
20557        &self,
20558        range: Range<OffsetUtf16>,
20559        cx: &mut App,
20560    ) -> Vec<Range<OffsetUtf16>> {
20561        let selections = self.selections.all::<OffsetUtf16>(cx);
20562        let newest_selection = selections
20563            .iter()
20564            .max_by_key(|selection| selection.id)
20565            .unwrap();
20566        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20567        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20568        let snapshot = self.buffer.read(cx).read(cx);
20569        selections
20570            .into_iter()
20571            .map(|mut selection| {
20572                selection.start.0 =
20573                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20574                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20575                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20576                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20577            })
20578            .collect()
20579    }
20580
20581    fn report_editor_event(
20582        &self,
20583        reported_event: ReportEditorEvent,
20584        file_extension: Option<String>,
20585        cx: &App,
20586    ) {
20587        if cfg!(any(test, feature = "test-support")) {
20588            return;
20589        }
20590
20591        let Some(project) = &self.project else { return };
20592
20593        // If None, we are in a file without an extension
20594        let file = self
20595            .buffer
20596            .read(cx)
20597            .as_singleton()
20598            .and_then(|b| b.read(cx).file());
20599        let file_extension = file_extension.or(file
20600            .as_ref()
20601            .and_then(|file| Path::new(file.file_name(cx)).extension())
20602            .and_then(|e| e.to_str())
20603            .map(|a| a.to_string()));
20604
20605        let vim_mode = vim_enabled(cx);
20606
20607        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20608        let copilot_enabled = edit_predictions_provider
20609            == language::language_settings::EditPredictionProvider::Copilot;
20610        let copilot_enabled_for_language = self
20611            .buffer
20612            .read(cx)
20613            .language_settings(cx)
20614            .show_edit_predictions;
20615
20616        let project = project.read(cx);
20617        let event_type = reported_event.event_type();
20618
20619        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20620            telemetry::event!(
20621                event_type,
20622                type = if auto_saved {"autosave"} else {"manual"},
20623                file_extension,
20624                vim_mode,
20625                copilot_enabled,
20626                copilot_enabled_for_language,
20627                edit_predictions_provider,
20628                is_via_ssh = project.is_via_ssh(),
20629            );
20630        } else {
20631            telemetry::event!(
20632                event_type,
20633                file_extension,
20634                vim_mode,
20635                copilot_enabled,
20636                copilot_enabled_for_language,
20637                edit_predictions_provider,
20638                is_via_ssh = project.is_via_ssh(),
20639            );
20640        };
20641    }
20642
20643    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20644    /// with each line being an array of {text, highlight} objects.
20645    fn copy_highlight_json(
20646        &mut self,
20647        _: &CopyHighlightJson,
20648        window: &mut Window,
20649        cx: &mut Context<Self>,
20650    ) {
20651        #[derive(Serialize)]
20652        struct Chunk<'a> {
20653            text: String,
20654            highlight: Option<&'a str>,
20655        }
20656
20657        let snapshot = self.buffer.read(cx).snapshot(cx);
20658        let range = self
20659            .selected_text_range(false, window, cx)
20660            .and_then(|selection| {
20661                if selection.range.is_empty() {
20662                    None
20663                } else {
20664                    Some(selection.range)
20665                }
20666            })
20667            .unwrap_or_else(|| 0..snapshot.len());
20668
20669        let chunks = snapshot.chunks(range, true);
20670        let mut lines = Vec::new();
20671        let mut line: VecDeque<Chunk> = VecDeque::new();
20672
20673        let Some(style) = self.style.as_ref() else {
20674            return;
20675        };
20676
20677        for chunk in chunks {
20678            let highlight = chunk
20679                .syntax_highlight_id
20680                .and_then(|id| id.name(&style.syntax));
20681            let mut chunk_lines = chunk.text.split('\n').peekable();
20682            while let Some(text) = chunk_lines.next() {
20683                let mut merged_with_last_token = false;
20684                if let Some(last_token) = line.back_mut()
20685                    && last_token.highlight == highlight
20686                {
20687                    last_token.text.push_str(text);
20688                    merged_with_last_token = true;
20689                }
20690
20691                if !merged_with_last_token {
20692                    line.push_back(Chunk {
20693                        text: text.into(),
20694                        highlight,
20695                    });
20696                }
20697
20698                if chunk_lines.peek().is_some() {
20699                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20700                        line.pop_front();
20701                    }
20702                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20703                        line.pop_back();
20704                    }
20705
20706                    lines.push(mem::take(&mut line));
20707                }
20708            }
20709        }
20710
20711        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20712            return;
20713        };
20714        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20715    }
20716
20717    pub fn open_context_menu(
20718        &mut self,
20719        _: &OpenContextMenu,
20720        window: &mut Window,
20721        cx: &mut Context<Self>,
20722    ) {
20723        self.request_autoscroll(Autoscroll::newest(), cx);
20724        let position = self.selections.newest_display(cx).start;
20725        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20726    }
20727
20728    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20729        &self.inlay_hint_cache
20730    }
20731
20732    pub fn replay_insert_event(
20733        &mut self,
20734        text: &str,
20735        relative_utf16_range: Option<Range<isize>>,
20736        window: &mut Window,
20737        cx: &mut Context<Self>,
20738    ) {
20739        if !self.input_enabled {
20740            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20741            return;
20742        }
20743        if let Some(relative_utf16_range) = relative_utf16_range {
20744            let selections = self.selections.all::<OffsetUtf16>(cx);
20745            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20746                let new_ranges = selections.into_iter().map(|range| {
20747                    let start = OffsetUtf16(
20748                        range
20749                            .head()
20750                            .0
20751                            .saturating_add_signed(relative_utf16_range.start),
20752                    );
20753                    let end = OffsetUtf16(
20754                        range
20755                            .head()
20756                            .0
20757                            .saturating_add_signed(relative_utf16_range.end),
20758                    );
20759                    start..end
20760                });
20761                s.select_ranges(new_ranges);
20762            });
20763        }
20764
20765        self.handle_input(text, window, cx);
20766    }
20767
20768    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20769        let Some(provider) = self.semantics_provider.as_ref() else {
20770            return false;
20771        };
20772
20773        let mut supports = false;
20774        self.buffer().update(cx, |this, cx| {
20775            this.for_each_buffer(|buffer| {
20776                supports |= provider.supports_inlay_hints(buffer, cx);
20777            });
20778        });
20779
20780        supports
20781    }
20782
20783    pub fn is_focused(&self, window: &Window) -> bool {
20784        self.focus_handle.is_focused(window)
20785    }
20786
20787    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20788        cx.emit(EditorEvent::Focused);
20789
20790        if let Some(descendant) = self
20791            .last_focused_descendant
20792            .take()
20793            .and_then(|descendant| descendant.upgrade())
20794        {
20795            window.focus(&descendant);
20796        } else {
20797            if let Some(blame) = self.blame.as_ref() {
20798                blame.update(cx, GitBlame::focus)
20799            }
20800
20801            self.blink_manager.update(cx, BlinkManager::enable);
20802            self.show_cursor_names(window, cx);
20803            self.buffer.update(cx, |buffer, cx| {
20804                buffer.finalize_last_transaction(cx);
20805                if self.leader_id.is_none() {
20806                    buffer.set_active_selections(
20807                        &self.selections.disjoint_anchors(),
20808                        self.selections.line_mode,
20809                        self.cursor_shape,
20810                        cx,
20811                    );
20812                }
20813            });
20814        }
20815    }
20816
20817    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20818        cx.emit(EditorEvent::FocusedIn)
20819    }
20820
20821    fn handle_focus_out(
20822        &mut self,
20823        event: FocusOutEvent,
20824        _window: &mut Window,
20825        cx: &mut Context<Self>,
20826    ) {
20827        if event.blurred != self.focus_handle {
20828            self.last_focused_descendant = Some(event.blurred);
20829        }
20830        self.selection_drag_state = SelectionDragState::None;
20831        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20832    }
20833
20834    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20835        self.blink_manager.update(cx, BlinkManager::disable);
20836        self.buffer
20837            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20838
20839        if let Some(blame) = self.blame.as_ref() {
20840            blame.update(cx, GitBlame::blur)
20841        }
20842        if !self.hover_state.focused(window, cx) {
20843            hide_hover(self, cx);
20844        }
20845        if !self
20846            .context_menu
20847            .borrow()
20848            .as_ref()
20849            .is_some_and(|context_menu| context_menu.focused(window, cx))
20850        {
20851            self.hide_context_menu(window, cx);
20852        }
20853        self.discard_edit_prediction(false, cx);
20854        cx.emit(EditorEvent::Blurred);
20855        cx.notify();
20856    }
20857
20858    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20859        let mut pending: String = window
20860            .pending_input_keystrokes()
20861            .into_iter()
20862            .flatten()
20863            .filter_map(|keystroke| {
20864                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20865                    keystroke.key_char.clone()
20866                } else {
20867                    None
20868                }
20869            })
20870            .collect();
20871
20872        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20873            pending = "".to_string();
20874        }
20875
20876        let existing_pending = self
20877            .text_highlights::<PendingInput>(cx)
20878            .map(|(_, ranges)| ranges.to_vec());
20879        if existing_pending.is_none() && pending.is_empty() {
20880            return;
20881        }
20882        let transaction =
20883            self.transact(window, cx, |this, window, cx| {
20884                let selections = this.selections.all::<usize>(cx);
20885                let edits = selections
20886                    .iter()
20887                    .map(|selection| (selection.end..selection.end, pending.clone()));
20888                this.edit(edits, cx);
20889                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20890                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20891                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20892                    }));
20893                });
20894                if let Some(existing_ranges) = existing_pending {
20895                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20896                    this.edit(edits, cx);
20897                }
20898            });
20899
20900        let snapshot = self.snapshot(window, cx);
20901        let ranges = self
20902            .selections
20903            .all::<usize>(cx)
20904            .into_iter()
20905            .map(|selection| {
20906                snapshot.buffer_snapshot.anchor_after(selection.end)
20907                    ..snapshot
20908                        .buffer_snapshot
20909                        .anchor_before(selection.end + pending.len())
20910            })
20911            .collect();
20912
20913        if pending.is_empty() {
20914            self.clear_highlights::<PendingInput>(cx);
20915        } else {
20916            self.highlight_text::<PendingInput>(
20917                ranges,
20918                HighlightStyle {
20919                    underline: Some(UnderlineStyle {
20920                        thickness: px(1.),
20921                        color: None,
20922                        wavy: false,
20923                    }),
20924                    ..Default::default()
20925                },
20926                cx,
20927            );
20928        }
20929
20930        self.ime_transaction = self.ime_transaction.or(transaction);
20931        if let Some(transaction) = self.ime_transaction {
20932            self.buffer.update(cx, |buffer, cx| {
20933                buffer.group_until_transaction(transaction, cx);
20934            });
20935        }
20936
20937        if self.text_highlights::<PendingInput>(cx).is_none() {
20938            self.ime_transaction.take();
20939        }
20940    }
20941
20942    pub fn register_action_renderer(
20943        &mut self,
20944        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20945    ) -> Subscription {
20946        let id = self.next_editor_action_id.post_inc();
20947        self.editor_actions
20948            .borrow_mut()
20949            .insert(id, Box::new(listener));
20950
20951        let editor_actions = self.editor_actions.clone();
20952        Subscription::new(move || {
20953            editor_actions.borrow_mut().remove(&id);
20954        })
20955    }
20956
20957    pub fn register_action<A: Action>(
20958        &mut self,
20959        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20960    ) -> Subscription {
20961        let id = self.next_editor_action_id.post_inc();
20962        let listener = Arc::new(listener);
20963        self.editor_actions.borrow_mut().insert(
20964            id,
20965            Box::new(move |_, window, _| {
20966                let listener = listener.clone();
20967                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20968                    let action = action.downcast_ref().unwrap();
20969                    if phase == DispatchPhase::Bubble {
20970                        listener(action, window, cx)
20971                    }
20972                })
20973            }),
20974        );
20975
20976        let editor_actions = self.editor_actions.clone();
20977        Subscription::new(move || {
20978            editor_actions.borrow_mut().remove(&id);
20979        })
20980    }
20981
20982    pub fn file_header_size(&self) -> u32 {
20983        FILE_HEADER_HEIGHT
20984    }
20985
20986    pub fn restore(
20987        &mut self,
20988        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20989        window: &mut Window,
20990        cx: &mut Context<Self>,
20991    ) {
20992        let workspace = self.workspace();
20993        let project = self.project();
20994        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20995            let mut tasks = Vec::new();
20996            for (buffer_id, changes) in revert_changes {
20997                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20998                    buffer.update(cx, |buffer, cx| {
20999                        buffer.edit(
21000                            changes
21001                                .into_iter()
21002                                .map(|(range, text)| (range, text.to_string())),
21003                            None,
21004                            cx,
21005                        );
21006                    });
21007
21008                    if let Some(project) =
21009                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21010                    {
21011                        project.update(cx, |project, cx| {
21012                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21013                        })
21014                    }
21015                }
21016            }
21017            tasks
21018        });
21019        cx.spawn_in(window, async move |_, cx| {
21020            for (buffer, task) in save_tasks {
21021                let result = task.await;
21022                if result.is_err() {
21023                    let Some(path) = buffer
21024                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21025                        .ok()
21026                    else {
21027                        continue;
21028                    };
21029                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21030                        let Some(task) = cx
21031                            .update_window_entity(workspace, |workspace, window, cx| {
21032                                workspace
21033                                    .open_path_preview(path, None, false, false, false, window, cx)
21034                            })
21035                            .ok()
21036                        else {
21037                            continue;
21038                        };
21039                        task.await.log_err();
21040                    }
21041                }
21042            }
21043        })
21044        .detach();
21045        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21046            selections.refresh()
21047        });
21048    }
21049
21050    pub fn to_pixel_point(
21051        &self,
21052        source: multi_buffer::Anchor,
21053        editor_snapshot: &EditorSnapshot,
21054        window: &mut Window,
21055    ) -> Option<gpui::Point<Pixels>> {
21056        let source_point = source.to_display_point(editor_snapshot);
21057        self.display_to_pixel_point(source_point, editor_snapshot, window)
21058    }
21059
21060    pub fn display_to_pixel_point(
21061        &self,
21062        source: DisplayPoint,
21063        editor_snapshot: &EditorSnapshot,
21064        window: &mut Window,
21065    ) -> Option<gpui::Point<Pixels>> {
21066        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21067        let text_layout_details = self.text_layout_details(window);
21068        let scroll_top = text_layout_details
21069            .scroll_anchor
21070            .scroll_position(editor_snapshot)
21071            .y;
21072
21073        if source.row().as_f32() < scroll_top.floor() {
21074            return None;
21075        }
21076        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21077        let source_y = line_height * (source.row().as_f32() - scroll_top);
21078        Some(gpui::Point::new(source_x, source_y))
21079    }
21080
21081    pub fn has_visible_completions_menu(&self) -> bool {
21082        !self.edit_prediction_preview_is_active()
21083            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21084                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21085            })
21086    }
21087
21088    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21089        if self.mode.is_minimap() {
21090            return;
21091        }
21092        self.addons
21093            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21094    }
21095
21096    pub fn unregister_addon<T: Addon>(&mut self) {
21097        self.addons.remove(&std::any::TypeId::of::<T>());
21098    }
21099
21100    pub fn addon<T: Addon>(&self) -> Option<&T> {
21101        let type_id = std::any::TypeId::of::<T>();
21102        self.addons
21103            .get(&type_id)
21104            .and_then(|item| item.to_any().downcast_ref::<T>())
21105    }
21106
21107    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21108        let type_id = std::any::TypeId::of::<T>();
21109        self.addons
21110            .get_mut(&type_id)
21111            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21112    }
21113
21114    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21115        let text_layout_details = self.text_layout_details(window);
21116        let style = &text_layout_details.editor_style;
21117        let font_id = window.text_system().resolve_font(&style.text.font());
21118        let font_size = style.text.font_size.to_pixels(window.rem_size());
21119        let line_height = style.text.line_height_in_pixels(window.rem_size());
21120        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21121        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21122
21123        CharacterDimensions {
21124            em_width,
21125            em_advance,
21126            line_height,
21127        }
21128    }
21129
21130    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21131        self.load_diff_task.clone()
21132    }
21133
21134    fn read_metadata_from_db(
21135        &mut self,
21136        item_id: u64,
21137        workspace_id: WorkspaceId,
21138        window: &mut Window,
21139        cx: &mut Context<Editor>,
21140    ) {
21141        if self.is_singleton(cx)
21142            && !self.mode.is_minimap()
21143            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21144        {
21145            let buffer_snapshot = OnceCell::new();
21146
21147            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21148                && !folds.is_empty()
21149            {
21150                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21151                self.fold_ranges(
21152                    folds
21153                        .into_iter()
21154                        .map(|(start, end)| {
21155                            snapshot.clip_offset(start, Bias::Left)
21156                                ..snapshot.clip_offset(end, Bias::Right)
21157                        })
21158                        .collect(),
21159                    false,
21160                    window,
21161                    cx,
21162                );
21163            }
21164
21165            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21166                && !selections.is_empty()
21167            {
21168                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21169                // skip adding the initial selection to selection history
21170                self.selection_history.mode = SelectionHistoryMode::Skipping;
21171                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21172                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21173                        snapshot.clip_offset(start, Bias::Left)
21174                            ..snapshot.clip_offset(end, Bias::Right)
21175                    }));
21176                });
21177                self.selection_history.mode = SelectionHistoryMode::Normal;
21178            };
21179        }
21180
21181        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21182    }
21183
21184    fn update_lsp_data(
21185        &mut self,
21186        ignore_cache: bool,
21187        for_buffer: Option<BufferId>,
21188        window: &mut Window,
21189        cx: &mut Context<'_, Self>,
21190    ) {
21191        self.pull_diagnostics(for_buffer, window, cx);
21192        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21193    }
21194}
21195
21196fn vim_enabled(cx: &App) -> bool {
21197    cx.global::<SettingsStore>()
21198        .raw_user_settings()
21199        .get("vim_mode")
21200        == Some(&serde_json::Value::Bool(true))
21201}
21202
21203fn process_completion_for_edit(
21204    completion: &Completion,
21205    intent: CompletionIntent,
21206    buffer: &Entity<Buffer>,
21207    cursor_position: &text::Anchor,
21208    cx: &mut Context<Editor>,
21209) -> CompletionEdit {
21210    let buffer = buffer.read(cx);
21211    let buffer_snapshot = buffer.snapshot();
21212    let (snippet, new_text) = if completion.is_snippet() {
21213        // Workaround for typescript language server issues so that methods don't expand within
21214        // strings and functions with type expressions. The previous point is used because the query
21215        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21216        let mut snippet_source = completion.new_text.clone();
21217        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21218        previous_point.column = previous_point.column.saturating_sub(1);
21219        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21220            && scope.prefers_label_for_snippet_in_completion()
21221            && let Some(label) = completion.label()
21222            && matches!(
21223                completion.kind(),
21224                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21225            )
21226        {
21227            snippet_source = label;
21228        }
21229        match Snippet::parse(&snippet_source).log_err() {
21230            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21231            None => (None, completion.new_text.clone()),
21232        }
21233    } else {
21234        (None, completion.new_text.clone())
21235    };
21236
21237    let mut range_to_replace = {
21238        let replace_range = &completion.replace_range;
21239        if let CompletionSource::Lsp {
21240            insert_range: Some(insert_range),
21241            ..
21242        } = &completion.source
21243        {
21244            debug_assert_eq!(
21245                insert_range.start, replace_range.start,
21246                "insert_range and replace_range should start at the same position"
21247            );
21248            debug_assert!(
21249                insert_range
21250                    .start
21251                    .cmp(cursor_position, &buffer_snapshot)
21252                    .is_le(),
21253                "insert_range should start before or at cursor position"
21254            );
21255            debug_assert!(
21256                replace_range
21257                    .start
21258                    .cmp(cursor_position, &buffer_snapshot)
21259                    .is_le(),
21260                "replace_range should start before or at cursor position"
21261            );
21262
21263            let should_replace = match intent {
21264                CompletionIntent::CompleteWithInsert => false,
21265                CompletionIntent::CompleteWithReplace => true,
21266                CompletionIntent::Complete | CompletionIntent::Compose => {
21267                    let insert_mode =
21268                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21269                            .completions
21270                            .lsp_insert_mode;
21271                    match insert_mode {
21272                        LspInsertMode::Insert => false,
21273                        LspInsertMode::Replace => true,
21274                        LspInsertMode::ReplaceSubsequence => {
21275                            let mut text_to_replace = buffer.chars_for_range(
21276                                buffer.anchor_before(replace_range.start)
21277                                    ..buffer.anchor_after(replace_range.end),
21278                            );
21279                            let mut current_needle = text_to_replace.next();
21280                            for haystack_ch in completion.label.text.chars() {
21281                                if let Some(needle_ch) = current_needle
21282                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21283                                {
21284                                    current_needle = text_to_replace.next();
21285                                }
21286                            }
21287                            current_needle.is_none()
21288                        }
21289                        LspInsertMode::ReplaceSuffix => {
21290                            if replace_range
21291                                .end
21292                                .cmp(cursor_position, &buffer_snapshot)
21293                                .is_gt()
21294                            {
21295                                let range_after_cursor = *cursor_position..replace_range.end;
21296                                let text_after_cursor = buffer
21297                                    .text_for_range(
21298                                        buffer.anchor_before(range_after_cursor.start)
21299                                            ..buffer.anchor_after(range_after_cursor.end),
21300                                    )
21301                                    .collect::<String>()
21302                                    .to_ascii_lowercase();
21303                                completion
21304                                    .label
21305                                    .text
21306                                    .to_ascii_lowercase()
21307                                    .ends_with(&text_after_cursor)
21308                            } else {
21309                                true
21310                            }
21311                        }
21312                    }
21313                }
21314            };
21315
21316            if should_replace {
21317                replace_range.clone()
21318            } else {
21319                insert_range.clone()
21320            }
21321        } else {
21322            replace_range.clone()
21323        }
21324    };
21325
21326    if range_to_replace
21327        .end
21328        .cmp(cursor_position, &buffer_snapshot)
21329        .is_lt()
21330    {
21331        range_to_replace.end = *cursor_position;
21332    }
21333
21334    CompletionEdit {
21335        new_text,
21336        replace_range: range_to_replace.to_offset(buffer),
21337        snippet,
21338    }
21339}
21340
21341struct CompletionEdit {
21342    new_text: String,
21343    replace_range: Range<usize>,
21344    snippet: Option<Snippet>,
21345}
21346
21347fn insert_extra_newline_brackets(
21348    buffer: &MultiBufferSnapshot,
21349    range: Range<usize>,
21350    language: &language::LanguageScope,
21351) -> bool {
21352    let leading_whitespace_len = buffer
21353        .reversed_chars_at(range.start)
21354        .take_while(|c| c.is_whitespace() && *c != '\n')
21355        .map(|c| c.len_utf8())
21356        .sum::<usize>();
21357    let trailing_whitespace_len = buffer
21358        .chars_at(range.end)
21359        .take_while(|c| c.is_whitespace() && *c != '\n')
21360        .map(|c| c.len_utf8())
21361        .sum::<usize>();
21362    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21363
21364    language.brackets().any(|(pair, enabled)| {
21365        let pair_start = pair.start.trim_end();
21366        let pair_end = pair.end.trim_start();
21367
21368        enabled
21369            && pair.newline
21370            && buffer.contains_str_at(range.end, pair_end)
21371            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21372    })
21373}
21374
21375fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21376    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21377        [(buffer, range, _)] => (*buffer, range.clone()),
21378        _ => return false,
21379    };
21380    let pair = {
21381        let mut result: Option<BracketMatch> = None;
21382
21383        for pair in buffer
21384            .all_bracket_ranges(range.clone())
21385            .filter(move |pair| {
21386                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21387            })
21388        {
21389            let len = pair.close_range.end - pair.open_range.start;
21390
21391            if let Some(existing) = &result {
21392                let existing_len = existing.close_range.end - existing.open_range.start;
21393                if len > existing_len {
21394                    continue;
21395                }
21396            }
21397
21398            result = Some(pair);
21399        }
21400
21401        result
21402    };
21403    let Some(pair) = pair else {
21404        return false;
21405    };
21406    pair.newline_only
21407        && buffer
21408            .chars_for_range(pair.open_range.end..range.start)
21409            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21410            .all(|c| c.is_whitespace() && c != '\n')
21411}
21412
21413fn update_uncommitted_diff_for_buffer(
21414    editor: Entity<Editor>,
21415    project: &Entity<Project>,
21416    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21417    buffer: Entity<MultiBuffer>,
21418    cx: &mut App,
21419) -> Task<()> {
21420    let mut tasks = Vec::new();
21421    project.update(cx, |project, cx| {
21422        for buffer in buffers {
21423            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21424                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21425            }
21426        }
21427    });
21428    cx.spawn(async move |cx| {
21429        let diffs = future::join_all(tasks).await;
21430        if editor
21431            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21432            .unwrap_or(false)
21433        {
21434            return;
21435        }
21436
21437        buffer
21438            .update(cx, |buffer, cx| {
21439                for diff in diffs.into_iter().flatten() {
21440                    buffer.add_diff(diff, cx);
21441                }
21442            })
21443            .ok();
21444    })
21445}
21446
21447fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21448    let tab_size = tab_size.get() as usize;
21449    let mut width = offset;
21450
21451    for ch in text.chars() {
21452        width += if ch == '\t' {
21453            tab_size - (width % tab_size)
21454        } else {
21455            1
21456        };
21457    }
21458
21459    width - offset
21460}
21461
21462#[cfg(test)]
21463mod tests {
21464    use super::*;
21465
21466    #[test]
21467    fn test_string_size_with_expanded_tabs() {
21468        let nz = |val| NonZeroU32::new(val).unwrap();
21469        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21470        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21471        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21472        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21473        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21474        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21475        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21476        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21477    }
21478}
21479
21480/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21481struct WordBreakingTokenizer<'a> {
21482    input: &'a str,
21483}
21484
21485impl<'a> WordBreakingTokenizer<'a> {
21486    fn new(input: &'a str) -> Self {
21487        Self { input }
21488    }
21489}
21490
21491fn is_char_ideographic(ch: char) -> bool {
21492    use unicode_script::Script::*;
21493    use unicode_script::UnicodeScript;
21494    matches!(ch.script(), Han | Tangut | Yi)
21495}
21496
21497fn is_grapheme_ideographic(text: &str) -> bool {
21498    text.chars().any(is_char_ideographic)
21499}
21500
21501fn is_grapheme_whitespace(text: &str) -> bool {
21502    text.chars().any(|x| x.is_whitespace())
21503}
21504
21505fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21506    text.chars()
21507        .next()
21508        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21509}
21510
21511#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21512enum WordBreakToken<'a> {
21513    Word { token: &'a str, grapheme_len: usize },
21514    InlineWhitespace { token: &'a str, grapheme_len: usize },
21515    Newline,
21516}
21517
21518impl<'a> Iterator for WordBreakingTokenizer<'a> {
21519    /// Yields a span, the count of graphemes in the token, and whether it was
21520    /// whitespace. Note that it also breaks at word boundaries.
21521    type Item = WordBreakToken<'a>;
21522
21523    fn next(&mut self) -> Option<Self::Item> {
21524        use unicode_segmentation::UnicodeSegmentation;
21525        if self.input.is_empty() {
21526            return None;
21527        }
21528
21529        let mut iter = self.input.graphemes(true).peekable();
21530        let mut offset = 0;
21531        let mut grapheme_len = 0;
21532        if let Some(first_grapheme) = iter.next() {
21533            let is_newline = first_grapheme == "\n";
21534            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21535            offset += first_grapheme.len();
21536            grapheme_len += 1;
21537            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21538                if let Some(grapheme) = iter.peek().copied()
21539                    && should_stay_with_preceding_ideograph(grapheme)
21540                {
21541                    offset += grapheme.len();
21542                    grapheme_len += 1;
21543                }
21544            } else {
21545                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21546                let mut next_word_bound = words.peek().copied();
21547                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21548                    next_word_bound = words.next();
21549                }
21550                while let Some(grapheme) = iter.peek().copied() {
21551                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21552                        break;
21553                    };
21554                    if is_grapheme_whitespace(grapheme) != is_whitespace
21555                        || (grapheme == "\n") != is_newline
21556                    {
21557                        break;
21558                    };
21559                    offset += grapheme.len();
21560                    grapheme_len += 1;
21561                    iter.next();
21562                }
21563            }
21564            let token = &self.input[..offset];
21565            self.input = &self.input[offset..];
21566            if token == "\n" {
21567                Some(WordBreakToken::Newline)
21568            } else if is_whitespace {
21569                Some(WordBreakToken::InlineWhitespace {
21570                    token,
21571                    grapheme_len,
21572                })
21573            } else {
21574                Some(WordBreakToken::Word {
21575                    token,
21576                    grapheme_len,
21577                })
21578            }
21579        } else {
21580            None
21581        }
21582    }
21583}
21584
21585#[test]
21586fn test_word_breaking_tokenizer() {
21587    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21588        ("", &[]),
21589        ("  ", &[whitespace("  ", 2)]),
21590        ("Ʒ", &[word("Ʒ", 1)]),
21591        ("Ǽ", &[word("Ǽ", 1)]),
21592        ("", &[word("", 1)]),
21593        ("⋑⋑", &[word("⋑⋑", 2)]),
21594        (
21595            "原理,进而",
21596            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21597        ),
21598        (
21599            "hello world",
21600            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21601        ),
21602        (
21603            "hello, world",
21604            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21605        ),
21606        (
21607            "  hello world",
21608            &[
21609                whitespace("  ", 2),
21610                word("hello", 5),
21611                whitespace(" ", 1),
21612                word("world", 5),
21613            ],
21614        ),
21615        (
21616            "这是什么 \n 钢笔",
21617            &[
21618                word("", 1),
21619                word("", 1),
21620                word("", 1),
21621                word("", 1),
21622                whitespace(" ", 1),
21623                newline(),
21624                whitespace(" ", 1),
21625                word("", 1),
21626                word("", 1),
21627            ],
21628        ),
21629        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21630    ];
21631
21632    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21633        WordBreakToken::Word {
21634            token,
21635            grapheme_len,
21636        }
21637    }
21638
21639    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21640        WordBreakToken::InlineWhitespace {
21641            token,
21642            grapheme_len,
21643        }
21644    }
21645
21646    fn newline() -> WordBreakToken<'static> {
21647        WordBreakToken::Newline
21648    }
21649
21650    for (input, result) in tests {
21651        assert_eq!(
21652            WordBreakingTokenizer::new(input)
21653                .collect::<Vec<_>>()
21654                .as_slice(),
21655            *result,
21656        );
21657    }
21658}
21659
21660fn wrap_with_prefix(
21661    first_line_prefix: String,
21662    subsequent_lines_prefix: String,
21663    unwrapped_text: String,
21664    wrap_column: usize,
21665    tab_size: NonZeroU32,
21666    preserve_existing_whitespace: bool,
21667) -> String {
21668    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21669    let subsequent_lines_prefix_len =
21670        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21671    let mut wrapped_text = String::new();
21672    let mut current_line = first_line_prefix;
21673    let mut is_first_line = true;
21674
21675    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21676    let mut current_line_len = first_line_prefix_len;
21677    let mut in_whitespace = false;
21678    for token in tokenizer {
21679        let have_preceding_whitespace = in_whitespace;
21680        match token {
21681            WordBreakToken::Word {
21682                token,
21683                grapheme_len,
21684            } => {
21685                in_whitespace = false;
21686                let current_prefix_len = if is_first_line {
21687                    first_line_prefix_len
21688                } else {
21689                    subsequent_lines_prefix_len
21690                };
21691                if current_line_len + grapheme_len > wrap_column
21692                    && current_line_len != current_prefix_len
21693                {
21694                    wrapped_text.push_str(current_line.trim_end());
21695                    wrapped_text.push('\n');
21696                    is_first_line = false;
21697                    current_line = subsequent_lines_prefix.clone();
21698                    current_line_len = subsequent_lines_prefix_len;
21699                }
21700                current_line.push_str(token);
21701                current_line_len += grapheme_len;
21702            }
21703            WordBreakToken::InlineWhitespace {
21704                mut token,
21705                mut grapheme_len,
21706            } => {
21707                in_whitespace = true;
21708                if have_preceding_whitespace && !preserve_existing_whitespace {
21709                    continue;
21710                }
21711                if !preserve_existing_whitespace {
21712                    token = " ";
21713                    grapheme_len = 1;
21714                }
21715                let current_prefix_len = if is_first_line {
21716                    first_line_prefix_len
21717                } else {
21718                    subsequent_lines_prefix_len
21719                };
21720                if current_line_len + grapheme_len > wrap_column {
21721                    wrapped_text.push_str(current_line.trim_end());
21722                    wrapped_text.push('\n');
21723                    is_first_line = false;
21724                    current_line = subsequent_lines_prefix.clone();
21725                    current_line_len = subsequent_lines_prefix_len;
21726                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21727                    current_line.push_str(token);
21728                    current_line_len += grapheme_len;
21729                }
21730            }
21731            WordBreakToken::Newline => {
21732                in_whitespace = true;
21733                let current_prefix_len = if is_first_line {
21734                    first_line_prefix_len
21735                } else {
21736                    subsequent_lines_prefix_len
21737                };
21738                if preserve_existing_whitespace {
21739                    wrapped_text.push_str(current_line.trim_end());
21740                    wrapped_text.push('\n');
21741                    is_first_line = false;
21742                    current_line = subsequent_lines_prefix.clone();
21743                    current_line_len = subsequent_lines_prefix_len;
21744                } else if have_preceding_whitespace {
21745                    continue;
21746                } else if current_line_len + 1 > 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                } else if current_line_len != current_prefix_len {
21755                    current_line.push(' ');
21756                    current_line_len += 1;
21757                }
21758            }
21759        }
21760    }
21761
21762    if !current_line.is_empty() {
21763        wrapped_text.push_str(&current_line);
21764    }
21765    wrapped_text
21766}
21767
21768#[test]
21769fn test_wrap_with_prefix() {
21770    assert_eq!(
21771        wrap_with_prefix(
21772            "# ".to_string(),
21773            "# ".to_string(),
21774            "abcdefg".to_string(),
21775            4,
21776            NonZeroU32::new(4).unwrap(),
21777            false,
21778        ),
21779        "# abcdefg"
21780    );
21781    assert_eq!(
21782        wrap_with_prefix(
21783            "".to_string(),
21784            "".to_string(),
21785            "\thello world".to_string(),
21786            8,
21787            NonZeroU32::new(4).unwrap(),
21788            false,
21789        ),
21790        "hello\nworld"
21791    );
21792    assert_eq!(
21793        wrap_with_prefix(
21794            "// ".to_string(),
21795            "// ".to_string(),
21796            "xx \nyy zz aa bb cc".to_string(),
21797            12,
21798            NonZeroU32::new(4).unwrap(),
21799            false,
21800        ),
21801        "// xx yy zz\n// aa bb cc"
21802    );
21803    assert_eq!(
21804        wrap_with_prefix(
21805            String::new(),
21806            String::new(),
21807            "这是什么 \n 钢笔".to_string(),
21808            3,
21809            NonZeroU32::new(4).unwrap(),
21810            false,
21811        ),
21812        "这是什\n么 钢\n"
21813    );
21814}
21815
21816pub trait CollaborationHub {
21817    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21818    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21819    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21820}
21821
21822impl CollaborationHub for Entity<Project> {
21823    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21824        self.read(cx).collaborators()
21825    }
21826
21827    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21828        self.read(cx).user_store().read(cx).participant_indices()
21829    }
21830
21831    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21832        let this = self.read(cx);
21833        let user_ids = this.collaborators().values().map(|c| c.user_id);
21834        this.user_store().read(cx).participant_names(user_ids, cx)
21835    }
21836}
21837
21838pub trait SemanticsProvider {
21839    fn hover(
21840        &self,
21841        buffer: &Entity<Buffer>,
21842        position: text::Anchor,
21843        cx: &mut App,
21844    ) -> Option<Task<Option<Vec<project::Hover>>>>;
21845
21846    fn inline_values(
21847        &self,
21848        buffer_handle: Entity<Buffer>,
21849        range: Range<text::Anchor>,
21850        cx: &mut App,
21851    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21852
21853    fn inlay_hints(
21854        &self,
21855        buffer_handle: Entity<Buffer>,
21856        range: Range<text::Anchor>,
21857        cx: &mut App,
21858    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21859
21860    fn resolve_inlay_hint(
21861        &self,
21862        hint: InlayHint,
21863        buffer_handle: Entity<Buffer>,
21864        server_id: LanguageServerId,
21865        cx: &mut App,
21866    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21867
21868    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21869
21870    fn document_highlights(
21871        &self,
21872        buffer: &Entity<Buffer>,
21873        position: text::Anchor,
21874        cx: &mut App,
21875    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21876
21877    fn definitions(
21878        &self,
21879        buffer: &Entity<Buffer>,
21880        position: text::Anchor,
21881        kind: GotoDefinitionKind,
21882        cx: &mut App,
21883    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
21884
21885    fn range_for_rename(
21886        &self,
21887        buffer: &Entity<Buffer>,
21888        position: text::Anchor,
21889        cx: &mut App,
21890    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21891
21892    fn perform_rename(
21893        &self,
21894        buffer: &Entity<Buffer>,
21895        position: text::Anchor,
21896        new_name: String,
21897        cx: &mut App,
21898    ) -> Option<Task<Result<ProjectTransaction>>>;
21899}
21900
21901pub trait CompletionProvider {
21902    fn completions(
21903        &self,
21904        excerpt_id: ExcerptId,
21905        buffer: &Entity<Buffer>,
21906        buffer_position: text::Anchor,
21907        trigger: CompletionContext,
21908        window: &mut Window,
21909        cx: &mut Context<Editor>,
21910    ) -> Task<Result<Vec<CompletionResponse>>>;
21911
21912    fn resolve_completions(
21913        &self,
21914        _buffer: Entity<Buffer>,
21915        _completion_indices: Vec<usize>,
21916        _completions: Rc<RefCell<Box<[Completion]>>>,
21917        _cx: &mut Context<Editor>,
21918    ) -> Task<Result<bool>> {
21919        Task::ready(Ok(false))
21920    }
21921
21922    fn apply_additional_edits_for_completion(
21923        &self,
21924        _buffer: Entity<Buffer>,
21925        _completions: Rc<RefCell<Box<[Completion]>>>,
21926        _completion_index: usize,
21927        _push_to_history: bool,
21928        _cx: &mut Context<Editor>,
21929    ) -> Task<Result<Option<language::Transaction>>> {
21930        Task::ready(Ok(None))
21931    }
21932
21933    fn is_completion_trigger(
21934        &self,
21935        buffer: &Entity<Buffer>,
21936        position: language::Anchor,
21937        text: &str,
21938        trigger_in_words: bool,
21939        menu_is_open: bool,
21940        cx: &mut Context<Editor>,
21941    ) -> bool;
21942
21943    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21944
21945    fn sort_completions(&self) -> bool {
21946        true
21947    }
21948
21949    fn filter_completions(&self) -> bool {
21950        true
21951    }
21952}
21953
21954pub trait CodeActionProvider {
21955    fn id(&self) -> Arc<str>;
21956
21957    fn code_actions(
21958        &self,
21959        buffer: &Entity<Buffer>,
21960        range: Range<text::Anchor>,
21961        window: &mut Window,
21962        cx: &mut App,
21963    ) -> Task<Result<Vec<CodeAction>>>;
21964
21965    fn apply_code_action(
21966        &self,
21967        buffer_handle: Entity<Buffer>,
21968        action: CodeAction,
21969        excerpt_id: ExcerptId,
21970        push_to_history: bool,
21971        window: &mut Window,
21972        cx: &mut App,
21973    ) -> Task<Result<ProjectTransaction>>;
21974}
21975
21976impl CodeActionProvider for Entity<Project> {
21977    fn id(&self) -> Arc<str> {
21978        "project".into()
21979    }
21980
21981    fn code_actions(
21982        &self,
21983        buffer: &Entity<Buffer>,
21984        range: Range<text::Anchor>,
21985        _window: &mut Window,
21986        cx: &mut App,
21987    ) -> Task<Result<Vec<CodeAction>>> {
21988        self.update(cx, |project, cx| {
21989            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21990            let code_actions = project.code_actions(buffer, range, None, cx);
21991            cx.background_spawn(async move {
21992                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21993                Ok(code_lens_actions
21994                    .context("code lens fetch")?
21995                    .into_iter()
21996                    .flatten()
21997                    .chain(
21998                        code_actions
21999                            .context("code action fetch")?
22000                            .into_iter()
22001                            .flatten(),
22002                    )
22003                    .collect())
22004            })
22005        })
22006    }
22007
22008    fn apply_code_action(
22009        &self,
22010        buffer_handle: Entity<Buffer>,
22011        action: CodeAction,
22012        _excerpt_id: ExcerptId,
22013        push_to_history: bool,
22014        _window: &mut Window,
22015        cx: &mut App,
22016    ) -> Task<Result<ProjectTransaction>> {
22017        self.update(cx, |project, cx| {
22018            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22019        })
22020    }
22021}
22022
22023fn snippet_completions(
22024    project: &Project,
22025    buffer: &Entity<Buffer>,
22026    buffer_position: text::Anchor,
22027    cx: &mut App,
22028) -> Task<Result<CompletionResponse>> {
22029    let languages = buffer.read(cx).languages_at(buffer_position);
22030    let snippet_store = project.snippets().read(cx);
22031
22032    let scopes: Vec<_> = languages
22033        .iter()
22034        .filter_map(|language| {
22035            let language_name = language.lsp_id();
22036            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22037
22038            if snippets.is_empty() {
22039                None
22040            } else {
22041                Some((language.default_scope(), snippets))
22042            }
22043        })
22044        .collect();
22045
22046    if scopes.is_empty() {
22047        return Task::ready(Ok(CompletionResponse {
22048            completions: vec![],
22049            is_incomplete: false,
22050        }));
22051    }
22052
22053    let snapshot = buffer.read(cx).text_snapshot();
22054    let chars: String = snapshot
22055        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22056        .collect();
22057    let executor = cx.background_executor().clone();
22058
22059    cx.background_spawn(async move {
22060        let mut is_incomplete = false;
22061        let mut completions: Vec<Completion> = Vec::new();
22062        for (scope, snippets) in scopes.into_iter() {
22063            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22064            let mut last_word = chars
22065                .chars()
22066                .take_while(|c| classifier.is_word(*c))
22067                .collect::<String>();
22068            last_word = last_word.chars().rev().collect();
22069
22070            if last_word.is_empty() {
22071                return Ok(CompletionResponse {
22072                    completions: vec![],
22073                    is_incomplete: true,
22074                });
22075            }
22076
22077            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22078            let to_lsp = |point: &text::Anchor| {
22079                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22080                point_to_lsp(end)
22081            };
22082            let lsp_end = to_lsp(&buffer_position);
22083
22084            let candidates = snippets
22085                .iter()
22086                .enumerate()
22087                .flat_map(|(ix, snippet)| {
22088                    snippet
22089                        .prefix
22090                        .iter()
22091                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22092                })
22093                .collect::<Vec<StringMatchCandidate>>();
22094
22095            const MAX_RESULTS: usize = 100;
22096            let mut matches = fuzzy::match_strings(
22097                &candidates,
22098                &last_word,
22099                last_word.chars().any(|c| c.is_uppercase()),
22100                true,
22101                MAX_RESULTS,
22102                &Default::default(),
22103                executor.clone(),
22104            )
22105            .await;
22106
22107            if matches.len() >= MAX_RESULTS {
22108                is_incomplete = true;
22109            }
22110
22111            // Remove all candidates where the query's start does not match the start of any word in the candidate
22112            if let Some(query_start) = last_word.chars().next() {
22113                matches.retain(|string_match| {
22114                    split_words(&string_match.string).any(|word| {
22115                        // Check that the first codepoint of the word as lowercase matches the first
22116                        // codepoint of the query as lowercase
22117                        word.chars()
22118                            .flat_map(|codepoint| codepoint.to_lowercase())
22119                            .zip(query_start.to_lowercase())
22120                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22121                    })
22122                });
22123            }
22124
22125            let matched_strings = matches
22126                .into_iter()
22127                .map(|m| m.string)
22128                .collect::<HashSet<_>>();
22129
22130            completions.extend(snippets.iter().filter_map(|snippet| {
22131                let matching_prefix = snippet
22132                    .prefix
22133                    .iter()
22134                    .find(|prefix| matched_strings.contains(*prefix))?;
22135                let start = as_offset - last_word.len();
22136                let start = snapshot.anchor_before(start);
22137                let range = start..buffer_position;
22138                let lsp_start = to_lsp(&start);
22139                let lsp_range = lsp::Range {
22140                    start: lsp_start,
22141                    end: lsp_end,
22142                };
22143                Some(Completion {
22144                    replace_range: range,
22145                    new_text: snippet.body.clone(),
22146                    source: CompletionSource::Lsp {
22147                        insert_range: None,
22148                        server_id: LanguageServerId(usize::MAX),
22149                        resolved: true,
22150                        lsp_completion: Box::new(lsp::CompletionItem {
22151                            label: snippet.prefix.first().unwrap().clone(),
22152                            kind: Some(CompletionItemKind::SNIPPET),
22153                            label_details: snippet.description.as_ref().map(|description| {
22154                                lsp::CompletionItemLabelDetails {
22155                                    detail: Some(description.clone()),
22156                                    description: None,
22157                                }
22158                            }),
22159                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22160                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22161                                lsp::InsertReplaceEdit {
22162                                    new_text: snippet.body.clone(),
22163                                    insert: lsp_range,
22164                                    replace: lsp_range,
22165                                },
22166                            )),
22167                            filter_text: Some(snippet.body.clone()),
22168                            sort_text: Some(char::MAX.to_string()),
22169                            ..lsp::CompletionItem::default()
22170                        }),
22171                        lsp_defaults: None,
22172                    },
22173                    label: CodeLabel {
22174                        text: matching_prefix.clone(),
22175                        runs: Vec::new(),
22176                        filter_range: 0..matching_prefix.len(),
22177                    },
22178                    icon_path: None,
22179                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22180                        single_line: snippet.name.clone().into(),
22181                        plain_text: snippet
22182                            .description
22183                            .clone()
22184                            .map(|description| description.into()),
22185                    }),
22186                    insert_text_mode: None,
22187                    confirm: None,
22188                })
22189            }))
22190        }
22191
22192        Ok(CompletionResponse {
22193            completions,
22194            is_incomplete,
22195        })
22196    })
22197}
22198
22199impl CompletionProvider for Entity<Project> {
22200    fn completions(
22201        &self,
22202        _excerpt_id: ExcerptId,
22203        buffer: &Entity<Buffer>,
22204        buffer_position: text::Anchor,
22205        options: CompletionContext,
22206        _window: &mut Window,
22207        cx: &mut Context<Editor>,
22208    ) -> Task<Result<Vec<CompletionResponse>>> {
22209        self.update(cx, |project, cx| {
22210            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22211            let project_completions = project.completions(buffer, buffer_position, options, cx);
22212            cx.background_spawn(async move {
22213                let mut responses = project_completions.await?;
22214                let snippets = snippets.await?;
22215                if !snippets.completions.is_empty() {
22216                    responses.push(snippets);
22217                }
22218                Ok(responses)
22219            })
22220        })
22221    }
22222
22223    fn resolve_completions(
22224        &self,
22225        buffer: Entity<Buffer>,
22226        completion_indices: Vec<usize>,
22227        completions: Rc<RefCell<Box<[Completion]>>>,
22228        cx: &mut Context<Editor>,
22229    ) -> Task<Result<bool>> {
22230        self.update(cx, |project, cx| {
22231            project.lsp_store().update(cx, |lsp_store, cx| {
22232                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22233            })
22234        })
22235    }
22236
22237    fn apply_additional_edits_for_completion(
22238        &self,
22239        buffer: Entity<Buffer>,
22240        completions: Rc<RefCell<Box<[Completion]>>>,
22241        completion_index: usize,
22242        push_to_history: bool,
22243        cx: &mut Context<Editor>,
22244    ) -> Task<Result<Option<language::Transaction>>> {
22245        self.update(cx, |project, cx| {
22246            project.lsp_store().update(cx, |lsp_store, cx| {
22247                lsp_store.apply_additional_edits_for_completion(
22248                    buffer,
22249                    completions,
22250                    completion_index,
22251                    push_to_history,
22252                    cx,
22253                )
22254            })
22255        })
22256    }
22257
22258    fn is_completion_trigger(
22259        &self,
22260        buffer: &Entity<Buffer>,
22261        position: language::Anchor,
22262        text: &str,
22263        trigger_in_words: bool,
22264        menu_is_open: bool,
22265        cx: &mut Context<Editor>,
22266    ) -> bool {
22267        let mut chars = text.chars();
22268        let char = if let Some(char) = chars.next() {
22269            char
22270        } else {
22271            return false;
22272        };
22273        if chars.next().is_some() {
22274            return false;
22275        }
22276
22277        let buffer = buffer.read(cx);
22278        let snapshot = buffer.snapshot();
22279        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22280            return false;
22281        }
22282        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22283        if trigger_in_words && classifier.is_word(char) {
22284            return true;
22285        }
22286
22287        buffer.completion_triggers().contains(text)
22288    }
22289}
22290
22291impl SemanticsProvider for Entity<Project> {
22292    fn hover(
22293        &self,
22294        buffer: &Entity<Buffer>,
22295        position: text::Anchor,
22296        cx: &mut App,
22297    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22298        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22299    }
22300
22301    fn document_highlights(
22302        &self,
22303        buffer: &Entity<Buffer>,
22304        position: text::Anchor,
22305        cx: &mut App,
22306    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22307        Some(self.update(cx, |project, cx| {
22308            project.document_highlights(buffer, position, cx)
22309        }))
22310    }
22311
22312    fn definitions(
22313        &self,
22314        buffer: &Entity<Buffer>,
22315        position: text::Anchor,
22316        kind: GotoDefinitionKind,
22317        cx: &mut App,
22318    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22319        Some(self.update(cx, |project, cx| match kind {
22320            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22321            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22322            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22323            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22324        }))
22325    }
22326
22327    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22328        self.update(cx, |project, cx| {
22329            if project
22330                .active_debug_session(cx)
22331                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22332            {
22333                return true;
22334            }
22335
22336            buffer.update(cx, |buffer, cx| {
22337                project.any_language_server_supports_inlay_hints(buffer, cx)
22338            })
22339        })
22340    }
22341
22342    fn inline_values(
22343        &self,
22344        buffer_handle: Entity<Buffer>,
22345        range: Range<text::Anchor>,
22346        cx: &mut App,
22347    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22348        self.update(cx, |project, cx| {
22349            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22350
22351            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22352        })
22353    }
22354
22355    fn inlay_hints(
22356        &self,
22357        buffer_handle: Entity<Buffer>,
22358        range: Range<text::Anchor>,
22359        cx: &mut App,
22360    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22361        Some(self.update(cx, |project, cx| {
22362            project.inlay_hints(buffer_handle, range, cx)
22363        }))
22364    }
22365
22366    fn resolve_inlay_hint(
22367        &self,
22368        hint: InlayHint,
22369        buffer_handle: Entity<Buffer>,
22370        server_id: LanguageServerId,
22371        cx: &mut App,
22372    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22373        Some(self.update(cx, |project, cx| {
22374            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22375        }))
22376    }
22377
22378    fn range_for_rename(
22379        &self,
22380        buffer: &Entity<Buffer>,
22381        position: text::Anchor,
22382        cx: &mut App,
22383    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22384        Some(self.update(cx, |project, cx| {
22385            let buffer = buffer.clone();
22386            let task = project.prepare_rename(buffer.clone(), position, cx);
22387            cx.spawn(async move |_, cx| {
22388                Ok(match task.await? {
22389                    PrepareRenameResponse::Success(range) => Some(range),
22390                    PrepareRenameResponse::InvalidPosition => None,
22391                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22392                        // Fallback on using TreeSitter info to determine identifier range
22393                        buffer.read_with(cx, |buffer, _| {
22394                            let snapshot = buffer.snapshot();
22395                            let (range, kind) = snapshot.surrounding_word(position, false);
22396                            if kind != Some(CharKind::Word) {
22397                                return None;
22398                            }
22399                            Some(
22400                                snapshot.anchor_before(range.start)
22401                                    ..snapshot.anchor_after(range.end),
22402                            )
22403                        })?
22404                    }
22405                })
22406            })
22407        }))
22408    }
22409
22410    fn perform_rename(
22411        &self,
22412        buffer: &Entity<Buffer>,
22413        position: text::Anchor,
22414        new_name: String,
22415        cx: &mut App,
22416    ) -> Option<Task<Result<ProjectTransaction>>> {
22417        Some(self.update(cx, |project, cx| {
22418            project.perform_rename(buffer.clone(), position, new_name, cx)
22419        }))
22420    }
22421}
22422
22423fn inlay_hint_settings(
22424    location: Anchor,
22425    snapshot: &MultiBufferSnapshot,
22426    cx: &mut Context<Editor>,
22427) -> InlayHintSettings {
22428    let file = snapshot.file_at(location);
22429    let language = snapshot.language_at(location).map(|l| l.name());
22430    language_settings(language, file, cx).inlay_hints
22431}
22432
22433fn consume_contiguous_rows(
22434    contiguous_row_selections: &mut Vec<Selection<Point>>,
22435    selection: &Selection<Point>,
22436    display_map: &DisplaySnapshot,
22437    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22438) -> (MultiBufferRow, MultiBufferRow) {
22439    contiguous_row_selections.push(selection.clone());
22440    let start_row = starting_row(selection, display_map);
22441    let mut end_row = ending_row(selection, display_map);
22442
22443    while let Some(next_selection) = selections.peek() {
22444        if next_selection.start.row <= end_row.0 {
22445            end_row = ending_row(next_selection, display_map);
22446            contiguous_row_selections.push(selections.next().unwrap().clone());
22447        } else {
22448            break;
22449        }
22450    }
22451    (start_row, end_row)
22452}
22453
22454fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22455    if selection.start.column > 0 {
22456        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22457    } else {
22458        MultiBufferRow(selection.start.row)
22459    }
22460}
22461
22462fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22463    if next_selection.end.column > 0 || next_selection.is_empty() {
22464        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22465    } else {
22466        MultiBufferRow(next_selection.end.row)
22467    }
22468}
22469
22470impl EditorSnapshot {
22471    pub fn remote_selections_in_range<'a>(
22472        &'a self,
22473        range: &'a Range<Anchor>,
22474        collaboration_hub: &dyn CollaborationHub,
22475        cx: &'a App,
22476    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22477        let participant_names = collaboration_hub.user_names(cx);
22478        let participant_indices = collaboration_hub.user_participant_indices(cx);
22479        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22480        let collaborators_by_replica_id = collaborators_by_peer_id
22481            .values()
22482            .map(|collaborator| (collaborator.replica_id, collaborator))
22483            .collect::<HashMap<_, _>>();
22484        self.buffer_snapshot
22485            .selections_in_range(range, false)
22486            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22487                if replica_id == AGENT_REPLICA_ID {
22488                    Some(RemoteSelection {
22489                        replica_id,
22490                        selection,
22491                        cursor_shape,
22492                        line_mode,
22493                        collaborator_id: CollaboratorId::Agent,
22494                        user_name: Some("Agent".into()),
22495                        color: cx.theme().players().agent(),
22496                    })
22497                } else {
22498                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22499                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22500                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22501                    Some(RemoteSelection {
22502                        replica_id,
22503                        selection,
22504                        cursor_shape,
22505                        line_mode,
22506                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22507                        user_name,
22508                        color: if let Some(index) = participant_index {
22509                            cx.theme().players().color_for_participant(index.0)
22510                        } else {
22511                            cx.theme().players().absent()
22512                        },
22513                    })
22514                }
22515            })
22516    }
22517
22518    pub fn hunks_for_ranges(
22519        &self,
22520        ranges: impl IntoIterator<Item = Range<Point>>,
22521    ) -> Vec<MultiBufferDiffHunk> {
22522        let mut hunks = Vec::new();
22523        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22524            HashMap::default();
22525        for query_range in ranges {
22526            let query_rows =
22527                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22528            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22529                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22530            ) {
22531                // Include deleted hunks that are adjacent to the query range, because
22532                // otherwise they would be missed.
22533                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22534                if hunk.status().is_deleted() {
22535                    intersects_range |= hunk.row_range.start == query_rows.end;
22536                    intersects_range |= hunk.row_range.end == query_rows.start;
22537                }
22538                if intersects_range {
22539                    if !processed_buffer_rows
22540                        .entry(hunk.buffer_id)
22541                        .or_default()
22542                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22543                    {
22544                        continue;
22545                    }
22546                    hunks.push(hunk);
22547                }
22548            }
22549        }
22550
22551        hunks
22552    }
22553
22554    fn display_diff_hunks_for_rows<'a>(
22555        &'a self,
22556        display_rows: Range<DisplayRow>,
22557        folded_buffers: &'a HashSet<BufferId>,
22558    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22559        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22560        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22561
22562        self.buffer_snapshot
22563            .diff_hunks_in_range(buffer_start..buffer_end)
22564            .filter_map(|hunk| {
22565                if folded_buffers.contains(&hunk.buffer_id) {
22566                    return None;
22567                }
22568
22569                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22570                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22571
22572                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22573                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22574
22575                let display_hunk = if hunk_display_start.column() != 0 {
22576                    DisplayDiffHunk::Folded {
22577                        display_row: hunk_display_start.row(),
22578                    }
22579                } else {
22580                    let mut end_row = hunk_display_end.row();
22581                    if hunk_display_end.column() > 0 {
22582                        end_row.0 += 1;
22583                    }
22584                    let is_created_file = hunk.is_created_file();
22585                    DisplayDiffHunk::Unfolded {
22586                        status: hunk.status(),
22587                        diff_base_byte_range: hunk.diff_base_byte_range,
22588                        display_row_range: hunk_display_start.row()..end_row,
22589                        multi_buffer_range: Anchor::range_in_buffer(
22590                            hunk.excerpt_id,
22591                            hunk.buffer_id,
22592                            hunk.buffer_range,
22593                        ),
22594                        is_created_file,
22595                    }
22596                };
22597
22598                Some(display_hunk)
22599            })
22600    }
22601
22602    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22603        self.display_snapshot.buffer_snapshot.language_at(position)
22604    }
22605
22606    pub fn is_focused(&self) -> bool {
22607        self.is_focused
22608    }
22609
22610    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22611        self.placeholder_text.as_ref()
22612    }
22613
22614    pub fn scroll_position(&self) -> gpui::Point<f32> {
22615        self.scroll_anchor.scroll_position(&self.display_snapshot)
22616    }
22617
22618    fn gutter_dimensions(
22619        &self,
22620        font_id: FontId,
22621        font_size: Pixels,
22622        max_line_number_width: Pixels,
22623        cx: &App,
22624    ) -> Option<GutterDimensions> {
22625        if !self.show_gutter {
22626            return None;
22627        }
22628
22629        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22630        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22631
22632        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22633            matches!(
22634                ProjectSettings::get_global(cx).git.git_gutter,
22635                Some(GitGutterSetting::TrackedFiles)
22636            )
22637        });
22638        let gutter_settings = EditorSettings::get_global(cx).gutter;
22639        let show_line_numbers = self
22640            .show_line_numbers
22641            .unwrap_or(gutter_settings.line_numbers);
22642        let line_gutter_width = if show_line_numbers {
22643            // Avoid flicker-like gutter resizes when the line number gains another digit by
22644            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22645            let min_width_for_number_on_gutter =
22646                ch_advance * gutter_settings.min_line_number_digits as f32;
22647            max_line_number_width.max(min_width_for_number_on_gutter)
22648        } else {
22649            0.0.into()
22650        };
22651
22652        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22653        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22654
22655        let git_blame_entries_width =
22656            self.git_blame_gutter_max_author_length
22657                .map(|max_author_length| {
22658                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22659                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22660
22661                    /// The number of characters to dedicate to gaps and margins.
22662                    const SPACING_WIDTH: usize = 4;
22663
22664                    let max_char_count = max_author_length.min(renderer.max_author_length())
22665                        + ::git::SHORT_SHA_LENGTH
22666                        + MAX_RELATIVE_TIMESTAMP.len()
22667                        + SPACING_WIDTH;
22668
22669                    ch_advance * max_char_count
22670                });
22671
22672        let is_singleton = self.buffer_snapshot.is_singleton();
22673
22674        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22675        left_padding += if !is_singleton {
22676            ch_width * 4.0
22677        } else if show_runnables || show_breakpoints {
22678            ch_width * 3.0
22679        } else if show_git_gutter && show_line_numbers {
22680            ch_width * 2.0
22681        } else if show_git_gutter || show_line_numbers {
22682            ch_width
22683        } else {
22684            px(0.)
22685        };
22686
22687        let shows_folds = is_singleton && gutter_settings.folds;
22688
22689        let right_padding = if shows_folds && show_line_numbers {
22690            ch_width * 4.0
22691        } else if shows_folds || (!is_singleton && show_line_numbers) {
22692            ch_width * 3.0
22693        } else if show_line_numbers {
22694            ch_width
22695        } else {
22696            px(0.)
22697        };
22698
22699        Some(GutterDimensions {
22700            left_padding,
22701            right_padding,
22702            width: line_gutter_width + left_padding + right_padding,
22703            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22704            git_blame_entries_width,
22705        })
22706    }
22707
22708    pub fn render_crease_toggle(
22709        &self,
22710        buffer_row: MultiBufferRow,
22711        row_contains_cursor: bool,
22712        editor: Entity<Editor>,
22713        window: &mut Window,
22714        cx: &mut App,
22715    ) -> Option<AnyElement> {
22716        let folded = self.is_line_folded(buffer_row);
22717        let mut is_foldable = false;
22718
22719        if let Some(crease) = self
22720            .crease_snapshot
22721            .query_row(buffer_row, &self.buffer_snapshot)
22722        {
22723            is_foldable = true;
22724            match crease {
22725                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22726                    if let Some(render_toggle) = render_toggle {
22727                        let toggle_callback =
22728                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22729                                if folded {
22730                                    editor.update(cx, |editor, cx| {
22731                                        editor.fold_at(buffer_row, window, cx)
22732                                    });
22733                                } else {
22734                                    editor.update(cx, |editor, cx| {
22735                                        editor.unfold_at(buffer_row, window, cx)
22736                                    });
22737                                }
22738                            });
22739                        return Some((render_toggle)(
22740                            buffer_row,
22741                            folded,
22742                            toggle_callback,
22743                            window,
22744                            cx,
22745                        ));
22746                    }
22747                }
22748            }
22749        }
22750
22751        is_foldable |= self.starts_indent(buffer_row);
22752
22753        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22754            Some(
22755                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22756                    .toggle_state(folded)
22757                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22758                        if folded {
22759                            this.unfold_at(buffer_row, window, cx);
22760                        } else {
22761                            this.fold_at(buffer_row, window, cx);
22762                        }
22763                    }))
22764                    .into_any_element(),
22765            )
22766        } else {
22767            None
22768        }
22769    }
22770
22771    pub fn render_crease_trailer(
22772        &self,
22773        buffer_row: MultiBufferRow,
22774        window: &mut Window,
22775        cx: &mut App,
22776    ) -> Option<AnyElement> {
22777        let folded = self.is_line_folded(buffer_row);
22778        if let Crease::Inline { render_trailer, .. } = self
22779            .crease_snapshot
22780            .query_row(buffer_row, &self.buffer_snapshot)?
22781        {
22782            let render_trailer = render_trailer.as_ref()?;
22783            Some(render_trailer(buffer_row, folded, window, cx))
22784        } else {
22785            None
22786        }
22787    }
22788}
22789
22790impl Deref for EditorSnapshot {
22791    type Target = DisplaySnapshot;
22792
22793    fn deref(&self) -> &Self::Target {
22794        &self.display_snapshot
22795    }
22796}
22797
22798#[derive(Clone, Debug, PartialEq, Eq)]
22799pub enum EditorEvent {
22800    InputIgnored {
22801        text: Arc<str>,
22802    },
22803    InputHandled {
22804        utf16_range_to_replace: Option<Range<isize>>,
22805        text: Arc<str>,
22806    },
22807    ExcerptsAdded {
22808        buffer: Entity<Buffer>,
22809        predecessor: ExcerptId,
22810        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22811    },
22812    ExcerptsRemoved {
22813        ids: Vec<ExcerptId>,
22814        removed_buffer_ids: Vec<BufferId>,
22815    },
22816    BufferFoldToggled {
22817        ids: Vec<ExcerptId>,
22818        folded: bool,
22819    },
22820    ExcerptsEdited {
22821        ids: Vec<ExcerptId>,
22822    },
22823    ExcerptsExpanded {
22824        ids: Vec<ExcerptId>,
22825    },
22826    BufferEdited,
22827    Edited {
22828        transaction_id: clock::Lamport,
22829    },
22830    Reparsed(BufferId),
22831    Focused,
22832    FocusedIn,
22833    Blurred,
22834    DirtyChanged,
22835    Saved,
22836    TitleChanged,
22837    DiffBaseChanged,
22838    SelectionsChanged {
22839        local: bool,
22840    },
22841    ScrollPositionChanged {
22842        local: bool,
22843        autoscroll: bool,
22844    },
22845    Closed,
22846    TransactionUndone {
22847        transaction_id: clock::Lamport,
22848    },
22849    TransactionBegun {
22850        transaction_id: clock::Lamport,
22851    },
22852    Reloaded,
22853    CursorShapeChanged,
22854    BreadcrumbsChanged,
22855    PushedToNavHistory {
22856        anchor: Anchor,
22857        is_deactivate: bool,
22858    },
22859}
22860
22861impl EventEmitter<EditorEvent> for Editor {}
22862
22863impl Focusable for Editor {
22864    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22865        self.focus_handle.clone()
22866    }
22867}
22868
22869impl Render for Editor {
22870    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22871        let settings = ThemeSettings::get_global(cx);
22872
22873        let mut text_style = match self.mode {
22874            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
22875                color: cx.theme().colors().editor_foreground,
22876                font_family: settings.ui_font.family.clone(),
22877                font_features: settings.ui_font.features.clone(),
22878                font_fallbacks: settings.ui_font.fallbacks.clone(),
22879                font_size: rems(0.875).into(),
22880                font_weight: settings.ui_font.weight,
22881                line_height: relative(settings.buffer_line_height.value()),
22882                ..Default::default()
22883            },
22884            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22885                color: cx.theme().colors().editor_foreground,
22886                font_family: settings.buffer_font.family.clone(),
22887                font_features: settings.buffer_font.features.clone(),
22888                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22889                font_size: settings.buffer_font_size(cx).into(),
22890                font_weight: settings.buffer_font.weight,
22891                line_height: relative(settings.buffer_line_height.value()),
22892                ..Default::default()
22893            },
22894        };
22895        if let Some(text_style_refinement) = &self.text_style_refinement {
22896            text_style.refine(text_style_refinement)
22897        }
22898
22899        let background = match self.mode {
22900            EditorMode::SingleLine => cx.theme().system().transparent,
22901            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22902            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22903            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22904        };
22905
22906        EditorElement::new(
22907            &cx.entity(),
22908            EditorStyle {
22909                background,
22910                border: cx.theme().colors().border,
22911                local_player: cx.theme().players().local(),
22912                text: text_style,
22913                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22914                syntax: cx.theme().syntax().clone(),
22915                status: cx.theme().status().clone(),
22916                inlay_hints_style: make_inlay_hints_style(cx),
22917                edit_prediction_styles: make_suggestion_styles(cx),
22918                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22919                show_underlines: self.diagnostics_enabled(),
22920            },
22921        )
22922    }
22923}
22924
22925impl EntityInputHandler for Editor {
22926    fn text_for_range(
22927        &mut self,
22928        range_utf16: Range<usize>,
22929        adjusted_range: &mut Option<Range<usize>>,
22930        _: &mut Window,
22931        cx: &mut Context<Self>,
22932    ) -> Option<String> {
22933        let snapshot = self.buffer.read(cx).read(cx);
22934        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22935        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22936        if (start.0..end.0) != range_utf16 {
22937            adjusted_range.replace(start.0..end.0);
22938        }
22939        Some(snapshot.text_for_range(start..end).collect())
22940    }
22941
22942    fn selected_text_range(
22943        &mut self,
22944        ignore_disabled_input: bool,
22945        _: &mut Window,
22946        cx: &mut Context<Self>,
22947    ) -> Option<UTF16Selection> {
22948        // Prevent the IME menu from appearing when holding down an alphabetic key
22949        // while input is disabled.
22950        if !ignore_disabled_input && !self.input_enabled {
22951            return None;
22952        }
22953
22954        let selection = self.selections.newest::<OffsetUtf16>(cx);
22955        let range = selection.range();
22956
22957        Some(UTF16Selection {
22958            range: range.start.0..range.end.0,
22959            reversed: selection.reversed,
22960        })
22961    }
22962
22963    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22964        let snapshot = self.buffer.read(cx).read(cx);
22965        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22966        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22967    }
22968
22969    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22970        self.clear_highlights::<InputComposition>(cx);
22971        self.ime_transaction.take();
22972    }
22973
22974    fn replace_text_in_range(
22975        &mut self,
22976        range_utf16: Option<Range<usize>>,
22977        text: &str,
22978        window: &mut Window,
22979        cx: &mut Context<Self>,
22980    ) {
22981        if !self.input_enabled {
22982            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22983            return;
22984        }
22985
22986        self.transact(window, cx, |this, window, cx| {
22987            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22988                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22989                Some(this.selection_replacement_ranges(range_utf16, cx))
22990            } else {
22991                this.marked_text_ranges(cx)
22992            };
22993
22994            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22995                let newest_selection_id = this.selections.newest_anchor().id;
22996                this.selections
22997                    .all::<OffsetUtf16>(cx)
22998                    .iter()
22999                    .zip(ranges_to_replace.iter())
23000                    .find_map(|(selection, range)| {
23001                        if selection.id == newest_selection_id {
23002                            Some(
23003                                (range.start.0 as isize - selection.head().0 as isize)
23004                                    ..(range.end.0 as isize - selection.head().0 as isize),
23005                            )
23006                        } else {
23007                            None
23008                        }
23009                    })
23010            });
23011
23012            cx.emit(EditorEvent::InputHandled {
23013                utf16_range_to_replace: range_to_replace,
23014                text: text.into(),
23015            });
23016
23017            if let Some(new_selected_ranges) = new_selected_ranges {
23018                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23019                    selections.select_ranges(new_selected_ranges)
23020                });
23021                this.backspace(&Default::default(), window, cx);
23022            }
23023
23024            this.handle_input(text, window, cx);
23025        });
23026
23027        if let Some(transaction) = self.ime_transaction {
23028            self.buffer.update(cx, |buffer, cx| {
23029                buffer.group_until_transaction(transaction, cx);
23030            });
23031        }
23032
23033        self.unmark_text(window, cx);
23034    }
23035
23036    fn replace_and_mark_text_in_range(
23037        &mut self,
23038        range_utf16: Option<Range<usize>>,
23039        text: &str,
23040        new_selected_range_utf16: Option<Range<usize>>,
23041        window: &mut Window,
23042        cx: &mut Context<Self>,
23043    ) {
23044        if !self.input_enabled {
23045            return;
23046        }
23047
23048        let transaction = self.transact(window, cx, |this, window, cx| {
23049            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23050                let snapshot = this.buffer.read(cx).read(cx);
23051                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23052                    for marked_range in &mut marked_ranges {
23053                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23054                        marked_range.start.0 += relative_range_utf16.start;
23055                        marked_range.start =
23056                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23057                        marked_range.end =
23058                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23059                    }
23060                }
23061                Some(marked_ranges)
23062            } else if let Some(range_utf16) = range_utf16 {
23063                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23064                Some(this.selection_replacement_ranges(range_utf16, cx))
23065            } else {
23066                None
23067            };
23068
23069            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23070                let newest_selection_id = this.selections.newest_anchor().id;
23071                this.selections
23072                    .all::<OffsetUtf16>(cx)
23073                    .iter()
23074                    .zip(ranges_to_replace.iter())
23075                    .find_map(|(selection, range)| {
23076                        if selection.id == newest_selection_id {
23077                            Some(
23078                                (range.start.0 as isize - selection.head().0 as isize)
23079                                    ..(range.end.0 as isize - selection.head().0 as isize),
23080                            )
23081                        } else {
23082                            None
23083                        }
23084                    })
23085            });
23086
23087            cx.emit(EditorEvent::InputHandled {
23088                utf16_range_to_replace: range_to_replace,
23089                text: text.into(),
23090            });
23091
23092            if let Some(ranges) = ranges_to_replace {
23093                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23094                    s.select_ranges(ranges)
23095                });
23096            }
23097
23098            let marked_ranges = {
23099                let snapshot = this.buffer.read(cx).read(cx);
23100                this.selections
23101                    .disjoint_anchors()
23102                    .iter()
23103                    .map(|selection| {
23104                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23105                    })
23106                    .collect::<Vec<_>>()
23107            };
23108
23109            if text.is_empty() {
23110                this.unmark_text(window, cx);
23111            } else {
23112                this.highlight_text::<InputComposition>(
23113                    marked_ranges.clone(),
23114                    HighlightStyle {
23115                        underline: Some(UnderlineStyle {
23116                            thickness: px(1.),
23117                            color: None,
23118                            wavy: false,
23119                        }),
23120                        ..Default::default()
23121                    },
23122                    cx,
23123                );
23124            }
23125
23126            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23127            let use_autoclose = this.use_autoclose;
23128            let use_auto_surround = this.use_auto_surround;
23129            this.set_use_autoclose(false);
23130            this.set_use_auto_surround(false);
23131            this.handle_input(text, window, cx);
23132            this.set_use_autoclose(use_autoclose);
23133            this.set_use_auto_surround(use_auto_surround);
23134
23135            if let Some(new_selected_range) = new_selected_range_utf16 {
23136                let snapshot = this.buffer.read(cx).read(cx);
23137                let new_selected_ranges = marked_ranges
23138                    .into_iter()
23139                    .map(|marked_range| {
23140                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23141                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23142                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23143                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23144                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23145                    })
23146                    .collect::<Vec<_>>();
23147
23148                drop(snapshot);
23149                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23150                    selections.select_ranges(new_selected_ranges)
23151                });
23152            }
23153        });
23154
23155        self.ime_transaction = self.ime_transaction.or(transaction);
23156        if let Some(transaction) = self.ime_transaction {
23157            self.buffer.update(cx, |buffer, cx| {
23158                buffer.group_until_transaction(transaction, cx);
23159            });
23160        }
23161
23162        if self.text_highlights::<InputComposition>(cx).is_none() {
23163            self.ime_transaction.take();
23164        }
23165    }
23166
23167    fn bounds_for_range(
23168        &mut self,
23169        range_utf16: Range<usize>,
23170        element_bounds: gpui::Bounds<Pixels>,
23171        window: &mut Window,
23172        cx: &mut Context<Self>,
23173    ) -> Option<gpui::Bounds<Pixels>> {
23174        let text_layout_details = self.text_layout_details(window);
23175        let CharacterDimensions {
23176            em_width,
23177            em_advance,
23178            line_height,
23179        } = self.character_dimensions(window);
23180
23181        let snapshot = self.snapshot(window, cx);
23182        let scroll_position = snapshot.scroll_position();
23183        let scroll_left = scroll_position.x * em_advance;
23184
23185        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23186        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23187            + self.gutter_dimensions.full_width();
23188        let y = line_height * (start.row().as_f32() - scroll_position.y);
23189
23190        Some(Bounds {
23191            origin: element_bounds.origin + point(x, y),
23192            size: size(em_width, line_height),
23193        })
23194    }
23195
23196    fn character_index_for_point(
23197        &mut self,
23198        point: gpui::Point<Pixels>,
23199        _window: &mut Window,
23200        _cx: &mut Context<Self>,
23201    ) -> Option<usize> {
23202        let position_map = self.last_position_map.as_ref()?;
23203        if !position_map.text_hitbox.contains(&point) {
23204            return None;
23205        }
23206        let display_point = position_map.point_for_position(point).previous_valid;
23207        let anchor = position_map
23208            .snapshot
23209            .display_point_to_anchor(display_point, Bias::Left);
23210        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23211        Some(utf16_offset.0)
23212    }
23213}
23214
23215trait SelectionExt {
23216    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23217    fn spanned_rows(
23218        &self,
23219        include_end_if_at_line_start: bool,
23220        map: &DisplaySnapshot,
23221    ) -> Range<MultiBufferRow>;
23222}
23223
23224impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23225    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23226        let start = self
23227            .start
23228            .to_point(&map.buffer_snapshot)
23229            .to_display_point(map);
23230        let end = self
23231            .end
23232            .to_point(&map.buffer_snapshot)
23233            .to_display_point(map);
23234        if self.reversed {
23235            end..start
23236        } else {
23237            start..end
23238        }
23239    }
23240
23241    fn spanned_rows(
23242        &self,
23243        include_end_if_at_line_start: bool,
23244        map: &DisplaySnapshot,
23245    ) -> Range<MultiBufferRow> {
23246        let start = self.start.to_point(&map.buffer_snapshot);
23247        let mut end = self.end.to_point(&map.buffer_snapshot);
23248        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23249            end.row -= 1;
23250        }
23251
23252        let buffer_start = map.prev_line_boundary(start).0;
23253        let buffer_end = map.next_line_boundary(end).0;
23254        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23255    }
23256}
23257
23258impl<T: InvalidationRegion> InvalidationStack<T> {
23259    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23260    where
23261        S: Clone + ToOffset,
23262    {
23263        while let Some(region) = self.last() {
23264            let all_selections_inside_invalidation_ranges =
23265                if selections.len() == region.ranges().len() {
23266                    selections
23267                        .iter()
23268                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23269                        .all(|(selection, invalidation_range)| {
23270                            let head = selection.head().to_offset(buffer);
23271                            invalidation_range.start <= head && invalidation_range.end >= head
23272                        })
23273                } else {
23274                    false
23275                };
23276
23277            if all_selections_inside_invalidation_ranges {
23278                break;
23279            } else {
23280                self.pop();
23281            }
23282        }
23283    }
23284}
23285
23286impl<T> Default for InvalidationStack<T> {
23287    fn default() -> Self {
23288        Self(Default::default())
23289    }
23290}
23291
23292impl<T> Deref for InvalidationStack<T> {
23293    type Target = Vec<T>;
23294
23295    fn deref(&self) -> &Self::Target {
23296        &self.0
23297    }
23298}
23299
23300impl<T> DerefMut for InvalidationStack<T> {
23301    fn deref_mut(&mut self) -> &mut Self::Target {
23302        &mut self.0
23303    }
23304}
23305
23306impl InvalidationRegion for SnippetState {
23307    fn ranges(&self) -> &[Range<Anchor>] {
23308        &self.ranges[self.active_index]
23309    }
23310}
23311
23312fn edit_prediction_edit_text(
23313    current_snapshot: &BufferSnapshot,
23314    edits: &[(Range<Anchor>, String)],
23315    edit_preview: &EditPreview,
23316    include_deletions: bool,
23317    cx: &App,
23318) -> HighlightedText {
23319    let edits = edits
23320        .iter()
23321        .map(|(anchor, text)| {
23322            (
23323                anchor.start.text_anchor..anchor.end.text_anchor,
23324                text.clone(),
23325            )
23326        })
23327        .collect::<Vec<_>>();
23328
23329    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23330}
23331
23332fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23333    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23334    // Just show the raw edit text with basic styling
23335    let mut text = String::new();
23336    let mut highlights = Vec::new();
23337
23338    let insertion_highlight_style = HighlightStyle {
23339        color: Some(cx.theme().colors().text),
23340        ..Default::default()
23341    };
23342
23343    for (_, edit_text) in edits {
23344        let start_offset = text.len();
23345        text.push_str(edit_text);
23346        let end_offset = text.len();
23347
23348        if start_offset < end_offset {
23349            highlights.push((start_offset..end_offset, insertion_highlight_style));
23350        }
23351    }
23352
23353    HighlightedText {
23354        text: text.into(),
23355        highlights,
23356    }
23357}
23358
23359pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23360    match severity {
23361        lsp::DiagnosticSeverity::ERROR => colors.error,
23362        lsp::DiagnosticSeverity::WARNING => colors.warning,
23363        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23364        lsp::DiagnosticSeverity::HINT => colors.info,
23365        _ => colors.ignored,
23366    }
23367}
23368
23369pub fn styled_runs_for_code_label<'a>(
23370    label: &'a CodeLabel,
23371    syntax_theme: &'a theme::SyntaxTheme,
23372) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23373    let fade_out = HighlightStyle {
23374        fade_out: Some(0.35),
23375        ..Default::default()
23376    };
23377
23378    let mut prev_end = label.filter_range.end;
23379    label
23380        .runs
23381        .iter()
23382        .enumerate()
23383        .flat_map(move |(ix, (range, highlight_id))| {
23384            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23385                style
23386            } else {
23387                return Default::default();
23388            };
23389            let mut muted_style = style;
23390            muted_style.highlight(fade_out);
23391
23392            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23393            if range.start >= label.filter_range.end {
23394                if range.start > prev_end {
23395                    runs.push((prev_end..range.start, fade_out));
23396                }
23397                runs.push((range.clone(), muted_style));
23398            } else if range.end <= label.filter_range.end {
23399                runs.push((range.clone(), style));
23400            } else {
23401                runs.push((range.start..label.filter_range.end, style));
23402                runs.push((label.filter_range.end..range.end, muted_style));
23403            }
23404            prev_end = cmp::max(prev_end, range.end);
23405
23406            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23407                runs.push((prev_end..label.text.len(), fade_out));
23408            }
23409
23410            runs
23411        })
23412}
23413
23414pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23415    let mut prev_index = 0;
23416    let mut prev_codepoint: Option<char> = None;
23417    text.char_indices()
23418        .chain([(text.len(), '\0')])
23419        .filter_map(move |(index, codepoint)| {
23420            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23421            let is_boundary = index == text.len()
23422                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23423                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23424            if is_boundary {
23425                let chunk = &text[prev_index..index];
23426                prev_index = index;
23427                Some(chunk)
23428            } else {
23429                None
23430            }
23431        })
23432}
23433
23434pub trait RangeToAnchorExt: Sized {
23435    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23436
23437    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23438        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23439        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23440    }
23441}
23442
23443impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23444    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23445        let start_offset = self.start.to_offset(snapshot);
23446        let end_offset = self.end.to_offset(snapshot);
23447        if start_offset == end_offset {
23448            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23449        } else {
23450            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23451        }
23452    }
23453}
23454
23455pub trait RowExt {
23456    fn as_f32(&self) -> f32;
23457
23458    fn next_row(&self) -> Self;
23459
23460    fn previous_row(&self) -> Self;
23461
23462    fn minus(&self, other: Self) -> u32;
23463}
23464
23465impl RowExt for DisplayRow {
23466    fn as_f32(&self) -> f32 {
23467        self.0 as f32
23468    }
23469
23470    fn next_row(&self) -> Self {
23471        Self(self.0 + 1)
23472    }
23473
23474    fn previous_row(&self) -> Self {
23475        Self(self.0.saturating_sub(1))
23476    }
23477
23478    fn minus(&self, other: Self) -> u32 {
23479        self.0 - other.0
23480    }
23481}
23482
23483impl RowExt for MultiBufferRow {
23484    fn as_f32(&self) -> f32 {
23485        self.0 as f32
23486    }
23487
23488    fn next_row(&self) -> Self {
23489        Self(self.0 + 1)
23490    }
23491
23492    fn previous_row(&self) -> Self {
23493        Self(self.0.saturating_sub(1))
23494    }
23495
23496    fn minus(&self, other: Self) -> u32 {
23497        self.0 - other.0
23498    }
23499}
23500
23501trait RowRangeExt {
23502    type Row;
23503
23504    fn len(&self) -> usize;
23505
23506    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23507}
23508
23509impl RowRangeExt for Range<MultiBufferRow> {
23510    type Row = MultiBufferRow;
23511
23512    fn len(&self) -> usize {
23513        (self.end.0 - self.start.0) as usize
23514    }
23515
23516    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23517        (self.start.0..self.end.0).map(MultiBufferRow)
23518    }
23519}
23520
23521impl RowRangeExt for Range<DisplayRow> {
23522    type Row = DisplayRow;
23523
23524    fn len(&self) -> usize {
23525        (self.end.0 - self.start.0) as usize
23526    }
23527
23528    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23529        (self.start.0..self.end.0).map(DisplayRow)
23530    }
23531}
23532
23533/// If select range has more than one line, we
23534/// just point the cursor to range.start.
23535fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23536    if range.start.row == range.end.row {
23537        range
23538    } else {
23539        range.start..range.start
23540    }
23541}
23542pub struct KillRing(ClipboardItem);
23543impl Global for KillRing {}
23544
23545const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23546
23547enum BreakpointPromptEditAction {
23548    Log,
23549    Condition,
23550    HitCondition,
23551}
23552
23553struct BreakpointPromptEditor {
23554    pub(crate) prompt: Entity<Editor>,
23555    editor: WeakEntity<Editor>,
23556    breakpoint_anchor: Anchor,
23557    breakpoint: Breakpoint,
23558    edit_action: BreakpointPromptEditAction,
23559    block_ids: HashSet<CustomBlockId>,
23560    editor_margins: Arc<Mutex<EditorMargins>>,
23561    _subscriptions: Vec<Subscription>,
23562}
23563
23564impl BreakpointPromptEditor {
23565    const MAX_LINES: u8 = 4;
23566
23567    fn new(
23568        editor: WeakEntity<Editor>,
23569        breakpoint_anchor: Anchor,
23570        breakpoint: Breakpoint,
23571        edit_action: BreakpointPromptEditAction,
23572        window: &mut Window,
23573        cx: &mut Context<Self>,
23574    ) -> Self {
23575        let base_text = match edit_action {
23576            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23577            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23578            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23579        }
23580        .map(|msg| msg.to_string())
23581        .unwrap_or_default();
23582
23583        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23584        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23585
23586        let prompt = cx.new(|cx| {
23587            let mut prompt = Editor::new(
23588                EditorMode::AutoHeight {
23589                    min_lines: 1,
23590                    max_lines: Some(Self::MAX_LINES as usize),
23591                },
23592                buffer,
23593                None,
23594                window,
23595                cx,
23596            );
23597            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23598            prompt.set_show_cursor_when_unfocused(false, cx);
23599            prompt.set_placeholder_text(
23600                match edit_action {
23601                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23602                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23603                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23604                },
23605                cx,
23606            );
23607
23608            prompt
23609        });
23610
23611        Self {
23612            prompt,
23613            editor,
23614            breakpoint_anchor,
23615            breakpoint,
23616            edit_action,
23617            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23618            block_ids: Default::default(),
23619            _subscriptions: vec![],
23620        }
23621    }
23622
23623    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23624        self.block_ids.extend(block_ids)
23625    }
23626
23627    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23628        if let Some(editor) = self.editor.upgrade() {
23629            let message = self
23630                .prompt
23631                .read(cx)
23632                .buffer
23633                .read(cx)
23634                .as_singleton()
23635                .expect("A multi buffer in breakpoint prompt isn't possible")
23636                .read(cx)
23637                .as_rope()
23638                .to_string();
23639
23640            editor.update(cx, |editor, cx| {
23641                editor.edit_breakpoint_at_anchor(
23642                    self.breakpoint_anchor,
23643                    self.breakpoint.clone(),
23644                    match self.edit_action {
23645                        BreakpointPromptEditAction::Log => {
23646                            BreakpointEditAction::EditLogMessage(message.into())
23647                        }
23648                        BreakpointPromptEditAction::Condition => {
23649                            BreakpointEditAction::EditCondition(message.into())
23650                        }
23651                        BreakpointPromptEditAction::HitCondition => {
23652                            BreakpointEditAction::EditHitCondition(message.into())
23653                        }
23654                    },
23655                    cx,
23656                );
23657
23658                editor.remove_blocks(self.block_ids.clone(), None, cx);
23659                cx.focus_self(window);
23660            });
23661        }
23662    }
23663
23664    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23665        self.editor
23666            .update(cx, |editor, cx| {
23667                editor.remove_blocks(self.block_ids.clone(), None, cx);
23668                window.focus(&editor.focus_handle);
23669            })
23670            .log_err();
23671    }
23672
23673    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23674        let settings = ThemeSettings::get_global(cx);
23675        let text_style = TextStyle {
23676            color: if self.prompt.read(cx).read_only(cx) {
23677                cx.theme().colors().text_disabled
23678            } else {
23679                cx.theme().colors().text
23680            },
23681            font_family: settings.buffer_font.family.clone(),
23682            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23683            font_size: settings.buffer_font_size(cx).into(),
23684            font_weight: settings.buffer_font.weight,
23685            line_height: relative(settings.buffer_line_height.value()),
23686            ..Default::default()
23687        };
23688        EditorElement::new(
23689            &self.prompt,
23690            EditorStyle {
23691                background: cx.theme().colors().editor_background,
23692                local_player: cx.theme().players().local(),
23693                text: text_style,
23694                ..Default::default()
23695            },
23696        )
23697    }
23698}
23699
23700impl Render for BreakpointPromptEditor {
23701    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23702        let editor_margins = *self.editor_margins.lock();
23703        let gutter_dimensions = editor_margins.gutter;
23704        h_flex()
23705            .key_context("Editor")
23706            .bg(cx.theme().colors().editor_background)
23707            .border_y_1()
23708            .border_color(cx.theme().status().info_border)
23709            .size_full()
23710            .py(window.line_height() / 2.5)
23711            .on_action(cx.listener(Self::confirm))
23712            .on_action(cx.listener(Self::cancel))
23713            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23714            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23715    }
23716}
23717
23718impl Focusable for BreakpointPromptEditor {
23719    fn focus_handle(&self, cx: &App) -> FocusHandle {
23720        self.prompt.focus_handle(cx)
23721    }
23722}
23723
23724fn all_edits_insertions_or_deletions(
23725    edits: &Vec<(Range<Anchor>, String)>,
23726    snapshot: &MultiBufferSnapshot,
23727) -> bool {
23728    let mut all_insertions = true;
23729    let mut all_deletions = true;
23730
23731    for (range, new_text) in edits.iter() {
23732        let range_is_empty = range.to_offset(snapshot).is_empty();
23733        let text_is_empty = new_text.is_empty();
23734
23735        if range_is_empty != text_is_empty {
23736            if range_is_empty {
23737                all_deletions = false;
23738            } else {
23739                all_insertions = false;
23740            }
23741        } else {
23742            return false;
23743        }
23744
23745        if !all_insertions && !all_deletions {
23746            return false;
23747        }
23748    }
23749    all_insertions || all_deletions
23750}
23751
23752struct MissingEditPredictionKeybindingTooltip;
23753
23754impl Render for MissingEditPredictionKeybindingTooltip {
23755    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23756        ui::tooltip_container(window, cx, |container, _, cx| {
23757            container
23758                .flex_shrink_0()
23759                .max_w_80()
23760                .min_h(rems_from_px(124.))
23761                .justify_between()
23762                .child(
23763                    v_flex()
23764                        .flex_1()
23765                        .text_ui_sm(cx)
23766                        .child(Label::new("Conflict with Accept Keybinding"))
23767                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23768                )
23769                .child(
23770                    h_flex()
23771                        .pb_1()
23772                        .gap_1()
23773                        .items_end()
23774                        .w_full()
23775                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23776                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23777                        }))
23778                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23779                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23780                        })),
23781                )
23782        })
23783    }
23784}
23785
23786#[derive(Debug, Clone, Copy, PartialEq)]
23787pub struct LineHighlight {
23788    pub background: Background,
23789    pub border: Option<gpui::Hsla>,
23790    pub include_gutter: bool,
23791    pub type_id: Option<TypeId>,
23792}
23793
23794struct LineManipulationResult {
23795    pub new_text: String,
23796    pub line_count_before: usize,
23797    pub line_count_after: usize,
23798}
23799
23800fn render_diff_hunk_controls(
23801    row: u32,
23802    status: &DiffHunkStatus,
23803    hunk_range: Range<Anchor>,
23804    is_created_file: bool,
23805    line_height: Pixels,
23806    editor: &Entity<Editor>,
23807    _window: &mut Window,
23808    cx: &mut App,
23809) -> AnyElement {
23810    h_flex()
23811        .h(line_height)
23812        .mr_1()
23813        .gap_1()
23814        .px_0p5()
23815        .pb_1()
23816        .border_x_1()
23817        .border_b_1()
23818        .border_color(cx.theme().colors().border_variant)
23819        .rounded_b_lg()
23820        .bg(cx.theme().colors().editor_background)
23821        .gap_1()
23822        .block_mouse_except_scroll()
23823        .shadow_md()
23824        .child(if status.has_secondary_hunk() {
23825            Button::new(("stage", row as u64), "Stage")
23826                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23827                .tooltip({
23828                    let focus_handle = editor.focus_handle(cx);
23829                    move |window, cx| {
23830                        Tooltip::for_action_in(
23831                            "Stage Hunk",
23832                            &::git::ToggleStaged,
23833                            &focus_handle,
23834                            window,
23835                            cx,
23836                        )
23837                    }
23838                })
23839                .on_click({
23840                    let editor = editor.clone();
23841                    move |_event, _window, cx| {
23842                        editor.update(cx, |editor, cx| {
23843                            editor.stage_or_unstage_diff_hunks(
23844                                true,
23845                                vec![hunk_range.start..hunk_range.start],
23846                                cx,
23847                            );
23848                        });
23849                    }
23850                })
23851        } else {
23852            Button::new(("unstage", row as u64), "Unstage")
23853                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23854                .tooltip({
23855                    let focus_handle = editor.focus_handle(cx);
23856                    move |window, cx| {
23857                        Tooltip::for_action_in(
23858                            "Unstage Hunk",
23859                            &::git::ToggleStaged,
23860                            &focus_handle,
23861                            window,
23862                            cx,
23863                        )
23864                    }
23865                })
23866                .on_click({
23867                    let editor = editor.clone();
23868                    move |_event, _window, cx| {
23869                        editor.update(cx, |editor, cx| {
23870                            editor.stage_or_unstage_diff_hunks(
23871                                false,
23872                                vec![hunk_range.start..hunk_range.start],
23873                                cx,
23874                            );
23875                        });
23876                    }
23877                })
23878        })
23879        .child(
23880            Button::new(("restore", row as u64), "Restore")
23881                .tooltip({
23882                    let focus_handle = editor.focus_handle(cx);
23883                    move |window, cx| {
23884                        Tooltip::for_action_in(
23885                            "Restore Hunk",
23886                            &::git::Restore,
23887                            &focus_handle,
23888                            window,
23889                            cx,
23890                        )
23891                    }
23892                })
23893                .on_click({
23894                    let editor = editor.clone();
23895                    move |_event, window, cx| {
23896                        editor.update(cx, |editor, cx| {
23897                            let snapshot = editor.snapshot(window, cx);
23898                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23899                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23900                        });
23901                    }
23902                })
23903                .disabled(is_created_file),
23904        )
23905        .when(
23906            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23907            |el| {
23908                el.child(
23909                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23910                        .shape(IconButtonShape::Square)
23911                        .icon_size(IconSize::Small)
23912                        // .disabled(!has_multiple_hunks)
23913                        .tooltip({
23914                            let focus_handle = editor.focus_handle(cx);
23915                            move |window, cx| {
23916                                Tooltip::for_action_in(
23917                                    "Next Hunk",
23918                                    &GoToHunk,
23919                                    &focus_handle,
23920                                    window,
23921                                    cx,
23922                                )
23923                            }
23924                        })
23925                        .on_click({
23926                            let editor = editor.clone();
23927                            move |_event, window, cx| {
23928                                editor.update(cx, |editor, cx| {
23929                                    let snapshot = editor.snapshot(window, cx);
23930                                    let position =
23931                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23932                                    editor.go_to_hunk_before_or_after_position(
23933                                        &snapshot,
23934                                        position,
23935                                        Direction::Next,
23936                                        window,
23937                                        cx,
23938                                    );
23939                                    editor.expand_selected_diff_hunks(cx);
23940                                });
23941                            }
23942                        }),
23943                )
23944                .child(
23945                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23946                        .shape(IconButtonShape::Square)
23947                        .icon_size(IconSize::Small)
23948                        // .disabled(!has_multiple_hunks)
23949                        .tooltip({
23950                            let focus_handle = editor.focus_handle(cx);
23951                            move |window, cx| {
23952                                Tooltip::for_action_in(
23953                                    "Previous Hunk",
23954                                    &GoToPreviousHunk,
23955                                    &focus_handle,
23956                                    window,
23957                                    cx,
23958                                )
23959                            }
23960                        })
23961                        .on_click({
23962                            let editor = editor.clone();
23963                            move |_event, window, cx| {
23964                                editor.update(cx, |editor, cx| {
23965                                    let snapshot = editor.snapshot(window, cx);
23966                                    let point =
23967                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23968                                    editor.go_to_hunk_before_or_after_position(
23969                                        &snapshot,
23970                                        point,
23971                                        Direction::Prev,
23972                                        window,
23973                                        cx,
23974                                    );
23975                                    editor.expand_selected_diff_hunks(cx);
23976                                });
23977                            }
23978                        }),
23979                )
23980            },
23981        )
23982        .into_any_element()
23983}