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
  253struct InlineValueCache {
  254    enabled: bool,
  255    inlays: Vec<InlayId>,
  256    refresh_task: Task<Option<()>>,
  257}
  258
  259impl InlineValueCache {
  260    fn new(enabled: bool) -> Self {
  261        Self {
  262            enabled,
  263            inlays: Vec::new(),
  264            refresh_task: Task::ready(None),
  265        }
  266    }
  267}
  268
  269#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  270pub enum InlayId {
  271    EditPrediction(usize),
  272    DebuggerValue(usize),
  273    // LSP
  274    Hint(usize),
  275    Color(usize),
  276}
  277
  278impl InlayId {
  279    fn id(&self) -> usize {
  280        match self {
  281            Self::EditPrediction(id) => *id,
  282            Self::DebuggerValue(id) => *id,
  283            Self::Hint(id) => *id,
  284            Self::Color(id) => *id,
  285        }
  286    }
  287}
  288
  289pub enum ActiveDebugLine {}
  290pub enum DebugStackFrameLine {}
  291enum DocumentHighlightRead {}
  292enum DocumentHighlightWrite {}
  293enum InputComposition {}
  294pub enum PendingInput {}
  295enum SelectedTextHighlight {}
  296
  297pub enum ConflictsOuter {}
  298pub enum ConflictsOurs {}
  299pub enum ConflictsTheirs {}
  300pub enum ConflictsOursMarker {}
  301pub enum ConflictsTheirsMarker {}
  302
  303#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  304pub enum Navigated {
  305    Yes,
  306    No,
  307}
  308
  309impl Navigated {
  310    pub fn from_bool(yes: bool) -> Navigated {
  311        if yes { Navigated::Yes } else { Navigated::No }
  312    }
  313}
  314
  315#[derive(Debug, Clone, PartialEq, Eq)]
  316enum DisplayDiffHunk {
  317    Folded {
  318        display_row: DisplayRow,
  319    },
  320    Unfolded {
  321        is_created_file: bool,
  322        diff_base_byte_range: Range<usize>,
  323        display_row_range: Range<DisplayRow>,
  324        multi_buffer_range: Range<Anchor>,
  325        status: DiffHunkStatus,
  326    },
  327}
  328
  329pub enum HideMouseCursorOrigin {
  330    TypingAction,
  331    MovementAction,
  332}
  333
  334pub fn init_settings(cx: &mut App) {
  335    EditorSettings::register(cx);
  336}
  337
  338pub fn init(cx: &mut App) {
  339    init_settings(cx);
  340
  341    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  342
  343    workspace::register_project_item::<Editor>(cx);
  344    workspace::FollowableViewRegistry::register::<Editor>(cx);
  345    workspace::register_serializable_item::<Editor>(cx);
  346
  347    cx.observe_new(
  348        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  349            workspace.register_action(Editor::new_file);
  350            workspace.register_action(Editor::new_file_vertical);
  351            workspace.register_action(Editor::new_file_horizontal);
  352            workspace.register_action(Editor::cancel_language_server_work);
  353            workspace.register_action(Editor::toggle_focus);
  354        },
  355    )
  356    .detach();
  357
  358    cx.on_action(move |_: &workspace::NewFile, cx| {
  359        let app_state = workspace::AppState::global(cx);
  360        if let Some(app_state) = app_state.upgrade() {
  361            workspace::open_new(
  362                Default::default(),
  363                app_state,
  364                cx,
  365                |workspace, window, cx| {
  366                    Editor::new_file(workspace, &Default::default(), window, cx)
  367                },
  368            )
  369            .detach();
  370        }
  371    });
  372    cx.on_action(move |_: &workspace::NewWindow, cx| {
  373        let app_state = workspace::AppState::global(cx);
  374        if let Some(app_state) = app_state.upgrade() {
  375            workspace::open_new(
  376                Default::default(),
  377                app_state,
  378                cx,
  379                |workspace, window, cx| {
  380                    cx.activate(true);
  381                    Editor::new_file(workspace, &Default::default(), window, cx)
  382                },
  383            )
  384            .detach();
  385        }
  386    });
  387}
  388
  389pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  390    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  391}
  392
  393pub trait DiagnosticRenderer {
  394    fn render_group(
  395        &self,
  396        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  397        buffer_id: BufferId,
  398        snapshot: EditorSnapshot,
  399        editor: WeakEntity<Editor>,
  400        cx: &mut App,
  401    ) -> Vec<BlockProperties<Anchor>>;
  402
  403    fn render_hover(
  404        &self,
  405        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  406        range: Range<Point>,
  407        buffer_id: BufferId,
  408        cx: &mut App,
  409    ) -> Option<Entity<markdown::Markdown>>;
  410
  411    fn open_link(
  412        &self,
  413        editor: &mut Editor,
  414        link: SharedString,
  415        window: &mut Window,
  416        cx: &mut Context<Editor>,
  417    );
  418}
  419
  420pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  421
  422impl GlobalDiagnosticRenderer {
  423    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  424        cx.try_global::<Self>().map(|g| g.0.clone())
  425    }
  426}
  427
  428impl gpui::Global for GlobalDiagnosticRenderer {}
  429pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  430    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  431}
  432
  433pub struct SearchWithinRange;
  434
  435trait InvalidationRegion {
  436    fn ranges(&self) -> &[Range<Anchor>];
  437}
  438
  439#[derive(Clone, Debug, PartialEq)]
  440pub enum SelectPhase {
  441    Begin {
  442        position: DisplayPoint,
  443        add: bool,
  444        click_count: usize,
  445    },
  446    BeginColumnar {
  447        position: DisplayPoint,
  448        reset: bool,
  449        mode: ColumnarMode,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug, PartialEq)]
  465pub enum ColumnarMode {
  466    FromMouse,
  467    FromSelection,
  468}
  469
  470#[derive(Clone, Debug)]
  471pub enum SelectMode {
  472    Character,
  473    Word(Range<Anchor>),
  474    Line(Range<Anchor>),
  475    All,
  476}
  477
  478#[derive(Clone, PartialEq, Eq, Debug)]
  479pub enum EditorMode {
  480    SingleLine,
  481    AutoHeight {
  482        min_lines: usize,
  483        max_lines: Option<usize>,
  484    },
  485    Full {
  486        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  487        scale_ui_elements_with_buffer_font_size: bool,
  488        /// When set to `true`, the editor will render a background for the active line.
  489        show_active_line_background: bool,
  490        /// When set to `true`, the editor's height will be determined by its content.
  491        sized_by_content: bool,
  492    },
  493    Minimap {
  494        parent: WeakEntity<Editor>,
  495    },
  496}
  497
  498impl EditorMode {
  499    pub fn full() -> Self {
  500        Self::Full {
  501            scale_ui_elements_with_buffer_font_size: true,
  502            show_active_line_background: true,
  503            sized_by_content: false,
  504        }
  505    }
  506
  507    #[inline]
  508    pub fn is_full(&self) -> bool {
  509        matches!(self, Self::Full { .. })
  510    }
  511
  512    #[inline]
  513    pub fn is_single_line(&self) -> bool {
  514        matches!(self, Self::SingleLine { .. })
  515    }
  516
  517    #[inline]
  518    fn is_minimap(&self) -> bool {
  519        matches!(self, Self::Minimap { .. })
  520    }
  521}
  522
  523#[derive(Copy, Clone, Debug)]
  524pub enum SoftWrap {
  525    /// Prefer not to wrap at all.
  526    ///
  527    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  528    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  529    GitDiff,
  530    /// Prefer a single line generally, unless an overly long line is encountered.
  531    None,
  532    /// Soft wrap lines that exceed the editor width.
  533    EditorWidth,
  534    /// Soft wrap lines at the preferred line length.
  535    Column(u32),
  536    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  537    Bounded(u32),
  538}
  539
  540#[derive(Clone)]
  541pub struct EditorStyle {
  542    pub background: Hsla,
  543    pub border: Hsla,
  544    pub local_player: PlayerColor,
  545    pub text: TextStyle,
  546    pub scrollbar_width: Pixels,
  547    pub syntax: Arc<SyntaxTheme>,
  548    pub status: StatusColors,
  549    pub inlay_hints_style: HighlightStyle,
  550    pub edit_prediction_styles: EditPredictionStyles,
  551    pub unnecessary_code_fade: f32,
  552    pub show_underlines: bool,
  553}
  554
  555impl Default for EditorStyle {
  556    fn default() -> Self {
  557        Self {
  558            background: Hsla::default(),
  559            border: Hsla::default(),
  560            local_player: PlayerColor::default(),
  561            text: TextStyle::default(),
  562            scrollbar_width: Pixels::default(),
  563            syntax: Default::default(),
  564            // HACK: Status colors don't have a real default.
  565            // We should look into removing the status colors from the editor
  566            // style and retrieve them directly from the theme.
  567            status: StatusColors::dark(),
  568            inlay_hints_style: HighlightStyle::default(),
  569            edit_prediction_styles: EditPredictionStyles {
  570                insertion: HighlightStyle::default(),
  571                whitespace: HighlightStyle::default(),
  572            },
  573            unnecessary_code_fade: Default::default(),
  574            show_underlines: true,
  575        }
  576    }
  577}
  578
  579pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  580    let show_background = language_settings::language_settings(None, None, cx)
  581        .inlay_hints
  582        .show_background;
  583
  584    HighlightStyle {
  585        color: Some(cx.theme().status().hint),
  586        background_color: show_background.then(|| cx.theme().status().hint_background),
  587        ..HighlightStyle::default()
  588    }
  589}
  590
  591pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  592    EditPredictionStyles {
  593        insertion: HighlightStyle {
  594            color: Some(cx.theme().status().predictive),
  595            ..HighlightStyle::default()
  596        },
  597        whitespace: HighlightStyle {
  598            background_color: Some(cx.theme().status().created_background),
  599            ..HighlightStyle::default()
  600        },
  601    }
  602}
  603
  604type CompletionId = usize;
  605
  606pub(crate) enum EditDisplayMode {
  607    TabAccept,
  608    DiffPopover,
  609    Inline,
  610}
  611
  612enum EditPrediction {
  613    Edit {
  614        edits: Vec<(Range<Anchor>, String)>,
  615        edit_preview: Option<EditPreview>,
  616        display_mode: EditDisplayMode,
  617        snapshot: BufferSnapshot,
  618    },
  619    Move {
  620        target: Anchor,
  621        snapshot: BufferSnapshot,
  622    },
  623}
  624
  625struct EditPredictionState {
  626    inlay_ids: Vec<InlayId>,
  627    completion: EditPrediction,
  628    completion_id: Option<SharedString>,
  629    invalidation_range: Range<Anchor>,
  630}
  631
  632enum EditPredictionSettings {
  633    Disabled,
  634    Enabled {
  635        show_in_menu: bool,
  636        preview_requires_modifier: bool,
  637    },
  638}
  639
  640enum EditPredictionHighlight {}
  641
  642#[derive(Debug, Clone)]
  643struct InlineDiagnostic {
  644    message: SharedString,
  645    group_id: usize,
  646    is_primary: bool,
  647    start: Point,
  648    severity: lsp::DiagnosticSeverity,
  649}
  650
  651pub enum MenuEditPredictionsPolicy {
  652    Never,
  653    ByProvider,
  654}
  655
  656pub enum EditPredictionPreview {
  657    /// Modifier is not pressed
  658    Inactive { released_too_fast: bool },
  659    /// Modifier pressed
  660    Active {
  661        since: Instant,
  662        previous_scroll_position: Option<ScrollAnchor>,
  663    },
  664}
  665
  666impl EditPredictionPreview {
  667    pub fn released_too_fast(&self) -> bool {
  668        match self {
  669            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  670            EditPredictionPreview::Active { .. } => false,
  671        }
  672    }
  673
  674    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  675        if let EditPredictionPreview::Active {
  676            previous_scroll_position,
  677            ..
  678        } = self
  679        {
  680            *previous_scroll_position = scroll_position;
  681        }
  682    }
  683}
  684
  685pub struct ContextMenuOptions {
  686    pub min_entries_visible: usize,
  687    pub max_entries_visible: usize,
  688    pub placement: Option<ContextMenuPlacement>,
  689}
  690
  691#[derive(Debug, Clone, PartialEq, Eq)]
  692pub enum ContextMenuPlacement {
  693    Above,
  694    Below,
  695}
  696
  697#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  698struct EditorActionId(usize);
  699
  700impl EditorActionId {
  701    pub fn post_inc(&mut self) -> Self {
  702        let answer = self.0;
  703
  704        *self = Self(answer + 1);
  705
  706        Self(answer)
  707    }
  708}
  709
  710// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  711// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  712
  713type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  714type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  715
  716#[derive(Default)]
  717struct ScrollbarMarkerState {
  718    scrollbar_size: Size<Pixels>,
  719    dirty: bool,
  720    markers: Arc<[PaintQuad]>,
  721    pending_refresh: Option<Task<Result<()>>>,
  722}
  723
  724impl ScrollbarMarkerState {
  725    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  726        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  727    }
  728}
  729
  730#[derive(Clone, Copy, PartialEq, Eq)]
  731pub enum MinimapVisibility {
  732    Disabled,
  733    Enabled {
  734        /// The configuration currently present in the users settings.
  735        setting_configuration: bool,
  736        /// Whether to override the currently set visibility from the users setting.
  737        toggle_override: bool,
  738    },
  739}
  740
  741impl MinimapVisibility {
  742    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  743        if mode.is_full() {
  744            Self::Enabled {
  745                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  746                toggle_override: false,
  747            }
  748        } else {
  749            Self::Disabled
  750        }
  751    }
  752
  753    fn hidden(&self) -> Self {
  754        match *self {
  755            Self::Enabled {
  756                setting_configuration,
  757                ..
  758            } => Self::Enabled {
  759                setting_configuration,
  760                toggle_override: setting_configuration,
  761            },
  762            Self::Disabled => Self::Disabled,
  763        }
  764    }
  765
  766    fn disabled(&self) -> bool {
  767        match *self {
  768            Self::Disabled => true,
  769            _ => false,
  770        }
  771    }
  772
  773    fn settings_visibility(&self) -> bool {
  774        match *self {
  775            Self::Enabled {
  776                setting_configuration,
  777                ..
  778            } => setting_configuration,
  779            _ => false,
  780        }
  781    }
  782
  783    fn visible(&self) -> bool {
  784        match *self {
  785            Self::Enabled {
  786                setting_configuration,
  787                toggle_override,
  788            } => setting_configuration ^ toggle_override,
  789            _ => false,
  790        }
  791    }
  792
  793    fn toggle_visibility(&self) -> Self {
  794        match *self {
  795            Self::Enabled {
  796                toggle_override,
  797                setting_configuration,
  798            } => Self::Enabled {
  799                setting_configuration,
  800                toggle_override: !toggle_override,
  801            },
  802            Self::Disabled => Self::Disabled,
  803        }
  804    }
  805}
  806
  807#[derive(Clone, Debug)]
  808struct RunnableTasks {
  809    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  810    offset: multi_buffer::Anchor,
  811    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  812    column: u32,
  813    // Values of all named captures, including those starting with '_'
  814    extra_variables: HashMap<String, String>,
  815    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  816    context_range: Range<BufferOffset>,
  817}
  818
  819impl RunnableTasks {
  820    fn resolve<'a>(
  821        &'a self,
  822        cx: &'a task::TaskContext,
  823    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  824        self.templates.iter().filter_map(|(kind, template)| {
  825            template
  826                .resolve_task(&kind.to_id_base(), cx)
  827                .map(|task| (kind.clone(), task))
  828        })
  829    }
  830}
  831
  832#[derive(Clone)]
  833pub struct ResolvedTasks {
  834    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  835    position: Anchor,
  836}
  837
  838#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  839struct BufferOffset(usize);
  840
  841// Addons allow storing per-editor state in other crates (e.g. Vim)
  842pub trait Addon: 'static {
  843    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  844
  845    fn render_buffer_header_controls(
  846        &self,
  847        _: &ExcerptInfo,
  848        _: &Window,
  849        _: &App,
  850    ) -> Option<AnyElement> {
  851        None
  852    }
  853
  854    fn to_any(&self) -> &dyn std::any::Any;
  855
  856    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  857        None
  858    }
  859}
  860
  861struct ChangeLocation {
  862    current: Option<Vec<Anchor>>,
  863    original: Vec<Anchor>,
  864}
  865impl ChangeLocation {
  866    fn locations(&self) -> &[Anchor] {
  867        self.current.as_ref().unwrap_or(&self.original)
  868    }
  869}
  870
  871/// A set of caret positions, registered when the editor was edited.
  872pub struct ChangeList {
  873    changes: Vec<ChangeLocation>,
  874    /// Currently "selected" change.
  875    position: Option<usize>,
  876}
  877
  878impl ChangeList {
  879    pub fn new() -> Self {
  880        Self {
  881            changes: Vec::new(),
  882            position: None,
  883        }
  884    }
  885
  886    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  887    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  888    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  889        if self.changes.is_empty() {
  890            return None;
  891        }
  892
  893        let prev = self.position.unwrap_or(self.changes.len());
  894        let next = if direction == Direction::Prev {
  895            prev.saturating_sub(count)
  896        } else {
  897            (prev + count).min(self.changes.len() - 1)
  898        };
  899        self.position = Some(next);
  900        self.changes.get(next).map(|change| change.locations())
  901    }
  902
  903    /// Adds a new change to the list, resetting the change list position.
  904    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  905        self.position.take();
  906        if let Some(last) = self.changes.last_mut()
  907            && group
  908        {
  909            last.current = Some(new_positions)
  910        } else {
  911            self.changes.push(ChangeLocation {
  912                original: new_positions,
  913                current: None,
  914            });
  915        }
  916    }
  917
  918    pub fn last(&self) -> Option<&[Anchor]> {
  919        self.changes.last().map(|change| change.locations())
  920    }
  921
  922    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  923        self.changes.last().map(|change| change.original.as_slice())
  924    }
  925
  926    pub fn invert_last_group(&mut self) {
  927        if let Some(last) = self.changes.last_mut() {
  928            if let Some(current) = last.current.as_mut() {
  929                mem::swap(&mut last.original, current);
  930            }
  931        }
  932    }
  933}
  934
  935#[derive(Clone)]
  936struct InlineBlamePopoverState {
  937    scroll_handle: ScrollHandle,
  938    commit_message: Option<ParsedCommitMessage>,
  939    markdown: Entity<Markdown>,
  940}
  941
  942struct InlineBlamePopover {
  943    position: gpui::Point<Pixels>,
  944    hide_task: Option<Task<()>>,
  945    popover_bounds: Option<Bounds<Pixels>>,
  946    popover_state: InlineBlamePopoverState,
  947    keyboard_grace: bool,
  948}
  949
  950enum SelectionDragState {
  951    /// State when no drag related activity is detected.
  952    None,
  953    /// State when the mouse is down on a selection that is about to be dragged.
  954    ReadyToDrag {
  955        selection: Selection<Anchor>,
  956        click_position: gpui::Point<Pixels>,
  957        mouse_down_time: Instant,
  958    },
  959    /// State when the mouse is dragging the selection in the editor.
  960    Dragging {
  961        selection: Selection<Anchor>,
  962        drop_cursor: Selection<Anchor>,
  963        hide_drop_cursor: bool,
  964    },
  965}
  966
  967enum ColumnarSelectionState {
  968    FromMouse {
  969        selection_tail: Anchor,
  970        display_point: Option<DisplayPoint>,
  971    },
  972    FromSelection {
  973        selection_tail: Anchor,
  974    },
  975}
  976
  977/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  978/// a breakpoint on them.
  979#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  980struct PhantomBreakpointIndicator {
  981    display_row: DisplayRow,
  982    /// There's a small debounce between hovering over the line and showing the indicator.
  983    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  984    is_active: bool,
  985    collides_with_existing_breakpoint: bool,
  986}
  987
  988/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  989///
  990/// See the [module level documentation](self) for more information.
  991pub struct Editor {
  992    focus_handle: FocusHandle,
  993    last_focused_descendant: Option<WeakFocusHandle>,
  994    /// The text buffer being edited
  995    buffer: Entity<MultiBuffer>,
  996    /// Map of how text in the buffer should be displayed.
  997    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  998    pub display_map: Entity<DisplayMap>,
  999    pub selections: SelectionsCollection,
 1000    pub scroll_manager: ScrollManager,
 1001    /// When inline assist editors are linked, they all render cursors because
 1002    /// typing enters text into each of them, even the ones that aren't focused.
 1003    pub(crate) show_cursor_when_unfocused: bool,
 1004    columnar_selection_state: Option<ColumnarSelectionState>,
 1005    add_selections_state: Option<AddSelectionsState>,
 1006    select_next_state: Option<SelectNextState>,
 1007    select_prev_state: Option<SelectNextState>,
 1008    selection_history: SelectionHistory,
 1009    defer_selection_effects: bool,
 1010    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1011    autoclose_regions: Vec<AutocloseRegion>,
 1012    snippet_stack: InvalidationStack<SnippetState>,
 1013    select_syntax_node_history: SelectSyntaxNodeHistory,
 1014    ime_transaction: Option<TransactionId>,
 1015    pub diagnostics_max_severity: DiagnosticSeverity,
 1016    active_diagnostics: ActiveDiagnostic,
 1017    show_inline_diagnostics: bool,
 1018    inline_diagnostics_update: Task<()>,
 1019    inline_diagnostics_enabled: bool,
 1020    diagnostics_enabled: bool,
 1021    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1022    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1023    hard_wrap: Option<usize>,
 1024
 1025    // TODO: make this a access method
 1026    pub project: Option<Entity<Project>>,
 1027    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1028    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1029    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1030    blink_manager: Entity<BlinkManager>,
 1031    show_cursor_names: bool,
 1032    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1033    pub show_local_selections: bool,
 1034    mode: EditorMode,
 1035    show_breadcrumbs: bool,
 1036    show_gutter: bool,
 1037    show_scrollbars: ScrollbarAxes,
 1038    minimap_visibility: MinimapVisibility,
 1039    offset_content: bool,
 1040    disable_expand_excerpt_buttons: bool,
 1041    show_line_numbers: Option<bool>,
 1042    use_relative_line_numbers: Option<bool>,
 1043    show_git_diff_gutter: Option<bool>,
 1044    show_code_actions: Option<bool>,
 1045    show_runnables: Option<bool>,
 1046    show_breakpoints: Option<bool>,
 1047    show_wrap_guides: Option<bool>,
 1048    show_indent_guides: Option<bool>,
 1049    placeholder_text: Option<Arc<str>>,
 1050    highlight_order: usize,
 1051    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1052    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1053    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1054    scrollbar_marker_state: ScrollbarMarkerState,
 1055    active_indent_guides_state: ActiveIndentGuidesState,
 1056    nav_history: Option<ItemNavHistory>,
 1057    context_menu: RefCell<Option<CodeContextMenu>>,
 1058    context_menu_options: Option<ContextMenuOptions>,
 1059    mouse_context_menu: Option<MouseContextMenu>,
 1060    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1061    inline_blame_popover: Option<InlineBlamePopover>,
 1062    inline_blame_popover_show_task: Option<Task<()>>,
 1063    signature_help_state: SignatureHelpState,
 1064    auto_signature_help: Option<bool>,
 1065    find_all_references_task_sources: Vec<Anchor>,
 1066    next_completion_id: CompletionId,
 1067    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1068    code_actions_task: Option<Task<Result<()>>>,
 1069    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1070    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1071    document_highlights_task: Option<Task<()>>,
 1072    linked_editing_range_task: Option<Task<Option<()>>>,
 1073    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1074    pending_rename: Option<RenameState>,
 1075    searchable: bool,
 1076    cursor_shape: CursorShape,
 1077    current_line_highlight: Option<CurrentLineHighlight>,
 1078    collapse_matches: bool,
 1079    autoindent_mode: Option<AutoindentMode>,
 1080    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1081    input_enabled: bool,
 1082    use_modal_editing: bool,
 1083    read_only: bool,
 1084    leader_id: Option<CollaboratorId>,
 1085    remote_id: Option<ViewId>,
 1086    pub hover_state: HoverState,
 1087    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1088    gutter_hovered: bool,
 1089    hovered_link_state: Option<HoveredLinkState>,
 1090    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1091    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1092    active_edit_prediction: Option<EditPredictionState>,
 1093    /// Used to prevent flickering as the user types while the menu is open
 1094    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1095    edit_prediction_settings: EditPredictionSettings,
 1096    edit_predictions_hidden_for_vim_mode: bool,
 1097    show_edit_predictions_override: Option<bool>,
 1098    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1099    edit_prediction_preview: EditPredictionPreview,
 1100    edit_prediction_indent_conflict: bool,
 1101    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1102    inlay_hint_cache: InlayHintCache,
 1103    next_inlay_id: usize,
 1104    _subscriptions: Vec<Subscription>,
 1105    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1106    gutter_dimensions: GutterDimensions,
 1107    style: Option<EditorStyle>,
 1108    text_style_refinement: Option<TextStyleRefinement>,
 1109    next_editor_action_id: EditorActionId,
 1110    editor_actions: Rc<
 1111        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1112    >,
 1113    use_autoclose: bool,
 1114    use_auto_surround: bool,
 1115    auto_replace_emoji_shortcode: bool,
 1116    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1117    show_git_blame_gutter: bool,
 1118    show_git_blame_inline: bool,
 1119    show_git_blame_inline_delay_task: Option<Task<()>>,
 1120    git_blame_inline_enabled: bool,
 1121    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1122    serialize_dirty_buffers: bool,
 1123    show_selection_menu: Option<bool>,
 1124    blame: Option<Entity<GitBlame>>,
 1125    blame_subscription: Option<Subscription>,
 1126    custom_context_menu: Option<
 1127        Box<
 1128            dyn 'static
 1129                + Fn(
 1130                    &mut Self,
 1131                    DisplayPoint,
 1132                    &mut Window,
 1133                    &mut Context<Self>,
 1134                ) -> Option<Entity<ui::ContextMenu>>,
 1135        >,
 1136    >,
 1137    last_bounds: Option<Bounds<Pixels>>,
 1138    last_position_map: Option<Rc<PositionMap>>,
 1139    expect_bounds_change: Option<Bounds<Pixels>>,
 1140    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1141    tasks_update_task: Option<Task<()>>,
 1142    breakpoint_store: Option<Entity<BreakpointStore>>,
 1143    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1144    hovered_diff_hunk_row: Option<DisplayRow>,
 1145    pull_diagnostics_task: Task<()>,
 1146    in_project_search: bool,
 1147    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1148    breadcrumb_header: Option<String>,
 1149    focused_block: Option<FocusedBlock>,
 1150    next_scroll_position: NextScrollCursorCenterTopBottom,
 1151    addons: HashMap<TypeId, Box<dyn Addon>>,
 1152    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1153    load_diff_task: Option<Shared<Task<()>>>,
 1154    /// Whether we are temporarily displaying a diff other than git's
 1155    temporary_diff_override: bool,
 1156    selection_mark_mode: bool,
 1157    toggle_fold_multiple_buffers: Task<()>,
 1158    _scroll_cursor_center_top_bottom_task: Task<()>,
 1159    serialize_selections: Task<()>,
 1160    serialize_folds: Task<()>,
 1161    mouse_cursor_hidden: bool,
 1162    minimap: Option<Entity<Self>>,
 1163    hide_mouse_mode: HideMouseMode,
 1164    pub change_list: ChangeList,
 1165    inline_value_cache: InlineValueCache,
 1166    selection_drag_state: SelectionDragState,
 1167    next_color_inlay_id: usize,
 1168    colors: Option<LspColorData>,
 1169    folding_newlines: Task<()>,
 1170}
 1171
 1172#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1173enum NextScrollCursorCenterTopBottom {
 1174    #[default]
 1175    Center,
 1176    Top,
 1177    Bottom,
 1178}
 1179
 1180impl NextScrollCursorCenterTopBottom {
 1181    fn next(&self) -> Self {
 1182        match self {
 1183            Self::Center => Self::Top,
 1184            Self::Top => Self::Bottom,
 1185            Self::Bottom => Self::Center,
 1186        }
 1187    }
 1188}
 1189
 1190#[derive(Clone)]
 1191pub struct EditorSnapshot {
 1192    pub mode: EditorMode,
 1193    show_gutter: bool,
 1194    show_line_numbers: Option<bool>,
 1195    show_git_diff_gutter: Option<bool>,
 1196    show_code_actions: Option<bool>,
 1197    show_runnables: Option<bool>,
 1198    show_breakpoints: Option<bool>,
 1199    git_blame_gutter_max_author_length: Option<usize>,
 1200    pub display_snapshot: DisplaySnapshot,
 1201    pub placeholder_text: Option<Arc<str>>,
 1202    is_focused: bool,
 1203    scroll_anchor: ScrollAnchor,
 1204    ongoing_scroll: OngoingScroll,
 1205    current_line_highlight: CurrentLineHighlight,
 1206    gutter_hovered: bool,
 1207}
 1208
 1209#[derive(Default, Debug, Clone, Copy)]
 1210pub struct GutterDimensions {
 1211    pub left_padding: Pixels,
 1212    pub right_padding: Pixels,
 1213    pub width: Pixels,
 1214    pub margin: Pixels,
 1215    pub git_blame_entries_width: Option<Pixels>,
 1216}
 1217
 1218impl GutterDimensions {
 1219    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1220        Self {
 1221            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1222            ..Default::default()
 1223        }
 1224    }
 1225
 1226    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1227        -cx.text_system().descent(font_id, font_size)
 1228    }
 1229    /// The full width of the space taken up by the gutter.
 1230    pub fn full_width(&self) -> Pixels {
 1231        self.margin + self.width
 1232    }
 1233
 1234    /// The width of the space reserved for the fold indicators,
 1235    /// use alongside 'justify_end' and `gutter_width` to
 1236    /// right align content with the line numbers
 1237    pub fn fold_area_width(&self) -> Pixels {
 1238        self.margin + self.right_padding
 1239    }
 1240}
 1241
 1242struct CharacterDimensions {
 1243    em_width: Pixels,
 1244    em_advance: Pixels,
 1245    line_height: Pixels,
 1246}
 1247
 1248#[derive(Debug)]
 1249pub struct RemoteSelection {
 1250    pub replica_id: ReplicaId,
 1251    pub selection: Selection<Anchor>,
 1252    pub cursor_shape: CursorShape,
 1253    pub collaborator_id: CollaboratorId,
 1254    pub line_mode: bool,
 1255    pub user_name: Option<SharedString>,
 1256    pub color: PlayerColor,
 1257}
 1258
 1259#[derive(Clone, Debug)]
 1260struct SelectionHistoryEntry {
 1261    selections: Arc<[Selection<Anchor>]>,
 1262    select_next_state: Option<SelectNextState>,
 1263    select_prev_state: Option<SelectNextState>,
 1264    add_selections_state: Option<AddSelectionsState>,
 1265}
 1266
 1267#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1268enum SelectionHistoryMode {
 1269    Normal,
 1270    Undoing,
 1271    Redoing,
 1272    Skipping,
 1273}
 1274
 1275#[derive(Clone, PartialEq, Eq, Hash)]
 1276struct HoveredCursor {
 1277    replica_id: u16,
 1278    selection_id: usize,
 1279}
 1280
 1281impl Default for SelectionHistoryMode {
 1282    fn default() -> Self {
 1283        Self::Normal
 1284    }
 1285}
 1286
 1287#[derive(Debug)]
 1288/// SelectionEffects controls the side-effects of updating the selection.
 1289///
 1290/// The default behaviour does "what you mostly want":
 1291/// - it pushes to the nav history if the cursor moved by >10 lines
 1292/// - it re-triggers completion requests
 1293/// - it scrolls to fit
 1294///
 1295/// You might want to modify these behaviours. For example when doing a "jump"
 1296/// like go to definition, we always want to add to nav history; but when scrolling
 1297/// in vim mode we never do.
 1298///
 1299/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1300/// move.
 1301#[derive(Clone)]
 1302pub struct SelectionEffects {
 1303    nav_history: Option<bool>,
 1304    completions: bool,
 1305    scroll: Option<Autoscroll>,
 1306}
 1307
 1308impl Default for SelectionEffects {
 1309    fn default() -> Self {
 1310        Self {
 1311            nav_history: None,
 1312            completions: true,
 1313            scroll: Some(Autoscroll::fit()),
 1314        }
 1315    }
 1316}
 1317impl SelectionEffects {
 1318    pub fn scroll(scroll: Autoscroll) -> Self {
 1319        Self {
 1320            scroll: Some(scroll),
 1321            ..Default::default()
 1322        }
 1323    }
 1324
 1325    pub fn no_scroll() -> Self {
 1326        Self {
 1327            scroll: None,
 1328            ..Default::default()
 1329        }
 1330    }
 1331
 1332    pub fn completions(self, completions: bool) -> Self {
 1333        Self {
 1334            completions,
 1335            ..self
 1336        }
 1337    }
 1338
 1339    pub fn nav_history(self, nav_history: bool) -> Self {
 1340        Self {
 1341            nav_history: Some(nav_history),
 1342            ..self
 1343        }
 1344    }
 1345}
 1346
 1347struct DeferredSelectionEffectsState {
 1348    changed: bool,
 1349    effects: SelectionEffects,
 1350    old_cursor_position: Anchor,
 1351    history_entry: SelectionHistoryEntry,
 1352}
 1353
 1354#[derive(Default)]
 1355struct SelectionHistory {
 1356    #[allow(clippy::type_complexity)]
 1357    selections_by_transaction:
 1358        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1359    mode: SelectionHistoryMode,
 1360    undo_stack: VecDeque<SelectionHistoryEntry>,
 1361    redo_stack: VecDeque<SelectionHistoryEntry>,
 1362}
 1363
 1364impl SelectionHistory {
 1365    #[track_caller]
 1366    fn insert_transaction(
 1367        &mut self,
 1368        transaction_id: TransactionId,
 1369        selections: Arc<[Selection<Anchor>]>,
 1370    ) {
 1371        if selections.is_empty() {
 1372            log::error!(
 1373                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1374                std::panic::Location::caller()
 1375            );
 1376            return;
 1377        }
 1378        self.selections_by_transaction
 1379            .insert(transaction_id, (selections, None));
 1380    }
 1381
 1382    #[allow(clippy::type_complexity)]
 1383    fn transaction(
 1384        &self,
 1385        transaction_id: TransactionId,
 1386    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1387        self.selections_by_transaction.get(&transaction_id)
 1388    }
 1389
 1390    #[allow(clippy::type_complexity)]
 1391    fn transaction_mut(
 1392        &mut self,
 1393        transaction_id: TransactionId,
 1394    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1395        self.selections_by_transaction.get_mut(&transaction_id)
 1396    }
 1397
 1398    fn push(&mut self, entry: SelectionHistoryEntry) {
 1399        if !entry.selections.is_empty() {
 1400            match self.mode {
 1401                SelectionHistoryMode::Normal => {
 1402                    self.push_undo(entry);
 1403                    self.redo_stack.clear();
 1404                }
 1405                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1406                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1407                SelectionHistoryMode::Skipping => {}
 1408            }
 1409        }
 1410    }
 1411
 1412    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1413        if self
 1414            .undo_stack
 1415            .back()
 1416            .map_or(true, |e| e.selections != entry.selections)
 1417        {
 1418            self.undo_stack.push_back(entry);
 1419            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1420                self.undo_stack.pop_front();
 1421            }
 1422        }
 1423    }
 1424
 1425    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1426        if self
 1427            .redo_stack
 1428            .back()
 1429            .map_or(true, |e| e.selections != entry.selections)
 1430        {
 1431            self.redo_stack.push_back(entry);
 1432            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1433                self.redo_stack.pop_front();
 1434            }
 1435        }
 1436    }
 1437}
 1438
 1439#[derive(Clone, Copy)]
 1440pub struct RowHighlightOptions {
 1441    pub autoscroll: bool,
 1442    pub include_gutter: bool,
 1443}
 1444
 1445impl Default for RowHighlightOptions {
 1446    fn default() -> Self {
 1447        Self {
 1448            autoscroll: Default::default(),
 1449            include_gutter: true,
 1450        }
 1451    }
 1452}
 1453
 1454struct RowHighlight {
 1455    index: usize,
 1456    range: Range<Anchor>,
 1457    color: Hsla,
 1458    options: RowHighlightOptions,
 1459    type_id: TypeId,
 1460}
 1461
 1462#[derive(Clone, Debug)]
 1463struct AddSelectionsState {
 1464    groups: Vec<AddSelectionsGroup>,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsGroup {
 1469    above: bool,
 1470    stack: Vec<usize>,
 1471}
 1472
 1473#[derive(Clone)]
 1474struct SelectNextState {
 1475    query: AhoCorasick,
 1476    wordwise: bool,
 1477    done: bool,
 1478}
 1479
 1480impl std::fmt::Debug for SelectNextState {
 1481    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1482        f.debug_struct(std::any::type_name::<Self>())
 1483            .field("wordwise", &self.wordwise)
 1484            .field("done", &self.done)
 1485            .finish()
 1486    }
 1487}
 1488
 1489#[derive(Debug)]
 1490struct AutocloseRegion {
 1491    selection_id: usize,
 1492    range: Range<Anchor>,
 1493    pair: BracketPair,
 1494}
 1495
 1496#[derive(Debug)]
 1497struct SnippetState {
 1498    ranges: Vec<Vec<Range<Anchor>>>,
 1499    active_index: usize,
 1500    choices: Vec<Option<Vec<String>>>,
 1501}
 1502
 1503#[doc(hidden)]
 1504pub struct RenameState {
 1505    pub range: Range<Anchor>,
 1506    pub old_name: Arc<str>,
 1507    pub editor: Entity<Editor>,
 1508    block_id: CustomBlockId,
 1509}
 1510
 1511struct InvalidationStack<T>(Vec<T>);
 1512
 1513struct RegisteredEditPredictionProvider {
 1514    provider: Arc<dyn EditPredictionProviderHandle>,
 1515    _subscription: Subscription,
 1516}
 1517
 1518#[derive(Debug, PartialEq, Eq)]
 1519pub struct ActiveDiagnosticGroup {
 1520    pub active_range: Range<Anchor>,
 1521    pub active_message: String,
 1522    pub group_id: usize,
 1523    pub blocks: HashSet<CustomBlockId>,
 1524}
 1525
 1526#[derive(Debug, PartialEq, Eq)]
 1527
 1528pub(crate) enum ActiveDiagnostic {
 1529    None,
 1530    All,
 1531    Group(ActiveDiagnosticGroup),
 1532}
 1533
 1534#[derive(Serialize, Deserialize, Clone, Debug)]
 1535pub struct ClipboardSelection {
 1536    /// The number of bytes in this selection.
 1537    pub len: usize,
 1538    /// Whether this was a full-line selection.
 1539    pub is_entire_line: bool,
 1540    /// The indentation of the first line when this content was originally copied.
 1541    pub first_line_indent: u32,
 1542}
 1543
 1544// selections, scroll behavior, was newest selection reversed
 1545type SelectSyntaxNodeHistoryState = (
 1546    Box<[Selection<usize>]>,
 1547    SelectSyntaxNodeScrollBehavior,
 1548    bool,
 1549);
 1550
 1551#[derive(Default)]
 1552struct SelectSyntaxNodeHistory {
 1553    stack: Vec<SelectSyntaxNodeHistoryState>,
 1554    // disable temporarily to allow changing selections without losing the stack
 1555    pub disable_clearing: bool,
 1556}
 1557
 1558impl SelectSyntaxNodeHistory {
 1559    pub fn try_clear(&mut self) {
 1560        if !self.disable_clearing {
 1561            self.stack.clear();
 1562        }
 1563    }
 1564
 1565    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1566        self.stack.push(selection);
 1567    }
 1568
 1569    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1570        self.stack.pop()
 1571    }
 1572}
 1573
 1574enum SelectSyntaxNodeScrollBehavior {
 1575    CursorTop,
 1576    FitSelection,
 1577    CursorBottom,
 1578}
 1579
 1580#[derive(Debug)]
 1581pub(crate) struct NavigationData {
 1582    cursor_anchor: Anchor,
 1583    cursor_position: Point,
 1584    scroll_anchor: ScrollAnchor,
 1585    scroll_top_row: u32,
 1586}
 1587
 1588#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1589pub enum GotoDefinitionKind {
 1590    Symbol,
 1591    Declaration,
 1592    Type,
 1593    Implementation,
 1594}
 1595
 1596#[derive(Debug, Clone)]
 1597enum InlayHintRefreshReason {
 1598    ModifiersChanged(bool),
 1599    Toggle(bool),
 1600    SettingsChange(InlayHintSettings),
 1601    NewLinesShown,
 1602    BufferEdited(HashSet<Arc<Language>>),
 1603    RefreshRequested,
 1604    ExcerptsRemoved(Vec<ExcerptId>),
 1605}
 1606
 1607impl InlayHintRefreshReason {
 1608    fn description(&self) -> &'static str {
 1609        match self {
 1610            Self::ModifiersChanged(_) => "modifiers changed",
 1611            Self::Toggle(_) => "toggle",
 1612            Self::SettingsChange(_) => "settings change",
 1613            Self::NewLinesShown => "new lines shown",
 1614            Self::BufferEdited(_) => "buffer edited",
 1615            Self::RefreshRequested => "refresh requested",
 1616            Self::ExcerptsRemoved(_) => "excerpts removed",
 1617        }
 1618    }
 1619}
 1620
 1621pub enum FormatTarget {
 1622    Buffers(HashSet<Entity<Buffer>>),
 1623    Ranges(Vec<Range<MultiBufferPoint>>),
 1624}
 1625
 1626pub(crate) struct FocusedBlock {
 1627    id: BlockId,
 1628    focus_handle: WeakFocusHandle,
 1629}
 1630
 1631#[derive(Clone)]
 1632enum JumpData {
 1633    MultiBufferRow {
 1634        row: MultiBufferRow,
 1635        line_offset_from_top: u32,
 1636    },
 1637    MultiBufferPoint {
 1638        excerpt_id: ExcerptId,
 1639        position: Point,
 1640        anchor: text::Anchor,
 1641        line_offset_from_top: u32,
 1642    },
 1643}
 1644
 1645pub enum MultibufferSelectionMode {
 1646    First,
 1647    All,
 1648}
 1649
 1650#[derive(Clone, Copy, Debug, Default)]
 1651pub struct RewrapOptions {
 1652    pub override_language_settings: bool,
 1653    pub preserve_existing_whitespace: bool,
 1654}
 1655
 1656impl Editor {
 1657    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1658        let buffer = cx.new(|cx| Buffer::local("", cx));
 1659        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1660        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1661    }
 1662
 1663    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1664        let buffer = cx.new(|cx| Buffer::local("", cx));
 1665        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1666        Self::new(EditorMode::full(), buffer, None, window, cx)
 1667    }
 1668
 1669    pub fn auto_height(
 1670        min_lines: usize,
 1671        max_lines: usize,
 1672        window: &mut Window,
 1673        cx: &mut Context<Self>,
 1674    ) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(
 1678            EditorMode::AutoHeight {
 1679                min_lines,
 1680                max_lines: Some(max_lines),
 1681            },
 1682            buffer,
 1683            None,
 1684            window,
 1685            cx,
 1686        )
 1687    }
 1688
 1689    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1690    /// The editor grows as tall as needed to fit its content.
 1691    pub fn auto_height_unbounded(
 1692        min_lines: usize,
 1693        window: &mut Window,
 1694        cx: &mut Context<Self>,
 1695    ) -> Self {
 1696        let buffer = cx.new(|cx| Buffer::local("", cx));
 1697        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1698        Self::new(
 1699            EditorMode::AutoHeight {
 1700                min_lines,
 1701                max_lines: None,
 1702            },
 1703            buffer,
 1704            None,
 1705            window,
 1706            cx,
 1707        )
 1708    }
 1709
 1710    pub fn for_buffer(
 1711        buffer: Entity<Buffer>,
 1712        project: Option<Entity<Project>>,
 1713        window: &mut Window,
 1714        cx: &mut Context<Self>,
 1715    ) -> Self {
 1716        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1717        Self::new(EditorMode::full(), buffer, project, window, cx)
 1718    }
 1719
 1720    pub fn for_multibuffer(
 1721        buffer: Entity<MultiBuffer>,
 1722        project: Option<Entity<Project>>,
 1723        window: &mut Window,
 1724        cx: &mut Context<Self>,
 1725    ) -> Self {
 1726        Self::new(EditorMode::full(), buffer, project, window, cx)
 1727    }
 1728
 1729    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1730        let mut clone = Self::new(
 1731            self.mode.clone(),
 1732            self.buffer.clone(),
 1733            self.project.clone(),
 1734            window,
 1735            cx,
 1736        );
 1737        self.display_map.update(cx, |display_map, cx| {
 1738            let snapshot = display_map.snapshot(cx);
 1739            clone.display_map.update(cx, |display_map, cx| {
 1740                display_map.set_state(&snapshot, cx);
 1741            });
 1742        });
 1743        clone.folds_did_change(cx);
 1744        clone.selections.clone_state(&self.selections);
 1745        clone.scroll_manager.clone_state(&self.scroll_manager);
 1746        clone.searchable = self.searchable;
 1747        clone.read_only = self.read_only;
 1748        clone
 1749    }
 1750
 1751    pub fn new(
 1752        mode: EditorMode,
 1753        buffer: Entity<MultiBuffer>,
 1754        project: Option<Entity<Project>>,
 1755        window: &mut Window,
 1756        cx: &mut Context<Self>,
 1757    ) -> Self {
 1758        Editor::new_internal(mode, buffer, project, None, window, cx)
 1759    }
 1760
 1761    fn new_internal(
 1762        mode: EditorMode,
 1763        buffer: Entity<MultiBuffer>,
 1764        project: Option<Entity<Project>>,
 1765        display_map: Option<Entity<DisplayMap>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        debug_assert!(
 1770            display_map.is_none() || mode.is_minimap(),
 1771            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1772        );
 1773
 1774        let full_mode = mode.is_full();
 1775        let is_minimap = mode.is_minimap();
 1776        let diagnostics_max_severity = if full_mode {
 1777            EditorSettings::get_global(cx)
 1778                .diagnostics_max_severity
 1779                .unwrap_or(DiagnosticSeverity::Hint)
 1780        } else {
 1781            DiagnosticSeverity::Off
 1782        };
 1783        let style = window.text_style();
 1784        let font_size = style.font_size.to_pixels(window.rem_size());
 1785        let editor = cx.entity().downgrade();
 1786        let fold_placeholder = FoldPlaceholder {
 1787            constrain_width: true,
 1788            render: Arc::new(move |fold_id, fold_range, cx| {
 1789                let editor = editor.clone();
 1790                div()
 1791                    .id(fold_id)
 1792                    .bg(cx.theme().colors().ghost_element_background)
 1793                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1794                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1795                    .rounded_xs()
 1796                    .size_full()
 1797                    .cursor_pointer()
 1798                    .child("")
 1799                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1800                    .on_click(move |_, _window, cx| {
 1801                        editor
 1802                            .update(cx, |editor, cx| {
 1803                                editor.unfold_ranges(
 1804                                    &[fold_range.start..fold_range.end],
 1805                                    true,
 1806                                    false,
 1807                                    cx,
 1808                                );
 1809                                cx.stop_propagation();
 1810                            })
 1811                            .ok();
 1812                    })
 1813                    .into_any()
 1814            }),
 1815            merge_adjacent: true,
 1816            ..FoldPlaceholder::default()
 1817        };
 1818        let display_map = display_map.unwrap_or_else(|| {
 1819            cx.new(|cx| {
 1820                DisplayMap::new(
 1821                    buffer.clone(),
 1822                    style.font(),
 1823                    font_size,
 1824                    None,
 1825                    FILE_HEADER_HEIGHT,
 1826                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1827                    fold_placeholder,
 1828                    diagnostics_max_severity,
 1829                    cx,
 1830                )
 1831            })
 1832        });
 1833
 1834        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1835
 1836        let blink_manager = cx.new(|cx| {
 1837            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1838            if is_minimap {
 1839                blink_manager.disable(cx);
 1840            }
 1841            blink_manager
 1842        });
 1843
 1844        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1845            .then(|| language_settings::SoftWrap::None);
 1846
 1847        let mut project_subscriptions = Vec::new();
 1848        if full_mode {
 1849            if let Some(project) = project.as_ref() {
 1850                project_subscriptions.push(cx.subscribe_in(
 1851                    project,
 1852                    window,
 1853                    |editor, _, event, window, cx| match event {
 1854                        project::Event::RefreshCodeLens => {
 1855                            // we always query lens with actions, without storing them, always refreshing them
 1856                        }
 1857                        project::Event::RefreshInlayHints => {
 1858                            editor
 1859                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1860                        }
 1861                        project::Event::LanguageServerAdded(..)
 1862                        | project::Event::LanguageServerRemoved(..) => {
 1863                            if editor.tasks_update_task.is_none() {
 1864                                editor.tasks_update_task =
 1865                                    Some(editor.refresh_runnables(window, cx));
 1866                            }
 1867                        }
 1868                        project::Event::SnippetEdit(id, snippet_edits) => {
 1869                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1870                                let focus_handle = editor.focus_handle(cx);
 1871                                if focus_handle.is_focused(window) {
 1872                                    let snapshot = buffer.read(cx).snapshot();
 1873                                    for (range, snippet) in snippet_edits {
 1874                                        let editor_range =
 1875                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1876                                        editor
 1877                                            .insert_snippet(
 1878                                                &[editor_range],
 1879                                                snippet.clone(),
 1880                                                window,
 1881                                                cx,
 1882                                            )
 1883                                            .ok();
 1884                                    }
 1885                                }
 1886                            }
 1887                        }
 1888                        project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1889                            if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1890                                editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1891                            }
 1892                        }
 1893                        _ => {}
 1894                    },
 1895                ));
 1896                if let Some(task_inventory) = project
 1897                    .read(cx)
 1898                    .task_store()
 1899                    .read(cx)
 1900                    .task_inventory()
 1901                    .cloned()
 1902                {
 1903                    project_subscriptions.push(cx.observe_in(
 1904                        &task_inventory,
 1905                        window,
 1906                        |editor, _, window, cx| {
 1907                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1908                        },
 1909                    ));
 1910                };
 1911
 1912                project_subscriptions.push(cx.subscribe_in(
 1913                    &project.read(cx).breakpoint_store(),
 1914                    window,
 1915                    |editor, _, event, window, cx| match event {
 1916                        BreakpointStoreEvent::ClearDebugLines => {
 1917                            editor.clear_row_highlights::<ActiveDebugLine>();
 1918                            editor.refresh_inline_values(cx);
 1919                        }
 1920                        BreakpointStoreEvent::SetDebugLine => {
 1921                            if editor.go_to_active_debug_line(window, cx) {
 1922                                cx.stop_propagation();
 1923                            }
 1924
 1925                            editor.refresh_inline_values(cx);
 1926                        }
 1927                        _ => {}
 1928                    },
 1929                ));
 1930                let git_store = project.read(cx).git_store().clone();
 1931                let project = project.clone();
 1932                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1933                    match event {
 1934                        GitStoreEvent::RepositoryUpdated(
 1935                            _,
 1936                            RepositoryEvent::Updated {
 1937                                new_instance: true, ..
 1938                            },
 1939                            _,
 1940                        ) => {
 1941                            this.load_diff_task = Some(
 1942                                update_uncommitted_diff_for_buffer(
 1943                                    cx.entity(),
 1944                                    &project,
 1945                                    this.buffer.read(cx).all_buffers(),
 1946                                    this.buffer.clone(),
 1947                                    cx,
 1948                                )
 1949                                .shared(),
 1950                            );
 1951                        }
 1952                        _ => {}
 1953                    }
 1954                }));
 1955            }
 1956        }
 1957
 1958        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1959
 1960        let inlay_hint_settings =
 1961            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1962        let focus_handle = cx.focus_handle();
 1963        if !is_minimap {
 1964            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1965                .detach();
 1966            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1967                .detach();
 1968            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1969                .detach();
 1970            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1971                .detach();
 1972            cx.observe_pending_input(window, Self::observe_pending_input)
 1973                .detach();
 1974        }
 1975
 1976        let show_indent_guides = if matches!(
 1977            mode,
 1978            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1979        ) {
 1980            Some(false)
 1981        } else {
 1982            None
 1983        };
 1984
 1985        let breakpoint_store = match (&mode, project.as_ref()) {
 1986            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1987            _ => None,
 1988        };
 1989
 1990        let mut code_action_providers = Vec::new();
 1991        let mut load_uncommitted_diff = None;
 1992        if let Some(project) = project.clone() {
 1993            load_uncommitted_diff = Some(
 1994                update_uncommitted_diff_for_buffer(
 1995                    cx.entity(),
 1996                    &project,
 1997                    buffer.read(cx).all_buffers(),
 1998                    buffer.clone(),
 1999                    cx,
 2000                )
 2001                .shared(),
 2002            );
 2003            code_action_providers.push(Rc::new(project) as Rc<_>);
 2004        }
 2005
 2006        let mut editor = Self {
 2007            focus_handle,
 2008            show_cursor_when_unfocused: false,
 2009            last_focused_descendant: None,
 2010            buffer: buffer.clone(),
 2011            display_map: display_map.clone(),
 2012            selections,
 2013            scroll_manager: ScrollManager::new(cx),
 2014            columnar_selection_state: None,
 2015            add_selections_state: None,
 2016            select_next_state: None,
 2017            select_prev_state: None,
 2018            selection_history: SelectionHistory::default(),
 2019            defer_selection_effects: false,
 2020            deferred_selection_effects_state: None,
 2021            autoclose_regions: Vec::new(),
 2022            snippet_stack: InvalidationStack::default(),
 2023            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2024            ime_transaction: None,
 2025            active_diagnostics: ActiveDiagnostic::None,
 2026            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2027            inline_diagnostics_update: Task::ready(()),
 2028            inline_diagnostics: Vec::new(),
 2029            soft_wrap_mode_override,
 2030            diagnostics_max_severity,
 2031            hard_wrap: None,
 2032            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2033            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2034            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2035            project,
 2036            blink_manager: blink_manager.clone(),
 2037            show_local_selections: true,
 2038            show_scrollbars: ScrollbarAxes {
 2039                horizontal: full_mode,
 2040                vertical: full_mode,
 2041            },
 2042            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2043            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2044            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2045            show_gutter: full_mode,
 2046            show_line_numbers: (!full_mode).then_some(false),
 2047            use_relative_line_numbers: None,
 2048            disable_expand_excerpt_buttons: !full_mode,
 2049            show_git_diff_gutter: None,
 2050            show_code_actions: None,
 2051            show_runnables: None,
 2052            show_breakpoints: None,
 2053            show_wrap_guides: None,
 2054            show_indent_guides,
 2055            placeholder_text: None,
 2056            highlight_order: 0,
 2057            highlighted_rows: HashMap::default(),
 2058            background_highlights: TreeMap::default(),
 2059            gutter_highlights: TreeMap::default(),
 2060            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2061            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2062            nav_history: None,
 2063            context_menu: RefCell::new(None),
 2064            context_menu_options: None,
 2065            mouse_context_menu: None,
 2066            completion_tasks: Vec::new(),
 2067            inline_blame_popover: None,
 2068            inline_blame_popover_show_task: None,
 2069            signature_help_state: SignatureHelpState::default(),
 2070            auto_signature_help: None,
 2071            find_all_references_task_sources: Vec::new(),
 2072            next_completion_id: 0,
 2073            next_inlay_id: 0,
 2074            code_action_providers,
 2075            available_code_actions: None,
 2076            code_actions_task: None,
 2077            quick_selection_highlight_task: None,
 2078            debounced_selection_highlight_task: None,
 2079            document_highlights_task: None,
 2080            linked_editing_range_task: None,
 2081            pending_rename: None,
 2082            searchable: !is_minimap,
 2083            cursor_shape: EditorSettings::get_global(cx)
 2084                .cursor_shape
 2085                .unwrap_or_default(),
 2086            current_line_highlight: None,
 2087            autoindent_mode: Some(AutoindentMode::EachLine),
 2088            collapse_matches: false,
 2089            workspace: None,
 2090            input_enabled: !is_minimap,
 2091            use_modal_editing: full_mode,
 2092            read_only: is_minimap,
 2093            use_autoclose: true,
 2094            use_auto_surround: true,
 2095            auto_replace_emoji_shortcode: false,
 2096            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2097            leader_id: None,
 2098            remote_id: None,
 2099            hover_state: HoverState::default(),
 2100            pending_mouse_down: None,
 2101            hovered_link_state: None,
 2102            edit_prediction_provider: None,
 2103            active_edit_prediction: None,
 2104            stale_edit_prediction_in_menu: None,
 2105            edit_prediction_preview: EditPredictionPreview::Inactive {
 2106                released_too_fast: false,
 2107            },
 2108            inline_diagnostics_enabled: full_mode,
 2109            diagnostics_enabled: full_mode,
 2110            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2111            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2112            gutter_hovered: false,
 2113            pixel_position_of_newest_cursor: None,
 2114            last_bounds: None,
 2115            last_position_map: None,
 2116            expect_bounds_change: None,
 2117            gutter_dimensions: GutterDimensions::default(),
 2118            style: None,
 2119            show_cursor_names: false,
 2120            hovered_cursors: HashMap::default(),
 2121            next_editor_action_id: EditorActionId::default(),
 2122            editor_actions: Rc::default(),
 2123            edit_predictions_hidden_for_vim_mode: false,
 2124            show_edit_predictions_override: None,
 2125            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2126            edit_prediction_settings: EditPredictionSettings::Disabled,
 2127            edit_prediction_indent_conflict: false,
 2128            edit_prediction_requires_modifier_in_indent_conflict: true,
 2129            custom_context_menu: None,
 2130            show_git_blame_gutter: false,
 2131            show_git_blame_inline: false,
 2132            show_selection_menu: None,
 2133            show_git_blame_inline_delay_task: None,
 2134            git_blame_inline_enabled: full_mode
 2135                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2136            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2137            serialize_dirty_buffers: !is_minimap
 2138                && ProjectSettings::get_global(cx)
 2139                    .session
 2140                    .restore_unsaved_buffers,
 2141            blame: None,
 2142            blame_subscription: None,
 2143            tasks: BTreeMap::default(),
 2144
 2145            breakpoint_store,
 2146            gutter_breakpoint_indicator: (None, None),
 2147            hovered_diff_hunk_row: None,
 2148            _subscriptions: (!is_minimap)
 2149                .then(|| {
 2150                    vec![
 2151                        cx.observe(&buffer, Self::on_buffer_changed),
 2152                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2153                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2154                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2155                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2156                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2157                        cx.observe_window_activation(window, |editor, window, cx| {
 2158                            let active = window.is_window_active();
 2159                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2160                                if active {
 2161                                    blink_manager.enable(cx);
 2162                                } else {
 2163                                    blink_manager.disable(cx);
 2164                                }
 2165                            });
 2166                            if active {
 2167                                editor.show_mouse_cursor(cx);
 2168                            }
 2169                        }),
 2170                    ]
 2171                })
 2172                .unwrap_or_default(),
 2173            tasks_update_task: None,
 2174            pull_diagnostics_task: Task::ready(()),
 2175            colors: None,
 2176            next_color_inlay_id: 0,
 2177            linked_edit_ranges: Default::default(),
 2178            in_project_search: false,
 2179            previous_search_ranges: None,
 2180            breadcrumb_header: None,
 2181            focused_block: None,
 2182            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2183            addons: HashMap::default(),
 2184            registered_buffers: HashMap::default(),
 2185            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2186            selection_mark_mode: false,
 2187            toggle_fold_multiple_buffers: Task::ready(()),
 2188            serialize_selections: Task::ready(()),
 2189            serialize_folds: Task::ready(()),
 2190            text_style_refinement: None,
 2191            load_diff_task: load_uncommitted_diff,
 2192            temporary_diff_override: false,
 2193            mouse_cursor_hidden: false,
 2194            minimap: None,
 2195            hide_mouse_mode: EditorSettings::get_global(cx)
 2196                .hide_mouse
 2197                .unwrap_or_default(),
 2198            change_list: ChangeList::new(),
 2199            mode,
 2200            selection_drag_state: SelectionDragState::None,
 2201            folding_newlines: Task::ready(()),
 2202        };
 2203
 2204        if is_minimap {
 2205            return editor;
 2206        }
 2207
 2208        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2209            editor
 2210                ._subscriptions
 2211                .push(cx.observe(breakpoints, |_, _, cx| {
 2212                    cx.notify();
 2213                }));
 2214        }
 2215        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2216        editor._subscriptions.extend(project_subscriptions);
 2217
 2218        editor._subscriptions.push(cx.subscribe_in(
 2219            &cx.entity(),
 2220            window,
 2221            |editor, _, e: &EditorEvent, window, cx| match e {
 2222                EditorEvent::ScrollPositionChanged { local, .. } => {
 2223                    if *local {
 2224                        let new_anchor = editor.scroll_manager.anchor();
 2225                        let snapshot = editor.snapshot(window, cx);
 2226                        editor.update_restoration_data(cx, move |data| {
 2227                            data.scroll_position = (
 2228                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2229                                new_anchor.offset,
 2230                            );
 2231                        });
 2232                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2233                        editor.inline_blame_popover.take();
 2234                    }
 2235                }
 2236                EditorEvent::Edited { .. } => {
 2237                    if !vim_enabled(cx) {
 2238                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2239                        let pop_state = editor
 2240                            .change_list
 2241                            .last()
 2242                            .map(|previous| {
 2243                                previous.len() == selections.len()
 2244                                    && previous.iter().enumerate().all(|(ix, p)| {
 2245                                        p.to_display_point(&map).row()
 2246                                            == selections[ix].head().row()
 2247                                    })
 2248                            })
 2249                            .unwrap_or(false);
 2250                        let new_positions = selections
 2251                            .into_iter()
 2252                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2253                            .collect();
 2254                        editor
 2255                            .change_list
 2256                            .push_to_change_list(pop_state, new_positions);
 2257                    }
 2258                }
 2259                _ => (),
 2260            },
 2261        ));
 2262
 2263        if let Some(dap_store) = editor
 2264            .project
 2265            .as_ref()
 2266            .map(|project| project.read(cx).dap_store())
 2267        {
 2268            let weak_editor = cx.weak_entity();
 2269
 2270            editor
 2271                ._subscriptions
 2272                .push(
 2273                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2274                        let session_entity = cx.entity();
 2275                        weak_editor
 2276                            .update(cx, |editor, cx| {
 2277                                editor._subscriptions.push(
 2278                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2279                                );
 2280                            })
 2281                            .ok();
 2282                    }),
 2283                );
 2284
 2285            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2286                editor
 2287                    ._subscriptions
 2288                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2289            }
 2290        }
 2291
 2292        // skip adding the initial selection to selection history
 2293        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2294        editor.end_selection(window, cx);
 2295        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2296
 2297        editor.scroll_manager.show_scrollbars(window, cx);
 2298        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2299
 2300        if full_mode {
 2301            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2302            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2303
 2304            if editor.git_blame_inline_enabled {
 2305                editor.start_git_blame_inline(false, window, cx);
 2306            }
 2307
 2308            editor.go_to_active_debug_line(window, cx);
 2309
 2310            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2311                if let Some(project) = editor.project.as_ref() {
 2312                    let handle = project.update(cx, |project, cx| {
 2313                        project.register_buffer_with_language_servers(&buffer, cx)
 2314                    });
 2315                    editor
 2316                        .registered_buffers
 2317                        .insert(buffer.read(cx).remote_id(), handle);
 2318                }
 2319            }
 2320
 2321            editor.minimap =
 2322                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2323            editor.colors = Some(LspColorData::new(cx));
 2324            editor.update_lsp_data(false, None, window, cx);
 2325        }
 2326
 2327        if editor.mode.is_full() {
 2328            editor.report_editor_event("Editor Opened", None, cx);
 2329        }
 2330
 2331        editor
 2332    }
 2333
 2334    pub fn deploy_mouse_context_menu(
 2335        &mut self,
 2336        position: gpui::Point<Pixels>,
 2337        context_menu: Entity<ContextMenu>,
 2338        window: &mut Window,
 2339        cx: &mut Context<Self>,
 2340    ) {
 2341        self.mouse_context_menu = Some(MouseContextMenu::new(
 2342            self,
 2343            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2344            context_menu,
 2345            window,
 2346            cx,
 2347        ));
 2348    }
 2349
 2350    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2351        self.mouse_context_menu
 2352            .as_ref()
 2353            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2354    }
 2355
 2356    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2357        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2358    }
 2359
 2360    fn key_context_internal(
 2361        &self,
 2362        has_active_edit_prediction: bool,
 2363        window: &Window,
 2364        cx: &App,
 2365    ) -> KeyContext {
 2366        let mut key_context = KeyContext::new_with_defaults();
 2367        key_context.add("Editor");
 2368        let mode = match self.mode {
 2369            EditorMode::SingleLine { .. } => "single_line",
 2370            EditorMode::AutoHeight { .. } => "auto_height",
 2371            EditorMode::Minimap { .. } => "minimap",
 2372            EditorMode::Full { .. } => "full",
 2373        };
 2374
 2375        if EditorSettings::jupyter_enabled(cx) {
 2376            key_context.add("jupyter");
 2377        }
 2378
 2379        key_context.set("mode", mode);
 2380        if self.pending_rename.is_some() {
 2381            key_context.add("renaming");
 2382        }
 2383
 2384        match self.context_menu.borrow().as_ref() {
 2385            Some(CodeContextMenu::Completions(menu)) => {
 2386                if menu.visible() {
 2387                    key_context.add("menu");
 2388                    key_context.add("showing_completions");
 2389                }
 2390            }
 2391            Some(CodeContextMenu::CodeActions(menu)) => {
 2392                if menu.visible() {
 2393                    key_context.add("menu");
 2394                    key_context.add("showing_code_actions")
 2395                }
 2396            }
 2397            None => {}
 2398        }
 2399
 2400        if self.signature_help_state.has_multiple_signatures() {
 2401            key_context.add("showing_signature_help");
 2402        }
 2403
 2404        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2405        if !self.focus_handle(cx).contains_focused(window, cx)
 2406            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2407        {
 2408            for addon in self.addons.values() {
 2409                addon.extend_key_context(&mut key_context, cx)
 2410            }
 2411        }
 2412
 2413        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2414            if let Some(extension) = singleton_buffer
 2415                .read(cx)
 2416                .file()
 2417                .and_then(|file| file.path().extension()?.to_str())
 2418            {
 2419                key_context.set("extension", extension.to_string());
 2420            }
 2421        } else {
 2422            key_context.add("multibuffer");
 2423        }
 2424
 2425        if has_active_edit_prediction {
 2426            if self.edit_prediction_in_conflict() {
 2427                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2428            } else {
 2429                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2430                key_context.add("copilot_suggestion");
 2431            }
 2432        }
 2433
 2434        if self.selection_mark_mode {
 2435            key_context.add("selection_mode");
 2436        }
 2437
 2438        key_context
 2439    }
 2440
 2441    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2442        if self.mouse_cursor_hidden {
 2443            self.mouse_cursor_hidden = false;
 2444            cx.notify();
 2445        }
 2446    }
 2447
 2448    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2449        let hide_mouse_cursor = match origin {
 2450            HideMouseCursorOrigin::TypingAction => {
 2451                matches!(
 2452                    self.hide_mouse_mode,
 2453                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2454                )
 2455            }
 2456            HideMouseCursorOrigin::MovementAction => {
 2457                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2458            }
 2459        };
 2460        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2461            self.mouse_cursor_hidden = hide_mouse_cursor;
 2462            cx.notify();
 2463        }
 2464    }
 2465
 2466    pub fn edit_prediction_in_conflict(&self) -> bool {
 2467        if !self.show_edit_predictions_in_menu() {
 2468            return false;
 2469        }
 2470
 2471        let showing_completions = self
 2472            .context_menu
 2473            .borrow()
 2474            .as_ref()
 2475            .map_or(false, |context| {
 2476                matches!(context, CodeContextMenu::Completions(_))
 2477            });
 2478
 2479        showing_completions
 2480            || self.edit_prediction_requires_modifier()
 2481            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2482            // bindings to insert tab characters.
 2483            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2484    }
 2485
 2486    pub fn accept_edit_prediction_keybind(
 2487        &self,
 2488        accept_partial: bool,
 2489        window: &Window,
 2490        cx: &App,
 2491    ) -> AcceptEditPredictionBinding {
 2492        let key_context = self.key_context_internal(true, window, cx);
 2493        let in_conflict = self.edit_prediction_in_conflict();
 2494
 2495        let bindings = if accept_partial {
 2496            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2497        } else {
 2498            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2499        };
 2500
 2501        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2502        // just the first one.
 2503        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2504            !in_conflict
 2505                || binding
 2506                    .keystrokes()
 2507                    .first()
 2508                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2509        }))
 2510    }
 2511
 2512    pub fn new_file(
 2513        workspace: &mut Workspace,
 2514        _: &workspace::NewFile,
 2515        window: &mut Window,
 2516        cx: &mut Context<Workspace>,
 2517    ) {
 2518        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2519            "Failed to create buffer",
 2520            window,
 2521            cx,
 2522            |e, _, _| match e.error_code() {
 2523                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2524                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2525                e.error_tag("required").unwrap_or("the latest version")
 2526            )),
 2527                _ => None,
 2528            },
 2529        );
 2530    }
 2531
 2532    pub fn new_in_workspace(
 2533        workspace: &mut Workspace,
 2534        window: &mut Window,
 2535        cx: &mut Context<Workspace>,
 2536    ) -> Task<Result<Entity<Editor>>> {
 2537        let project = workspace.project().clone();
 2538        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2539
 2540        cx.spawn_in(window, async move |workspace, cx| {
 2541            let buffer = create.await?;
 2542            workspace.update_in(cx, |workspace, window, cx| {
 2543                let editor =
 2544                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2545                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2546                editor
 2547            })
 2548        })
 2549    }
 2550
 2551    fn new_file_vertical(
 2552        workspace: &mut Workspace,
 2553        _: &workspace::NewFileSplitVertical,
 2554        window: &mut Window,
 2555        cx: &mut Context<Workspace>,
 2556    ) {
 2557        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2558    }
 2559
 2560    fn new_file_horizontal(
 2561        workspace: &mut Workspace,
 2562        _: &workspace::NewFileSplitHorizontal,
 2563        window: &mut Window,
 2564        cx: &mut Context<Workspace>,
 2565    ) {
 2566        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2567    }
 2568
 2569    fn new_file_in_direction(
 2570        workspace: &mut Workspace,
 2571        direction: SplitDirection,
 2572        window: &mut Window,
 2573        cx: &mut Context<Workspace>,
 2574    ) {
 2575        let project = workspace.project().clone();
 2576        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2577
 2578        cx.spawn_in(window, async move |workspace, cx| {
 2579            let buffer = create.await?;
 2580            workspace.update_in(cx, move |workspace, window, cx| {
 2581                workspace.split_item(
 2582                    direction,
 2583                    Box::new(
 2584                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2585                    ),
 2586                    window,
 2587                    cx,
 2588                )
 2589            })?;
 2590            anyhow::Ok(())
 2591        })
 2592        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2593            match e.error_code() {
 2594                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2595                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2596                e.error_tag("required").unwrap_or("the latest version")
 2597            )),
 2598                _ => None,
 2599            }
 2600        });
 2601    }
 2602
 2603    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2604        self.leader_id
 2605    }
 2606
 2607    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2608        &self.buffer
 2609    }
 2610
 2611    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2612        self.workspace.as_ref()?.0.upgrade()
 2613    }
 2614
 2615    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2616        self.buffer().read(cx).title(cx)
 2617    }
 2618
 2619    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2620        let git_blame_gutter_max_author_length = self
 2621            .render_git_blame_gutter(cx)
 2622            .then(|| {
 2623                if let Some(blame) = self.blame.as_ref() {
 2624                    let max_author_length =
 2625                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2626                    Some(max_author_length)
 2627                } else {
 2628                    None
 2629                }
 2630            })
 2631            .flatten();
 2632
 2633        EditorSnapshot {
 2634            mode: self.mode.clone(),
 2635            show_gutter: self.show_gutter,
 2636            show_line_numbers: self.show_line_numbers,
 2637            show_git_diff_gutter: self.show_git_diff_gutter,
 2638            show_code_actions: self.show_code_actions,
 2639            show_runnables: self.show_runnables,
 2640            show_breakpoints: self.show_breakpoints,
 2641            git_blame_gutter_max_author_length,
 2642            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2643            scroll_anchor: self.scroll_manager.anchor(),
 2644            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2645            placeholder_text: self.placeholder_text.clone(),
 2646            is_focused: self.focus_handle.is_focused(window),
 2647            current_line_highlight: self
 2648                .current_line_highlight
 2649                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2650            gutter_hovered: self.gutter_hovered,
 2651        }
 2652    }
 2653
 2654    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2655        self.buffer.read(cx).language_at(point, cx)
 2656    }
 2657
 2658    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2659        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2660    }
 2661
 2662    pub fn active_excerpt(
 2663        &self,
 2664        cx: &App,
 2665    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2666        self.buffer
 2667            .read(cx)
 2668            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2669    }
 2670
 2671    pub fn mode(&self) -> &EditorMode {
 2672        &self.mode
 2673    }
 2674
 2675    pub fn set_mode(&mut self, mode: EditorMode) {
 2676        self.mode = mode;
 2677    }
 2678
 2679    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2680        self.collaboration_hub.as_deref()
 2681    }
 2682
 2683    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2684        self.collaboration_hub = Some(hub);
 2685    }
 2686
 2687    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2688        self.in_project_search = in_project_search;
 2689    }
 2690
 2691    pub fn set_custom_context_menu(
 2692        &mut self,
 2693        f: impl 'static
 2694        + Fn(
 2695            &mut Self,
 2696            DisplayPoint,
 2697            &mut Window,
 2698            &mut Context<Self>,
 2699        ) -> Option<Entity<ui::ContextMenu>>,
 2700    ) {
 2701        self.custom_context_menu = Some(Box::new(f))
 2702    }
 2703
 2704    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2705        self.completion_provider = provider;
 2706    }
 2707
 2708    #[cfg(any(test, feature = "test-support"))]
 2709    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2710        self.completion_provider.clone()
 2711    }
 2712
 2713    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2714        self.semantics_provider.clone()
 2715    }
 2716
 2717    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2718        self.semantics_provider = provider;
 2719    }
 2720
 2721    pub fn set_edit_prediction_provider<T>(
 2722        &mut self,
 2723        provider: Option<Entity<T>>,
 2724        window: &mut Window,
 2725        cx: &mut Context<Self>,
 2726    ) where
 2727        T: EditPredictionProvider,
 2728    {
 2729        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2730            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2731                if this.focus_handle.is_focused(window) {
 2732                    this.update_visible_edit_prediction(window, cx);
 2733                }
 2734            }),
 2735            provider: Arc::new(provider),
 2736        });
 2737        self.update_edit_prediction_settings(cx);
 2738        self.refresh_edit_prediction(false, false, window, cx);
 2739    }
 2740
 2741    pub fn placeholder_text(&self) -> Option<&str> {
 2742        self.placeholder_text.as_deref()
 2743    }
 2744
 2745    pub fn set_placeholder_text(
 2746        &mut self,
 2747        placeholder_text: impl Into<Arc<str>>,
 2748        cx: &mut Context<Self>,
 2749    ) {
 2750        let placeholder_text = Some(placeholder_text.into());
 2751        if self.placeholder_text != placeholder_text {
 2752            self.placeholder_text = placeholder_text;
 2753            cx.notify();
 2754        }
 2755    }
 2756
 2757    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2758        self.cursor_shape = cursor_shape;
 2759
 2760        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2761        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2762
 2763        cx.notify();
 2764    }
 2765
 2766    pub fn set_current_line_highlight(
 2767        &mut self,
 2768        current_line_highlight: Option<CurrentLineHighlight>,
 2769    ) {
 2770        self.current_line_highlight = current_line_highlight;
 2771    }
 2772
 2773    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2774        self.collapse_matches = collapse_matches;
 2775    }
 2776
 2777    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2778        let buffers = self.buffer.read(cx).all_buffers();
 2779        let Some(project) = self.project.as_ref() else {
 2780            return;
 2781        };
 2782        project.update(cx, |project, cx| {
 2783            for buffer in buffers {
 2784                self.registered_buffers
 2785                    .entry(buffer.read(cx).remote_id())
 2786                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2787            }
 2788        })
 2789    }
 2790
 2791    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2792        if self.collapse_matches {
 2793            return range.start..range.start;
 2794        }
 2795        range.clone()
 2796    }
 2797
 2798    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2799        if self.display_map.read(cx).clip_at_line_ends != clip {
 2800            self.display_map
 2801                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2802        }
 2803    }
 2804
 2805    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2806        self.input_enabled = input_enabled;
 2807    }
 2808
 2809    pub fn set_edit_predictions_hidden_for_vim_mode(
 2810        &mut self,
 2811        hidden: bool,
 2812        window: &mut Window,
 2813        cx: &mut Context<Self>,
 2814    ) {
 2815        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2816            self.edit_predictions_hidden_for_vim_mode = hidden;
 2817            if hidden {
 2818                self.update_visible_edit_prediction(window, cx);
 2819            } else {
 2820                self.refresh_edit_prediction(true, false, window, cx);
 2821            }
 2822        }
 2823    }
 2824
 2825    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2826        self.menu_edit_predictions_policy = value;
 2827    }
 2828
 2829    pub fn set_autoindent(&mut self, autoindent: bool) {
 2830        if autoindent {
 2831            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2832        } else {
 2833            self.autoindent_mode = None;
 2834        }
 2835    }
 2836
 2837    pub fn read_only(&self, cx: &App) -> bool {
 2838        self.read_only || self.buffer.read(cx).read_only()
 2839    }
 2840
 2841    pub fn set_read_only(&mut self, read_only: bool) {
 2842        self.read_only = read_only;
 2843    }
 2844
 2845    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2846        self.use_autoclose = autoclose;
 2847    }
 2848
 2849    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2850        self.use_auto_surround = auto_surround;
 2851    }
 2852
 2853    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2854        self.auto_replace_emoji_shortcode = auto_replace;
 2855    }
 2856
 2857    pub fn toggle_edit_predictions(
 2858        &mut self,
 2859        _: &ToggleEditPrediction,
 2860        window: &mut Window,
 2861        cx: &mut Context<Self>,
 2862    ) {
 2863        if self.show_edit_predictions_override.is_some() {
 2864            self.set_show_edit_predictions(None, window, cx);
 2865        } else {
 2866            let show_edit_predictions = !self.edit_predictions_enabled();
 2867            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2868        }
 2869    }
 2870
 2871    pub fn set_show_edit_predictions(
 2872        &mut self,
 2873        show_edit_predictions: Option<bool>,
 2874        window: &mut Window,
 2875        cx: &mut Context<Self>,
 2876    ) {
 2877        self.show_edit_predictions_override = show_edit_predictions;
 2878        self.update_edit_prediction_settings(cx);
 2879
 2880        if let Some(false) = show_edit_predictions {
 2881            self.discard_edit_prediction(false, cx);
 2882        } else {
 2883            self.refresh_edit_prediction(false, true, window, cx);
 2884        }
 2885    }
 2886
 2887    fn edit_predictions_disabled_in_scope(
 2888        &self,
 2889        buffer: &Entity<Buffer>,
 2890        buffer_position: language::Anchor,
 2891        cx: &App,
 2892    ) -> bool {
 2893        let snapshot = buffer.read(cx).snapshot();
 2894        let settings = snapshot.settings_at(buffer_position, cx);
 2895
 2896        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2897            return false;
 2898        };
 2899
 2900        scope.override_name().map_or(false, |scope_name| {
 2901            settings
 2902                .edit_predictions_disabled_in
 2903                .iter()
 2904                .any(|s| s == scope_name)
 2905        })
 2906    }
 2907
 2908    pub fn set_use_modal_editing(&mut self, to: bool) {
 2909        self.use_modal_editing = to;
 2910    }
 2911
 2912    pub fn use_modal_editing(&self) -> bool {
 2913        self.use_modal_editing
 2914    }
 2915
 2916    fn selections_did_change(
 2917        &mut self,
 2918        local: bool,
 2919        old_cursor_position: &Anchor,
 2920        effects: SelectionEffects,
 2921        window: &mut Window,
 2922        cx: &mut Context<Self>,
 2923    ) {
 2924        window.invalidate_character_coordinates();
 2925
 2926        // Copy selections to primary selection buffer
 2927        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2928        if local {
 2929            let selections = self.selections.all::<usize>(cx);
 2930            let buffer_handle = self.buffer.read(cx).read(cx);
 2931
 2932            let mut text = String::new();
 2933            for (index, selection) in selections.iter().enumerate() {
 2934                let text_for_selection = buffer_handle
 2935                    .text_for_range(selection.start..selection.end)
 2936                    .collect::<String>();
 2937
 2938                text.push_str(&text_for_selection);
 2939                if index != selections.len() - 1 {
 2940                    text.push('\n');
 2941                }
 2942            }
 2943
 2944            if !text.is_empty() {
 2945                cx.write_to_primary(ClipboardItem::new_string(text));
 2946            }
 2947        }
 2948
 2949        let selection_anchors = self.selections.disjoint_anchors();
 2950
 2951        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2952            self.buffer.update(cx, |buffer, cx| {
 2953                buffer.set_active_selections(
 2954                    &selection_anchors,
 2955                    self.selections.line_mode,
 2956                    self.cursor_shape,
 2957                    cx,
 2958                )
 2959            });
 2960        }
 2961        let display_map = self
 2962            .display_map
 2963            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2964        let buffer = &display_map.buffer_snapshot;
 2965        if self.selections.count() == 1 {
 2966            self.add_selections_state = None;
 2967        }
 2968        self.select_next_state = None;
 2969        self.select_prev_state = None;
 2970        self.select_syntax_node_history.try_clear();
 2971        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 2972        self.snippet_stack.invalidate(&selection_anchors, buffer);
 2973        self.take_rename(false, window, cx);
 2974
 2975        let newest_selection = self.selections.newest_anchor();
 2976        let new_cursor_position = newest_selection.head();
 2977        let selection_start = newest_selection.start;
 2978
 2979        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2980            self.push_to_nav_history(
 2981                *old_cursor_position,
 2982                Some(new_cursor_position.to_point(buffer)),
 2983                false,
 2984                effects.nav_history == Some(true),
 2985                cx,
 2986            );
 2987        }
 2988
 2989        if local {
 2990            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2991                if !self.registered_buffers.contains_key(&buffer_id) {
 2992                    if let Some(project) = self.project.as_ref() {
 2993                        project.update(cx, |project, cx| {
 2994                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2995                                return;
 2996                            };
 2997                            self.registered_buffers.insert(
 2998                                buffer_id,
 2999                                project.register_buffer_with_language_servers(&buffer, cx),
 3000                            );
 3001                        })
 3002                    }
 3003                }
 3004            }
 3005
 3006            let mut context_menu = self.context_menu.borrow_mut();
 3007            let completion_menu = match context_menu.as_ref() {
 3008                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3009                Some(CodeContextMenu::CodeActions(_)) => {
 3010                    *context_menu = None;
 3011                    None
 3012                }
 3013                None => None,
 3014            };
 3015            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3016            drop(context_menu);
 3017
 3018            if effects.completions {
 3019                if let Some(completion_position) = completion_position {
 3020                    let start_offset = selection_start.to_offset(buffer);
 3021                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3022                    let continue_showing = if position_matches {
 3023                        if self.snippet_stack.is_empty() {
 3024                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3025                        } else {
 3026                            // Snippet choices can be shown even when the cursor is in whitespace.
 3027                            // Dismissing the menu with actions like backspace is handled by
 3028                            // invalidation regions.
 3029                            true
 3030                        }
 3031                    } else {
 3032                        false
 3033                    };
 3034
 3035                    if continue_showing {
 3036                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3037                    } else {
 3038                        self.hide_context_menu(window, cx);
 3039                    }
 3040                }
 3041            }
 3042
 3043            hide_hover(self, cx);
 3044
 3045            if old_cursor_position.to_display_point(&display_map).row()
 3046                != new_cursor_position.to_display_point(&display_map).row()
 3047            {
 3048                self.available_code_actions.take();
 3049            }
 3050            self.refresh_code_actions(window, cx);
 3051            self.refresh_document_highlights(cx);
 3052            self.refresh_selected_text_highlights(false, window, cx);
 3053            refresh_matching_bracket_highlights(self, window, cx);
 3054            self.update_visible_edit_prediction(window, cx);
 3055            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3056            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3057            self.inline_blame_popover.take();
 3058            if self.git_blame_inline_enabled {
 3059                self.start_inline_blame_timer(window, cx);
 3060            }
 3061        }
 3062
 3063        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3064        cx.emit(EditorEvent::SelectionsChanged { local });
 3065
 3066        let selections = &self.selections.disjoint;
 3067        if selections.len() == 1 {
 3068            cx.emit(SearchEvent::ActiveMatchChanged)
 3069        }
 3070        if local {
 3071            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3072                let inmemory_selections = selections
 3073                    .iter()
 3074                    .map(|s| {
 3075                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3076                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3077                    })
 3078                    .collect();
 3079                self.update_restoration_data(cx, |data| {
 3080                    data.selections = inmemory_selections;
 3081                });
 3082
 3083                if WorkspaceSettings::get(None, cx).restore_on_startup
 3084                    != RestoreOnStartupBehavior::None
 3085                {
 3086                    if let Some(workspace_id) =
 3087                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3088                    {
 3089                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3090                        let selections = selections.clone();
 3091                        let background_executor = cx.background_executor().clone();
 3092                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3093                        self.serialize_selections = cx.background_spawn(async move {
 3094                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3095                            let db_selections = selections
 3096                                .iter()
 3097                                .map(|selection| {
 3098                                    (
 3099                                        selection.start.to_offset(&snapshot),
 3100                                        selection.end.to_offset(&snapshot),
 3101                                    )
 3102                                })
 3103                                .collect();
 3104
 3105                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3106                                .await
 3107                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3108                                .log_err();
 3109                        });
 3110                    }
 3111                }
 3112            }
 3113        }
 3114
 3115        cx.notify();
 3116    }
 3117
 3118    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3119        use text::ToOffset as _;
 3120        use text::ToPoint as _;
 3121
 3122        if self.mode.is_minimap()
 3123            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3124        {
 3125            return;
 3126        }
 3127
 3128        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3129            return;
 3130        };
 3131
 3132        let snapshot = singleton.read(cx).snapshot();
 3133        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3134            let display_snapshot = display_map.snapshot(cx);
 3135
 3136            display_snapshot
 3137                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3138                .map(|fold| {
 3139                    fold.range.start.text_anchor.to_point(&snapshot)
 3140                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3141                })
 3142                .collect()
 3143        });
 3144        self.update_restoration_data(cx, |data| {
 3145            data.folds = inmemory_folds;
 3146        });
 3147
 3148        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3149            return;
 3150        };
 3151        let background_executor = cx.background_executor().clone();
 3152        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3153        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3154            display_map
 3155                .snapshot(cx)
 3156                .folds_in_range(0..snapshot.len())
 3157                .map(|fold| {
 3158                    (
 3159                        fold.range.start.text_anchor.to_offset(&snapshot),
 3160                        fold.range.end.text_anchor.to_offset(&snapshot),
 3161                    )
 3162                })
 3163                .collect()
 3164        });
 3165        self.serialize_folds = cx.background_spawn(async move {
 3166            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3167            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3168                .await
 3169                .with_context(|| {
 3170                    format!(
 3171                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3172                    )
 3173                })
 3174                .log_err();
 3175        });
 3176    }
 3177
 3178    pub fn sync_selections(
 3179        &mut self,
 3180        other: Entity<Editor>,
 3181        cx: &mut Context<Self>,
 3182    ) -> gpui::Subscription {
 3183        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3184        self.selections.change_with(cx, |selections| {
 3185            selections.select_anchors(other_selections);
 3186        });
 3187
 3188        let other_subscription =
 3189            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3190                EditorEvent::SelectionsChanged { local: true } => {
 3191                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3192                    if other_selections.is_empty() {
 3193                        return;
 3194                    }
 3195                    this.selections.change_with(cx, |selections| {
 3196                        selections.select_anchors(other_selections);
 3197                    });
 3198                }
 3199                _ => {}
 3200            });
 3201
 3202        let this_subscription =
 3203            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3204                EditorEvent::SelectionsChanged { local: true } => {
 3205                    let these_selections = this.selections.disjoint.to_vec();
 3206                    if these_selections.is_empty() {
 3207                        return;
 3208                    }
 3209                    other.update(cx, |other_editor, cx| {
 3210                        other_editor.selections.change_with(cx, |selections| {
 3211                            selections.select_anchors(these_selections);
 3212                        })
 3213                    });
 3214                }
 3215                _ => {}
 3216            });
 3217
 3218        Subscription::join(other_subscription, this_subscription)
 3219    }
 3220
 3221    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3222    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3223    /// effects of selection change occur at the end of the transaction.
 3224    pub fn change_selections<R>(
 3225        &mut self,
 3226        effects: SelectionEffects,
 3227        window: &mut Window,
 3228        cx: &mut Context<Self>,
 3229        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3230    ) -> R {
 3231        if let Some(state) = &mut self.deferred_selection_effects_state {
 3232            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3233            state.effects.completions = effects.completions;
 3234            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3235            let (changed, result) = self.selections.change_with(cx, change);
 3236            state.changed |= changed;
 3237            return result;
 3238        }
 3239        let mut state = DeferredSelectionEffectsState {
 3240            changed: false,
 3241            effects,
 3242            old_cursor_position: self.selections.newest_anchor().head(),
 3243            history_entry: SelectionHistoryEntry {
 3244                selections: self.selections.disjoint_anchors(),
 3245                select_next_state: self.select_next_state.clone(),
 3246                select_prev_state: self.select_prev_state.clone(),
 3247                add_selections_state: self.add_selections_state.clone(),
 3248            },
 3249        };
 3250        let (changed, result) = self.selections.change_with(cx, change);
 3251        state.changed = state.changed || changed;
 3252        if self.defer_selection_effects {
 3253            self.deferred_selection_effects_state = Some(state);
 3254        } else {
 3255            self.apply_selection_effects(state, window, cx);
 3256        }
 3257        result
 3258    }
 3259
 3260    /// Defers the effects of selection change, so that the effects of multiple calls to
 3261    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3262    /// to selection history and the state of popovers based on selection position aren't
 3263    /// erroneously updated.
 3264    pub fn with_selection_effects_deferred<R>(
 3265        &mut self,
 3266        window: &mut Window,
 3267        cx: &mut Context<Self>,
 3268        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3269    ) -> R {
 3270        let already_deferred = self.defer_selection_effects;
 3271        self.defer_selection_effects = true;
 3272        let result = update(self, window, cx);
 3273        if !already_deferred {
 3274            self.defer_selection_effects = false;
 3275            if let Some(state) = self.deferred_selection_effects_state.take() {
 3276                self.apply_selection_effects(state, window, cx);
 3277            }
 3278        }
 3279        result
 3280    }
 3281
 3282    fn apply_selection_effects(
 3283        &mut self,
 3284        state: DeferredSelectionEffectsState,
 3285        window: &mut Window,
 3286        cx: &mut Context<Self>,
 3287    ) {
 3288        if state.changed {
 3289            self.selection_history.push(state.history_entry);
 3290
 3291            if let Some(autoscroll) = state.effects.scroll {
 3292                self.request_autoscroll(autoscroll, cx);
 3293            }
 3294
 3295            let old_cursor_position = &state.old_cursor_position;
 3296
 3297            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3298
 3299            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3300                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3301            }
 3302        }
 3303    }
 3304
 3305    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3306    where
 3307        I: IntoIterator<Item = (Range<S>, T)>,
 3308        S: ToOffset,
 3309        T: Into<Arc<str>>,
 3310    {
 3311        if self.read_only(cx) {
 3312            return;
 3313        }
 3314
 3315        self.buffer
 3316            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3317    }
 3318
 3319    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3320    where
 3321        I: IntoIterator<Item = (Range<S>, T)>,
 3322        S: ToOffset,
 3323        T: Into<Arc<str>>,
 3324    {
 3325        if self.read_only(cx) {
 3326            return;
 3327        }
 3328
 3329        self.buffer.update(cx, |buffer, cx| {
 3330            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3331        });
 3332    }
 3333
 3334    pub fn edit_with_block_indent<I, S, T>(
 3335        &mut self,
 3336        edits: I,
 3337        original_indent_columns: Vec<Option<u32>>,
 3338        cx: &mut Context<Self>,
 3339    ) where
 3340        I: IntoIterator<Item = (Range<S>, T)>,
 3341        S: ToOffset,
 3342        T: Into<Arc<str>>,
 3343    {
 3344        if self.read_only(cx) {
 3345            return;
 3346        }
 3347
 3348        self.buffer.update(cx, |buffer, cx| {
 3349            buffer.edit(
 3350                edits,
 3351                Some(AutoindentMode::Block {
 3352                    original_indent_columns,
 3353                }),
 3354                cx,
 3355            )
 3356        });
 3357    }
 3358
 3359    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3360        self.hide_context_menu(window, cx);
 3361
 3362        match phase {
 3363            SelectPhase::Begin {
 3364                position,
 3365                add,
 3366                click_count,
 3367            } => self.begin_selection(position, add, click_count, window, cx),
 3368            SelectPhase::BeginColumnar {
 3369                position,
 3370                goal_column,
 3371                reset,
 3372                mode,
 3373            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3374            SelectPhase::Extend {
 3375                position,
 3376                click_count,
 3377            } => self.extend_selection(position, click_count, window, cx),
 3378            SelectPhase::Update {
 3379                position,
 3380                goal_column,
 3381                scroll_delta,
 3382            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3383            SelectPhase::End => self.end_selection(window, cx),
 3384        }
 3385    }
 3386
 3387    fn extend_selection(
 3388        &mut self,
 3389        position: DisplayPoint,
 3390        click_count: usize,
 3391        window: &mut Window,
 3392        cx: &mut Context<Self>,
 3393    ) {
 3394        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3395        let tail = self.selections.newest::<usize>(cx).tail();
 3396        self.begin_selection(position, false, click_count, window, cx);
 3397
 3398        let position = position.to_offset(&display_map, Bias::Left);
 3399        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3400
 3401        let mut pending_selection = self
 3402            .selections
 3403            .pending_anchor()
 3404            .expect("extend_selection not called with pending selection");
 3405        if position >= tail {
 3406            pending_selection.start = tail_anchor;
 3407        } else {
 3408            pending_selection.end = tail_anchor;
 3409            pending_selection.reversed = true;
 3410        }
 3411
 3412        let mut pending_mode = self.selections.pending_mode().unwrap();
 3413        match &mut pending_mode {
 3414            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3415            _ => {}
 3416        }
 3417
 3418        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3419            SelectionEffects::scroll(Autoscroll::fit())
 3420        } else {
 3421            SelectionEffects::no_scroll()
 3422        };
 3423
 3424        self.change_selections(effects, window, cx, |s| {
 3425            s.set_pending(pending_selection, pending_mode)
 3426        });
 3427    }
 3428
 3429    fn begin_selection(
 3430        &mut self,
 3431        position: DisplayPoint,
 3432        add: bool,
 3433        click_count: usize,
 3434        window: &mut Window,
 3435        cx: &mut Context<Self>,
 3436    ) {
 3437        if !self.focus_handle.is_focused(window) {
 3438            self.last_focused_descendant = None;
 3439            window.focus(&self.focus_handle);
 3440        }
 3441
 3442        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3443        let buffer = &display_map.buffer_snapshot;
 3444        let position = display_map.clip_point(position, Bias::Left);
 3445
 3446        let start;
 3447        let end;
 3448        let mode;
 3449        let mut auto_scroll;
 3450        match click_count {
 3451            1 => {
 3452                start = buffer.anchor_before(position.to_point(&display_map));
 3453                end = start;
 3454                mode = SelectMode::Character;
 3455                auto_scroll = true;
 3456            }
 3457            2 => {
 3458                let position = display_map
 3459                    .clip_point(position, Bias::Left)
 3460                    .to_offset(&display_map, Bias::Left);
 3461                let (range, _) = buffer.surrounding_word(position, false);
 3462                start = buffer.anchor_before(range.start);
 3463                end = buffer.anchor_before(range.end);
 3464                mode = SelectMode::Word(start..end);
 3465                auto_scroll = true;
 3466            }
 3467            3 => {
 3468                let position = display_map
 3469                    .clip_point(position, Bias::Left)
 3470                    .to_point(&display_map);
 3471                let line_start = display_map.prev_line_boundary(position).0;
 3472                let next_line_start = buffer.clip_point(
 3473                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3474                    Bias::Left,
 3475                );
 3476                start = buffer.anchor_before(line_start);
 3477                end = buffer.anchor_before(next_line_start);
 3478                mode = SelectMode::Line(start..end);
 3479                auto_scroll = true;
 3480            }
 3481            _ => {
 3482                start = buffer.anchor_before(0);
 3483                end = buffer.anchor_before(buffer.len());
 3484                mode = SelectMode::All;
 3485                auto_scroll = false;
 3486            }
 3487        }
 3488        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3489
 3490        let point_to_delete: Option<usize> = {
 3491            let selected_points: Vec<Selection<Point>> =
 3492                self.selections.disjoint_in_range(start..end, cx);
 3493
 3494            if !add || click_count > 1 {
 3495                None
 3496            } else if !selected_points.is_empty() {
 3497                Some(selected_points[0].id)
 3498            } else {
 3499                let clicked_point_already_selected =
 3500                    self.selections.disjoint.iter().find(|selection| {
 3501                        selection.start.to_point(buffer) == start.to_point(buffer)
 3502                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3503                    });
 3504
 3505                clicked_point_already_selected.map(|selection| selection.id)
 3506            }
 3507        };
 3508
 3509        let selections_count = self.selections.count();
 3510        let effects = if auto_scroll {
 3511            SelectionEffects::default()
 3512        } else {
 3513            SelectionEffects::no_scroll()
 3514        };
 3515
 3516        self.change_selections(effects, window, cx, |s| {
 3517            if let Some(point_to_delete) = point_to_delete {
 3518                s.delete(point_to_delete);
 3519
 3520                if selections_count == 1 {
 3521                    s.set_pending_anchor_range(start..end, mode);
 3522                }
 3523            } else {
 3524                if !add {
 3525                    s.clear_disjoint();
 3526                }
 3527
 3528                s.set_pending_anchor_range(start..end, mode);
 3529            }
 3530        });
 3531    }
 3532
 3533    fn begin_columnar_selection(
 3534        &mut self,
 3535        position: DisplayPoint,
 3536        goal_column: u32,
 3537        reset: bool,
 3538        mode: ColumnarMode,
 3539        window: &mut Window,
 3540        cx: &mut Context<Self>,
 3541    ) {
 3542        if !self.focus_handle.is_focused(window) {
 3543            self.last_focused_descendant = None;
 3544            window.focus(&self.focus_handle);
 3545        }
 3546
 3547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3548
 3549        if reset {
 3550            let pointer_position = display_map
 3551                .buffer_snapshot
 3552                .anchor_before(position.to_point(&display_map));
 3553
 3554            self.change_selections(
 3555                SelectionEffects::scroll(Autoscroll::newest()),
 3556                window,
 3557                cx,
 3558                |s| {
 3559                    s.clear_disjoint();
 3560                    s.set_pending_anchor_range(
 3561                        pointer_position..pointer_position,
 3562                        SelectMode::Character,
 3563                    );
 3564                },
 3565            );
 3566        };
 3567
 3568        let tail = self.selections.newest::<Point>(cx).tail();
 3569        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3570        self.columnar_selection_state = match mode {
 3571            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3572                selection_tail: selection_anchor,
 3573                display_point: if reset {
 3574                    if position.column() != goal_column {
 3575                        Some(DisplayPoint::new(position.row(), goal_column))
 3576                    } else {
 3577                        None
 3578                    }
 3579                } else {
 3580                    None
 3581                },
 3582            }),
 3583            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3584                selection_tail: selection_anchor,
 3585            }),
 3586        };
 3587
 3588        if !reset {
 3589            self.select_columns(position, goal_column, &display_map, window, cx);
 3590        }
 3591    }
 3592
 3593    fn update_selection(
 3594        &mut self,
 3595        position: DisplayPoint,
 3596        goal_column: u32,
 3597        scroll_delta: gpui::Point<f32>,
 3598        window: &mut Window,
 3599        cx: &mut Context<Self>,
 3600    ) {
 3601        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3602
 3603        if self.columnar_selection_state.is_some() {
 3604            self.select_columns(position, goal_column, &display_map, window, cx);
 3605        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3606            let buffer = &display_map.buffer_snapshot;
 3607            let head;
 3608            let tail;
 3609            let mode = self.selections.pending_mode().unwrap();
 3610            match &mode {
 3611                SelectMode::Character => {
 3612                    head = position.to_point(&display_map);
 3613                    tail = pending.tail().to_point(buffer);
 3614                }
 3615                SelectMode::Word(original_range) => {
 3616                    let offset = display_map
 3617                        .clip_point(position, Bias::Left)
 3618                        .to_offset(&display_map, Bias::Left);
 3619                    let original_range = original_range.to_offset(buffer);
 3620
 3621                    let head_offset = if buffer.is_inside_word(offset, false)
 3622                        || original_range.contains(&offset)
 3623                    {
 3624                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3625                        if word_range.start < original_range.start {
 3626                            word_range.start
 3627                        } else {
 3628                            word_range.end
 3629                        }
 3630                    } else {
 3631                        offset
 3632                    };
 3633
 3634                    head = head_offset.to_point(buffer);
 3635                    if head_offset <= original_range.start {
 3636                        tail = original_range.end.to_point(buffer);
 3637                    } else {
 3638                        tail = original_range.start.to_point(buffer);
 3639                    }
 3640                }
 3641                SelectMode::Line(original_range) => {
 3642                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3643
 3644                    let position = display_map
 3645                        .clip_point(position, Bias::Left)
 3646                        .to_point(&display_map);
 3647                    let line_start = display_map.prev_line_boundary(position).0;
 3648                    let next_line_start = buffer.clip_point(
 3649                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3650                        Bias::Left,
 3651                    );
 3652
 3653                    if line_start < original_range.start {
 3654                        head = line_start
 3655                    } else {
 3656                        head = next_line_start
 3657                    }
 3658
 3659                    if head <= original_range.start {
 3660                        tail = original_range.end;
 3661                    } else {
 3662                        tail = original_range.start;
 3663                    }
 3664                }
 3665                SelectMode::All => {
 3666                    return;
 3667                }
 3668            };
 3669
 3670            if head < tail {
 3671                pending.start = buffer.anchor_before(head);
 3672                pending.end = buffer.anchor_before(tail);
 3673                pending.reversed = true;
 3674            } else {
 3675                pending.start = buffer.anchor_before(tail);
 3676                pending.end = buffer.anchor_before(head);
 3677                pending.reversed = false;
 3678            }
 3679
 3680            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3681                s.set_pending(pending, mode);
 3682            });
 3683        } else {
 3684            log::error!("update_selection dispatched with no pending selection");
 3685            return;
 3686        }
 3687
 3688        self.apply_scroll_delta(scroll_delta, window, cx);
 3689        cx.notify();
 3690    }
 3691
 3692    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3693        self.columnar_selection_state.take();
 3694        if self.selections.pending_anchor().is_some() {
 3695            let selections = self.selections.all::<usize>(cx);
 3696            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3697                s.select(selections);
 3698                s.clear_pending();
 3699            });
 3700        }
 3701    }
 3702
 3703    fn select_columns(
 3704        &mut self,
 3705        head: DisplayPoint,
 3706        goal_column: u32,
 3707        display_map: &DisplaySnapshot,
 3708        window: &mut Window,
 3709        cx: &mut Context<Self>,
 3710    ) {
 3711        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3712            return;
 3713        };
 3714
 3715        let tail = match columnar_state {
 3716            ColumnarSelectionState::FromMouse {
 3717                selection_tail,
 3718                display_point,
 3719            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3720            ColumnarSelectionState::FromSelection { selection_tail } => {
 3721                selection_tail.to_display_point(&display_map)
 3722            }
 3723        };
 3724
 3725        let start_row = cmp::min(tail.row(), head.row());
 3726        let end_row = cmp::max(tail.row(), head.row());
 3727        let start_column = cmp::min(tail.column(), goal_column);
 3728        let end_column = cmp::max(tail.column(), goal_column);
 3729        let reversed = start_column < tail.column();
 3730
 3731        let selection_ranges = (start_row.0..=end_row.0)
 3732            .map(DisplayRow)
 3733            .filter_map(|row| {
 3734                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3735                    || start_column <= display_map.line_len(row))
 3736                    && !display_map.is_block_line(row)
 3737                {
 3738                    let start = display_map
 3739                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3740                        .to_point(display_map);
 3741                    let end = display_map
 3742                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3743                        .to_point(display_map);
 3744                    if reversed {
 3745                        Some(end..start)
 3746                    } else {
 3747                        Some(start..end)
 3748                    }
 3749                } else {
 3750                    None
 3751                }
 3752            })
 3753            .collect::<Vec<_>>();
 3754
 3755        let ranges = match columnar_state {
 3756            ColumnarSelectionState::FromMouse { .. } => {
 3757                let mut non_empty_ranges = selection_ranges
 3758                    .iter()
 3759                    .filter(|selection_range| selection_range.start != selection_range.end)
 3760                    .peekable();
 3761                if non_empty_ranges.peek().is_some() {
 3762                    non_empty_ranges.cloned().collect()
 3763                } else {
 3764                    selection_ranges
 3765                }
 3766            }
 3767            _ => selection_ranges,
 3768        };
 3769
 3770        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3771            s.select_ranges(ranges);
 3772        });
 3773        cx.notify();
 3774    }
 3775
 3776    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3777        self.selections
 3778            .all_adjusted(cx)
 3779            .iter()
 3780            .any(|selection| !selection.is_empty())
 3781    }
 3782
 3783    pub fn has_pending_nonempty_selection(&self) -> bool {
 3784        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3785            Some(Selection { start, end, .. }) => start != end,
 3786            None => false,
 3787        };
 3788
 3789        pending_nonempty_selection
 3790            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3791    }
 3792
 3793    pub fn has_pending_selection(&self) -> bool {
 3794        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3795    }
 3796
 3797    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3798        self.selection_mark_mode = false;
 3799        self.selection_drag_state = SelectionDragState::None;
 3800
 3801        if self.clear_expanded_diff_hunks(cx) {
 3802            cx.notify();
 3803            return;
 3804        }
 3805        if self.dismiss_menus_and_popups(true, window, cx) {
 3806            return;
 3807        }
 3808
 3809        if self.mode.is_full()
 3810            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3811        {
 3812            return;
 3813        }
 3814
 3815        cx.propagate();
 3816    }
 3817
 3818    pub fn dismiss_menus_and_popups(
 3819        &mut self,
 3820        is_user_requested: bool,
 3821        window: &mut Window,
 3822        cx: &mut Context<Self>,
 3823    ) -> bool {
 3824        if self.take_rename(false, window, cx).is_some() {
 3825            return true;
 3826        }
 3827
 3828        if hide_hover(self, cx) {
 3829            return true;
 3830        }
 3831
 3832        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3833            return true;
 3834        }
 3835
 3836        if self.hide_context_menu(window, cx).is_some() {
 3837            return true;
 3838        }
 3839
 3840        if self.mouse_context_menu.take().is_some() {
 3841            return true;
 3842        }
 3843
 3844        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3845            return true;
 3846        }
 3847
 3848        if self.snippet_stack.pop().is_some() {
 3849            return true;
 3850        }
 3851
 3852        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3853            self.dismiss_diagnostics(cx);
 3854            return true;
 3855        }
 3856
 3857        false
 3858    }
 3859
 3860    fn linked_editing_ranges_for(
 3861        &self,
 3862        selection: Range<text::Anchor>,
 3863        cx: &App,
 3864    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3865        if self.linked_edit_ranges.is_empty() {
 3866            return None;
 3867        }
 3868        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3869            selection.end.buffer_id.and_then(|end_buffer_id| {
 3870                if selection.start.buffer_id != Some(end_buffer_id) {
 3871                    return None;
 3872                }
 3873                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3874                let snapshot = buffer.read(cx).snapshot();
 3875                self.linked_edit_ranges
 3876                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3877                    .map(|ranges| (ranges, snapshot, buffer))
 3878            })?;
 3879        use text::ToOffset as TO;
 3880        // find offset from the start of current range to current cursor position
 3881        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3882
 3883        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3884        let start_difference = start_offset - start_byte_offset;
 3885        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3886        let end_difference = end_offset - start_byte_offset;
 3887        // Current range has associated linked ranges.
 3888        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3889        for range in linked_ranges.iter() {
 3890            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3891            let end_offset = start_offset + end_difference;
 3892            let start_offset = start_offset + start_difference;
 3893            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3894                continue;
 3895            }
 3896            if self.selections.disjoint_anchor_ranges().any(|s| {
 3897                if s.start.buffer_id != selection.start.buffer_id
 3898                    || s.end.buffer_id != selection.end.buffer_id
 3899                {
 3900                    return false;
 3901                }
 3902                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3903                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3904            }) {
 3905                continue;
 3906            }
 3907            let start = buffer_snapshot.anchor_after(start_offset);
 3908            let end = buffer_snapshot.anchor_after(end_offset);
 3909            linked_edits
 3910                .entry(buffer.clone())
 3911                .or_default()
 3912                .push(start..end);
 3913        }
 3914        Some(linked_edits)
 3915    }
 3916
 3917    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3918        let text: Arc<str> = text.into();
 3919
 3920        if self.read_only(cx) {
 3921            return;
 3922        }
 3923
 3924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3925
 3926        let selections = self.selections.all_adjusted(cx);
 3927        let mut bracket_inserted = false;
 3928        let mut edits = Vec::new();
 3929        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3930        let mut new_selections = Vec::with_capacity(selections.len());
 3931        let mut new_autoclose_regions = Vec::new();
 3932        let snapshot = self.buffer.read(cx).read(cx);
 3933        let mut clear_linked_edit_ranges = false;
 3934
 3935        for (selection, autoclose_region) in
 3936            self.selections_with_autoclose_regions(selections, &snapshot)
 3937        {
 3938            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3939                // Determine if the inserted text matches the opening or closing
 3940                // bracket of any of this language's bracket pairs.
 3941                let mut bracket_pair = None;
 3942                let mut is_bracket_pair_start = false;
 3943                let mut is_bracket_pair_end = false;
 3944                if !text.is_empty() {
 3945                    let mut bracket_pair_matching_end = None;
 3946                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3947                    //  and they are removing the character that triggered IME popup.
 3948                    for (pair, enabled) in scope.brackets() {
 3949                        if !pair.close && !pair.surround {
 3950                            continue;
 3951                        }
 3952
 3953                        if enabled && pair.start.ends_with(text.as_ref()) {
 3954                            let prefix_len = pair.start.len() - text.len();
 3955                            let preceding_text_matches_prefix = prefix_len == 0
 3956                                || (selection.start.column >= (prefix_len as u32)
 3957                                    && snapshot.contains_str_at(
 3958                                        Point::new(
 3959                                            selection.start.row,
 3960                                            selection.start.column - (prefix_len as u32),
 3961                                        ),
 3962                                        &pair.start[..prefix_len],
 3963                                    ));
 3964                            if preceding_text_matches_prefix {
 3965                                bracket_pair = Some(pair.clone());
 3966                                is_bracket_pair_start = true;
 3967                                break;
 3968                            }
 3969                        }
 3970                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3971                        {
 3972                            // take first bracket pair matching end, but don't break in case a later bracket
 3973                            // pair matches start
 3974                            bracket_pair_matching_end = Some(pair.clone());
 3975                        }
 3976                    }
 3977                    if let Some(end) = bracket_pair_matching_end
 3978                        && bracket_pair.is_none()
 3979                    {
 3980                        bracket_pair = Some(end);
 3981                        is_bracket_pair_end = true;
 3982                    }
 3983                }
 3984
 3985                if let Some(bracket_pair) = bracket_pair {
 3986                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3987                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3988                    let auto_surround =
 3989                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3990                    if selection.is_empty() {
 3991                        if is_bracket_pair_start {
 3992                            // If the inserted text is a suffix of an opening bracket and the
 3993                            // selection is preceded by the rest of the opening bracket, then
 3994                            // insert the closing bracket.
 3995                            let following_text_allows_autoclose = snapshot
 3996                                .chars_at(selection.start)
 3997                                .next()
 3998                                .map_or(true, |c| scope.should_autoclose_before(c));
 3999
 4000                            let preceding_text_allows_autoclose = selection.start.column == 0
 4001                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 4002                                    true,
 4003                                    |c| {
 4004                                        bracket_pair.start != bracket_pair.end
 4005                                            || !snapshot
 4006                                                .char_classifier_at(selection.start)
 4007                                                .is_word(c)
 4008                                    },
 4009                                );
 4010
 4011                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4012                                && bracket_pair.start.len() == 1
 4013                            {
 4014                                let target = bracket_pair.start.chars().next().unwrap();
 4015                                let current_line_count = snapshot
 4016                                    .reversed_chars_at(selection.start)
 4017                                    .take_while(|&c| c != '\n')
 4018                                    .filter(|&c| c == target)
 4019                                    .count();
 4020                                current_line_count % 2 == 1
 4021                            } else {
 4022                                false
 4023                            };
 4024
 4025                            if autoclose
 4026                                && bracket_pair.close
 4027                                && following_text_allows_autoclose
 4028                                && preceding_text_allows_autoclose
 4029                                && !is_closing_quote
 4030                            {
 4031                                let anchor = snapshot.anchor_before(selection.end);
 4032                                new_selections.push((selection.map(|_| anchor), text.len()));
 4033                                new_autoclose_regions.push((
 4034                                    anchor,
 4035                                    text.len(),
 4036                                    selection.id,
 4037                                    bracket_pair.clone(),
 4038                                ));
 4039                                edits.push((
 4040                                    selection.range(),
 4041                                    format!("{}{}", text, bracket_pair.end).into(),
 4042                                ));
 4043                                bracket_inserted = true;
 4044                                continue;
 4045                            }
 4046                        }
 4047
 4048                        if let Some(region) = autoclose_region {
 4049                            // If the selection is followed by an auto-inserted closing bracket,
 4050                            // then don't insert that closing bracket again; just move the selection
 4051                            // past the closing bracket.
 4052                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4053                                && text.as_ref() == region.pair.end.as_str()
 4054                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4055                            if should_skip {
 4056                                let anchor = snapshot.anchor_after(selection.end);
 4057                                new_selections
 4058                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4059                                continue;
 4060                            }
 4061                        }
 4062
 4063                        let always_treat_brackets_as_autoclosed = snapshot
 4064                            .language_settings_at(selection.start, cx)
 4065                            .always_treat_brackets_as_autoclosed;
 4066                        if always_treat_brackets_as_autoclosed
 4067                            && is_bracket_pair_end
 4068                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4069                        {
 4070                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4071                            // and the inserted text is a closing bracket and the selection is followed
 4072                            // by the closing bracket then move the selection past the closing bracket.
 4073                            let anchor = snapshot.anchor_after(selection.end);
 4074                            new_selections.push((selection.map(|_| anchor), text.len()));
 4075                            continue;
 4076                        }
 4077                    }
 4078                    // If an opening bracket is 1 character long and is typed while
 4079                    // text is selected, then surround that text with the bracket pair.
 4080                    else if auto_surround
 4081                        && bracket_pair.surround
 4082                        && is_bracket_pair_start
 4083                        && bracket_pair.start.chars().count() == 1
 4084                    {
 4085                        edits.push((selection.start..selection.start, text.clone()));
 4086                        edits.push((
 4087                            selection.end..selection.end,
 4088                            bracket_pair.end.as_str().into(),
 4089                        ));
 4090                        bracket_inserted = true;
 4091                        new_selections.push((
 4092                            Selection {
 4093                                id: selection.id,
 4094                                start: snapshot.anchor_after(selection.start),
 4095                                end: snapshot.anchor_before(selection.end),
 4096                                reversed: selection.reversed,
 4097                                goal: selection.goal,
 4098                            },
 4099                            0,
 4100                        ));
 4101                        continue;
 4102                    }
 4103                }
 4104            }
 4105
 4106            if self.auto_replace_emoji_shortcode
 4107                && selection.is_empty()
 4108                && text.as_ref().ends_with(':')
 4109            {
 4110                if let Some(possible_emoji_short_code) =
 4111                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4112                {
 4113                    if !possible_emoji_short_code.is_empty() {
 4114                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4115                            let emoji_shortcode_start = Point::new(
 4116                                selection.start.row,
 4117                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4118                            );
 4119
 4120                            // Remove shortcode from buffer
 4121                            edits.push((
 4122                                emoji_shortcode_start..selection.start,
 4123                                "".to_string().into(),
 4124                            ));
 4125                            new_selections.push((
 4126                                Selection {
 4127                                    id: selection.id,
 4128                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4129                                    end: snapshot.anchor_before(selection.start),
 4130                                    reversed: selection.reversed,
 4131                                    goal: selection.goal,
 4132                                },
 4133                                0,
 4134                            ));
 4135
 4136                            // Insert emoji
 4137                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4138                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4139                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4140
 4141                            continue;
 4142                        }
 4143                    }
 4144                }
 4145            }
 4146
 4147            // If not handling any auto-close operation, then just replace the selected
 4148            // text with the given input and move the selection to the end of the
 4149            // newly inserted text.
 4150            let anchor = snapshot.anchor_after(selection.end);
 4151            if !self.linked_edit_ranges.is_empty() {
 4152                let start_anchor = snapshot.anchor_before(selection.start);
 4153
 4154                let is_word_char = text.chars().next().map_or(true, |char| {
 4155                    let classifier = snapshot
 4156                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4157                        .ignore_punctuation(true);
 4158                    classifier.is_word(char)
 4159                });
 4160
 4161                if is_word_char {
 4162                    if let Some(ranges) = self
 4163                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4164                    {
 4165                        for (buffer, edits) in ranges {
 4166                            linked_edits
 4167                                .entry(buffer.clone())
 4168                                .or_default()
 4169                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4170                        }
 4171                    }
 4172                } else {
 4173                    clear_linked_edit_ranges = true;
 4174                }
 4175            }
 4176
 4177            new_selections.push((selection.map(|_| anchor), 0));
 4178            edits.push((selection.start..selection.end, text.clone()));
 4179        }
 4180
 4181        drop(snapshot);
 4182
 4183        self.transact(window, cx, |this, window, cx| {
 4184            if clear_linked_edit_ranges {
 4185                this.linked_edit_ranges.clear();
 4186            }
 4187            let initial_buffer_versions =
 4188                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4189
 4190            this.buffer.update(cx, |buffer, cx| {
 4191                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4192            });
 4193            for (buffer, edits) in linked_edits {
 4194                buffer.update(cx, |buffer, cx| {
 4195                    let snapshot = buffer.snapshot();
 4196                    let edits = edits
 4197                        .into_iter()
 4198                        .map(|(range, text)| {
 4199                            use text::ToPoint as TP;
 4200                            let end_point = TP::to_point(&range.end, &snapshot);
 4201                            let start_point = TP::to_point(&range.start, &snapshot);
 4202                            (start_point..end_point, text)
 4203                        })
 4204                        .sorted_by_key(|(range, _)| range.start);
 4205                    buffer.edit(edits, None, cx);
 4206                })
 4207            }
 4208            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4209            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4210            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4211            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4212                .zip(new_selection_deltas)
 4213                .map(|(selection, delta)| Selection {
 4214                    id: selection.id,
 4215                    start: selection.start + delta,
 4216                    end: selection.end + delta,
 4217                    reversed: selection.reversed,
 4218                    goal: SelectionGoal::None,
 4219                })
 4220                .collect::<Vec<_>>();
 4221
 4222            let mut i = 0;
 4223            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4224                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4225                let start = map.buffer_snapshot.anchor_before(position);
 4226                let end = map.buffer_snapshot.anchor_after(position);
 4227                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4228                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4229                        Ordering::Less => i += 1,
 4230                        Ordering::Greater => break,
 4231                        Ordering::Equal => {
 4232                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4233                                Ordering::Less => i += 1,
 4234                                Ordering::Equal => break,
 4235                                Ordering::Greater => break,
 4236                            }
 4237                        }
 4238                    }
 4239                }
 4240                this.autoclose_regions.insert(
 4241                    i,
 4242                    AutocloseRegion {
 4243                        selection_id,
 4244                        range: start..end,
 4245                        pair,
 4246                    },
 4247                );
 4248            }
 4249
 4250            let had_active_edit_prediction = this.has_active_edit_prediction();
 4251            this.change_selections(
 4252                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4253                window,
 4254                cx,
 4255                |s| s.select(new_selections),
 4256            );
 4257
 4258            if !bracket_inserted {
 4259                if let Some(on_type_format_task) =
 4260                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4261                {
 4262                    on_type_format_task.detach_and_log_err(cx);
 4263                }
 4264            }
 4265
 4266            let editor_settings = EditorSettings::get_global(cx);
 4267            if bracket_inserted
 4268                && (editor_settings.auto_signature_help
 4269                    || editor_settings.show_signature_help_after_edits)
 4270            {
 4271                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4272            }
 4273
 4274            let trigger_in_words =
 4275                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4276            if this.hard_wrap.is_some() {
 4277                let latest: Range<Point> = this.selections.newest(cx).range();
 4278                if latest.is_empty()
 4279                    && this
 4280                        .buffer()
 4281                        .read(cx)
 4282                        .snapshot(cx)
 4283                        .line_len(MultiBufferRow(latest.start.row))
 4284                        == latest.start.column
 4285                {
 4286                    this.rewrap_impl(
 4287                        RewrapOptions {
 4288                            override_language_settings: true,
 4289                            preserve_existing_whitespace: true,
 4290                        },
 4291                        cx,
 4292                    )
 4293                }
 4294            }
 4295            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4296            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4297            this.refresh_edit_prediction(true, false, window, cx);
 4298            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4299        });
 4300    }
 4301
 4302    fn find_possible_emoji_shortcode_at_position(
 4303        snapshot: &MultiBufferSnapshot,
 4304        position: Point,
 4305    ) -> Option<String> {
 4306        let mut chars = Vec::new();
 4307        let mut found_colon = false;
 4308        for char in snapshot.reversed_chars_at(position).take(100) {
 4309            // Found a possible emoji shortcode in the middle of the buffer
 4310            if found_colon {
 4311                if char.is_whitespace() {
 4312                    chars.reverse();
 4313                    return Some(chars.iter().collect());
 4314                }
 4315                // If the previous character is not a whitespace, we are in the middle of a word
 4316                // and we only want to complete the shortcode if the word is made up of other emojis
 4317                let mut containing_word = String::new();
 4318                for ch in snapshot
 4319                    .reversed_chars_at(position)
 4320                    .skip(chars.len() + 1)
 4321                    .take(100)
 4322                {
 4323                    if ch.is_whitespace() {
 4324                        break;
 4325                    }
 4326                    containing_word.push(ch);
 4327                }
 4328                let containing_word = containing_word.chars().rev().collect::<String>();
 4329                if util::word_consists_of_emojis(containing_word.as_str()) {
 4330                    chars.reverse();
 4331                    return Some(chars.iter().collect());
 4332                }
 4333            }
 4334
 4335            if char.is_whitespace() || !char.is_ascii() {
 4336                return None;
 4337            }
 4338            if char == ':' {
 4339                found_colon = true;
 4340            } else {
 4341                chars.push(char);
 4342            }
 4343        }
 4344        // Found a possible emoji shortcode at the beginning of the buffer
 4345        chars.reverse();
 4346        Some(chars.iter().collect())
 4347    }
 4348
 4349    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4350        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4351        self.transact(window, cx, |this, window, cx| {
 4352            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4353                let selections = this.selections.all::<usize>(cx);
 4354                let multi_buffer = this.buffer.read(cx);
 4355                let buffer = multi_buffer.snapshot(cx);
 4356                selections
 4357                    .iter()
 4358                    .map(|selection| {
 4359                        let start_point = selection.start.to_point(&buffer);
 4360                        let mut existing_indent =
 4361                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4362                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4363                        let start = selection.start;
 4364                        let end = selection.end;
 4365                        let selection_is_empty = start == end;
 4366                        let language_scope = buffer.language_scope_at(start);
 4367                        let (
 4368                            comment_delimiter,
 4369                            doc_delimiter,
 4370                            insert_extra_newline,
 4371                            indent_on_newline,
 4372                            indent_on_extra_newline,
 4373                        ) = if let Some(language) = &language_scope {
 4374                            let mut insert_extra_newline =
 4375                                insert_extra_newline_brackets(&buffer, start..end, language)
 4376                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4377
 4378                            // Comment extension on newline is allowed only for cursor selections
 4379                            let comment_delimiter = maybe!({
 4380                                if !selection_is_empty {
 4381                                    return None;
 4382                                }
 4383
 4384                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4385                                    return None;
 4386                                }
 4387
 4388                                let delimiters = language.line_comment_prefixes();
 4389                                let max_len_of_delimiter =
 4390                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4391                                let (snapshot, range) =
 4392                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4393
 4394                                let num_of_whitespaces = snapshot
 4395                                    .chars_for_range(range.clone())
 4396                                    .take_while(|c| c.is_whitespace())
 4397                                    .count();
 4398                                let comment_candidate = snapshot
 4399                                    .chars_for_range(range.clone())
 4400                                    .skip(num_of_whitespaces)
 4401                                    .take(max_len_of_delimiter)
 4402                                    .collect::<String>();
 4403                                let (delimiter, trimmed_len) = delimiters
 4404                                    .iter()
 4405                                    .filter_map(|delimiter| {
 4406                                        let prefix = delimiter.trim_end();
 4407                                        if comment_candidate.starts_with(prefix) {
 4408                                            Some((delimiter, prefix.len()))
 4409                                        } else {
 4410                                            None
 4411                                        }
 4412                                    })
 4413                                    .max_by_key(|(_, len)| *len)?;
 4414
 4415                                if let Some(BlockCommentConfig {
 4416                                    start: block_start, ..
 4417                                }) = language.block_comment()
 4418                                {
 4419                                    let block_start_trimmed = block_start.trim_end();
 4420                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4421                                        let line_content = snapshot
 4422                                            .chars_for_range(range)
 4423                                            .skip(num_of_whitespaces)
 4424                                            .take(block_start_trimmed.len())
 4425                                            .collect::<String>();
 4426
 4427                                        if line_content.starts_with(block_start_trimmed) {
 4428                                            return None;
 4429                                        }
 4430                                    }
 4431                                }
 4432
 4433                                let cursor_is_placed_after_comment_marker =
 4434                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4435                                if cursor_is_placed_after_comment_marker {
 4436                                    Some(delimiter.clone())
 4437                                } else {
 4438                                    None
 4439                                }
 4440                            });
 4441
 4442                            let mut indent_on_newline = IndentSize::spaces(0);
 4443                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4444
 4445                            let doc_delimiter = maybe!({
 4446                                if !selection_is_empty {
 4447                                    return None;
 4448                                }
 4449
 4450                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4451                                    return None;
 4452                                }
 4453
 4454                                let BlockCommentConfig {
 4455                                    start: start_tag,
 4456                                    end: end_tag,
 4457                                    prefix: delimiter,
 4458                                    tab_size: len,
 4459                                } = language.documentation_comment()?;
 4460                                let is_within_block_comment = buffer
 4461                                    .language_scope_at(start_point)
 4462                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4463                                if !is_within_block_comment {
 4464                                    return None;
 4465                                }
 4466
 4467                                let (snapshot, range) =
 4468                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4469
 4470                                let num_of_whitespaces = snapshot
 4471                                    .chars_for_range(range.clone())
 4472                                    .take_while(|c| c.is_whitespace())
 4473                                    .count();
 4474
 4475                                // 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.
 4476                                let column = start_point.column;
 4477                                let cursor_is_after_start_tag = {
 4478                                    let start_tag_len = start_tag.len();
 4479                                    let start_tag_line = snapshot
 4480                                        .chars_for_range(range.clone())
 4481                                        .skip(num_of_whitespaces)
 4482                                        .take(start_tag_len)
 4483                                        .collect::<String>();
 4484                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4485                                        num_of_whitespaces + start_tag_len <= column as usize
 4486                                    } else {
 4487                                        false
 4488                                    }
 4489                                };
 4490
 4491                                let cursor_is_after_delimiter = {
 4492                                    let delimiter_trim = delimiter.trim_end();
 4493                                    let delimiter_line = snapshot
 4494                                        .chars_for_range(range.clone())
 4495                                        .skip(num_of_whitespaces)
 4496                                        .take(delimiter_trim.len())
 4497                                        .collect::<String>();
 4498                                    if delimiter_line.starts_with(delimiter_trim) {
 4499                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4500                                    } else {
 4501                                        false
 4502                                    }
 4503                                };
 4504
 4505                                let cursor_is_before_end_tag_if_exists = {
 4506                                    let mut char_position = 0u32;
 4507                                    let mut end_tag_offset = None;
 4508
 4509                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4510                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4511                                            let chars_before_match =
 4512                                                chunk[..byte_pos].chars().count() as u32;
 4513                                            end_tag_offset =
 4514                                                Some(char_position + chars_before_match);
 4515                                            break 'outer;
 4516                                        }
 4517                                        char_position += chunk.chars().count() as u32;
 4518                                    }
 4519
 4520                                    if let Some(end_tag_offset) = end_tag_offset {
 4521                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4522                                        if cursor_is_after_start_tag {
 4523                                            if cursor_is_before_end_tag {
 4524                                                insert_extra_newline = true;
 4525                                            }
 4526                                            let cursor_is_at_start_of_end_tag =
 4527                                                column == end_tag_offset;
 4528                                            if cursor_is_at_start_of_end_tag {
 4529                                                indent_on_extra_newline.len = *len;
 4530                                            }
 4531                                        }
 4532                                        cursor_is_before_end_tag
 4533                                    } else {
 4534                                        true
 4535                                    }
 4536                                };
 4537
 4538                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4539                                    && cursor_is_before_end_tag_if_exists
 4540                                {
 4541                                    if cursor_is_after_start_tag {
 4542                                        indent_on_newline.len = *len;
 4543                                    }
 4544                                    Some(delimiter.clone())
 4545                                } else {
 4546                                    None
 4547                                }
 4548                            });
 4549
 4550                            (
 4551                                comment_delimiter,
 4552                                doc_delimiter,
 4553                                insert_extra_newline,
 4554                                indent_on_newline,
 4555                                indent_on_extra_newline,
 4556                            )
 4557                        } else {
 4558                            (
 4559                                None,
 4560                                None,
 4561                                false,
 4562                                IndentSize::default(),
 4563                                IndentSize::default(),
 4564                            )
 4565                        };
 4566
 4567                        let prevent_auto_indent = doc_delimiter.is_some();
 4568                        let delimiter = comment_delimiter.or(doc_delimiter);
 4569
 4570                        let capacity_for_delimiter =
 4571                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4572                        let mut new_text = String::with_capacity(
 4573                            1 + capacity_for_delimiter
 4574                                + existing_indent.len as usize
 4575                                + indent_on_newline.len as usize
 4576                                + indent_on_extra_newline.len as usize,
 4577                        );
 4578                        new_text.push('\n');
 4579                        new_text.extend(existing_indent.chars());
 4580                        new_text.extend(indent_on_newline.chars());
 4581
 4582                        if let Some(delimiter) = &delimiter {
 4583                            new_text.push_str(delimiter);
 4584                        }
 4585
 4586                        if insert_extra_newline {
 4587                            new_text.push('\n');
 4588                            new_text.extend(existing_indent.chars());
 4589                            new_text.extend(indent_on_extra_newline.chars());
 4590                        }
 4591
 4592                        let anchor = buffer.anchor_after(end);
 4593                        let new_selection = selection.map(|_| anchor);
 4594                        (
 4595                            ((start..end, new_text), prevent_auto_indent),
 4596                            (insert_extra_newline, new_selection),
 4597                        )
 4598                    })
 4599                    .unzip()
 4600            };
 4601
 4602            let mut auto_indent_edits = Vec::new();
 4603            let mut edits = Vec::new();
 4604            for (edit, prevent_auto_indent) in edits_with_flags {
 4605                if prevent_auto_indent {
 4606                    edits.push(edit);
 4607                } else {
 4608                    auto_indent_edits.push(edit);
 4609                }
 4610            }
 4611            if !edits.is_empty() {
 4612                this.edit(edits, cx);
 4613            }
 4614            if !auto_indent_edits.is_empty() {
 4615                this.edit_with_autoindent(auto_indent_edits, cx);
 4616            }
 4617
 4618            let buffer = this.buffer.read(cx).snapshot(cx);
 4619            let new_selections = selection_info
 4620                .into_iter()
 4621                .map(|(extra_newline_inserted, new_selection)| {
 4622                    let mut cursor = new_selection.end.to_point(&buffer);
 4623                    if extra_newline_inserted {
 4624                        cursor.row -= 1;
 4625                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4626                    }
 4627                    new_selection.map(|_| cursor)
 4628                })
 4629                .collect();
 4630
 4631            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4632            this.refresh_edit_prediction(true, false, window, cx);
 4633        });
 4634    }
 4635
 4636    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4637        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4638
 4639        let buffer = self.buffer.read(cx);
 4640        let snapshot = buffer.snapshot(cx);
 4641
 4642        let mut edits = Vec::new();
 4643        let mut rows = Vec::new();
 4644
 4645        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4646            let cursor = selection.head();
 4647            let row = cursor.row;
 4648
 4649            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4650
 4651            let newline = "\n".to_string();
 4652            edits.push((start_of_line..start_of_line, newline));
 4653
 4654            rows.push(row + rows_inserted as u32);
 4655        }
 4656
 4657        self.transact(window, cx, |editor, window, cx| {
 4658            editor.edit(edits, cx);
 4659
 4660            editor.change_selections(Default::default(), window, cx, |s| {
 4661                let mut index = 0;
 4662                s.move_cursors_with(|map, _, _| {
 4663                    let row = rows[index];
 4664                    index += 1;
 4665
 4666                    let point = Point::new(row, 0);
 4667                    let boundary = map.next_line_boundary(point).1;
 4668                    let clipped = map.clip_point(boundary, Bias::Left);
 4669
 4670                    (clipped, SelectionGoal::None)
 4671                });
 4672            });
 4673
 4674            let mut indent_edits = Vec::new();
 4675            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4676            for row in rows {
 4677                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4678                for (row, indent) in indents {
 4679                    if indent.len == 0 {
 4680                        continue;
 4681                    }
 4682
 4683                    let text = match indent.kind {
 4684                        IndentKind::Space => " ".repeat(indent.len as usize),
 4685                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4686                    };
 4687                    let point = Point::new(row.0, 0);
 4688                    indent_edits.push((point..point, text));
 4689                }
 4690            }
 4691            editor.edit(indent_edits, cx);
 4692        });
 4693    }
 4694
 4695    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4696        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4697
 4698        let buffer = self.buffer.read(cx);
 4699        let snapshot = buffer.snapshot(cx);
 4700
 4701        let mut edits = Vec::new();
 4702        let mut rows = Vec::new();
 4703        let mut rows_inserted = 0;
 4704
 4705        for selection in self.selections.all_adjusted(cx) {
 4706            let cursor = selection.head();
 4707            let row = cursor.row;
 4708
 4709            let point = Point::new(row + 1, 0);
 4710            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4711
 4712            let newline = "\n".to_string();
 4713            edits.push((start_of_line..start_of_line, newline));
 4714
 4715            rows_inserted += 1;
 4716            rows.push(row + rows_inserted);
 4717        }
 4718
 4719        self.transact(window, cx, |editor, window, cx| {
 4720            editor.edit(edits, cx);
 4721
 4722            editor.change_selections(Default::default(), window, cx, |s| {
 4723                let mut index = 0;
 4724                s.move_cursors_with(|map, _, _| {
 4725                    let row = rows[index];
 4726                    index += 1;
 4727
 4728                    let point = Point::new(row, 0);
 4729                    let boundary = map.next_line_boundary(point).1;
 4730                    let clipped = map.clip_point(boundary, Bias::Left);
 4731
 4732                    (clipped, SelectionGoal::None)
 4733                });
 4734            });
 4735
 4736            let mut indent_edits = Vec::new();
 4737            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4738            for row in rows {
 4739                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4740                for (row, indent) in indents {
 4741                    if indent.len == 0 {
 4742                        continue;
 4743                    }
 4744
 4745                    let text = match indent.kind {
 4746                        IndentKind::Space => " ".repeat(indent.len as usize),
 4747                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4748                    };
 4749                    let point = Point::new(row.0, 0);
 4750                    indent_edits.push((point..point, text));
 4751                }
 4752            }
 4753            editor.edit(indent_edits, cx);
 4754        });
 4755    }
 4756
 4757    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4758        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4759            original_indent_columns: Vec::new(),
 4760        });
 4761        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4762    }
 4763
 4764    fn insert_with_autoindent_mode(
 4765        &mut self,
 4766        text: &str,
 4767        autoindent_mode: Option<AutoindentMode>,
 4768        window: &mut Window,
 4769        cx: &mut Context<Self>,
 4770    ) {
 4771        if self.read_only(cx) {
 4772            return;
 4773        }
 4774
 4775        let text: Arc<str> = text.into();
 4776        self.transact(window, cx, |this, window, cx| {
 4777            let old_selections = this.selections.all_adjusted(cx);
 4778            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4779                let anchors = {
 4780                    let snapshot = buffer.read(cx);
 4781                    old_selections
 4782                        .iter()
 4783                        .map(|s| {
 4784                            let anchor = snapshot.anchor_after(s.head());
 4785                            s.map(|_| anchor)
 4786                        })
 4787                        .collect::<Vec<_>>()
 4788                };
 4789                buffer.edit(
 4790                    old_selections
 4791                        .iter()
 4792                        .map(|s| (s.start..s.end, text.clone())),
 4793                    autoindent_mode,
 4794                    cx,
 4795                );
 4796                anchors
 4797            });
 4798
 4799            this.change_selections(Default::default(), window, cx, |s| {
 4800                s.select_anchors(selection_anchors);
 4801            });
 4802
 4803            cx.notify();
 4804        });
 4805    }
 4806
 4807    fn trigger_completion_on_input(
 4808        &mut self,
 4809        text: &str,
 4810        trigger_in_words: bool,
 4811        window: &mut Window,
 4812        cx: &mut Context<Self>,
 4813    ) {
 4814        let completions_source = self
 4815            .context_menu
 4816            .borrow()
 4817            .as_ref()
 4818            .and_then(|menu| match menu {
 4819                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4820                CodeContextMenu::CodeActions(_) => None,
 4821            });
 4822
 4823        match completions_source {
 4824            Some(CompletionsMenuSource::Words) => {
 4825                self.show_word_completions(&ShowWordCompletions, window, cx)
 4826            }
 4827            Some(CompletionsMenuSource::Normal)
 4828            | Some(CompletionsMenuSource::SnippetChoices)
 4829            | None
 4830                if self.is_completion_trigger(
 4831                    text,
 4832                    trigger_in_words,
 4833                    completions_source.is_some(),
 4834                    cx,
 4835                ) =>
 4836            {
 4837                self.show_completions(
 4838                    &ShowCompletions {
 4839                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4840                    },
 4841                    window,
 4842                    cx,
 4843                )
 4844            }
 4845            _ => {
 4846                self.hide_context_menu(window, cx);
 4847            }
 4848        }
 4849    }
 4850
 4851    fn is_completion_trigger(
 4852        &self,
 4853        text: &str,
 4854        trigger_in_words: bool,
 4855        menu_is_open: bool,
 4856        cx: &mut Context<Self>,
 4857    ) -> bool {
 4858        let position = self.selections.newest_anchor().head();
 4859        let multibuffer = self.buffer.read(cx);
 4860        let Some(buffer) = position
 4861            .buffer_id
 4862            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4863        else {
 4864            return false;
 4865        };
 4866
 4867        if let Some(completion_provider) = &self.completion_provider {
 4868            completion_provider.is_completion_trigger(
 4869                &buffer,
 4870                position.text_anchor,
 4871                text,
 4872                trigger_in_words,
 4873                menu_is_open,
 4874                cx,
 4875            )
 4876        } else {
 4877            false
 4878        }
 4879    }
 4880
 4881    /// If any empty selections is touching the start of its innermost containing autoclose
 4882    /// region, expand it to select the brackets.
 4883    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4884        let selections = self.selections.all::<usize>(cx);
 4885        let buffer = self.buffer.read(cx).read(cx);
 4886        let new_selections = self
 4887            .selections_with_autoclose_regions(selections, &buffer)
 4888            .map(|(mut selection, region)| {
 4889                if !selection.is_empty() {
 4890                    return selection;
 4891                }
 4892
 4893                if let Some(region) = region {
 4894                    let mut range = region.range.to_offset(&buffer);
 4895                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4896                        range.start -= region.pair.start.len();
 4897                        if buffer.contains_str_at(range.start, &region.pair.start)
 4898                            && buffer.contains_str_at(range.end, &region.pair.end)
 4899                        {
 4900                            range.end += region.pair.end.len();
 4901                            selection.start = range.start;
 4902                            selection.end = range.end;
 4903
 4904                            return selection;
 4905                        }
 4906                    }
 4907                }
 4908
 4909                let always_treat_brackets_as_autoclosed = buffer
 4910                    .language_settings_at(selection.start, cx)
 4911                    .always_treat_brackets_as_autoclosed;
 4912
 4913                if !always_treat_brackets_as_autoclosed {
 4914                    return selection;
 4915                }
 4916
 4917                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4918                    for (pair, enabled) in scope.brackets() {
 4919                        if !enabled || !pair.close {
 4920                            continue;
 4921                        }
 4922
 4923                        if buffer.contains_str_at(selection.start, &pair.end) {
 4924                            let pair_start_len = pair.start.len();
 4925                            if buffer.contains_str_at(
 4926                                selection.start.saturating_sub(pair_start_len),
 4927                                &pair.start,
 4928                            ) {
 4929                                selection.start -= pair_start_len;
 4930                                selection.end += pair.end.len();
 4931
 4932                                return selection;
 4933                            }
 4934                        }
 4935                    }
 4936                }
 4937
 4938                selection
 4939            })
 4940            .collect();
 4941
 4942        drop(buffer);
 4943        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4944            selections.select(new_selections)
 4945        });
 4946    }
 4947
 4948    /// Iterate the given selections, and for each one, find the smallest surrounding
 4949    /// autoclose region. This uses the ordering of the selections and the autoclose
 4950    /// regions to avoid repeated comparisons.
 4951    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4952        &'a self,
 4953        selections: impl IntoIterator<Item = Selection<D>>,
 4954        buffer: &'a MultiBufferSnapshot,
 4955    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4956        let mut i = 0;
 4957        let mut regions = self.autoclose_regions.as_slice();
 4958        selections.into_iter().map(move |selection| {
 4959            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4960
 4961            let mut enclosing = None;
 4962            while let Some(pair_state) = regions.get(i) {
 4963                if pair_state.range.end.to_offset(buffer) < range.start {
 4964                    regions = &regions[i + 1..];
 4965                    i = 0;
 4966                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4967                    break;
 4968                } else {
 4969                    if pair_state.selection_id == selection.id {
 4970                        enclosing = Some(pair_state);
 4971                    }
 4972                    i += 1;
 4973                }
 4974            }
 4975
 4976            (selection, enclosing)
 4977        })
 4978    }
 4979
 4980    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4981    fn invalidate_autoclose_regions(
 4982        &mut self,
 4983        mut selections: &[Selection<Anchor>],
 4984        buffer: &MultiBufferSnapshot,
 4985    ) {
 4986        self.autoclose_regions.retain(|state| {
 4987            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 4988                return false;
 4989            }
 4990
 4991            let mut i = 0;
 4992            while let Some(selection) = selections.get(i) {
 4993                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4994                    selections = &selections[1..];
 4995                    continue;
 4996                }
 4997                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4998                    break;
 4999                }
 5000                if selection.id == state.selection_id {
 5001                    return true;
 5002                } else {
 5003                    i += 1;
 5004                }
 5005            }
 5006            false
 5007        });
 5008    }
 5009
 5010    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5011        let offset = position.to_offset(buffer);
 5012        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5013        if offset > word_range.start && kind == Some(CharKind::Word) {
 5014            Some(
 5015                buffer
 5016                    .text_for_range(word_range.start..offset)
 5017                    .collect::<String>(),
 5018            )
 5019        } else {
 5020            None
 5021        }
 5022    }
 5023
 5024    pub fn toggle_inline_values(
 5025        &mut self,
 5026        _: &ToggleInlineValues,
 5027        _: &mut Window,
 5028        cx: &mut Context<Self>,
 5029    ) {
 5030        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5031
 5032        self.refresh_inline_values(cx);
 5033    }
 5034
 5035    pub fn toggle_inlay_hints(
 5036        &mut self,
 5037        _: &ToggleInlayHints,
 5038        _: &mut Window,
 5039        cx: &mut Context<Self>,
 5040    ) {
 5041        self.refresh_inlay_hints(
 5042            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5043            cx,
 5044        );
 5045    }
 5046
 5047    pub fn inlay_hints_enabled(&self) -> bool {
 5048        self.inlay_hint_cache.enabled
 5049    }
 5050
 5051    pub fn inline_values_enabled(&self) -> bool {
 5052        self.inline_value_cache.enabled
 5053    }
 5054
 5055    #[cfg(any(test, feature = "test-support"))]
 5056    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5057        self.display_map
 5058            .read(cx)
 5059            .current_inlays()
 5060            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5061            .cloned()
 5062            .collect()
 5063    }
 5064
 5065    #[cfg(any(test, feature = "test-support"))]
 5066    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5067        self.display_map
 5068            .read(cx)
 5069            .current_inlays()
 5070            .cloned()
 5071            .collect()
 5072    }
 5073
 5074    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5075        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5076            return;
 5077        }
 5078
 5079        let reason_description = reason.description();
 5080        let ignore_debounce = matches!(
 5081            reason,
 5082            InlayHintRefreshReason::SettingsChange(_)
 5083                | InlayHintRefreshReason::Toggle(_)
 5084                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5085                | InlayHintRefreshReason::ModifiersChanged(_)
 5086        );
 5087        let (invalidate_cache, required_languages) = match reason {
 5088            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5089                match self.inlay_hint_cache.modifiers_override(enabled) {
 5090                    Some(enabled) => {
 5091                        if enabled {
 5092                            (InvalidationStrategy::RefreshRequested, None)
 5093                        } else {
 5094                            self.splice_inlays(
 5095                                &self
 5096                                    .visible_inlay_hints(cx)
 5097                                    .iter()
 5098                                    .map(|inlay| inlay.id)
 5099                                    .collect::<Vec<InlayId>>(),
 5100                                Vec::new(),
 5101                                cx,
 5102                            );
 5103                            return;
 5104                        }
 5105                    }
 5106                    None => return,
 5107                }
 5108            }
 5109            InlayHintRefreshReason::Toggle(enabled) => {
 5110                if self.inlay_hint_cache.toggle(enabled) {
 5111                    if enabled {
 5112                        (InvalidationStrategy::RefreshRequested, None)
 5113                    } else {
 5114                        self.splice_inlays(
 5115                            &self
 5116                                .visible_inlay_hints(cx)
 5117                                .iter()
 5118                                .map(|inlay| inlay.id)
 5119                                .collect::<Vec<InlayId>>(),
 5120                            Vec::new(),
 5121                            cx,
 5122                        );
 5123                        return;
 5124                    }
 5125                } else {
 5126                    return;
 5127                }
 5128            }
 5129            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5130                match self.inlay_hint_cache.update_settings(
 5131                    &self.buffer,
 5132                    new_settings,
 5133                    self.visible_inlay_hints(cx),
 5134                    cx,
 5135                ) {
 5136                    ControlFlow::Break(Some(InlaySplice {
 5137                        to_remove,
 5138                        to_insert,
 5139                    })) => {
 5140                        self.splice_inlays(&to_remove, to_insert, cx);
 5141                        return;
 5142                    }
 5143                    ControlFlow::Break(None) => return,
 5144                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5145                }
 5146            }
 5147            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5148                if let Some(InlaySplice {
 5149                    to_remove,
 5150                    to_insert,
 5151                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5152                {
 5153                    self.splice_inlays(&to_remove, to_insert, cx);
 5154                }
 5155                self.display_map.update(cx, |display_map, _| {
 5156                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5157                });
 5158                return;
 5159            }
 5160            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5161            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5162                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5163            }
 5164            InlayHintRefreshReason::RefreshRequested => {
 5165                (InvalidationStrategy::RefreshRequested, None)
 5166            }
 5167        };
 5168
 5169        if let Some(InlaySplice {
 5170            to_remove,
 5171            to_insert,
 5172        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5173            reason_description,
 5174            self.visible_excerpts(required_languages.as_ref(), cx),
 5175            invalidate_cache,
 5176            ignore_debounce,
 5177            cx,
 5178        ) {
 5179            self.splice_inlays(&to_remove, to_insert, cx);
 5180        }
 5181    }
 5182
 5183    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5184        self.display_map
 5185            .read(cx)
 5186            .current_inlays()
 5187            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5188            .cloned()
 5189            .collect()
 5190    }
 5191
 5192    pub fn visible_excerpts(
 5193        &self,
 5194        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5195        cx: &mut Context<Editor>,
 5196    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5197        let Some(project) = self.project.as_ref() else {
 5198            return HashMap::default();
 5199        };
 5200        let project = project.read(cx);
 5201        let multi_buffer = self.buffer().read(cx);
 5202        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5203        let multi_buffer_visible_start = self
 5204            .scroll_manager
 5205            .anchor()
 5206            .anchor
 5207            .to_point(&multi_buffer_snapshot);
 5208        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5209            multi_buffer_visible_start
 5210                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5211            Bias::Left,
 5212        );
 5213        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5214        multi_buffer_snapshot
 5215            .range_to_buffer_ranges(multi_buffer_visible_range)
 5216            .into_iter()
 5217            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5218            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5219                let buffer_file = project::File::from_dyn(buffer.file())?;
 5220                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5221                let worktree_entry = buffer_worktree
 5222                    .read(cx)
 5223                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5224                if worktree_entry.is_ignored {
 5225                    return None;
 5226                }
 5227
 5228                let language = buffer.language()?;
 5229                if let Some(restrict_to_languages) = restrict_to_languages {
 5230                    if !restrict_to_languages.contains(language) {
 5231                        return None;
 5232                    }
 5233                }
 5234                Some((
 5235                    excerpt_id,
 5236                    (
 5237                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5238                        buffer.version().clone(),
 5239                        excerpt_visible_range,
 5240                    ),
 5241                ))
 5242            })
 5243            .collect()
 5244    }
 5245
 5246    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5247        TextLayoutDetails {
 5248            text_system: window.text_system().clone(),
 5249            editor_style: self.style.clone().unwrap(),
 5250            rem_size: window.rem_size(),
 5251            scroll_anchor: self.scroll_manager.anchor(),
 5252            visible_rows: self.visible_line_count(),
 5253            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5254        }
 5255    }
 5256
 5257    pub fn splice_inlays(
 5258        &self,
 5259        to_remove: &[InlayId],
 5260        to_insert: Vec<Inlay>,
 5261        cx: &mut Context<Self>,
 5262    ) {
 5263        self.display_map.update(cx, |display_map, cx| {
 5264            display_map.splice_inlays(to_remove, to_insert, cx)
 5265        });
 5266        cx.notify();
 5267    }
 5268
 5269    fn trigger_on_type_formatting(
 5270        &self,
 5271        input: String,
 5272        window: &mut Window,
 5273        cx: &mut Context<Self>,
 5274    ) -> Option<Task<Result<()>>> {
 5275        if input.len() != 1 {
 5276            return None;
 5277        }
 5278
 5279        let project = self.project.as_ref()?;
 5280        let position = self.selections.newest_anchor().head();
 5281        let (buffer, buffer_position) = self
 5282            .buffer
 5283            .read(cx)
 5284            .text_anchor_for_position(position, cx)?;
 5285
 5286        let settings = language_settings::language_settings(
 5287            buffer
 5288                .read(cx)
 5289                .language_at(buffer_position)
 5290                .map(|l| l.name()),
 5291            buffer.read(cx).file(),
 5292            cx,
 5293        );
 5294        if !settings.use_on_type_format {
 5295            return None;
 5296        }
 5297
 5298        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5299        // hence we do LSP request & edit on host side only — add formats to host's history.
 5300        let push_to_lsp_host_history = true;
 5301        // If this is not the host, append its history with new edits.
 5302        let push_to_client_history = project.read(cx).is_via_collab();
 5303
 5304        let on_type_formatting = project.update(cx, |project, cx| {
 5305            project.on_type_format(
 5306                buffer.clone(),
 5307                buffer_position,
 5308                input,
 5309                push_to_lsp_host_history,
 5310                cx,
 5311            )
 5312        });
 5313        Some(cx.spawn_in(window, async move |editor, cx| {
 5314            if let Some(transaction) = on_type_formatting.await? {
 5315                if push_to_client_history {
 5316                    buffer
 5317                        .update(cx, |buffer, _| {
 5318                            buffer.push_transaction(transaction, Instant::now());
 5319                            buffer.finalize_last_transaction();
 5320                        })
 5321                        .ok();
 5322                }
 5323                editor.update(cx, |editor, cx| {
 5324                    editor.refresh_document_highlights(cx);
 5325                })?;
 5326            }
 5327            Ok(())
 5328        }))
 5329    }
 5330
 5331    pub fn show_word_completions(
 5332        &mut self,
 5333        _: &ShowWordCompletions,
 5334        window: &mut Window,
 5335        cx: &mut Context<Self>,
 5336    ) {
 5337        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5338    }
 5339
 5340    pub fn show_completions(
 5341        &mut self,
 5342        options: &ShowCompletions,
 5343        window: &mut Window,
 5344        cx: &mut Context<Self>,
 5345    ) {
 5346        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5347    }
 5348
 5349    fn open_or_update_completions_menu(
 5350        &mut self,
 5351        requested_source: Option<CompletionsMenuSource>,
 5352        trigger: Option<&str>,
 5353        window: &mut Window,
 5354        cx: &mut Context<Self>,
 5355    ) {
 5356        if self.pending_rename.is_some() {
 5357            return;
 5358        }
 5359
 5360        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5361
 5362        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5363        // inserted and selected. To handle that case, the start of the selection is used so that
 5364        // the menu starts with all choices.
 5365        let position = self
 5366            .selections
 5367            .newest_anchor()
 5368            .start
 5369            .bias_right(&multibuffer_snapshot);
 5370        if position.diff_base_anchor.is_some() {
 5371            return;
 5372        }
 5373        let (buffer, buffer_position) =
 5374            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5375                output
 5376            } else {
 5377                return;
 5378            };
 5379        let buffer_snapshot = buffer.read(cx).snapshot();
 5380
 5381        let query: Option<Arc<String>> =
 5382            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5383
 5384        drop(multibuffer_snapshot);
 5385
 5386        let provider = match requested_source {
 5387            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5388            Some(CompletionsMenuSource::Words) => None,
 5389            Some(CompletionsMenuSource::SnippetChoices) => {
 5390                log::error!("bug: SnippetChoices requested_source is not handled");
 5391                None
 5392            }
 5393        };
 5394
 5395        let sort_completions = provider
 5396            .as_ref()
 5397            .map_or(false, |provider| provider.sort_completions());
 5398
 5399        let filter_completions = provider
 5400            .as_ref()
 5401            .map_or(true, |provider| provider.filter_completions());
 5402
 5403        let trigger_kind = match trigger {
 5404            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5405                CompletionTriggerKind::TRIGGER_CHARACTER
 5406            }
 5407            _ => CompletionTriggerKind::INVOKED,
 5408        };
 5409        let completion_context = CompletionContext {
 5410            trigger_character: trigger.and_then(|trigger| {
 5411                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5412                    Some(String::from(trigger))
 5413                } else {
 5414                    None
 5415                }
 5416            }),
 5417            trigger_kind,
 5418        };
 5419
 5420        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5421        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5422        // involve trigger chars, so this is skipped in that case.
 5423        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5424        {
 5425            let menu_is_open = matches!(
 5426                self.context_menu.borrow().as_ref(),
 5427                Some(CodeContextMenu::Completions(_))
 5428            );
 5429            if menu_is_open {
 5430                self.hide_context_menu(window, cx);
 5431            }
 5432        }
 5433
 5434        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5435            if filter_completions {
 5436                menu.filter(query.clone(), provider.clone(), window, cx);
 5437            }
 5438            // When `is_incomplete` is false, no need to re-query completions when the current query
 5439            // is a suffix of the initial query.
 5440            if !menu.is_incomplete {
 5441                // If the new query is a suffix of the old query (typing more characters) and
 5442                // the previous result was complete, the existing completions can be filtered.
 5443                //
 5444                // Note that this is always true for snippet completions.
 5445                let query_matches = match (&menu.initial_query, &query) {
 5446                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5447                    (None, _) => true,
 5448                    _ => false,
 5449                };
 5450                if query_matches {
 5451                    let position_matches = if menu.initial_position == position {
 5452                        true
 5453                    } else {
 5454                        let snapshot = self.buffer.read(cx).read(cx);
 5455                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5456                    };
 5457                    if position_matches {
 5458                        return;
 5459                    }
 5460                }
 5461            }
 5462        };
 5463
 5464        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5465            buffer_snapshot.surrounding_word(buffer_position, false)
 5466        {
 5467            let word_to_exclude = buffer_snapshot
 5468                .text_for_range(word_range.clone())
 5469                .collect::<String>();
 5470            (
 5471                buffer_snapshot.anchor_before(word_range.start)
 5472                    ..buffer_snapshot.anchor_after(buffer_position),
 5473                Some(word_to_exclude),
 5474            )
 5475        } else {
 5476            (buffer_position..buffer_position, None)
 5477        };
 5478
 5479        let language = buffer_snapshot
 5480            .language_at(buffer_position)
 5481            .map(|language| language.name());
 5482
 5483        let completion_settings =
 5484            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5485
 5486        let show_completion_documentation = buffer_snapshot
 5487            .settings_at(buffer_position, cx)
 5488            .show_completion_documentation;
 5489
 5490        // The document can be large, so stay in reasonable bounds when searching for words,
 5491        // otherwise completion pop-up might be slow to appear.
 5492        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5493        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5494        let min_word_search = buffer_snapshot.clip_point(
 5495            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5496            Bias::Left,
 5497        );
 5498        let max_word_search = buffer_snapshot.clip_point(
 5499            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5500            Bias::Right,
 5501        );
 5502        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5503            ..buffer_snapshot.point_to_offset(max_word_search);
 5504
 5505        let skip_digits = query
 5506            .as_ref()
 5507            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5508
 5509        let (mut words, provider_responses) = match &provider {
 5510            Some(provider) => {
 5511                let provider_responses = provider.completions(
 5512                    position.excerpt_id,
 5513                    &buffer,
 5514                    buffer_position,
 5515                    completion_context,
 5516                    window,
 5517                    cx,
 5518                );
 5519
 5520                let words = match completion_settings.words {
 5521                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5522                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5523                        .background_spawn(async move {
 5524                            buffer_snapshot.words_in_range(WordsQuery {
 5525                                fuzzy_contents: None,
 5526                                range: word_search_range,
 5527                                skip_digits,
 5528                            })
 5529                        }),
 5530                };
 5531
 5532                (words, provider_responses)
 5533            }
 5534            None => (
 5535                cx.background_spawn(async move {
 5536                    buffer_snapshot.words_in_range(WordsQuery {
 5537                        fuzzy_contents: None,
 5538                        range: word_search_range,
 5539                        skip_digits,
 5540                    })
 5541                }),
 5542                Task::ready(Ok(Vec::new())),
 5543            ),
 5544        };
 5545
 5546        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5547
 5548        let id = post_inc(&mut self.next_completion_id);
 5549        let task = cx.spawn_in(window, async move |editor, cx| {
 5550            let Ok(()) = editor.update(cx, |this, _| {
 5551                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5552            }) else {
 5553                return;
 5554            };
 5555
 5556            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5557            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5558            let mut completions = Vec::new();
 5559            let mut is_incomplete = false;
 5560            if let Some(provider_responses) = provider_responses.await.log_err() {
 5561                if !provider_responses.is_empty() {
 5562                    for response in provider_responses {
 5563                        completions.extend(response.completions);
 5564                        is_incomplete = is_incomplete || response.is_incomplete;
 5565                    }
 5566                    if completion_settings.words == WordsCompletionMode::Fallback {
 5567                        words = Task::ready(BTreeMap::default());
 5568                    }
 5569                }
 5570            }
 5571
 5572            let mut words = words.await;
 5573            if let Some(word_to_exclude) = &word_to_exclude {
 5574                words.remove(word_to_exclude);
 5575            }
 5576            for lsp_completion in &completions {
 5577                words.remove(&lsp_completion.new_text);
 5578            }
 5579            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5580                replace_range: word_replace_range.clone(),
 5581                new_text: word.clone(),
 5582                label: CodeLabel::plain(word, None),
 5583                icon_path: None,
 5584                documentation: None,
 5585                source: CompletionSource::BufferWord {
 5586                    word_range,
 5587                    resolved: false,
 5588                },
 5589                insert_text_mode: Some(InsertTextMode::AS_IS),
 5590                confirm: None,
 5591            }));
 5592
 5593            let menu = if completions.is_empty() {
 5594                None
 5595            } else {
 5596                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5597                    let languages = editor
 5598                        .workspace
 5599                        .as_ref()
 5600                        .and_then(|(workspace, _)| workspace.upgrade())
 5601                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5602                    let menu = CompletionsMenu::new(
 5603                        id,
 5604                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5605                        sort_completions,
 5606                        show_completion_documentation,
 5607                        position,
 5608                        query.clone(),
 5609                        is_incomplete,
 5610                        buffer.clone(),
 5611                        completions.into(),
 5612                        snippet_sort_order,
 5613                        languages,
 5614                        language,
 5615                        cx,
 5616                    );
 5617
 5618                    let query = if filter_completions { query } else { None };
 5619                    let matches_task = if let Some(query) = query {
 5620                        menu.do_async_filtering(query, cx)
 5621                    } else {
 5622                        Task::ready(menu.unfiltered_matches())
 5623                    };
 5624                    (menu, matches_task)
 5625                }) else {
 5626                    return;
 5627                };
 5628
 5629                let matches = matches_task.await;
 5630
 5631                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5632                    // Newer menu already set, so exit.
 5633                    match editor.context_menu.borrow().as_ref() {
 5634                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5635                            if prev_menu.id > id {
 5636                                return;
 5637                            }
 5638                        }
 5639                        _ => {}
 5640                    };
 5641
 5642                    // Only valid to take prev_menu because it the new menu is immediately set
 5643                    // below, or the menu is hidden.
 5644                    match editor.context_menu.borrow_mut().take() {
 5645                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5646                            let position_matches =
 5647                                if prev_menu.initial_position == menu.initial_position {
 5648                                    true
 5649                                } else {
 5650                                    let snapshot = editor.buffer.read(cx).read(cx);
 5651                                    prev_menu.initial_position.to_offset(&snapshot)
 5652                                        == menu.initial_position.to_offset(&snapshot)
 5653                                };
 5654                            if position_matches {
 5655                                // Preserve markdown cache before `set_filter_results` because it will
 5656                                // try to populate the documentation cache.
 5657                                menu.preserve_markdown_cache(prev_menu);
 5658                            }
 5659                        }
 5660                        _ => {}
 5661                    };
 5662
 5663                    menu.set_filter_results(matches, provider, window, cx);
 5664                }) else {
 5665                    return;
 5666                };
 5667
 5668                menu.visible().then_some(menu)
 5669            };
 5670
 5671            editor
 5672                .update_in(cx, |editor, window, cx| {
 5673                    if editor.focus_handle.is_focused(window) {
 5674                        if let Some(menu) = menu {
 5675                            *editor.context_menu.borrow_mut() =
 5676                                Some(CodeContextMenu::Completions(menu));
 5677
 5678                            crate::hover_popover::hide_hover(editor, cx);
 5679                            if editor.show_edit_predictions_in_menu() {
 5680                                editor.update_visible_edit_prediction(window, cx);
 5681                            } else {
 5682                                editor.discard_edit_prediction(false, cx);
 5683                            }
 5684
 5685                            cx.notify();
 5686                            return;
 5687                        }
 5688                    }
 5689
 5690                    if editor.completion_tasks.len() <= 1 {
 5691                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5692                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5693                        // If it was already hidden and we don't show edit predictions in the menu,
 5694                        // we should also show the edit prediction when available.
 5695                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5696                            editor.update_visible_edit_prediction(window, cx);
 5697                        }
 5698                    }
 5699                })
 5700                .ok();
 5701        });
 5702
 5703        self.completion_tasks.push((id, task));
 5704    }
 5705
 5706    #[cfg(feature = "test-support")]
 5707    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5708        let menu = self.context_menu.borrow();
 5709        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5710            let completions = menu.completions.borrow();
 5711            Some(completions.to_vec())
 5712        } else {
 5713            None
 5714        }
 5715    }
 5716
 5717    pub fn with_completions_menu_matching_id<R>(
 5718        &self,
 5719        id: CompletionId,
 5720        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5721    ) -> R {
 5722        let mut context_menu = self.context_menu.borrow_mut();
 5723        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5724            return f(None);
 5725        };
 5726        if completions_menu.id != id {
 5727            return f(None);
 5728        }
 5729        f(Some(completions_menu))
 5730    }
 5731
 5732    pub fn confirm_completion(
 5733        &mut self,
 5734        action: &ConfirmCompletion,
 5735        window: &mut Window,
 5736        cx: &mut Context<Self>,
 5737    ) -> Option<Task<Result<()>>> {
 5738        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5739        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5740    }
 5741
 5742    pub fn confirm_completion_insert(
 5743        &mut self,
 5744        _: &ConfirmCompletionInsert,
 5745        window: &mut Window,
 5746        cx: &mut Context<Self>,
 5747    ) -> Option<Task<Result<()>>> {
 5748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5749        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5750    }
 5751
 5752    pub fn confirm_completion_replace(
 5753        &mut self,
 5754        _: &ConfirmCompletionReplace,
 5755        window: &mut Window,
 5756        cx: &mut Context<Self>,
 5757    ) -> Option<Task<Result<()>>> {
 5758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5759        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5760    }
 5761
 5762    pub fn compose_completion(
 5763        &mut self,
 5764        action: &ComposeCompletion,
 5765        window: &mut Window,
 5766        cx: &mut Context<Self>,
 5767    ) -> Option<Task<Result<()>>> {
 5768        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5769        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5770    }
 5771
 5772    fn do_completion(
 5773        &mut self,
 5774        item_ix: Option<usize>,
 5775        intent: CompletionIntent,
 5776        window: &mut Window,
 5777        cx: &mut Context<Editor>,
 5778    ) -> Option<Task<Result<()>>> {
 5779        use language::ToOffset as _;
 5780
 5781        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5782        else {
 5783            return None;
 5784        };
 5785
 5786        let candidate_id = {
 5787            let entries = completions_menu.entries.borrow();
 5788            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5789            if self.show_edit_predictions_in_menu() {
 5790                self.discard_edit_prediction(true, cx);
 5791            }
 5792            mat.candidate_id
 5793        };
 5794
 5795        let completion = completions_menu
 5796            .completions
 5797            .borrow()
 5798            .get(candidate_id)?
 5799            .clone();
 5800        cx.stop_propagation();
 5801
 5802        let buffer_handle = completions_menu.buffer.clone();
 5803
 5804        let CompletionEdit {
 5805            new_text,
 5806            snippet,
 5807            replace_range,
 5808        } = process_completion_for_edit(
 5809            &completion,
 5810            intent,
 5811            &buffer_handle,
 5812            &completions_menu.initial_position.text_anchor,
 5813            cx,
 5814        );
 5815
 5816        let buffer = buffer_handle.read(cx);
 5817        let snapshot = self.buffer.read(cx).snapshot(cx);
 5818        let newest_anchor = self.selections.newest_anchor();
 5819        let replace_range_multibuffer = {
 5820            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5821            let multibuffer_anchor = snapshot
 5822                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5823                .unwrap()
 5824                ..snapshot
 5825                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5826                    .unwrap();
 5827            multibuffer_anchor.start.to_offset(&snapshot)
 5828                ..multibuffer_anchor.end.to_offset(&snapshot)
 5829        };
 5830        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5831            return None;
 5832        }
 5833
 5834        let old_text = buffer
 5835            .text_for_range(replace_range.clone())
 5836            .collect::<String>();
 5837        let lookbehind = newest_anchor
 5838            .start
 5839            .text_anchor
 5840            .to_offset(buffer)
 5841            .saturating_sub(replace_range.start);
 5842        let lookahead = replace_range
 5843            .end
 5844            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5845        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5846        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5847
 5848        let selections = self.selections.all::<usize>(cx);
 5849        let mut ranges = Vec::new();
 5850        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5851
 5852        for selection in &selections {
 5853            let range = if selection.id == newest_anchor.id {
 5854                replace_range_multibuffer.clone()
 5855            } else {
 5856                let mut range = selection.range();
 5857
 5858                // if prefix is present, don't duplicate it
 5859                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5860                    range.start = range.start.saturating_sub(lookbehind);
 5861
 5862                    // if suffix is also present, mimic the newest cursor and replace it
 5863                    if selection.id != newest_anchor.id
 5864                        && snapshot.contains_str_at(range.end, suffix)
 5865                    {
 5866                        range.end += lookahead;
 5867                    }
 5868                }
 5869                range
 5870            };
 5871
 5872            ranges.push(range.clone());
 5873
 5874            if !self.linked_edit_ranges.is_empty() {
 5875                let start_anchor = snapshot.anchor_before(range.start);
 5876                let end_anchor = snapshot.anchor_after(range.end);
 5877                if let Some(ranges) = self
 5878                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5879                {
 5880                    for (buffer, edits) in ranges {
 5881                        linked_edits
 5882                            .entry(buffer.clone())
 5883                            .or_default()
 5884                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5885                    }
 5886                }
 5887            }
 5888        }
 5889
 5890        let common_prefix_len = old_text
 5891            .chars()
 5892            .zip(new_text.chars())
 5893            .take_while(|(a, b)| a == b)
 5894            .map(|(a, _)| a.len_utf8())
 5895            .sum::<usize>();
 5896
 5897        cx.emit(EditorEvent::InputHandled {
 5898            utf16_range_to_replace: None,
 5899            text: new_text[common_prefix_len..].into(),
 5900        });
 5901
 5902        self.transact(window, cx, |editor, window, cx| {
 5903            if let Some(mut snippet) = snippet {
 5904                snippet.text = new_text.to_string();
 5905                editor
 5906                    .insert_snippet(&ranges, snippet, window, cx)
 5907                    .log_err();
 5908            } else {
 5909                editor.buffer.update(cx, |multi_buffer, cx| {
 5910                    let auto_indent = match completion.insert_text_mode {
 5911                        Some(InsertTextMode::AS_IS) => None,
 5912                        _ => editor.autoindent_mode.clone(),
 5913                    };
 5914                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5915                    multi_buffer.edit(edits, auto_indent, cx);
 5916                });
 5917            }
 5918            for (buffer, edits) in linked_edits {
 5919                buffer.update(cx, |buffer, cx| {
 5920                    let snapshot = buffer.snapshot();
 5921                    let edits = edits
 5922                        .into_iter()
 5923                        .map(|(range, text)| {
 5924                            use text::ToPoint as TP;
 5925                            let end_point = TP::to_point(&range.end, &snapshot);
 5926                            let start_point = TP::to_point(&range.start, &snapshot);
 5927                            (start_point..end_point, text)
 5928                        })
 5929                        .sorted_by_key(|(range, _)| range.start);
 5930                    buffer.edit(edits, None, cx);
 5931                })
 5932            }
 5933
 5934            editor.refresh_edit_prediction(true, false, window, cx);
 5935        });
 5936        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5937
 5938        let show_new_completions_on_confirm = completion
 5939            .confirm
 5940            .as_ref()
 5941            .map_or(false, |confirm| confirm(intent, window, cx));
 5942        if show_new_completions_on_confirm {
 5943            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5944        }
 5945
 5946        let provider = self.completion_provider.as_ref()?;
 5947        drop(completion);
 5948        let apply_edits = provider.apply_additional_edits_for_completion(
 5949            buffer_handle,
 5950            completions_menu.completions.clone(),
 5951            candidate_id,
 5952            true,
 5953            cx,
 5954        );
 5955
 5956        let editor_settings = EditorSettings::get_global(cx);
 5957        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5958            // After the code completion is finished, users often want to know what signatures are needed.
 5959            // so we should automatically call signature_help
 5960            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5961        }
 5962
 5963        Some(cx.foreground_executor().spawn(async move {
 5964            apply_edits.await?;
 5965            Ok(())
 5966        }))
 5967    }
 5968
 5969    pub fn toggle_code_actions(
 5970        &mut self,
 5971        action: &ToggleCodeActions,
 5972        window: &mut Window,
 5973        cx: &mut Context<Self>,
 5974    ) {
 5975        let quick_launch = action.quick_launch;
 5976        let mut context_menu = self.context_menu.borrow_mut();
 5977        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5978            if code_actions.deployed_from == action.deployed_from {
 5979                // Toggle if we're selecting the same one
 5980                *context_menu = None;
 5981                cx.notify();
 5982                return;
 5983            } else {
 5984                // Otherwise, clear it and start a new one
 5985                *context_menu = None;
 5986                cx.notify();
 5987            }
 5988        }
 5989        drop(context_menu);
 5990        let snapshot = self.snapshot(window, cx);
 5991        let deployed_from = action.deployed_from.clone();
 5992        let action = action.clone();
 5993        self.completion_tasks.clear();
 5994        self.discard_edit_prediction(false, cx);
 5995
 5996        let multibuffer_point = match &action.deployed_from {
 5997            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5998                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5999            }
 6000            _ => self.selections.newest::<Point>(cx).head(),
 6001        };
 6002        let Some((buffer, buffer_row)) = snapshot
 6003            .buffer_snapshot
 6004            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6005            .and_then(|(buffer_snapshot, range)| {
 6006                self.buffer()
 6007                    .read(cx)
 6008                    .buffer(buffer_snapshot.remote_id())
 6009                    .map(|buffer| (buffer, range.start.row))
 6010            })
 6011        else {
 6012            return;
 6013        };
 6014        let buffer_id = buffer.read(cx).remote_id();
 6015        let tasks = self
 6016            .tasks
 6017            .get(&(buffer_id, buffer_row))
 6018            .map(|t| Arc::new(t.to_owned()));
 6019
 6020        if !self.focus_handle.is_focused(window) {
 6021            return;
 6022        }
 6023        let project = self.project.clone();
 6024
 6025        let code_actions_task = match deployed_from {
 6026            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6027            _ => self.code_actions(buffer_row, window, cx),
 6028        };
 6029
 6030        let runnable_task = match deployed_from {
 6031            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6032            _ => {
 6033                let mut task_context_task = Task::ready(None);
 6034                if let Some(tasks) = &tasks {
 6035                    if let Some(project) = project {
 6036                        task_context_task =
 6037                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6038                    }
 6039                }
 6040
 6041                cx.spawn_in(window, {
 6042                    let buffer = buffer.clone();
 6043                    async move |editor, cx| {
 6044                        let task_context = task_context_task.await;
 6045
 6046                        let resolved_tasks =
 6047                            tasks
 6048                                .zip(task_context.clone())
 6049                                .map(|(tasks, task_context)| ResolvedTasks {
 6050                                    templates: tasks.resolve(&task_context).collect(),
 6051                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6052                                        multibuffer_point.row,
 6053                                        tasks.column,
 6054                                    )),
 6055                                });
 6056                        let debug_scenarios = editor
 6057                            .update(cx, |editor, cx| {
 6058                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6059                            })?
 6060                            .await;
 6061                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6062                    }
 6063                })
 6064            }
 6065        };
 6066
 6067        cx.spawn_in(window, async move |editor, cx| {
 6068            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6069            let code_actions = code_actions_task.await;
 6070            let spawn_straight_away = quick_launch
 6071                && resolved_tasks
 6072                    .as_ref()
 6073                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6074                && code_actions
 6075                    .as_ref()
 6076                    .map_or(true, |actions| actions.is_empty())
 6077                && debug_scenarios.is_empty();
 6078
 6079            editor.update_in(cx, |editor, window, cx| {
 6080                crate::hover_popover::hide_hover(editor, cx);
 6081                let actions = CodeActionContents::new(
 6082                    resolved_tasks,
 6083                    code_actions,
 6084                    debug_scenarios,
 6085                    task_context.unwrap_or_default(),
 6086                );
 6087
 6088                // Don't show the menu if there are no actions available
 6089                if actions.is_empty() {
 6090                    cx.notify();
 6091                    return Task::ready(Ok(()));
 6092                }
 6093
 6094                *editor.context_menu.borrow_mut() =
 6095                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6096                        buffer,
 6097                        actions,
 6098                        selected_item: Default::default(),
 6099                        scroll_handle: UniformListScrollHandle::default(),
 6100                        deployed_from,
 6101                    }));
 6102                cx.notify();
 6103                if spawn_straight_away {
 6104                    if let Some(task) = editor.confirm_code_action(
 6105                        &ConfirmCodeAction { item_ix: Some(0) },
 6106                        window,
 6107                        cx,
 6108                    ) {
 6109                        return task;
 6110                    }
 6111                }
 6112
 6113                Task::ready(Ok(()))
 6114            })
 6115        })
 6116        .detach_and_log_err(cx);
 6117    }
 6118
 6119    fn debug_scenarios(
 6120        &mut self,
 6121        resolved_tasks: &Option<ResolvedTasks>,
 6122        buffer: &Entity<Buffer>,
 6123        cx: &mut App,
 6124    ) -> Task<Vec<task::DebugScenario>> {
 6125        maybe!({
 6126            let project = self.project.as_ref()?;
 6127            let dap_store = project.read(cx).dap_store();
 6128            let mut scenarios = vec![];
 6129            let resolved_tasks = resolved_tasks.as_ref()?;
 6130            let buffer = buffer.read(cx);
 6131            let language = buffer.language()?;
 6132            let file = buffer.file();
 6133            let debug_adapter = language_settings(language.name().into(), file, cx)
 6134                .debuggers
 6135                .first()
 6136                .map(SharedString::from)
 6137                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6138
 6139            dap_store.update(cx, |dap_store, cx| {
 6140                for (_, task) in &resolved_tasks.templates {
 6141                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6142                        task.original_task().clone(),
 6143                        debug_adapter.clone().into(),
 6144                        task.display_label().to_owned().into(),
 6145                        cx,
 6146                    );
 6147                    scenarios.push(maybe_scenario);
 6148                }
 6149            });
 6150            Some(cx.background_spawn(async move {
 6151                let scenarios = futures::future::join_all(scenarios)
 6152                    .await
 6153                    .into_iter()
 6154                    .flatten()
 6155                    .collect::<Vec<_>>();
 6156                scenarios
 6157            }))
 6158        })
 6159        .unwrap_or_else(|| Task::ready(vec![]))
 6160    }
 6161
 6162    fn code_actions(
 6163        &mut self,
 6164        buffer_row: u32,
 6165        window: &mut Window,
 6166        cx: &mut Context<Self>,
 6167    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6168        let mut task = self.code_actions_task.take();
 6169        cx.spawn_in(window, async move |editor, cx| {
 6170            while let Some(prev_task) = task {
 6171                prev_task.await.log_err();
 6172                task = editor
 6173                    .update(cx, |this, _| this.code_actions_task.take())
 6174                    .ok()?;
 6175            }
 6176
 6177            editor
 6178                .update(cx, |editor, cx| {
 6179                    editor
 6180                        .available_code_actions
 6181                        .clone()
 6182                        .and_then(|(location, code_actions)| {
 6183                            let snapshot = location.buffer.read(cx).snapshot();
 6184                            let point_range = location.range.to_point(&snapshot);
 6185                            let point_range = point_range.start.row..=point_range.end.row;
 6186                            if point_range.contains(&buffer_row) {
 6187                                Some(code_actions)
 6188                            } else {
 6189                                None
 6190                            }
 6191                        })
 6192                })
 6193                .ok()
 6194                .flatten()
 6195        })
 6196    }
 6197
 6198    pub fn confirm_code_action(
 6199        &mut self,
 6200        action: &ConfirmCodeAction,
 6201        window: &mut Window,
 6202        cx: &mut Context<Self>,
 6203    ) -> Option<Task<Result<()>>> {
 6204        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6205
 6206        let actions_menu =
 6207            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6208                menu
 6209            } else {
 6210                return None;
 6211            };
 6212
 6213        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6214        let action = actions_menu.actions.get(action_ix)?;
 6215        let title = action.label();
 6216        let buffer = actions_menu.buffer;
 6217        let workspace = self.workspace()?;
 6218
 6219        match action {
 6220            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6221                workspace.update(cx, |workspace, cx| {
 6222                    workspace.schedule_resolved_task(
 6223                        task_source_kind,
 6224                        resolved_task,
 6225                        false,
 6226                        window,
 6227                        cx,
 6228                    );
 6229
 6230                    Some(Task::ready(Ok(())))
 6231                })
 6232            }
 6233            CodeActionsItem::CodeAction {
 6234                excerpt_id,
 6235                action,
 6236                provider,
 6237            } => {
 6238                let apply_code_action =
 6239                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6240                let workspace = workspace.downgrade();
 6241                Some(cx.spawn_in(window, async move |editor, cx| {
 6242                    let project_transaction = apply_code_action.await?;
 6243                    Self::open_project_transaction(
 6244                        &editor,
 6245                        workspace,
 6246                        project_transaction,
 6247                        title,
 6248                        cx,
 6249                    )
 6250                    .await
 6251                }))
 6252            }
 6253            CodeActionsItem::DebugScenario(scenario) => {
 6254                let context = actions_menu.actions.context.clone();
 6255
 6256                workspace.update(cx, |workspace, cx| {
 6257                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6258                    workspace.start_debug_session(
 6259                        scenario,
 6260                        context,
 6261                        Some(buffer),
 6262                        None,
 6263                        window,
 6264                        cx,
 6265                    );
 6266                });
 6267                Some(Task::ready(Ok(())))
 6268            }
 6269        }
 6270    }
 6271
 6272    pub async fn open_project_transaction(
 6273        this: &WeakEntity<Editor>,
 6274        workspace: WeakEntity<Workspace>,
 6275        transaction: ProjectTransaction,
 6276        title: String,
 6277        cx: &mut AsyncWindowContext,
 6278    ) -> Result<()> {
 6279        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6280        cx.update(|_, cx| {
 6281            entries.sort_unstable_by_key(|(buffer, _)| {
 6282                buffer.read(cx).file().map(|f| f.path().clone())
 6283            });
 6284        })?;
 6285
 6286        // If the project transaction's edits are all contained within this editor, then
 6287        // avoid opening a new editor to display them.
 6288
 6289        if let Some((buffer, transaction)) = entries.first() {
 6290            if entries.len() == 1 {
 6291                let excerpt = this.update(cx, |editor, cx| {
 6292                    editor
 6293                        .buffer()
 6294                        .read(cx)
 6295                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6296                })?;
 6297                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6298                    if excerpted_buffer == *buffer {
 6299                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6300                            let excerpt_range = excerpt_range.to_offset(buffer);
 6301                            buffer
 6302                                .edited_ranges_for_transaction::<usize>(transaction)
 6303                                .all(|range| {
 6304                                    excerpt_range.start <= range.start
 6305                                        && excerpt_range.end >= range.end
 6306                                })
 6307                        })?;
 6308
 6309                        if all_edits_within_excerpt {
 6310                            return Ok(());
 6311                        }
 6312                    }
 6313                }
 6314            }
 6315        } else {
 6316            return Ok(());
 6317        }
 6318
 6319        let mut ranges_to_highlight = Vec::new();
 6320        let excerpt_buffer = cx.new(|cx| {
 6321            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6322            for (buffer_handle, transaction) in &entries {
 6323                let edited_ranges = buffer_handle
 6324                    .read(cx)
 6325                    .edited_ranges_for_transaction::<Point>(transaction)
 6326                    .collect::<Vec<_>>();
 6327                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6328                    PathKey::for_buffer(buffer_handle, cx),
 6329                    buffer_handle.clone(),
 6330                    edited_ranges,
 6331                    DEFAULT_MULTIBUFFER_CONTEXT,
 6332                    cx,
 6333                );
 6334
 6335                ranges_to_highlight.extend(ranges);
 6336            }
 6337            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6338            multibuffer
 6339        })?;
 6340
 6341        workspace.update_in(cx, |workspace, window, cx| {
 6342            let project = workspace.project().clone();
 6343            let editor =
 6344                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6345            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6346            editor.update(cx, |editor, cx| {
 6347                editor.highlight_background::<Self>(
 6348                    &ranges_to_highlight,
 6349                    |theme| theme.colors().editor_highlighted_line_background,
 6350                    cx,
 6351                );
 6352            });
 6353        })?;
 6354
 6355        Ok(())
 6356    }
 6357
 6358    pub fn clear_code_action_providers(&mut self) {
 6359        self.code_action_providers.clear();
 6360        self.available_code_actions.take();
 6361    }
 6362
 6363    pub fn add_code_action_provider(
 6364        &mut self,
 6365        provider: Rc<dyn CodeActionProvider>,
 6366        window: &mut Window,
 6367        cx: &mut Context<Self>,
 6368    ) {
 6369        if self
 6370            .code_action_providers
 6371            .iter()
 6372            .any(|existing_provider| existing_provider.id() == provider.id())
 6373        {
 6374            return;
 6375        }
 6376
 6377        self.code_action_providers.push(provider);
 6378        self.refresh_code_actions(window, cx);
 6379    }
 6380
 6381    pub fn remove_code_action_provider(
 6382        &mut self,
 6383        id: Arc<str>,
 6384        window: &mut Window,
 6385        cx: &mut Context<Self>,
 6386    ) {
 6387        self.code_action_providers
 6388            .retain(|provider| provider.id() != id);
 6389        self.refresh_code_actions(window, cx);
 6390    }
 6391
 6392    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6393        !self.code_action_providers.is_empty()
 6394            && EditorSettings::get_global(cx).toolbar.code_actions
 6395    }
 6396
 6397    pub fn has_available_code_actions(&self) -> bool {
 6398        self.available_code_actions
 6399            .as_ref()
 6400            .is_some_and(|(_, actions)| !actions.is_empty())
 6401    }
 6402
 6403    fn render_inline_code_actions(
 6404        &self,
 6405        icon_size: ui::IconSize,
 6406        display_row: DisplayRow,
 6407        is_active: bool,
 6408        cx: &mut Context<Self>,
 6409    ) -> AnyElement {
 6410        let show_tooltip = !self.context_menu_visible();
 6411        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6412            .icon_size(icon_size)
 6413            .shape(ui::IconButtonShape::Square)
 6414            .icon_color(ui::Color::Hidden)
 6415            .toggle_state(is_active)
 6416            .when(show_tooltip, |this| {
 6417                this.tooltip({
 6418                    let focus_handle = self.focus_handle.clone();
 6419                    move |window, cx| {
 6420                        Tooltip::for_action_in(
 6421                            "Toggle Code Actions",
 6422                            &ToggleCodeActions {
 6423                                deployed_from: None,
 6424                                quick_launch: false,
 6425                            },
 6426                            &focus_handle,
 6427                            window,
 6428                            cx,
 6429                        )
 6430                    }
 6431                })
 6432            })
 6433            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6434                window.focus(&editor.focus_handle(cx));
 6435                editor.toggle_code_actions(
 6436                    &crate::actions::ToggleCodeActions {
 6437                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6438                            display_row,
 6439                        )),
 6440                        quick_launch: false,
 6441                    },
 6442                    window,
 6443                    cx,
 6444                );
 6445            }))
 6446            .into_any_element()
 6447    }
 6448
 6449    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6450        &self.context_menu
 6451    }
 6452
 6453    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6454        let newest_selection = self.selections.newest_anchor().clone();
 6455        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6456        let buffer = self.buffer.read(cx);
 6457        if newest_selection.head().diff_base_anchor.is_some() {
 6458            return None;
 6459        }
 6460        let (start_buffer, start) =
 6461            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6462        let (end_buffer, end) =
 6463            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6464        if start_buffer != end_buffer {
 6465            return None;
 6466        }
 6467
 6468        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6469            cx.background_executor()
 6470                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6471                .await;
 6472
 6473            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6474                let providers = this.code_action_providers.clone();
 6475                let tasks = this
 6476                    .code_action_providers
 6477                    .iter()
 6478                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6479                    .collect::<Vec<_>>();
 6480                (providers, tasks)
 6481            })?;
 6482
 6483            let mut actions = Vec::new();
 6484            for (provider, provider_actions) in
 6485                providers.into_iter().zip(future::join_all(tasks).await)
 6486            {
 6487                if let Some(provider_actions) = provider_actions.log_err() {
 6488                    actions.extend(provider_actions.into_iter().map(|action| {
 6489                        AvailableCodeAction {
 6490                            excerpt_id: newest_selection.start.excerpt_id,
 6491                            action,
 6492                            provider: provider.clone(),
 6493                        }
 6494                    }));
 6495                }
 6496            }
 6497
 6498            this.update(cx, |this, cx| {
 6499                this.available_code_actions = if actions.is_empty() {
 6500                    None
 6501                } else {
 6502                    Some((
 6503                        Location {
 6504                            buffer: start_buffer,
 6505                            range: start..end,
 6506                        },
 6507                        actions.into(),
 6508                    ))
 6509                };
 6510                cx.notify();
 6511            })
 6512        }));
 6513        None
 6514    }
 6515
 6516    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6517        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6518            self.show_git_blame_inline = false;
 6519
 6520            self.show_git_blame_inline_delay_task =
 6521                Some(cx.spawn_in(window, async move |this, cx| {
 6522                    cx.background_executor().timer(delay).await;
 6523
 6524                    this.update(cx, |this, cx| {
 6525                        this.show_git_blame_inline = true;
 6526                        cx.notify();
 6527                    })
 6528                    .log_err();
 6529                }));
 6530        }
 6531    }
 6532
 6533    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6534        let snapshot = self.snapshot(window, cx);
 6535        let cursor = self.selections.newest::<Point>(cx).head();
 6536        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6537        else {
 6538            return;
 6539        };
 6540
 6541        let Some(blame) = self.blame.as_ref() else {
 6542            return;
 6543        };
 6544
 6545        let row_info = RowInfo {
 6546            buffer_id: Some(buffer.remote_id()),
 6547            buffer_row: Some(point.row),
 6548            ..Default::default()
 6549        };
 6550        let Some(blame_entry) = blame
 6551            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6552            .flatten()
 6553        else {
 6554            return;
 6555        };
 6556
 6557        let anchor = self.selections.newest_anchor().head();
 6558        let position = self.to_pixel_point(anchor, &snapshot, window);
 6559        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6560            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6561        };
 6562    }
 6563
 6564    fn show_blame_popover(
 6565        &mut self,
 6566        blame_entry: &BlameEntry,
 6567        position: gpui::Point<Pixels>,
 6568        ignore_timeout: bool,
 6569        cx: &mut Context<Self>,
 6570    ) {
 6571        if let Some(state) = &mut self.inline_blame_popover {
 6572            state.hide_task.take();
 6573        } else {
 6574            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6575            let blame_entry = blame_entry.clone();
 6576            let show_task = cx.spawn(async move |editor, cx| {
 6577                if !ignore_timeout {
 6578                    cx.background_executor()
 6579                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6580                        .await;
 6581                }
 6582                editor
 6583                    .update(cx, |editor, cx| {
 6584                        editor.inline_blame_popover_show_task.take();
 6585                        let Some(blame) = editor.blame.as_ref() else {
 6586                            return;
 6587                        };
 6588                        let blame = blame.read(cx);
 6589                        let details = blame.details_for_entry(&blame_entry);
 6590                        let markdown = cx.new(|cx| {
 6591                            Markdown::new(
 6592                                details
 6593                                    .as_ref()
 6594                                    .map(|message| message.message.clone())
 6595                                    .unwrap_or_default(),
 6596                                None,
 6597                                None,
 6598                                cx,
 6599                            )
 6600                        });
 6601                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6602                            position,
 6603                            hide_task: None,
 6604                            popover_bounds: None,
 6605                            popover_state: InlineBlamePopoverState {
 6606                                scroll_handle: ScrollHandle::new(),
 6607                                commit_message: details,
 6608                                markdown,
 6609                            },
 6610                            keyboard_grace: ignore_timeout,
 6611                        });
 6612                        cx.notify();
 6613                    })
 6614                    .ok();
 6615            });
 6616            self.inline_blame_popover_show_task = Some(show_task);
 6617        }
 6618    }
 6619
 6620    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6621        self.inline_blame_popover_show_task.take();
 6622        if let Some(state) = &mut self.inline_blame_popover {
 6623            let hide_task = cx.spawn(async move |editor, cx| {
 6624                cx.background_executor()
 6625                    .timer(std::time::Duration::from_millis(100))
 6626                    .await;
 6627                editor
 6628                    .update(cx, |editor, cx| {
 6629                        editor.inline_blame_popover.take();
 6630                        cx.notify();
 6631                    })
 6632                    .ok();
 6633            });
 6634            state.hide_task = Some(hide_task);
 6635        }
 6636    }
 6637
 6638    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6639        if self.pending_rename.is_some() {
 6640            return None;
 6641        }
 6642
 6643        let provider = self.semantics_provider.clone()?;
 6644        let buffer = self.buffer.read(cx);
 6645        let newest_selection = self.selections.newest_anchor().clone();
 6646        let cursor_position = newest_selection.head();
 6647        let (cursor_buffer, cursor_buffer_position) =
 6648            buffer.text_anchor_for_position(cursor_position, cx)?;
 6649        let (tail_buffer, tail_buffer_position) =
 6650            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6651        if cursor_buffer != tail_buffer {
 6652            return None;
 6653        }
 6654
 6655        let snapshot = cursor_buffer.read(cx).snapshot();
 6656        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6657        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6658        if start_word_range != end_word_range {
 6659            self.document_highlights_task.take();
 6660            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6661            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6662            return None;
 6663        }
 6664
 6665        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6666        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6667            cx.background_executor()
 6668                .timer(Duration::from_millis(debounce))
 6669                .await;
 6670
 6671            let highlights = if let Some(highlights) = cx
 6672                .update(|cx| {
 6673                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6674                })
 6675                .ok()
 6676                .flatten()
 6677            {
 6678                highlights.await.log_err()
 6679            } else {
 6680                None
 6681            };
 6682
 6683            if let Some(highlights) = highlights {
 6684                this.update(cx, |this, cx| {
 6685                    if this.pending_rename.is_some() {
 6686                        return;
 6687                    }
 6688
 6689                    let buffer_id = cursor_position.buffer_id;
 6690                    let buffer = this.buffer.read(cx);
 6691                    if !buffer
 6692                        .text_anchor_for_position(cursor_position, cx)
 6693                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6694                    {
 6695                        return;
 6696                    }
 6697
 6698                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6699                    let mut write_ranges = Vec::new();
 6700                    let mut read_ranges = Vec::new();
 6701                    for highlight in highlights {
 6702                        for (excerpt_id, excerpt_range) in
 6703                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6704                        {
 6705                            let start = highlight
 6706                                .range
 6707                                .start
 6708                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6709                            let end = highlight
 6710                                .range
 6711                                .end
 6712                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6713                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6714                                continue;
 6715                            }
 6716
 6717                            let range = Anchor {
 6718                                buffer_id,
 6719                                excerpt_id,
 6720                                text_anchor: start,
 6721                                diff_base_anchor: None,
 6722                            }..Anchor {
 6723                                buffer_id,
 6724                                excerpt_id,
 6725                                text_anchor: end,
 6726                                diff_base_anchor: None,
 6727                            };
 6728                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6729                                write_ranges.push(range);
 6730                            } else {
 6731                                read_ranges.push(range);
 6732                            }
 6733                        }
 6734                    }
 6735
 6736                    this.highlight_background::<DocumentHighlightRead>(
 6737                        &read_ranges,
 6738                        |theme| theme.colors().editor_document_highlight_read_background,
 6739                        cx,
 6740                    );
 6741                    this.highlight_background::<DocumentHighlightWrite>(
 6742                        &write_ranges,
 6743                        |theme| theme.colors().editor_document_highlight_write_background,
 6744                        cx,
 6745                    );
 6746                    cx.notify();
 6747                })
 6748                .log_err();
 6749            }
 6750        }));
 6751        None
 6752    }
 6753
 6754    fn prepare_highlight_query_from_selection(
 6755        &mut self,
 6756        cx: &mut Context<Editor>,
 6757    ) -> Option<(String, Range<Anchor>)> {
 6758        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6759            return None;
 6760        }
 6761        if !EditorSettings::get_global(cx).selection_highlight {
 6762            return None;
 6763        }
 6764        if self.selections.count() != 1 || self.selections.line_mode {
 6765            return None;
 6766        }
 6767        let selection = self.selections.newest::<Point>(cx);
 6768        if selection.is_empty() || selection.start.row != selection.end.row {
 6769            return None;
 6770        }
 6771        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6772        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6773        let query = multi_buffer_snapshot
 6774            .text_for_range(selection_anchor_range.clone())
 6775            .collect::<String>();
 6776        if query.trim().is_empty() {
 6777            return None;
 6778        }
 6779        Some((query, selection_anchor_range))
 6780    }
 6781
 6782    fn update_selection_occurrence_highlights(
 6783        &mut self,
 6784        query_text: String,
 6785        query_range: Range<Anchor>,
 6786        multi_buffer_range_to_query: Range<Point>,
 6787        use_debounce: bool,
 6788        window: &mut Window,
 6789        cx: &mut Context<Editor>,
 6790    ) -> Task<()> {
 6791        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6792        cx.spawn_in(window, async move |editor, cx| {
 6793            if use_debounce {
 6794                cx.background_executor()
 6795                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6796                    .await;
 6797            }
 6798            let match_task = cx.background_spawn(async move {
 6799                let buffer_ranges = multi_buffer_snapshot
 6800                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6801                    .into_iter()
 6802                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6803                let mut match_ranges = Vec::new();
 6804                let Ok(regex) = project::search::SearchQuery::text(
 6805                    query_text.clone(),
 6806                    false,
 6807                    false,
 6808                    false,
 6809                    Default::default(),
 6810                    Default::default(),
 6811                    false,
 6812                    None,
 6813                ) else {
 6814                    return Vec::default();
 6815                };
 6816                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6817                    match_ranges.extend(
 6818                        regex
 6819                            .search(&buffer_snapshot, Some(search_range.clone()))
 6820                            .await
 6821                            .into_iter()
 6822                            .filter_map(|match_range| {
 6823                                let match_start = buffer_snapshot
 6824                                    .anchor_after(search_range.start + match_range.start);
 6825                                let match_end = buffer_snapshot
 6826                                    .anchor_before(search_range.start + match_range.end);
 6827                                let match_anchor_range = Anchor::range_in_buffer(
 6828                                    excerpt_id,
 6829                                    buffer_snapshot.remote_id(),
 6830                                    match_start..match_end,
 6831                                );
 6832                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6833                            }),
 6834                    );
 6835                }
 6836                match_ranges
 6837            });
 6838            let match_ranges = match_task.await;
 6839            editor
 6840                .update_in(cx, |editor, _, cx| {
 6841                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6842                    if !match_ranges.is_empty() {
 6843                        editor.highlight_background::<SelectedTextHighlight>(
 6844                            &match_ranges,
 6845                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6846                            cx,
 6847                        )
 6848                    }
 6849                })
 6850                .log_err();
 6851        })
 6852    }
 6853
 6854    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6855        struct NewlineFold;
 6856        let type_id = std::any::TypeId::of::<NewlineFold>();
 6857        if !self.mode.is_single_line() {
 6858            return;
 6859        }
 6860        let snapshot = self.snapshot(window, cx);
 6861        if snapshot.buffer_snapshot.max_point().row == 0 {
 6862            return;
 6863        }
 6864        let task = cx.background_spawn(async move {
 6865            let new_newlines = snapshot
 6866                .buffer_chars_at(0)
 6867                .filter_map(|(c, i)| {
 6868                    if c == '\n' {
 6869                        Some(
 6870                            snapshot.buffer_snapshot.anchor_after(i)
 6871                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6872                        )
 6873                    } else {
 6874                        None
 6875                    }
 6876                })
 6877                .collect::<Vec<_>>();
 6878            let existing_newlines = snapshot
 6879                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6880                .filter_map(|fold| {
 6881                    if fold.placeholder.type_tag == Some(type_id) {
 6882                        Some(fold.range.start..fold.range.end)
 6883                    } else {
 6884                        None
 6885                    }
 6886                })
 6887                .collect::<Vec<_>>();
 6888
 6889            (new_newlines, existing_newlines)
 6890        });
 6891        self.folding_newlines = cx.spawn(async move |this, cx| {
 6892            let (new_newlines, existing_newlines) = task.await;
 6893            if new_newlines == existing_newlines {
 6894                return;
 6895            }
 6896            let placeholder = FoldPlaceholder {
 6897                render: Arc::new(move |_, _, cx| {
 6898                    div()
 6899                        .bg(cx.theme().status().hint_background)
 6900                        .border_b_1()
 6901                        .size_full()
 6902                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6903                        .border_color(cx.theme().status().hint)
 6904                        .child("\\n")
 6905                        .into_any()
 6906                }),
 6907                constrain_width: false,
 6908                merge_adjacent: false,
 6909                type_tag: Some(type_id),
 6910            };
 6911            let creases = new_newlines
 6912                .into_iter()
 6913                .map(|range| Crease::simple(range, placeholder.clone()))
 6914                .collect();
 6915            this.update(cx, |this, cx| {
 6916                this.display_map.update(cx, |display_map, cx| {
 6917                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6918                    display_map.fold(creases, cx);
 6919                });
 6920            })
 6921            .ok();
 6922        });
 6923    }
 6924
 6925    fn refresh_selected_text_highlights(
 6926        &mut self,
 6927        on_buffer_edit: bool,
 6928        window: &mut Window,
 6929        cx: &mut Context<Editor>,
 6930    ) {
 6931        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6932        else {
 6933            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6934            self.quick_selection_highlight_task.take();
 6935            self.debounced_selection_highlight_task.take();
 6936            return;
 6937        };
 6938        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6939        if on_buffer_edit
 6940            || self
 6941                .quick_selection_highlight_task
 6942                .as_ref()
 6943                .map_or(true, |(prev_anchor_range, _)| {
 6944                    prev_anchor_range != &query_range
 6945                })
 6946        {
 6947            let multi_buffer_visible_start = self
 6948                .scroll_manager
 6949                .anchor()
 6950                .anchor
 6951                .to_point(&multi_buffer_snapshot);
 6952            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6953                multi_buffer_visible_start
 6954                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6955                Bias::Left,
 6956            );
 6957            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6958            self.quick_selection_highlight_task = Some((
 6959                query_range.clone(),
 6960                self.update_selection_occurrence_highlights(
 6961                    query_text.clone(),
 6962                    query_range.clone(),
 6963                    multi_buffer_visible_range,
 6964                    false,
 6965                    window,
 6966                    cx,
 6967                ),
 6968            ));
 6969        }
 6970        if on_buffer_edit
 6971            || self
 6972                .debounced_selection_highlight_task
 6973                .as_ref()
 6974                .map_or(true, |(prev_anchor_range, _)| {
 6975                    prev_anchor_range != &query_range
 6976                })
 6977        {
 6978            let multi_buffer_start = multi_buffer_snapshot
 6979                .anchor_before(0)
 6980                .to_point(&multi_buffer_snapshot);
 6981            let multi_buffer_end = multi_buffer_snapshot
 6982                .anchor_after(multi_buffer_snapshot.len())
 6983                .to_point(&multi_buffer_snapshot);
 6984            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6985            self.debounced_selection_highlight_task = Some((
 6986                query_range.clone(),
 6987                self.update_selection_occurrence_highlights(
 6988                    query_text,
 6989                    query_range,
 6990                    multi_buffer_full_range,
 6991                    true,
 6992                    window,
 6993                    cx,
 6994                ),
 6995            ));
 6996        }
 6997    }
 6998
 6999    pub fn refresh_edit_prediction(
 7000        &mut self,
 7001        debounce: bool,
 7002        user_requested: bool,
 7003        window: &mut Window,
 7004        cx: &mut Context<Self>,
 7005    ) -> Option<()> {
 7006        if DisableAiSettings::get_global(cx).disable_ai {
 7007            return None;
 7008        }
 7009
 7010        let provider = self.edit_prediction_provider()?;
 7011        let cursor = self.selections.newest_anchor().head();
 7012        let (buffer, cursor_buffer_position) =
 7013            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7014
 7015        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7016            self.discard_edit_prediction(false, cx);
 7017            return None;
 7018        }
 7019
 7020        if !user_requested
 7021            && (!self.should_show_edit_predictions()
 7022                || !self.is_focused(window)
 7023                || buffer.read(cx).is_empty())
 7024        {
 7025            self.discard_edit_prediction(false, cx);
 7026            return None;
 7027        }
 7028
 7029        self.update_visible_edit_prediction(window, cx);
 7030        provider.refresh(
 7031            self.project.clone(),
 7032            buffer,
 7033            cursor_buffer_position,
 7034            debounce,
 7035            cx,
 7036        );
 7037        Some(())
 7038    }
 7039
 7040    fn show_edit_predictions_in_menu(&self) -> bool {
 7041        match self.edit_prediction_settings {
 7042            EditPredictionSettings::Disabled => false,
 7043            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7044        }
 7045    }
 7046
 7047    pub fn edit_predictions_enabled(&self) -> bool {
 7048        match self.edit_prediction_settings {
 7049            EditPredictionSettings::Disabled => false,
 7050            EditPredictionSettings::Enabled { .. } => true,
 7051        }
 7052    }
 7053
 7054    fn edit_prediction_requires_modifier(&self) -> bool {
 7055        match self.edit_prediction_settings {
 7056            EditPredictionSettings::Disabled => false,
 7057            EditPredictionSettings::Enabled {
 7058                preview_requires_modifier,
 7059                ..
 7060            } => preview_requires_modifier,
 7061        }
 7062    }
 7063
 7064    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7065        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7066            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7067            self.discard_edit_prediction(false, cx);
 7068        } else {
 7069            let selection = self.selections.newest_anchor();
 7070            let cursor = selection.head();
 7071
 7072            if let Some((buffer, cursor_buffer_position)) =
 7073                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7074            {
 7075                self.edit_prediction_settings =
 7076                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7077            }
 7078        }
 7079    }
 7080
 7081    fn edit_prediction_settings_at_position(
 7082        &self,
 7083        buffer: &Entity<Buffer>,
 7084        buffer_position: language::Anchor,
 7085        cx: &App,
 7086    ) -> EditPredictionSettings {
 7087        if !self.mode.is_full()
 7088            || !self.show_edit_predictions_override.unwrap_or(true)
 7089            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7090        {
 7091            return EditPredictionSettings::Disabled;
 7092        }
 7093
 7094        let buffer = buffer.read(cx);
 7095
 7096        let file = buffer.file();
 7097
 7098        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7099            return EditPredictionSettings::Disabled;
 7100        };
 7101
 7102        let by_provider = matches!(
 7103            self.menu_edit_predictions_policy,
 7104            MenuEditPredictionsPolicy::ByProvider
 7105        );
 7106
 7107        let show_in_menu = by_provider
 7108            && self
 7109                .edit_prediction_provider
 7110                .as_ref()
 7111                .map_or(false, |provider| {
 7112                    provider.provider.show_completions_in_menu()
 7113                });
 7114
 7115        let preview_requires_modifier =
 7116            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7117
 7118        EditPredictionSettings::Enabled {
 7119            show_in_menu,
 7120            preview_requires_modifier,
 7121        }
 7122    }
 7123
 7124    fn should_show_edit_predictions(&self) -> bool {
 7125        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7126    }
 7127
 7128    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7129        matches!(
 7130            self.edit_prediction_preview,
 7131            EditPredictionPreview::Active { .. }
 7132        )
 7133    }
 7134
 7135    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7136        let cursor = self.selections.newest_anchor().head();
 7137        if let Some((buffer, cursor_position)) =
 7138            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7139        {
 7140            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7141        } else {
 7142            false
 7143        }
 7144    }
 7145
 7146    pub fn supports_minimap(&self, cx: &App) -> bool {
 7147        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7148    }
 7149
 7150    fn edit_predictions_enabled_in_buffer(
 7151        &self,
 7152        buffer: &Entity<Buffer>,
 7153        buffer_position: language::Anchor,
 7154        cx: &App,
 7155    ) -> bool {
 7156        maybe!({
 7157            if self.read_only(cx) {
 7158                return Some(false);
 7159            }
 7160            let provider = self.edit_prediction_provider()?;
 7161            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7162                return Some(false);
 7163            }
 7164            let buffer = buffer.read(cx);
 7165            let Some(file) = buffer.file() else {
 7166                return Some(true);
 7167            };
 7168            let settings = all_language_settings(Some(file), cx);
 7169            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7170        })
 7171        .unwrap_or(false)
 7172    }
 7173
 7174    fn cycle_edit_prediction(
 7175        &mut self,
 7176        direction: Direction,
 7177        window: &mut Window,
 7178        cx: &mut Context<Self>,
 7179    ) -> Option<()> {
 7180        let provider = self.edit_prediction_provider()?;
 7181        let cursor = self.selections.newest_anchor().head();
 7182        let (buffer, cursor_buffer_position) =
 7183            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7184        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7185            return None;
 7186        }
 7187
 7188        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7189        self.update_visible_edit_prediction(window, cx);
 7190
 7191        Some(())
 7192    }
 7193
 7194    pub fn show_edit_prediction(
 7195        &mut self,
 7196        _: &ShowEditPrediction,
 7197        window: &mut Window,
 7198        cx: &mut Context<Self>,
 7199    ) {
 7200        if !self.has_active_edit_prediction() {
 7201            self.refresh_edit_prediction(false, true, window, cx);
 7202            return;
 7203        }
 7204
 7205        self.update_visible_edit_prediction(window, cx);
 7206    }
 7207
 7208    pub fn display_cursor_names(
 7209        &mut self,
 7210        _: &DisplayCursorNames,
 7211        window: &mut Window,
 7212        cx: &mut Context<Self>,
 7213    ) {
 7214        self.show_cursor_names(window, cx);
 7215    }
 7216
 7217    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7218        self.show_cursor_names = true;
 7219        cx.notify();
 7220        cx.spawn_in(window, async move |this, cx| {
 7221            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7222            this.update(cx, |this, cx| {
 7223                this.show_cursor_names = false;
 7224                cx.notify()
 7225            })
 7226            .ok()
 7227        })
 7228        .detach();
 7229    }
 7230
 7231    pub fn next_edit_prediction(
 7232        &mut self,
 7233        _: &NextEditPrediction,
 7234        window: &mut Window,
 7235        cx: &mut Context<Self>,
 7236    ) {
 7237        if self.has_active_edit_prediction() {
 7238            self.cycle_edit_prediction(Direction::Next, window, cx);
 7239        } else {
 7240            let is_copilot_disabled = self
 7241                .refresh_edit_prediction(false, true, window, cx)
 7242                .is_none();
 7243            if is_copilot_disabled {
 7244                cx.propagate();
 7245            }
 7246        }
 7247    }
 7248
 7249    pub fn previous_edit_prediction(
 7250        &mut self,
 7251        _: &PreviousEditPrediction,
 7252        window: &mut Window,
 7253        cx: &mut Context<Self>,
 7254    ) {
 7255        if self.has_active_edit_prediction() {
 7256            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7257        } else {
 7258            let is_copilot_disabled = self
 7259                .refresh_edit_prediction(false, true, window, cx)
 7260                .is_none();
 7261            if is_copilot_disabled {
 7262                cx.propagate();
 7263            }
 7264        }
 7265    }
 7266
 7267    pub fn accept_edit_prediction(
 7268        &mut self,
 7269        _: &AcceptEditPrediction,
 7270        window: &mut Window,
 7271        cx: &mut Context<Self>,
 7272    ) {
 7273        if self.show_edit_predictions_in_menu() {
 7274            self.hide_context_menu(window, cx);
 7275        }
 7276
 7277        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7278            return;
 7279        };
 7280
 7281        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7282
 7283        match &active_edit_prediction.completion {
 7284            EditPrediction::Move { target, .. } => {
 7285                let target = *target;
 7286
 7287                if let Some(position_map) = &self.last_position_map {
 7288                    if position_map
 7289                        .visible_row_range
 7290                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7291                        || !self.edit_prediction_requires_modifier()
 7292                    {
 7293                        self.unfold_ranges(&[target..target], true, false, cx);
 7294                        // Note that this is also done in vim's handler of the Tab action.
 7295                        self.change_selections(
 7296                            SelectionEffects::scroll(Autoscroll::newest()),
 7297                            window,
 7298                            cx,
 7299                            |selections| {
 7300                                selections.select_anchor_ranges([target..target]);
 7301                            },
 7302                        );
 7303                        self.clear_row_highlights::<EditPredictionPreview>();
 7304
 7305                        self.edit_prediction_preview
 7306                            .set_previous_scroll_position(None);
 7307                    } else {
 7308                        self.edit_prediction_preview
 7309                            .set_previous_scroll_position(Some(
 7310                                position_map.snapshot.scroll_anchor,
 7311                            ));
 7312
 7313                        self.highlight_rows::<EditPredictionPreview>(
 7314                            target..target,
 7315                            cx.theme().colors().editor_highlighted_line_background,
 7316                            RowHighlightOptions {
 7317                                autoscroll: true,
 7318                                ..Default::default()
 7319                            },
 7320                            cx,
 7321                        );
 7322                        self.request_autoscroll(Autoscroll::fit(), cx);
 7323                    }
 7324                }
 7325            }
 7326            EditPrediction::Edit { edits, .. } => {
 7327                if let Some(provider) = self.edit_prediction_provider() {
 7328                    provider.accept(cx);
 7329                }
 7330
 7331                // Store the transaction ID and selections before applying the edit
 7332                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7333
 7334                let snapshot = self.buffer.read(cx).snapshot(cx);
 7335                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7336
 7337                self.buffer.update(cx, |buffer, cx| {
 7338                    buffer.edit(edits.iter().cloned(), None, cx)
 7339                });
 7340
 7341                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7342                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7343                });
 7344
 7345                let selections = self.selections.disjoint_anchors();
 7346                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7347                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7348                    if has_new_transaction {
 7349                        self.selection_history
 7350                            .insert_transaction(transaction_id_now, selections);
 7351                    }
 7352                }
 7353
 7354                self.update_visible_edit_prediction(window, cx);
 7355                if self.active_edit_prediction.is_none() {
 7356                    self.refresh_edit_prediction(true, true, window, cx);
 7357                }
 7358
 7359                cx.notify();
 7360            }
 7361        }
 7362
 7363        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7364    }
 7365
 7366    pub fn accept_partial_edit_prediction(
 7367        &mut self,
 7368        _: &AcceptPartialEditPrediction,
 7369        window: &mut Window,
 7370        cx: &mut Context<Self>,
 7371    ) {
 7372        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7373            return;
 7374        };
 7375        if self.selections.count() != 1 {
 7376            return;
 7377        }
 7378
 7379        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7380
 7381        match &active_edit_prediction.completion {
 7382            EditPrediction::Move { target, .. } => {
 7383                let target = *target;
 7384                self.change_selections(
 7385                    SelectionEffects::scroll(Autoscroll::newest()),
 7386                    window,
 7387                    cx,
 7388                    |selections| {
 7389                        selections.select_anchor_ranges([target..target]);
 7390                    },
 7391                );
 7392            }
 7393            EditPrediction::Edit { edits, .. } => {
 7394                // Find an insertion that starts at the cursor position.
 7395                let snapshot = self.buffer.read(cx).snapshot(cx);
 7396                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7397                let insertion = edits.iter().find_map(|(range, text)| {
 7398                    let range = range.to_offset(&snapshot);
 7399                    if range.is_empty() && range.start == cursor_offset {
 7400                        Some(text)
 7401                    } else {
 7402                        None
 7403                    }
 7404                });
 7405
 7406                if let Some(text) = insertion {
 7407                    let mut partial_completion = text
 7408                        .chars()
 7409                        .by_ref()
 7410                        .take_while(|c| c.is_alphabetic())
 7411                        .collect::<String>();
 7412                    if partial_completion.is_empty() {
 7413                        partial_completion = text
 7414                            .chars()
 7415                            .by_ref()
 7416                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7417                            .collect::<String>();
 7418                    }
 7419
 7420                    cx.emit(EditorEvent::InputHandled {
 7421                        utf16_range_to_replace: None,
 7422                        text: partial_completion.clone().into(),
 7423                    });
 7424
 7425                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7426
 7427                    self.refresh_edit_prediction(true, true, window, cx);
 7428                    cx.notify();
 7429                } else {
 7430                    self.accept_edit_prediction(&Default::default(), window, cx);
 7431                }
 7432            }
 7433        }
 7434    }
 7435
 7436    fn discard_edit_prediction(
 7437        &mut self,
 7438        should_report_edit_prediction_event: bool,
 7439        cx: &mut Context<Self>,
 7440    ) -> bool {
 7441        if should_report_edit_prediction_event {
 7442            let completion_id = self
 7443                .active_edit_prediction
 7444                .as_ref()
 7445                .and_then(|active_completion| active_completion.completion_id.clone());
 7446
 7447            self.report_edit_prediction_event(completion_id, false, cx);
 7448        }
 7449
 7450        if let Some(provider) = self.edit_prediction_provider() {
 7451            provider.discard(cx);
 7452        }
 7453
 7454        self.take_active_edit_prediction(cx)
 7455    }
 7456
 7457    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7458        let Some(provider) = self.edit_prediction_provider() else {
 7459            return;
 7460        };
 7461
 7462        let Some((_, buffer, _)) = self
 7463            .buffer
 7464            .read(cx)
 7465            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7466        else {
 7467            return;
 7468        };
 7469
 7470        let extension = buffer
 7471            .read(cx)
 7472            .file()
 7473            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7474
 7475        let event_type = match accepted {
 7476            true => "Edit Prediction Accepted",
 7477            false => "Edit Prediction Discarded",
 7478        };
 7479        telemetry::event!(
 7480            event_type,
 7481            provider = provider.name(),
 7482            prediction_id = id,
 7483            suggestion_accepted = accepted,
 7484            file_extension = extension,
 7485        );
 7486    }
 7487
 7488    pub fn has_active_edit_prediction(&self) -> bool {
 7489        self.active_edit_prediction.is_some()
 7490    }
 7491
 7492    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7493        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7494            return false;
 7495        };
 7496
 7497        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7498        self.clear_highlights::<EditPredictionHighlight>(cx);
 7499        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7500        true
 7501    }
 7502
 7503    /// Returns true when we're displaying the edit prediction popover below the cursor
 7504    /// like we are not previewing and the LSP autocomplete menu is visible
 7505    /// or we are in `when_holding_modifier` mode.
 7506    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7507        if self.edit_prediction_preview_is_active()
 7508            || !self.show_edit_predictions_in_menu()
 7509            || !self.edit_predictions_enabled()
 7510        {
 7511            return false;
 7512        }
 7513
 7514        if self.has_visible_completions_menu() {
 7515            return true;
 7516        }
 7517
 7518        has_completion && self.edit_prediction_requires_modifier()
 7519    }
 7520
 7521    fn handle_modifiers_changed(
 7522        &mut self,
 7523        modifiers: Modifiers,
 7524        position_map: &PositionMap,
 7525        window: &mut Window,
 7526        cx: &mut Context<Self>,
 7527    ) {
 7528        if self.show_edit_predictions_in_menu() {
 7529            self.update_edit_prediction_preview(&modifiers, window, cx);
 7530        }
 7531
 7532        self.update_selection_mode(&modifiers, position_map, window, cx);
 7533
 7534        let mouse_position = window.mouse_position();
 7535        if !position_map.text_hitbox.is_hovered(window) {
 7536            return;
 7537        }
 7538
 7539        self.update_hovered_link(
 7540            position_map.point_for_position(mouse_position),
 7541            &position_map.snapshot,
 7542            modifiers,
 7543            window,
 7544            cx,
 7545        )
 7546    }
 7547
 7548    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7549        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7550        if invert {
 7551            match multi_cursor_setting {
 7552                MultiCursorModifier::Alt => modifiers.alt,
 7553                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7554            }
 7555        } else {
 7556            match multi_cursor_setting {
 7557                MultiCursorModifier::Alt => modifiers.secondary(),
 7558                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7559            }
 7560        }
 7561    }
 7562
 7563    fn columnar_selection_mode(
 7564        modifiers: &Modifiers,
 7565        cx: &mut Context<Self>,
 7566    ) -> Option<ColumnarMode> {
 7567        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7568            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7569                Some(ColumnarMode::FromMouse)
 7570            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7571                Some(ColumnarMode::FromSelection)
 7572            } else {
 7573                None
 7574            }
 7575        } else {
 7576            None
 7577        }
 7578    }
 7579
 7580    fn update_selection_mode(
 7581        &mut self,
 7582        modifiers: &Modifiers,
 7583        position_map: &PositionMap,
 7584        window: &mut Window,
 7585        cx: &mut Context<Self>,
 7586    ) {
 7587        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7588            return;
 7589        };
 7590        if self.selections.pending.is_none() {
 7591            return;
 7592        }
 7593
 7594        let mouse_position = window.mouse_position();
 7595        let point_for_position = position_map.point_for_position(mouse_position);
 7596        let position = point_for_position.previous_valid;
 7597
 7598        self.select(
 7599            SelectPhase::BeginColumnar {
 7600                position,
 7601                reset: false,
 7602                mode,
 7603                goal_column: point_for_position.exact_unclipped.column(),
 7604            },
 7605            window,
 7606            cx,
 7607        );
 7608    }
 7609
 7610    fn update_edit_prediction_preview(
 7611        &mut self,
 7612        modifiers: &Modifiers,
 7613        window: &mut Window,
 7614        cx: &mut Context<Self>,
 7615    ) {
 7616        let mut modifiers_held = false;
 7617        if let Some(accept_keystroke) = self
 7618            .accept_edit_prediction_keybind(false, window, cx)
 7619            .keystroke()
 7620        {
 7621            modifiers_held = modifiers_held
 7622                || (&accept_keystroke.modifiers == modifiers
 7623                    && accept_keystroke.modifiers.modified());
 7624        };
 7625        if let Some(accept_partial_keystroke) = self
 7626            .accept_edit_prediction_keybind(true, window, cx)
 7627            .keystroke()
 7628        {
 7629            modifiers_held = modifiers_held
 7630                || (&accept_partial_keystroke.modifiers == modifiers
 7631                    && accept_partial_keystroke.modifiers.modified());
 7632        }
 7633
 7634        if modifiers_held {
 7635            if matches!(
 7636                self.edit_prediction_preview,
 7637                EditPredictionPreview::Inactive { .. }
 7638            ) {
 7639                self.edit_prediction_preview = EditPredictionPreview::Active {
 7640                    previous_scroll_position: None,
 7641                    since: Instant::now(),
 7642                };
 7643
 7644                self.update_visible_edit_prediction(window, cx);
 7645                cx.notify();
 7646            }
 7647        } else if let EditPredictionPreview::Active {
 7648            previous_scroll_position,
 7649            since,
 7650        } = self.edit_prediction_preview
 7651        {
 7652            if let (Some(previous_scroll_position), Some(position_map)) =
 7653                (previous_scroll_position, self.last_position_map.as_ref())
 7654            {
 7655                self.set_scroll_position(
 7656                    previous_scroll_position
 7657                        .scroll_position(&position_map.snapshot.display_snapshot),
 7658                    window,
 7659                    cx,
 7660                );
 7661            }
 7662
 7663            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7664                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7665            };
 7666            self.clear_row_highlights::<EditPredictionPreview>();
 7667            self.update_visible_edit_prediction(window, cx);
 7668            cx.notify();
 7669        }
 7670    }
 7671
 7672    fn update_visible_edit_prediction(
 7673        &mut self,
 7674        _window: &mut Window,
 7675        cx: &mut Context<Self>,
 7676    ) -> Option<()> {
 7677        if DisableAiSettings::get_global(cx).disable_ai {
 7678            return None;
 7679        }
 7680
 7681        let selection = self.selections.newest_anchor();
 7682        let cursor = selection.head();
 7683        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7684        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7685        let excerpt_id = cursor.excerpt_id;
 7686
 7687        let show_in_menu = self.show_edit_predictions_in_menu();
 7688        let completions_menu_has_precedence = !show_in_menu
 7689            && (self.context_menu.borrow().is_some()
 7690                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7691
 7692        if completions_menu_has_precedence
 7693            || !offset_selection.is_empty()
 7694            || self
 7695                .active_edit_prediction
 7696                .as_ref()
 7697                .map_or(false, |completion| {
 7698                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7699                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7700                    !invalidation_range.contains(&offset_selection.head())
 7701                })
 7702        {
 7703            self.discard_edit_prediction(false, cx);
 7704            return None;
 7705        }
 7706
 7707        self.take_active_edit_prediction(cx);
 7708        let Some(provider) = self.edit_prediction_provider() else {
 7709            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7710            return None;
 7711        };
 7712
 7713        let (buffer, cursor_buffer_position) =
 7714            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7715
 7716        self.edit_prediction_settings =
 7717            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7718
 7719        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7720
 7721        if self.edit_prediction_indent_conflict {
 7722            let cursor_point = cursor.to_point(&multibuffer);
 7723
 7724            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7725
 7726            if let Some((_, indent)) = indents.iter().next() {
 7727                if indent.len == cursor_point.column {
 7728                    self.edit_prediction_indent_conflict = false;
 7729                }
 7730            }
 7731        }
 7732
 7733        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7734        let edits = edit_prediction
 7735            .edits
 7736            .into_iter()
 7737            .flat_map(|(range, new_text)| {
 7738                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7739                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7740                Some((start..end, new_text))
 7741            })
 7742            .collect::<Vec<_>>();
 7743        if edits.is_empty() {
 7744            return None;
 7745        }
 7746
 7747        let first_edit_start = edits.first().unwrap().0.start;
 7748        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7749        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7750
 7751        let last_edit_end = edits.last().unwrap().0.end;
 7752        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7753        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7754
 7755        let cursor_row = cursor.to_point(&multibuffer).row;
 7756
 7757        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7758
 7759        let mut inlay_ids = Vec::new();
 7760        let invalidation_row_range;
 7761        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7762            Some(cursor_row..edit_end_row)
 7763        } else if cursor_row > edit_end_row {
 7764            Some(edit_start_row..cursor_row)
 7765        } else {
 7766            None
 7767        };
 7768        let supports_jump = self
 7769            .edit_prediction_provider
 7770            .as_ref()
 7771            .map(|provider| provider.provider.supports_jump_to_edit())
 7772            .unwrap_or(true);
 7773
 7774        let is_move = supports_jump
 7775            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7776        let completion = if is_move {
 7777            invalidation_row_range =
 7778                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7779            let target = first_edit_start;
 7780            EditPrediction::Move { target, snapshot }
 7781        } else {
 7782            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7783                && !self.edit_predictions_hidden_for_vim_mode;
 7784
 7785            if show_completions_in_buffer {
 7786                if edits
 7787                    .iter()
 7788                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7789                {
 7790                    let mut inlays = Vec::new();
 7791                    for (range, new_text) in &edits {
 7792                        let inlay = Inlay::edit_prediction(
 7793                            post_inc(&mut self.next_inlay_id),
 7794                            range.start,
 7795                            new_text.as_str(),
 7796                        );
 7797                        inlay_ids.push(inlay.id);
 7798                        inlays.push(inlay);
 7799                    }
 7800
 7801                    self.splice_inlays(&[], inlays, cx);
 7802                } else {
 7803                    let background_color = cx.theme().status().deleted_background;
 7804                    self.highlight_text::<EditPredictionHighlight>(
 7805                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7806                        HighlightStyle {
 7807                            background_color: Some(background_color),
 7808                            ..Default::default()
 7809                        },
 7810                        cx,
 7811                    );
 7812                }
 7813            }
 7814
 7815            invalidation_row_range = edit_start_row..edit_end_row;
 7816
 7817            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7818                if provider.show_tab_accept_marker() {
 7819                    EditDisplayMode::TabAccept
 7820                } else {
 7821                    EditDisplayMode::Inline
 7822                }
 7823            } else {
 7824                EditDisplayMode::DiffPopover
 7825            };
 7826
 7827            EditPrediction::Edit {
 7828                edits,
 7829                edit_preview: edit_prediction.edit_preview,
 7830                display_mode,
 7831                snapshot,
 7832            }
 7833        };
 7834
 7835        let invalidation_range = multibuffer
 7836            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7837            ..multibuffer.anchor_after(Point::new(
 7838                invalidation_row_range.end,
 7839                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7840            ));
 7841
 7842        self.stale_edit_prediction_in_menu = None;
 7843        self.active_edit_prediction = Some(EditPredictionState {
 7844            inlay_ids,
 7845            completion,
 7846            completion_id: edit_prediction.id,
 7847            invalidation_range,
 7848        });
 7849
 7850        cx.notify();
 7851
 7852        Some(())
 7853    }
 7854
 7855    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7856        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7857    }
 7858
 7859    fn clear_tasks(&mut self) {
 7860        self.tasks.clear()
 7861    }
 7862
 7863    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7864        if self.tasks.insert(key, value).is_some() {
 7865            // This case should hopefully be rare, but just in case...
 7866            log::error!(
 7867                "multiple different run targets found on a single line, only the last target will be rendered"
 7868            )
 7869        }
 7870    }
 7871
 7872    /// Get all display points of breakpoints that will be rendered within editor
 7873    ///
 7874    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7875    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7876    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7877    fn active_breakpoints(
 7878        &self,
 7879        range: Range<DisplayRow>,
 7880        window: &mut Window,
 7881        cx: &mut Context<Self>,
 7882    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7883        let mut breakpoint_display_points = HashMap::default();
 7884
 7885        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7886            return breakpoint_display_points;
 7887        };
 7888
 7889        let snapshot = self.snapshot(window, cx);
 7890
 7891        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7892        let Some(project) = self.project.as_ref() else {
 7893            return breakpoint_display_points;
 7894        };
 7895
 7896        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7897            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7898
 7899        for (buffer_snapshot, range, excerpt_id) in
 7900            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7901        {
 7902            let Some(buffer) = project
 7903                .read(cx)
 7904                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7905            else {
 7906                continue;
 7907            };
 7908            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7909                &buffer,
 7910                Some(
 7911                    buffer_snapshot.anchor_before(range.start)
 7912                        ..buffer_snapshot.anchor_after(range.end),
 7913                ),
 7914                buffer_snapshot,
 7915                cx,
 7916            );
 7917            for (breakpoint, state) in breakpoints {
 7918                let multi_buffer_anchor =
 7919                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7920                let position = multi_buffer_anchor
 7921                    .to_point(&multi_buffer_snapshot)
 7922                    .to_display_point(&snapshot);
 7923
 7924                breakpoint_display_points.insert(
 7925                    position.row(),
 7926                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7927                );
 7928            }
 7929        }
 7930
 7931        breakpoint_display_points
 7932    }
 7933
 7934    fn breakpoint_context_menu(
 7935        &self,
 7936        anchor: Anchor,
 7937        window: &mut Window,
 7938        cx: &mut Context<Self>,
 7939    ) -> Entity<ui::ContextMenu> {
 7940        let weak_editor = cx.weak_entity();
 7941        let focus_handle = self.focus_handle(cx);
 7942
 7943        let row = self
 7944            .buffer
 7945            .read(cx)
 7946            .snapshot(cx)
 7947            .summary_for_anchor::<Point>(&anchor)
 7948            .row;
 7949
 7950        let breakpoint = self
 7951            .breakpoint_at_row(row, window, cx)
 7952            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7953
 7954        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7955            "Edit Log Breakpoint"
 7956        } else {
 7957            "Set Log Breakpoint"
 7958        };
 7959
 7960        let condition_breakpoint_msg = if breakpoint
 7961            .as_ref()
 7962            .is_some_and(|bp| bp.1.condition.is_some())
 7963        {
 7964            "Edit Condition Breakpoint"
 7965        } else {
 7966            "Set Condition Breakpoint"
 7967        };
 7968
 7969        let hit_condition_breakpoint_msg = if breakpoint
 7970            .as_ref()
 7971            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7972        {
 7973            "Edit Hit Condition Breakpoint"
 7974        } else {
 7975            "Set Hit Condition Breakpoint"
 7976        };
 7977
 7978        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7979            "Unset Breakpoint"
 7980        } else {
 7981            "Set Breakpoint"
 7982        };
 7983
 7984        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7985
 7986        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7987            BreakpointState::Enabled => Some("Disable"),
 7988            BreakpointState::Disabled => Some("Enable"),
 7989        });
 7990
 7991        let (anchor, breakpoint) =
 7992            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7993
 7994        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7995            menu.on_blur_subscription(Subscription::new(|| {}))
 7996                .context(focus_handle)
 7997                .when(run_to_cursor, |this| {
 7998                    let weak_editor = weak_editor.clone();
 7999                    this.entry("Run to cursor", None, move |window, cx| {
 8000                        weak_editor
 8001                            .update(cx, |editor, cx| {
 8002                                editor.change_selections(
 8003                                    SelectionEffects::no_scroll(),
 8004                                    window,
 8005                                    cx,
 8006                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8007                                );
 8008                            })
 8009                            .ok();
 8010
 8011                        window.dispatch_action(Box::new(RunToCursor), cx);
 8012                    })
 8013                    .separator()
 8014                })
 8015                .when_some(toggle_state_msg, |this, msg| {
 8016                    this.entry(msg, None, {
 8017                        let weak_editor = weak_editor.clone();
 8018                        let breakpoint = breakpoint.clone();
 8019                        move |_window, cx| {
 8020                            weak_editor
 8021                                .update(cx, |this, cx| {
 8022                                    this.edit_breakpoint_at_anchor(
 8023                                        anchor,
 8024                                        breakpoint.as_ref().clone(),
 8025                                        BreakpointEditAction::InvertState,
 8026                                        cx,
 8027                                    );
 8028                                })
 8029                                .log_err();
 8030                        }
 8031                    })
 8032                })
 8033                .entry(set_breakpoint_msg, None, {
 8034                    let weak_editor = weak_editor.clone();
 8035                    let breakpoint = breakpoint.clone();
 8036                    move |_window, cx| {
 8037                        weak_editor
 8038                            .update(cx, |this, cx| {
 8039                                this.edit_breakpoint_at_anchor(
 8040                                    anchor,
 8041                                    breakpoint.as_ref().clone(),
 8042                                    BreakpointEditAction::Toggle,
 8043                                    cx,
 8044                                );
 8045                            })
 8046                            .log_err();
 8047                    }
 8048                })
 8049                .entry(log_breakpoint_msg, None, {
 8050                    let breakpoint = breakpoint.clone();
 8051                    let weak_editor = weak_editor.clone();
 8052                    move |window, cx| {
 8053                        weak_editor
 8054                            .update(cx, |this, cx| {
 8055                                this.add_edit_breakpoint_block(
 8056                                    anchor,
 8057                                    breakpoint.as_ref(),
 8058                                    BreakpointPromptEditAction::Log,
 8059                                    window,
 8060                                    cx,
 8061                                );
 8062                            })
 8063                            .log_err();
 8064                    }
 8065                })
 8066                .entry(condition_breakpoint_msg, None, {
 8067                    let breakpoint = breakpoint.clone();
 8068                    let weak_editor = weak_editor.clone();
 8069                    move |window, cx| {
 8070                        weak_editor
 8071                            .update(cx, |this, cx| {
 8072                                this.add_edit_breakpoint_block(
 8073                                    anchor,
 8074                                    breakpoint.as_ref(),
 8075                                    BreakpointPromptEditAction::Condition,
 8076                                    window,
 8077                                    cx,
 8078                                );
 8079                            })
 8080                            .log_err();
 8081                    }
 8082                })
 8083                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8084                    weak_editor
 8085                        .update(cx, |this, cx| {
 8086                            this.add_edit_breakpoint_block(
 8087                                anchor,
 8088                                breakpoint.as_ref(),
 8089                                BreakpointPromptEditAction::HitCondition,
 8090                                window,
 8091                                cx,
 8092                            );
 8093                        })
 8094                        .log_err();
 8095                })
 8096        })
 8097    }
 8098
 8099    fn render_breakpoint(
 8100        &self,
 8101        position: Anchor,
 8102        row: DisplayRow,
 8103        breakpoint: &Breakpoint,
 8104        state: Option<BreakpointSessionState>,
 8105        cx: &mut Context<Self>,
 8106    ) -> IconButton {
 8107        let is_rejected = state.is_some_and(|s| !s.verified);
 8108        // Is it a breakpoint that shows up when hovering over gutter?
 8109        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8110            (false, false),
 8111            |PhantomBreakpointIndicator {
 8112                 is_active,
 8113                 display_row,
 8114                 collides_with_existing_breakpoint,
 8115             }| {
 8116                (
 8117                    is_active && display_row == row,
 8118                    collides_with_existing_breakpoint,
 8119                )
 8120            },
 8121        );
 8122
 8123        let (color, icon) = {
 8124            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8125                (false, false) => ui::IconName::DebugBreakpoint,
 8126                (true, false) => ui::IconName::DebugLogBreakpoint,
 8127                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8128                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8129            };
 8130
 8131            let color = if is_phantom {
 8132                Color::Hint
 8133            } else if is_rejected {
 8134                Color::Disabled
 8135            } else {
 8136                Color::Debugger
 8137            };
 8138
 8139            (color, icon)
 8140        };
 8141
 8142        let breakpoint = Arc::from(breakpoint.clone());
 8143
 8144        let alt_as_text = gpui::Keystroke {
 8145            modifiers: Modifiers::secondary_key(),
 8146            ..Default::default()
 8147        };
 8148        let primary_action_text = if breakpoint.is_disabled() {
 8149            "Enable breakpoint"
 8150        } else if is_phantom && !collides_with_existing {
 8151            "Set breakpoint"
 8152        } else {
 8153            "Unset breakpoint"
 8154        };
 8155        let focus_handle = self.focus_handle.clone();
 8156
 8157        let meta = if is_rejected {
 8158            SharedString::from("No executable code is associated with this line.")
 8159        } else if collides_with_existing && !breakpoint.is_disabled() {
 8160            SharedString::from(format!(
 8161                "{alt_as_text}-click to disable,\nright-click for more options."
 8162            ))
 8163        } else {
 8164            SharedString::from("Right-click for more options.")
 8165        };
 8166        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8167            .icon_size(IconSize::XSmall)
 8168            .size(ui::ButtonSize::None)
 8169            .when(is_rejected, |this| {
 8170                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8171            })
 8172            .icon_color(color)
 8173            .style(ButtonStyle::Transparent)
 8174            .on_click(cx.listener({
 8175                let breakpoint = breakpoint.clone();
 8176
 8177                move |editor, event: &ClickEvent, window, cx| {
 8178                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8179                        BreakpointEditAction::InvertState
 8180                    } else {
 8181                        BreakpointEditAction::Toggle
 8182                    };
 8183
 8184                    window.focus(&editor.focus_handle(cx));
 8185                    editor.edit_breakpoint_at_anchor(
 8186                        position,
 8187                        breakpoint.as_ref().clone(),
 8188                        edit_action,
 8189                        cx,
 8190                    );
 8191                }
 8192            }))
 8193            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8194                editor.set_breakpoint_context_menu(
 8195                    row,
 8196                    Some(position),
 8197                    event.position(),
 8198                    window,
 8199                    cx,
 8200                );
 8201            }))
 8202            .tooltip(move |window, cx| {
 8203                Tooltip::with_meta_in(
 8204                    primary_action_text,
 8205                    Some(&ToggleBreakpoint),
 8206                    meta.clone(),
 8207                    &focus_handle,
 8208                    window,
 8209                    cx,
 8210                )
 8211            })
 8212    }
 8213
 8214    fn build_tasks_context(
 8215        project: &Entity<Project>,
 8216        buffer: &Entity<Buffer>,
 8217        buffer_row: u32,
 8218        tasks: &Arc<RunnableTasks>,
 8219        cx: &mut Context<Self>,
 8220    ) -> Task<Option<task::TaskContext>> {
 8221        let position = Point::new(buffer_row, tasks.column);
 8222        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8223        let location = Location {
 8224            buffer: buffer.clone(),
 8225            range: range_start..range_start,
 8226        };
 8227        // Fill in the environmental variables from the tree-sitter captures
 8228        let mut captured_task_variables = TaskVariables::default();
 8229        for (capture_name, value) in tasks.extra_variables.clone() {
 8230            captured_task_variables.insert(
 8231                task::VariableName::Custom(capture_name.into()),
 8232                value.clone(),
 8233            );
 8234        }
 8235        project.update(cx, |project, cx| {
 8236            project.task_store().update(cx, |task_store, cx| {
 8237                task_store.task_context_for_location(captured_task_variables, location, cx)
 8238            })
 8239        })
 8240    }
 8241
 8242    pub fn spawn_nearest_task(
 8243        &mut self,
 8244        action: &SpawnNearestTask,
 8245        window: &mut Window,
 8246        cx: &mut Context<Self>,
 8247    ) {
 8248        let Some((workspace, _)) = self.workspace.clone() else {
 8249            return;
 8250        };
 8251        let Some(project) = self.project.clone() else {
 8252            return;
 8253        };
 8254
 8255        // Try to find a closest, enclosing node using tree-sitter that has a task
 8256        let Some((buffer, buffer_row, tasks)) = self
 8257            .find_enclosing_node_task(cx)
 8258            // Or find the task that's closest in row-distance.
 8259            .or_else(|| self.find_closest_task(cx))
 8260        else {
 8261            return;
 8262        };
 8263
 8264        let reveal_strategy = action.reveal;
 8265        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8266        cx.spawn_in(window, async move |_, cx| {
 8267            let context = task_context.await?;
 8268            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8269
 8270            let resolved = &mut resolved_task.resolved;
 8271            resolved.reveal = reveal_strategy;
 8272
 8273            workspace
 8274                .update_in(cx, |workspace, window, cx| {
 8275                    workspace.schedule_resolved_task(
 8276                        task_source_kind,
 8277                        resolved_task,
 8278                        false,
 8279                        window,
 8280                        cx,
 8281                    );
 8282                })
 8283                .ok()
 8284        })
 8285        .detach();
 8286    }
 8287
 8288    fn find_closest_task(
 8289        &mut self,
 8290        cx: &mut Context<Self>,
 8291    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8292        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8293
 8294        let ((buffer_id, row), tasks) = self
 8295            .tasks
 8296            .iter()
 8297            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8298
 8299        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8300        let tasks = Arc::new(tasks.to_owned());
 8301        Some((buffer, *row, tasks))
 8302    }
 8303
 8304    fn find_enclosing_node_task(
 8305        &mut self,
 8306        cx: &mut Context<Self>,
 8307    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8308        let snapshot = self.buffer.read(cx).snapshot(cx);
 8309        let offset = self.selections.newest::<usize>(cx).head();
 8310        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8311        let buffer_id = excerpt.buffer().remote_id();
 8312
 8313        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8314        let mut cursor = layer.node().walk();
 8315
 8316        while cursor.goto_first_child_for_byte(offset).is_some() {
 8317            if cursor.node().end_byte() == offset {
 8318                cursor.goto_next_sibling();
 8319            }
 8320        }
 8321
 8322        // Ascend to the smallest ancestor that contains the range and has a task.
 8323        loop {
 8324            let node = cursor.node();
 8325            let node_range = node.byte_range();
 8326            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8327
 8328            // Check if this node contains our offset
 8329            if node_range.start <= offset && node_range.end >= offset {
 8330                // If it contains offset, check for task
 8331                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8332                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8333                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8334                }
 8335            }
 8336
 8337            if !cursor.goto_parent() {
 8338                break;
 8339            }
 8340        }
 8341        None
 8342    }
 8343
 8344    fn render_run_indicator(
 8345        &self,
 8346        _style: &EditorStyle,
 8347        is_active: bool,
 8348        row: DisplayRow,
 8349        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8350        cx: &mut Context<Self>,
 8351    ) -> IconButton {
 8352        let color = Color::Muted;
 8353        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8354
 8355        IconButton::new(
 8356            ("run_indicator", row.0 as usize),
 8357            ui::IconName::PlayOutlined,
 8358        )
 8359        .shape(ui::IconButtonShape::Square)
 8360        .icon_size(IconSize::XSmall)
 8361        .icon_color(color)
 8362        .toggle_state(is_active)
 8363        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8364            let quick_launch = match e {
 8365                ClickEvent::Keyboard(_) => true,
 8366                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8367            };
 8368
 8369            window.focus(&editor.focus_handle(cx));
 8370            editor.toggle_code_actions(
 8371                &ToggleCodeActions {
 8372                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8373                    quick_launch,
 8374                },
 8375                window,
 8376                cx,
 8377            );
 8378        }))
 8379        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8380            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8381        }))
 8382    }
 8383
 8384    pub fn context_menu_visible(&self) -> bool {
 8385        !self.edit_prediction_preview_is_active()
 8386            && self
 8387                .context_menu
 8388                .borrow()
 8389                .as_ref()
 8390                .map_or(false, |menu| menu.visible())
 8391    }
 8392
 8393    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8394        self.context_menu
 8395            .borrow()
 8396            .as_ref()
 8397            .map(|menu| menu.origin())
 8398    }
 8399
 8400    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8401        self.context_menu_options = Some(options);
 8402    }
 8403
 8404    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8405    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8406
 8407    fn render_edit_prediction_popover(
 8408        &mut self,
 8409        text_bounds: &Bounds<Pixels>,
 8410        content_origin: gpui::Point<Pixels>,
 8411        right_margin: Pixels,
 8412        editor_snapshot: &EditorSnapshot,
 8413        visible_row_range: Range<DisplayRow>,
 8414        scroll_top: f32,
 8415        scroll_bottom: f32,
 8416        line_layouts: &[LineWithInvisibles],
 8417        line_height: Pixels,
 8418        scroll_pixel_position: gpui::Point<Pixels>,
 8419        newest_selection_head: Option<DisplayPoint>,
 8420        editor_width: Pixels,
 8421        style: &EditorStyle,
 8422        window: &mut Window,
 8423        cx: &mut App,
 8424    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8425        if self.mode().is_minimap() {
 8426            return None;
 8427        }
 8428        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8429
 8430        if self.edit_prediction_visible_in_cursor_popover(true) {
 8431            return None;
 8432        }
 8433
 8434        match &active_edit_prediction.completion {
 8435            EditPrediction::Move { target, .. } => {
 8436                let target_display_point = target.to_display_point(editor_snapshot);
 8437
 8438                if self.edit_prediction_requires_modifier() {
 8439                    if !self.edit_prediction_preview_is_active() {
 8440                        return None;
 8441                    }
 8442
 8443                    self.render_edit_prediction_modifier_jump_popover(
 8444                        text_bounds,
 8445                        content_origin,
 8446                        visible_row_range,
 8447                        line_layouts,
 8448                        line_height,
 8449                        scroll_pixel_position,
 8450                        newest_selection_head,
 8451                        target_display_point,
 8452                        window,
 8453                        cx,
 8454                    )
 8455                } else {
 8456                    self.render_edit_prediction_eager_jump_popover(
 8457                        text_bounds,
 8458                        content_origin,
 8459                        editor_snapshot,
 8460                        visible_row_range,
 8461                        scroll_top,
 8462                        scroll_bottom,
 8463                        line_height,
 8464                        scroll_pixel_position,
 8465                        target_display_point,
 8466                        editor_width,
 8467                        window,
 8468                        cx,
 8469                    )
 8470                }
 8471            }
 8472            EditPrediction::Edit {
 8473                display_mode: EditDisplayMode::Inline,
 8474                ..
 8475            } => None,
 8476            EditPrediction::Edit {
 8477                display_mode: EditDisplayMode::TabAccept,
 8478                edits,
 8479                ..
 8480            } => {
 8481                let range = &edits.first()?.0;
 8482                let target_display_point = range.end.to_display_point(editor_snapshot);
 8483
 8484                self.render_edit_prediction_end_of_line_popover(
 8485                    "Accept",
 8486                    editor_snapshot,
 8487                    visible_row_range,
 8488                    target_display_point,
 8489                    line_height,
 8490                    scroll_pixel_position,
 8491                    content_origin,
 8492                    editor_width,
 8493                    window,
 8494                    cx,
 8495                )
 8496            }
 8497            EditPrediction::Edit {
 8498                edits,
 8499                edit_preview,
 8500                display_mode: EditDisplayMode::DiffPopover,
 8501                snapshot,
 8502            } => self.render_edit_prediction_diff_popover(
 8503                text_bounds,
 8504                content_origin,
 8505                right_margin,
 8506                editor_snapshot,
 8507                visible_row_range,
 8508                line_layouts,
 8509                line_height,
 8510                scroll_pixel_position,
 8511                newest_selection_head,
 8512                editor_width,
 8513                style,
 8514                edits,
 8515                edit_preview,
 8516                snapshot,
 8517                window,
 8518                cx,
 8519            ),
 8520        }
 8521    }
 8522
 8523    fn render_edit_prediction_modifier_jump_popover(
 8524        &mut self,
 8525        text_bounds: &Bounds<Pixels>,
 8526        content_origin: gpui::Point<Pixels>,
 8527        visible_row_range: Range<DisplayRow>,
 8528        line_layouts: &[LineWithInvisibles],
 8529        line_height: Pixels,
 8530        scroll_pixel_position: gpui::Point<Pixels>,
 8531        newest_selection_head: Option<DisplayPoint>,
 8532        target_display_point: DisplayPoint,
 8533        window: &mut Window,
 8534        cx: &mut App,
 8535    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8536        let scrolled_content_origin =
 8537            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8538
 8539        const SCROLL_PADDING_Y: Pixels = px(12.);
 8540
 8541        if target_display_point.row() < visible_row_range.start {
 8542            return self.render_edit_prediction_scroll_popover(
 8543                |_| SCROLL_PADDING_Y,
 8544                IconName::ArrowUp,
 8545                visible_row_range,
 8546                line_layouts,
 8547                newest_selection_head,
 8548                scrolled_content_origin,
 8549                window,
 8550                cx,
 8551            );
 8552        } else if target_display_point.row() >= visible_row_range.end {
 8553            return self.render_edit_prediction_scroll_popover(
 8554                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8555                IconName::ArrowDown,
 8556                visible_row_range,
 8557                line_layouts,
 8558                newest_selection_head,
 8559                scrolled_content_origin,
 8560                window,
 8561                cx,
 8562            );
 8563        }
 8564
 8565        const POLE_WIDTH: Pixels = px(2.);
 8566
 8567        let line_layout =
 8568            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8569        let target_column = target_display_point.column() as usize;
 8570
 8571        let target_x = line_layout.x_for_index(target_column);
 8572        let target_y =
 8573            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8574
 8575        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8576
 8577        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8578        border_color.l += 0.001;
 8579
 8580        let mut element = v_flex()
 8581            .items_end()
 8582            .when(flag_on_right, |el| el.items_start())
 8583            .child(if flag_on_right {
 8584                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8585                    .rounded_bl(px(0.))
 8586                    .rounded_tl(px(0.))
 8587                    .border_l_2()
 8588                    .border_color(border_color)
 8589            } else {
 8590                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8591                    .rounded_br(px(0.))
 8592                    .rounded_tr(px(0.))
 8593                    .border_r_2()
 8594                    .border_color(border_color)
 8595            })
 8596            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8597            .into_any();
 8598
 8599        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8600
 8601        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8602            - point(
 8603                if flag_on_right {
 8604                    POLE_WIDTH
 8605                } else {
 8606                    size.width - POLE_WIDTH
 8607                },
 8608                size.height - line_height,
 8609            );
 8610
 8611        origin.x = origin.x.max(content_origin.x);
 8612
 8613        element.prepaint_at(origin, window, cx);
 8614
 8615        Some((element, origin))
 8616    }
 8617
 8618    fn render_edit_prediction_scroll_popover(
 8619        &mut self,
 8620        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8621        scroll_icon: IconName,
 8622        visible_row_range: Range<DisplayRow>,
 8623        line_layouts: &[LineWithInvisibles],
 8624        newest_selection_head: Option<DisplayPoint>,
 8625        scrolled_content_origin: gpui::Point<Pixels>,
 8626        window: &mut Window,
 8627        cx: &mut App,
 8628    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8629        let mut element = self
 8630            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8631            .into_any();
 8632
 8633        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8634
 8635        let cursor = newest_selection_head?;
 8636        let cursor_row_layout =
 8637            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8638        let cursor_column = cursor.column() as usize;
 8639
 8640        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8641
 8642        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8643
 8644        element.prepaint_at(origin, window, cx);
 8645        Some((element, origin))
 8646    }
 8647
 8648    fn render_edit_prediction_eager_jump_popover(
 8649        &mut self,
 8650        text_bounds: &Bounds<Pixels>,
 8651        content_origin: gpui::Point<Pixels>,
 8652        editor_snapshot: &EditorSnapshot,
 8653        visible_row_range: Range<DisplayRow>,
 8654        scroll_top: f32,
 8655        scroll_bottom: f32,
 8656        line_height: Pixels,
 8657        scroll_pixel_position: gpui::Point<Pixels>,
 8658        target_display_point: DisplayPoint,
 8659        editor_width: Pixels,
 8660        window: &mut Window,
 8661        cx: &mut App,
 8662    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8663        if target_display_point.row().as_f32() < scroll_top {
 8664            let mut element = self
 8665                .render_edit_prediction_line_popover(
 8666                    "Jump to Edit",
 8667                    Some(IconName::ArrowUp),
 8668                    window,
 8669                    cx,
 8670                )?
 8671                .into_any();
 8672
 8673            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8674            let offset = point(
 8675                (text_bounds.size.width - size.width) / 2.,
 8676                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8677            );
 8678
 8679            let origin = text_bounds.origin + offset;
 8680            element.prepaint_at(origin, window, cx);
 8681            Some((element, origin))
 8682        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8683            let mut element = self
 8684                .render_edit_prediction_line_popover(
 8685                    "Jump to Edit",
 8686                    Some(IconName::ArrowDown),
 8687                    window,
 8688                    cx,
 8689                )?
 8690                .into_any();
 8691
 8692            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8693            let offset = point(
 8694                (text_bounds.size.width - size.width) / 2.,
 8695                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8696            );
 8697
 8698            let origin = text_bounds.origin + offset;
 8699            element.prepaint_at(origin, window, cx);
 8700            Some((element, origin))
 8701        } else {
 8702            self.render_edit_prediction_end_of_line_popover(
 8703                "Jump to Edit",
 8704                editor_snapshot,
 8705                visible_row_range,
 8706                target_display_point,
 8707                line_height,
 8708                scroll_pixel_position,
 8709                content_origin,
 8710                editor_width,
 8711                window,
 8712                cx,
 8713            )
 8714        }
 8715    }
 8716
 8717    fn render_edit_prediction_end_of_line_popover(
 8718        self: &mut Editor,
 8719        label: &'static str,
 8720        editor_snapshot: &EditorSnapshot,
 8721        visible_row_range: Range<DisplayRow>,
 8722        target_display_point: DisplayPoint,
 8723        line_height: Pixels,
 8724        scroll_pixel_position: gpui::Point<Pixels>,
 8725        content_origin: gpui::Point<Pixels>,
 8726        editor_width: Pixels,
 8727        window: &mut Window,
 8728        cx: &mut App,
 8729    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8730        let target_line_end = DisplayPoint::new(
 8731            target_display_point.row(),
 8732            editor_snapshot.line_len(target_display_point.row()),
 8733        );
 8734
 8735        let mut element = self
 8736            .render_edit_prediction_line_popover(label, None, window, cx)?
 8737            .into_any();
 8738
 8739        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8740
 8741        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8742
 8743        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8744        let mut origin = start_point
 8745            + line_origin
 8746            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8747        origin.x = origin.x.max(content_origin.x);
 8748
 8749        let max_x = content_origin.x + editor_width - size.width;
 8750
 8751        if origin.x > max_x {
 8752            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8753
 8754            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8755                origin.y += offset;
 8756                IconName::ArrowUp
 8757            } else {
 8758                origin.y -= offset;
 8759                IconName::ArrowDown
 8760            };
 8761
 8762            element = self
 8763                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8764                .into_any();
 8765
 8766            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8767
 8768            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8769        }
 8770
 8771        element.prepaint_at(origin, window, cx);
 8772        Some((element, origin))
 8773    }
 8774
 8775    fn render_edit_prediction_diff_popover(
 8776        self: &Editor,
 8777        text_bounds: &Bounds<Pixels>,
 8778        content_origin: gpui::Point<Pixels>,
 8779        right_margin: Pixels,
 8780        editor_snapshot: &EditorSnapshot,
 8781        visible_row_range: Range<DisplayRow>,
 8782        line_layouts: &[LineWithInvisibles],
 8783        line_height: Pixels,
 8784        scroll_pixel_position: gpui::Point<Pixels>,
 8785        newest_selection_head: Option<DisplayPoint>,
 8786        editor_width: Pixels,
 8787        style: &EditorStyle,
 8788        edits: &Vec<(Range<Anchor>, String)>,
 8789        edit_preview: &Option<language::EditPreview>,
 8790        snapshot: &language::BufferSnapshot,
 8791        window: &mut Window,
 8792        cx: &mut App,
 8793    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8794        let edit_start = edits
 8795            .first()
 8796            .unwrap()
 8797            .0
 8798            .start
 8799            .to_display_point(editor_snapshot);
 8800        let edit_end = edits
 8801            .last()
 8802            .unwrap()
 8803            .0
 8804            .end
 8805            .to_display_point(editor_snapshot);
 8806
 8807        let is_visible = visible_row_range.contains(&edit_start.row())
 8808            || visible_row_range.contains(&edit_end.row());
 8809        if !is_visible {
 8810            return None;
 8811        }
 8812
 8813        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8814            crate::edit_prediction_edit_text(&snapshot, edits, edit_preview, false, cx)
 8815        } else {
 8816            // Fallback for providers without edit_preview
 8817            crate::edit_prediction_fallback_text(edits, cx)
 8818        };
 8819
 8820        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8821        let line_count = highlighted_edits.text.lines().count();
 8822
 8823        const BORDER_WIDTH: Pixels = px(1.);
 8824
 8825        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8826        let has_keybind = keybind.is_some();
 8827
 8828        let mut element = h_flex()
 8829            .items_start()
 8830            .child(
 8831                h_flex()
 8832                    .bg(cx.theme().colors().editor_background)
 8833                    .border(BORDER_WIDTH)
 8834                    .shadow_xs()
 8835                    .border_color(cx.theme().colors().border)
 8836                    .rounded_l_lg()
 8837                    .when(line_count > 1, |el| el.rounded_br_lg())
 8838                    .pr_1()
 8839                    .child(styled_text),
 8840            )
 8841            .child(
 8842                h_flex()
 8843                    .h(line_height + BORDER_WIDTH * 2.)
 8844                    .px_1p5()
 8845                    .gap_1()
 8846                    // Workaround: For some reason, there's a gap if we don't do this
 8847                    .ml(-BORDER_WIDTH)
 8848                    .shadow(vec![gpui::BoxShadow {
 8849                        color: gpui::black().opacity(0.05),
 8850                        offset: point(px(1.), px(1.)),
 8851                        blur_radius: px(2.),
 8852                        spread_radius: px(0.),
 8853                    }])
 8854                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8855                    .border(BORDER_WIDTH)
 8856                    .border_color(cx.theme().colors().border)
 8857                    .rounded_r_lg()
 8858                    .id("edit_prediction_diff_popover_keybind")
 8859                    .when(!has_keybind, |el| {
 8860                        let status_colors = cx.theme().status();
 8861
 8862                        el.bg(status_colors.error_background)
 8863                            .border_color(status_colors.error.opacity(0.6))
 8864                            .child(Icon::new(IconName::Info).color(Color::Error))
 8865                            .cursor_default()
 8866                            .hoverable_tooltip(move |_window, cx| {
 8867                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8868                            })
 8869                    })
 8870                    .children(keybind),
 8871            )
 8872            .into_any();
 8873
 8874        let longest_row =
 8875            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8876        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8877            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8878        } else {
 8879            layout_line(
 8880                longest_row,
 8881                editor_snapshot,
 8882                style,
 8883                editor_width,
 8884                |_| false,
 8885                window,
 8886                cx,
 8887            )
 8888            .width
 8889        };
 8890
 8891        let viewport_bounds =
 8892            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8893                right: -right_margin,
 8894                ..Default::default()
 8895            });
 8896
 8897        let x_after_longest =
 8898            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8899                - scroll_pixel_position.x;
 8900
 8901        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8902
 8903        // Fully visible if it can be displayed within the window (allow overlapping other
 8904        // panes). However, this is only allowed if the popover starts within text_bounds.
 8905        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8906            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8907
 8908        let mut origin = if can_position_to_the_right {
 8909            point(
 8910                x_after_longest,
 8911                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8912                    - scroll_pixel_position.y,
 8913            )
 8914        } else {
 8915            let cursor_row = newest_selection_head.map(|head| head.row());
 8916            let above_edit = edit_start
 8917                .row()
 8918                .0
 8919                .checked_sub(line_count as u32)
 8920                .map(DisplayRow);
 8921            let below_edit = Some(edit_end.row() + 1);
 8922            let above_cursor =
 8923                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8924            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8925
 8926            // Place the edit popover adjacent to the edit if there is a location
 8927            // available that is onscreen and does not obscure the cursor. Otherwise,
 8928            // place it adjacent to the cursor.
 8929            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8930                .into_iter()
 8931                .flatten()
 8932                .find(|&start_row| {
 8933                    let end_row = start_row + line_count as u32;
 8934                    visible_row_range.contains(&start_row)
 8935                        && visible_row_range.contains(&end_row)
 8936                        && cursor_row.map_or(true, |cursor_row| {
 8937                            !((start_row..end_row).contains(&cursor_row))
 8938                        })
 8939                })?;
 8940
 8941            content_origin
 8942                + point(
 8943                    -scroll_pixel_position.x,
 8944                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8945                )
 8946        };
 8947
 8948        origin.x -= BORDER_WIDTH;
 8949
 8950        window.defer_draw(element, origin, 1);
 8951
 8952        // Do not return an element, since it will already be drawn due to defer_draw.
 8953        None
 8954    }
 8955
 8956    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8957        px(30.)
 8958    }
 8959
 8960    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8961        if self.read_only(cx) {
 8962            cx.theme().players().read_only()
 8963        } else {
 8964            self.style.as_ref().unwrap().local_player
 8965        }
 8966    }
 8967
 8968    fn render_edit_prediction_accept_keybind(
 8969        &self,
 8970        window: &mut Window,
 8971        cx: &App,
 8972    ) -> Option<AnyElement> {
 8973        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8974        let accept_keystroke = accept_binding.keystroke()?;
 8975
 8976        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8977
 8978        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8979            Color::Accent
 8980        } else {
 8981            Color::Muted
 8982        };
 8983
 8984        h_flex()
 8985            .px_0p5()
 8986            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8987            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8988            .text_size(TextSize::XSmall.rems(cx))
 8989            .child(h_flex().children(ui::render_modifiers(
 8990                &accept_keystroke.modifiers,
 8991                PlatformStyle::platform(),
 8992                Some(modifiers_color),
 8993                Some(IconSize::XSmall.rems().into()),
 8994                true,
 8995            )))
 8996            .when(is_platform_style_mac, |parent| {
 8997                parent.child(accept_keystroke.key.clone())
 8998            })
 8999            .when(!is_platform_style_mac, |parent| {
 9000                parent.child(
 9001                    Key::new(
 9002                        util::capitalize(&accept_keystroke.key),
 9003                        Some(Color::Default),
 9004                    )
 9005                    .size(Some(IconSize::XSmall.rems().into())),
 9006                )
 9007            })
 9008            .into_any()
 9009            .into()
 9010    }
 9011
 9012    fn render_edit_prediction_line_popover(
 9013        &self,
 9014        label: impl Into<SharedString>,
 9015        icon: Option<IconName>,
 9016        window: &mut Window,
 9017        cx: &App,
 9018    ) -> Option<Stateful<Div>> {
 9019        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9020
 9021        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9022        let has_keybind = keybind.is_some();
 9023
 9024        let result = h_flex()
 9025            .id("ep-line-popover")
 9026            .py_0p5()
 9027            .pl_1()
 9028            .pr(padding_right)
 9029            .gap_1()
 9030            .rounded_md()
 9031            .border_1()
 9032            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9033            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9034            .shadow_xs()
 9035            .when(!has_keybind, |el| {
 9036                let status_colors = cx.theme().status();
 9037
 9038                el.bg(status_colors.error_background)
 9039                    .border_color(status_colors.error.opacity(0.6))
 9040                    .pl_2()
 9041                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9042                    .cursor_default()
 9043                    .hoverable_tooltip(move |_window, cx| {
 9044                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9045                    })
 9046            })
 9047            .children(keybind)
 9048            .child(
 9049                Label::new(label)
 9050                    .size(LabelSize::Small)
 9051                    .when(!has_keybind, |el| {
 9052                        el.color(cx.theme().status().error.into()).strikethrough()
 9053                    }),
 9054            )
 9055            .when(!has_keybind, |el| {
 9056                el.child(
 9057                    h_flex().ml_1().child(
 9058                        Icon::new(IconName::Info)
 9059                            .size(IconSize::Small)
 9060                            .color(cx.theme().status().error.into()),
 9061                    ),
 9062                )
 9063            })
 9064            .when_some(icon, |element, icon| {
 9065                element.child(
 9066                    div()
 9067                        .mt(px(1.5))
 9068                        .child(Icon::new(icon).size(IconSize::Small)),
 9069                )
 9070            });
 9071
 9072        Some(result)
 9073    }
 9074
 9075    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9076        let accent_color = cx.theme().colors().text_accent;
 9077        let editor_bg_color = cx.theme().colors().editor_background;
 9078        editor_bg_color.blend(accent_color.opacity(0.1))
 9079    }
 9080
 9081    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9082        let accent_color = cx.theme().colors().text_accent;
 9083        let editor_bg_color = cx.theme().colors().editor_background;
 9084        editor_bg_color.blend(accent_color.opacity(0.6))
 9085    }
 9086    fn get_prediction_provider_icon_name(
 9087        provider: &Option<RegisteredEditPredictionProvider>,
 9088    ) -> IconName {
 9089        match provider {
 9090            Some(provider) => match provider.provider.name() {
 9091                "copilot" => IconName::Copilot,
 9092                "supermaven" => IconName::Supermaven,
 9093                _ => IconName::ZedPredict,
 9094            },
 9095            None => IconName::ZedPredict,
 9096        }
 9097    }
 9098
 9099    fn render_edit_prediction_cursor_popover(
 9100        &self,
 9101        min_width: Pixels,
 9102        max_width: Pixels,
 9103        cursor_point: Point,
 9104        style: &EditorStyle,
 9105        accept_keystroke: Option<&gpui::Keystroke>,
 9106        _window: &Window,
 9107        cx: &mut Context<Editor>,
 9108    ) -> Option<AnyElement> {
 9109        let provider = self.edit_prediction_provider.as_ref()?;
 9110        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9111
 9112        if provider.provider.needs_terms_acceptance(cx) {
 9113            return Some(
 9114                h_flex()
 9115                    .min_w(min_width)
 9116                    .flex_1()
 9117                    .px_2()
 9118                    .py_1()
 9119                    .gap_3()
 9120                    .elevation_2(cx)
 9121                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9122                    .id("accept-terms")
 9123                    .cursor_pointer()
 9124                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9125                    .on_click(cx.listener(|this, _event, window, cx| {
 9126                        cx.stop_propagation();
 9127                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9128                        window.dispatch_action(
 9129                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9130                            cx,
 9131                        );
 9132                    }))
 9133                    .child(
 9134                        h_flex()
 9135                            .flex_1()
 9136                            .gap_2()
 9137                            .child(Icon::new(provider_icon))
 9138                            .child(Label::new("Accept Terms of Service"))
 9139                            .child(div().w_full())
 9140                            .child(
 9141                                Icon::new(IconName::ArrowUpRight)
 9142                                    .color(Color::Muted)
 9143                                    .size(IconSize::Small),
 9144                            )
 9145                            .into_any_element(),
 9146                    )
 9147                    .into_any(),
 9148            );
 9149        }
 9150
 9151        let is_refreshing = provider.provider.is_refreshing(cx);
 9152
 9153        fn pending_completion_container(icon: IconName) -> Div {
 9154            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9155        }
 9156
 9157        let completion = match &self.active_edit_prediction {
 9158            Some(prediction) => {
 9159                if !self.has_visible_completions_menu() {
 9160                    const RADIUS: Pixels = px(6.);
 9161                    const BORDER_WIDTH: Pixels = px(1.);
 9162
 9163                    return Some(
 9164                        h_flex()
 9165                            .elevation_2(cx)
 9166                            .border(BORDER_WIDTH)
 9167                            .border_color(cx.theme().colors().border)
 9168                            .when(accept_keystroke.is_none(), |el| {
 9169                                el.border_color(cx.theme().status().error)
 9170                            })
 9171                            .rounded(RADIUS)
 9172                            .rounded_tl(px(0.))
 9173                            .overflow_hidden()
 9174                            .child(div().px_1p5().child(match &prediction.completion {
 9175                                EditPrediction::Move { target, snapshot } => {
 9176                                    use text::ToPoint as _;
 9177                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9178                                    {
 9179                                        Icon::new(IconName::ZedPredictDown)
 9180                                    } else {
 9181                                        Icon::new(IconName::ZedPredictUp)
 9182                                    }
 9183                                }
 9184                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9185                            }))
 9186                            .child(
 9187                                h_flex()
 9188                                    .gap_1()
 9189                                    .py_1()
 9190                                    .px_2()
 9191                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9192                                    .border_l_1()
 9193                                    .border_color(cx.theme().colors().border)
 9194                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9195                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9196                                        el.child(
 9197                                            Label::new("Hold")
 9198                                                .size(LabelSize::Small)
 9199                                                .when(accept_keystroke.is_none(), |el| {
 9200                                                    el.strikethrough()
 9201                                                })
 9202                                                .line_height_style(LineHeightStyle::UiLabel),
 9203                                        )
 9204                                    })
 9205                                    .id("edit_prediction_cursor_popover_keybind")
 9206                                    .when(accept_keystroke.is_none(), |el| {
 9207                                        let status_colors = cx.theme().status();
 9208
 9209                                        el.bg(status_colors.error_background)
 9210                                            .border_color(status_colors.error.opacity(0.6))
 9211                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9212                                            .cursor_default()
 9213                                            .hoverable_tooltip(move |_window, cx| {
 9214                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9215                                                    .into()
 9216                                            })
 9217                                    })
 9218                                    .when_some(
 9219                                        accept_keystroke.as_ref(),
 9220                                        |el, accept_keystroke| {
 9221                                            el.child(h_flex().children(ui::render_modifiers(
 9222                                                &accept_keystroke.modifiers,
 9223                                                PlatformStyle::platform(),
 9224                                                Some(Color::Default),
 9225                                                Some(IconSize::XSmall.rems().into()),
 9226                                                false,
 9227                                            )))
 9228                                        },
 9229                                    ),
 9230                            )
 9231                            .into_any(),
 9232                    );
 9233                }
 9234
 9235                self.render_edit_prediction_cursor_popover_preview(
 9236                    prediction,
 9237                    cursor_point,
 9238                    style,
 9239                    cx,
 9240                )?
 9241            }
 9242
 9243            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9244                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9245                    stale_completion,
 9246                    cursor_point,
 9247                    style,
 9248                    cx,
 9249                )?,
 9250
 9251                None => pending_completion_container(provider_icon)
 9252                    .child(Label::new("...").size(LabelSize::Small)),
 9253            },
 9254
 9255            None => pending_completion_container(provider_icon)
 9256                .child(Label::new("...").size(LabelSize::Small)),
 9257        };
 9258
 9259        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9260            completion
 9261                .with_animation(
 9262                    "loading-completion",
 9263                    Animation::new(Duration::from_secs(2))
 9264                        .repeat()
 9265                        .with_easing(pulsating_between(0.4, 0.8)),
 9266                    |label, delta| label.opacity(delta),
 9267                )
 9268                .into_any_element()
 9269        } else {
 9270            completion.into_any_element()
 9271        };
 9272
 9273        let has_completion = self.active_edit_prediction.is_some();
 9274
 9275        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9276        Some(
 9277            h_flex()
 9278                .min_w(min_width)
 9279                .max_w(max_width)
 9280                .flex_1()
 9281                .elevation_2(cx)
 9282                .border_color(cx.theme().colors().border)
 9283                .child(
 9284                    div()
 9285                        .flex_1()
 9286                        .py_1()
 9287                        .px_2()
 9288                        .overflow_hidden()
 9289                        .child(completion),
 9290                )
 9291                .when_some(accept_keystroke, |el, accept_keystroke| {
 9292                    if !accept_keystroke.modifiers.modified() {
 9293                        return el;
 9294                    }
 9295
 9296                    el.child(
 9297                        h_flex()
 9298                            .h_full()
 9299                            .border_l_1()
 9300                            .rounded_r_lg()
 9301                            .border_color(cx.theme().colors().border)
 9302                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9303                            .gap_1()
 9304                            .py_1()
 9305                            .px_2()
 9306                            .child(
 9307                                h_flex()
 9308                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9309                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9310                                    .child(h_flex().children(ui::render_modifiers(
 9311                                        &accept_keystroke.modifiers,
 9312                                        PlatformStyle::platform(),
 9313                                        Some(if !has_completion {
 9314                                            Color::Muted
 9315                                        } else {
 9316                                            Color::Default
 9317                                        }),
 9318                                        None,
 9319                                        false,
 9320                                    ))),
 9321                            )
 9322                            .child(Label::new("Preview").into_any_element())
 9323                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9324                    )
 9325                })
 9326                .into_any(),
 9327        )
 9328    }
 9329
 9330    fn render_edit_prediction_cursor_popover_preview(
 9331        &self,
 9332        completion: &EditPredictionState,
 9333        cursor_point: Point,
 9334        style: &EditorStyle,
 9335        cx: &mut Context<Editor>,
 9336    ) -> Option<Div> {
 9337        use text::ToPoint as _;
 9338
 9339        fn render_relative_row_jump(
 9340            prefix: impl Into<String>,
 9341            current_row: u32,
 9342            target_row: u32,
 9343        ) -> Div {
 9344            let (row_diff, arrow) = if target_row < current_row {
 9345                (current_row - target_row, IconName::ArrowUp)
 9346            } else {
 9347                (target_row - current_row, IconName::ArrowDown)
 9348            };
 9349
 9350            h_flex()
 9351                .child(
 9352                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9353                        .color(Color::Muted)
 9354                        .size(LabelSize::Small),
 9355                )
 9356                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9357        }
 9358
 9359        let supports_jump = self
 9360            .edit_prediction_provider
 9361            .as_ref()
 9362            .map(|provider| provider.provider.supports_jump_to_edit())
 9363            .unwrap_or(true);
 9364
 9365        match &completion.completion {
 9366            EditPrediction::Move {
 9367                target, snapshot, ..
 9368            } => {
 9369                if !supports_jump {
 9370                    return None;
 9371                }
 9372
 9373                Some(
 9374                    h_flex()
 9375                        .px_2()
 9376                        .gap_2()
 9377                        .flex_1()
 9378                        .child(
 9379                            if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9380                                Icon::new(IconName::ZedPredictDown)
 9381                            } else {
 9382                                Icon::new(IconName::ZedPredictUp)
 9383                            },
 9384                        )
 9385                        .child(Label::new("Jump to Edit")),
 9386                )
 9387            }
 9388
 9389            EditPrediction::Edit {
 9390                edits,
 9391                edit_preview,
 9392                snapshot,
 9393                display_mode: _,
 9394            } => {
 9395                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9396
 9397                let (highlighted_edits, has_more_lines) =
 9398                    if let Some(edit_preview) = edit_preview.as_ref() {
 9399                        crate::edit_prediction_edit_text(&snapshot, &edits, edit_preview, true, cx)
 9400                            .first_line_preview()
 9401                    } else {
 9402                        crate::edit_prediction_fallback_text(&edits, cx).first_line_preview()
 9403                    };
 9404
 9405                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9406                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9407
 9408                let preview = h_flex()
 9409                    .gap_1()
 9410                    .min_w_16()
 9411                    .child(styled_text)
 9412                    .when(has_more_lines, |parent| parent.child(""));
 9413
 9414                let left = if supports_jump && first_edit_row != cursor_point.row {
 9415                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9416                        .into_any_element()
 9417                } else {
 9418                    let icon_name =
 9419                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9420                    Icon::new(icon_name).into_any_element()
 9421                };
 9422
 9423                Some(
 9424                    h_flex()
 9425                        .h_full()
 9426                        .flex_1()
 9427                        .gap_2()
 9428                        .pr_1()
 9429                        .overflow_x_hidden()
 9430                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9431                        .child(left)
 9432                        .child(preview),
 9433                )
 9434            }
 9435        }
 9436    }
 9437
 9438    pub fn render_context_menu(
 9439        &self,
 9440        style: &EditorStyle,
 9441        max_height_in_lines: u32,
 9442        window: &mut Window,
 9443        cx: &mut Context<Editor>,
 9444    ) -> Option<AnyElement> {
 9445        let menu = self.context_menu.borrow();
 9446        let menu = menu.as_ref()?;
 9447        if !menu.visible() {
 9448            return None;
 9449        };
 9450        Some(menu.render(style, max_height_in_lines, window, cx))
 9451    }
 9452
 9453    fn render_context_menu_aside(
 9454        &mut self,
 9455        max_size: Size<Pixels>,
 9456        window: &mut Window,
 9457        cx: &mut Context<Editor>,
 9458    ) -> Option<AnyElement> {
 9459        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9460            if menu.visible() {
 9461                menu.render_aside(max_size, window, cx)
 9462            } else {
 9463                None
 9464            }
 9465        })
 9466    }
 9467
 9468    fn hide_context_menu(
 9469        &mut self,
 9470        window: &mut Window,
 9471        cx: &mut Context<Self>,
 9472    ) -> Option<CodeContextMenu> {
 9473        cx.notify();
 9474        self.completion_tasks.clear();
 9475        let context_menu = self.context_menu.borrow_mut().take();
 9476        self.stale_edit_prediction_in_menu.take();
 9477        self.update_visible_edit_prediction(window, cx);
 9478        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9479            if let Some(completion_provider) = &self.completion_provider {
 9480                completion_provider.selection_changed(None, window, cx);
 9481            }
 9482        }
 9483        context_menu
 9484    }
 9485
 9486    fn show_snippet_choices(
 9487        &mut self,
 9488        choices: &Vec<String>,
 9489        selection: Range<Anchor>,
 9490        cx: &mut Context<Self>,
 9491    ) {
 9492        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9493            (Some(a), Some(b)) if a == b => a,
 9494            _ => {
 9495                log::error!("expected anchor range to have matching buffer IDs");
 9496                return;
 9497            }
 9498        };
 9499        let multi_buffer = self.buffer().read(cx);
 9500        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9501            return;
 9502        };
 9503
 9504        let id = post_inc(&mut self.next_completion_id);
 9505        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9506        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9507            CompletionsMenu::new_snippet_choices(
 9508                id,
 9509                true,
 9510                choices,
 9511                selection,
 9512                buffer,
 9513                snippet_sort_order,
 9514            ),
 9515        ));
 9516    }
 9517
 9518    pub fn insert_snippet(
 9519        &mut self,
 9520        insertion_ranges: &[Range<usize>],
 9521        snippet: Snippet,
 9522        window: &mut Window,
 9523        cx: &mut Context<Self>,
 9524    ) -> Result<()> {
 9525        struct Tabstop<T> {
 9526            is_end_tabstop: bool,
 9527            ranges: Vec<Range<T>>,
 9528            choices: Option<Vec<String>>,
 9529        }
 9530
 9531        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9532            let snippet_text: Arc<str> = snippet.text.clone().into();
 9533            let edits = insertion_ranges
 9534                .iter()
 9535                .cloned()
 9536                .map(|range| (range, snippet_text.clone()));
 9537            let autoindent_mode = AutoindentMode::Block {
 9538                original_indent_columns: Vec::new(),
 9539            };
 9540            buffer.edit(edits, Some(autoindent_mode), cx);
 9541
 9542            let snapshot = &*buffer.read(cx);
 9543            let snippet = &snippet;
 9544            snippet
 9545                .tabstops
 9546                .iter()
 9547                .map(|tabstop| {
 9548                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9549                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9550                    });
 9551                    let mut tabstop_ranges = tabstop
 9552                        .ranges
 9553                        .iter()
 9554                        .flat_map(|tabstop_range| {
 9555                            let mut delta = 0_isize;
 9556                            insertion_ranges.iter().map(move |insertion_range| {
 9557                                let insertion_start = insertion_range.start as isize + delta;
 9558                                delta +=
 9559                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9560
 9561                                let start = ((insertion_start + tabstop_range.start) as usize)
 9562                                    .min(snapshot.len());
 9563                                let end = ((insertion_start + tabstop_range.end) as usize)
 9564                                    .min(snapshot.len());
 9565                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9566                            })
 9567                        })
 9568                        .collect::<Vec<_>>();
 9569                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9570
 9571                    Tabstop {
 9572                        is_end_tabstop,
 9573                        ranges: tabstop_ranges,
 9574                        choices: tabstop.choices.clone(),
 9575                    }
 9576                })
 9577                .collect::<Vec<_>>()
 9578        });
 9579        if let Some(tabstop) = tabstops.first() {
 9580            self.change_selections(Default::default(), window, cx, |s| {
 9581                // Reverse order so that the first range is the newest created selection.
 9582                // Completions will use it and autoscroll will prioritize it.
 9583                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9584            });
 9585
 9586            if let Some(choices) = &tabstop.choices {
 9587                if let Some(selection) = tabstop.ranges.first() {
 9588                    self.show_snippet_choices(choices, selection.clone(), cx)
 9589                }
 9590            }
 9591
 9592            // If we're already at the last tabstop and it's at the end of the snippet,
 9593            // we're done, we don't need to keep the state around.
 9594            if !tabstop.is_end_tabstop {
 9595                let choices = tabstops
 9596                    .iter()
 9597                    .map(|tabstop| tabstop.choices.clone())
 9598                    .collect();
 9599
 9600                let ranges = tabstops
 9601                    .into_iter()
 9602                    .map(|tabstop| tabstop.ranges)
 9603                    .collect::<Vec<_>>();
 9604
 9605                self.snippet_stack.push(SnippetState {
 9606                    active_index: 0,
 9607                    ranges,
 9608                    choices,
 9609                });
 9610            }
 9611
 9612            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9613            if self.autoclose_regions.is_empty() {
 9614                let snapshot = self.buffer.read(cx).snapshot(cx);
 9615                let mut all_selections = self.selections.all::<Point>(cx);
 9616                for selection in &mut all_selections {
 9617                    let selection_head = selection.head();
 9618                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9619                        continue;
 9620                    };
 9621
 9622                    let mut bracket_pair = None;
 9623                    let max_lookup_length = scope
 9624                        .brackets()
 9625                        .map(|(pair, _)| {
 9626                            pair.start
 9627                                .as_str()
 9628                                .chars()
 9629                                .count()
 9630                                .max(pair.end.as_str().chars().count())
 9631                        })
 9632                        .max();
 9633                    if let Some(max_lookup_length) = max_lookup_length {
 9634                        let next_text = snapshot
 9635                            .chars_at(selection_head)
 9636                            .take(max_lookup_length)
 9637                            .collect::<String>();
 9638                        let prev_text = snapshot
 9639                            .reversed_chars_at(selection_head)
 9640                            .take(max_lookup_length)
 9641                            .collect::<String>();
 9642
 9643                        for (pair, enabled) in scope.brackets() {
 9644                            if enabled
 9645                                && pair.close
 9646                                && prev_text.starts_with(pair.start.as_str())
 9647                                && next_text.starts_with(pair.end.as_str())
 9648                            {
 9649                                bracket_pair = Some(pair.clone());
 9650                                break;
 9651                            }
 9652                        }
 9653                    }
 9654
 9655                    if let Some(pair) = bracket_pair {
 9656                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9657                        let autoclose_enabled =
 9658                            self.use_autoclose && snapshot_settings.use_autoclose;
 9659                        if autoclose_enabled {
 9660                            let start = snapshot.anchor_after(selection_head);
 9661                            let end = snapshot.anchor_after(selection_head);
 9662                            self.autoclose_regions.push(AutocloseRegion {
 9663                                selection_id: selection.id,
 9664                                range: start..end,
 9665                                pair,
 9666                            });
 9667                        }
 9668                    }
 9669                }
 9670            }
 9671        }
 9672        Ok(())
 9673    }
 9674
 9675    pub fn move_to_next_snippet_tabstop(
 9676        &mut self,
 9677        window: &mut Window,
 9678        cx: &mut Context<Self>,
 9679    ) -> bool {
 9680        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9681    }
 9682
 9683    pub fn move_to_prev_snippet_tabstop(
 9684        &mut self,
 9685        window: &mut Window,
 9686        cx: &mut Context<Self>,
 9687    ) -> bool {
 9688        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9689    }
 9690
 9691    pub fn move_to_snippet_tabstop(
 9692        &mut self,
 9693        bias: Bias,
 9694        window: &mut Window,
 9695        cx: &mut Context<Self>,
 9696    ) -> bool {
 9697        if let Some(mut snippet) = self.snippet_stack.pop() {
 9698            match bias {
 9699                Bias::Left => {
 9700                    if snippet.active_index > 0 {
 9701                        snippet.active_index -= 1;
 9702                    } else {
 9703                        self.snippet_stack.push(snippet);
 9704                        return false;
 9705                    }
 9706                }
 9707                Bias::Right => {
 9708                    if snippet.active_index + 1 < snippet.ranges.len() {
 9709                        snippet.active_index += 1;
 9710                    } else {
 9711                        self.snippet_stack.push(snippet);
 9712                        return false;
 9713                    }
 9714                }
 9715            }
 9716            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9717                self.change_selections(Default::default(), window, cx, |s| {
 9718                    // Reverse order so that the first range is the newest created selection.
 9719                    // Completions will use it and autoscroll will prioritize it.
 9720                    s.select_ranges(current_ranges.iter().rev().cloned())
 9721                });
 9722
 9723                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9724                    if let Some(selection) = current_ranges.first() {
 9725                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9726                    }
 9727                }
 9728
 9729                // If snippet state is not at the last tabstop, push it back on the stack
 9730                if snippet.active_index + 1 < snippet.ranges.len() {
 9731                    self.snippet_stack.push(snippet);
 9732                }
 9733                return true;
 9734            }
 9735        }
 9736
 9737        false
 9738    }
 9739
 9740    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9741        self.transact(window, cx, |this, window, cx| {
 9742            this.select_all(&SelectAll, window, cx);
 9743            this.insert("", window, cx);
 9744        });
 9745    }
 9746
 9747    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9749        self.transact(window, cx, |this, window, cx| {
 9750            this.select_autoclose_pair(window, cx);
 9751            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9752            if !this.linked_edit_ranges.is_empty() {
 9753                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9754                let snapshot = this.buffer.read(cx).snapshot(cx);
 9755
 9756                for selection in selections.iter() {
 9757                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9758                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9759                    if selection_start.buffer_id != selection_end.buffer_id {
 9760                        continue;
 9761                    }
 9762                    if let Some(ranges) =
 9763                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9764                    {
 9765                        for (buffer, entries) in ranges {
 9766                            linked_ranges.entry(buffer).or_default().extend(entries);
 9767                        }
 9768                    }
 9769                }
 9770            }
 9771
 9772            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9773            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9774            for selection in &mut selections {
 9775                if selection.is_empty() {
 9776                    let old_head = selection.head();
 9777                    let mut new_head =
 9778                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9779                            .to_point(&display_map);
 9780                    if let Some((buffer, line_buffer_range)) = display_map
 9781                        .buffer_snapshot
 9782                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9783                    {
 9784                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9785                        let indent_len = match indent_size.kind {
 9786                            IndentKind::Space => {
 9787                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9788                            }
 9789                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9790                        };
 9791                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9792                            let indent_len = indent_len.get();
 9793                            new_head = cmp::min(
 9794                                new_head,
 9795                                MultiBufferPoint::new(
 9796                                    old_head.row,
 9797                                    ((old_head.column - 1) / indent_len) * indent_len,
 9798                                ),
 9799                            );
 9800                        }
 9801                    }
 9802
 9803                    selection.set_head(new_head, SelectionGoal::None);
 9804                }
 9805            }
 9806
 9807            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9808            this.insert("", window, cx);
 9809            let empty_str: Arc<str> = Arc::from("");
 9810            for (buffer, edits) in linked_ranges {
 9811                let snapshot = buffer.read(cx).snapshot();
 9812                use text::ToPoint as TP;
 9813
 9814                let edits = edits
 9815                    .into_iter()
 9816                    .map(|range| {
 9817                        let end_point = TP::to_point(&range.end, &snapshot);
 9818                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9819
 9820                        if end_point == start_point {
 9821                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9822                                .saturating_sub(1);
 9823                            start_point =
 9824                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9825                        };
 9826
 9827                        (start_point..end_point, empty_str.clone())
 9828                    })
 9829                    .sorted_by_key(|(range, _)| range.start)
 9830                    .collect::<Vec<_>>();
 9831                buffer.update(cx, |this, cx| {
 9832                    this.edit(edits, None, cx);
 9833                })
 9834            }
 9835            this.refresh_edit_prediction(true, false, window, cx);
 9836            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9837        });
 9838    }
 9839
 9840    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9841        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9842        self.transact(window, cx, |this, window, cx| {
 9843            this.change_selections(Default::default(), window, cx, |s| {
 9844                s.move_with(|map, selection| {
 9845                    if selection.is_empty() {
 9846                        let cursor = movement::right(map, selection.head());
 9847                        selection.end = cursor;
 9848                        selection.reversed = true;
 9849                        selection.goal = SelectionGoal::None;
 9850                    }
 9851                })
 9852            });
 9853            this.insert("", window, cx);
 9854            this.refresh_edit_prediction(true, false, window, cx);
 9855        });
 9856    }
 9857
 9858    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9859        if self.mode.is_single_line() {
 9860            cx.propagate();
 9861            return;
 9862        }
 9863
 9864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9865        if self.move_to_prev_snippet_tabstop(window, cx) {
 9866            return;
 9867        }
 9868        self.outdent(&Outdent, window, cx);
 9869    }
 9870
 9871    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9872        if self.mode.is_single_line() {
 9873            cx.propagate();
 9874            return;
 9875        }
 9876
 9877        if self.move_to_next_snippet_tabstop(window, cx) {
 9878            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9879            return;
 9880        }
 9881        if self.read_only(cx) {
 9882            return;
 9883        }
 9884        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9885        let mut selections = self.selections.all_adjusted(cx);
 9886        let buffer = self.buffer.read(cx);
 9887        let snapshot = buffer.snapshot(cx);
 9888        let rows_iter = selections.iter().map(|s| s.head().row);
 9889        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9890
 9891        let has_some_cursor_in_whitespace = selections
 9892            .iter()
 9893            .filter(|selection| selection.is_empty())
 9894            .any(|selection| {
 9895                let cursor = selection.head();
 9896                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9897                cursor.column < current_indent.len
 9898            });
 9899
 9900        let mut edits = Vec::new();
 9901        let mut prev_edited_row = 0;
 9902        let mut row_delta = 0;
 9903        for selection in &mut selections {
 9904            if selection.start.row != prev_edited_row {
 9905                row_delta = 0;
 9906            }
 9907            prev_edited_row = selection.end.row;
 9908
 9909            // If the selection is non-empty, then increase the indentation of the selected lines.
 9910            if !selection.is_empty() {
 9911                row_delta =
 9912                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9913                continue;
 9914            }
 9915
 9916            let cursor = selection.head();
 9917            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9918            if let Some(suggested_indent) =
 9919                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9920            {
 9921                // Don't do anything if already at suggested indent
 9922                // and there is any other cursor which is not
 9923                if has_some_cursor_in_whitespace
 9924                    && cursor.column == current_indent.len
 9925                    && current_indent.len == suggested_indent.len
 9926                {
 9927                    continue;
 9928                }
 9929
 9930                // Adjust line and move cursor to suggested indent
 9931                // if cursor is not at suggested indent
 9932                if cursor.column < suggested_indent.len
 9933                    && cursor.column <= current_indent.len
 9934                    && current_indent.len <= suggested_indent.len
 9935                {
 9936                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9937                    selection.end = selection.start;
 9938                    if row_delta == 0 {
 9939                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9940                            cursor.row,
 9941                            current_indent,
 9942                            suggested_indent,
 9943                        ));
 9944                        row_delta = suggested_indent.len - current_indent.len;
 9945                    }
 9946                    continue;
 9947                }
 9948
 9949                // If current indent is more than suggested indent
 9950                // only move cursor to current indent and skip indent
 9951                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9952                    selection.start = Point::new(cursor.row, current_indent.len);
 9953                    selection.end = selection.start;
 9954                    continue;
 9955                }
 9956            }
 9957
 9958            // Otherwise, insert a hard or soft tab.
 9959            let settings = buffer.language_settings_at(cursor, cx);
 9960            let tab_size = if settings.hard_tabs {
 9961                IndentSize::tab()
 9962            } else {
 9963                let tab_size = settings.tab_size.get();
 9964                let indent_remainder = snapshot
 9965                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9966                    .flat_map(str::chars)
 9967                    .fold(row_delta % tab_size, |counter: u32, c| {
 9968                        if c == '\t' {
 9969                            0
 9970                        } else {
 9971                            (counter + 1) % tab_size
 9972                        }
 9973                    });
 9974
 9975                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9976                IndentSize::spaces(chars_to_next_tab_stop)
 9977            };
 9978            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9979            selection.end = selection.start;
 9980            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9981            row_delta += tab_size.len;
 9982        }
 9983
 9984        self.transact(window, cx, |this, window, cx| {
 9985            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9986            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9987            this.refresh_edit_prediction(true, false, window, cx);
 9988        });
 9989    }
 9990
 9991    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9992        if self.read_only(cx) {
 9993            return;
 9994        }
 9995        if self.mode.is_single_line() {
 9996            cx.propagate();
 9997            return;
 9998        }
 9999
10000        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10001        let mut selections = self.selections.all::<Point>(cx);
10002        let mut prev_edited_row = 0;
10003        let mut row_delta = 0;
10004        let mut edits = Vec::new();
10005        let buffer = self.buffer.read(cx);
10006        let snapshot = buffer.snapshot(cx);
10007        for selection in &mut selections {
10008            if selection.start.row != prev_edited_row {
10009                row_delta = 0;
10010            }
10011            prev_edited_row = selection.end.row;
10012
10013            row_delta =
10014                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10015        }
10016
10017        self.transact(window, cx, |this, window, cx| {
10018            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10019            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10020        });
10021    }
10022
10023    fn indent_selection(
10024        buffer: &MultiBuffer,
10025        snapshot: &MultiBufferSnapshot,
10026        selection: &mut Selection<Point>,
10027        edits: &mut Vec<(Range<Point>, String)>,
10028        delta_for_start_row: u32,
10029        cx: &App,
10030    ) -> u32 {
10031        let settings = buffer.language_settings_at(selection.start, cx);
10032        let tab_size = settings.tab_size.get();
10033        let indent_kind = if settings.hard_tabs {
10034            IndentKind::Tab
10035        } else {
10036            IndentKind::Space
10037        };
10038        let mut start_row = selection.start.row;
10039        let mut end_row = selection.end.row + 1;
10040
10041        // If a selection ends at the beginning of a line, don't indent
10042        // that last line.
10043        if selection.end.column == 0 && selection.end.row > selection.start.row {
10044            end_row -= 1;
10045        }
10046
10047        // Avoid re-indenting a row that has already been indented by a
10048        // previous selection, but still update this selection's column
10049        // to reflect that indentation.
10050        if delta_for_start_row > 0 {
10051            start_row += 1;
10052            selection.start.column += delta_for_start_row;
10053            if selection.end.row == selection.start.row {
10054                selection.end.column += delta_for_start_row;
10055            }
10056        }
10057
10058        let mut delta_for_end_row = 0;
10059        let has_multiple_rows = start_row + 1 != end_row;
10060        for row in start_row..end_row {
10061            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10062            let indent_delta = match (current_indent.kind, indent_kind) {
10063                (IndentKind::Space, IndentKind::Space) => {
10064                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10065                    IndentSize::spaces(columns_to_next_tab_stop)
10066                }
10067                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10068                (_, IndentKind::Tab) => IndentSize::tab(),
10069            };
10070
10071            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10072                0
10073            } else {
10074                selection.start.column
10075            };
10076            let row_start = Point::new(row, start);
10077            edits.push((
10078                row_start..row_start,
10079                indent_delta.chars().collect::<String>(),
10080            ));
10081
10082            // Update this selection's endpoints to reflect the indentation.
10083            if row == selection.start.row {
10084                selection.start.column += indent_delta.len;
10085            }
10086            if row == selection.end.row {
10087                selection.end.column += indent_delta.len;
10088                delta_for_end_row = indent_delta.len;
10089            }
10090        }
10091
10092        if selection.start.row == selection.end.row {
10093            delta_for_start_row + delta_for_end_row
10094        } else {
10095            delta_for_end_row
10096        }
10097    }
10098
10099    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10100        if self.read_only(cx) {
10101            return;
10102        }
10103        if self.mode.is_single_line() {
10104            cx.propagate();
10105            return;
10106        }
10107
10108        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10109        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10110        let selections = self.selections.all::<Point>(cx);
10111        let mut deletion_ranges = Vec::new();
10112        let mut last_outdent = None;
10113        {
10114            let buffer = self.buffer.read(cx);
10115            let snapshot = buffer.snapshot(cx);
10116            for selection in &selections {
10117                let settings = buffer.language_settings_at(selection.start, cx);
10118                let tab_size = settings.tab_size.get();
10119                let mut rows = selection.spanned_rows(false, &display_map);
10120
10121                // Avoid re-outdenting a row that has already been outdented by a
10122                // previous selection.
10123                if let Some(last_row) = last_outdent {
10124                    if last_row == rows.start {
10125                        rows.start = rows.start.next_row();
10126                    }
10127                }
10128                let has_multiple_rows = rows.len() > 1;
10129                for row in rows.iter_rows() {
10130                    let indent_size = snapshot.indent_size_for_line(row);
10131                    if indent_size.len > 0 {
10132                        let deletion_len = match indent_size.kind {
10133                            IndentKind::Space => {
10134                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10135                                if columns_to_prev_tab_stop == 0 {
10136                                    tab_size
10137                                } else {
10138                                    columns_to_prev_tab_stop
10139                                }
10140                            }
10141                            IndentKind::Tab => 1,
10142                        };
10143                        let start = if has_multiple_rows
10144                            || deletion_len > selection.start.column
10145                            || indent_size.len < selection.start.column
10146                        {
10147                            0
10148                        } else {
10149                            selection.start.column - deletion_len
10150                        };
10151                        deletion_ranges.push(
10152                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10153                        );
10154                        last_outdent = Some(row);
10155                    }
10156                }
10157            }
10158        }
10159
10160        self.transact(window, cx, |this, window, cx| {
10161            this.buffer.update(cx, |buffer, cx| {
10162                let empty_str: Arc<str> = Arc::default();
10163                buffer.edit(
10164                    deletion_ranges
10165                        .into_iter()
10166                        .map(|range| (range, empty_str.clone())),
10167                    None,
10168                    cx,
10169                );
10170            });
10171            let selections = this.selections.all::<usize>(cx);
10172            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10173        });
10174    }
10175
10176    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10177        if self.read_only(cx) {
10178            return;
10179        }
10180        if self.mode.is_single_line() {
10181            cx.propagate();
10182            return;
10183        }
10184
10185        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10186        let selections = self
10187            .selections
10188            .all::<usize>(cx)
10189            .into_iter()
10190            .map(|s| s.range());
10191
10192        self.transact(window, cx, |this, window, cx| {
10193            this.buffer.update(cx, |buffer, cx| {
10194                buffer.autoindent_ranges(selections, cx);
10195            });
10196            let selections = this.selections.all::<usize>(cx);
10197            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10198        });
10199    }
10200
10201    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10202        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10203        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10204        let selections = self.selections.all::<Point>(cx);
10205
10206        let mut new_cursors = Vec::new();
10207        let mut edit_ranges = Vec::new();
10208        let mut selections = selections.iter().peekable();
10209        while let Some(selection) = selections.next() {
10210            let mut rows = selection.spanned_rows(false, &display_map);
10211            let goal_display_column = selection.head().to_display_point(&display_map).column();
10212
10213            // Accumulate contiguous regions of rows that we want to delete.
10214            while let Some(next_selection) = selections.peek() {
10215                let next_rows = next_selection.spanned_rows(false, &display_map);
10216                if next_rows.start <= rows.end {
10217                    rows.end = next_rows.end;
10218                    selections.next().unwrap();
10219                } else {
10220                    break;
10221                }
10222            }
10223
10224            let buffer = &display_map.buffer_snapshot;
10225            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10226            let edit_end;
10227            let cursor_buffer_row;
10228            if buffer.max_point().row >= rows.end.0 {
10229                // If there's a line after the range, delete the \n from the end of the row range
10230                // and position the cursor on the next line.
10231                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10232                cursor_buffer_row = rows.end;
10233            } else {
10234                // If there isn't a line after the range, delete the \n from the line before the
10235                // start of the row range and position the cursor there.
10236                edit_start = edit_start.saturating_sub(1);
10237                edit_end = buffer.len();
10238                cursor_buffer_row = rows.start.previous_row();
10239            }
10240
10241            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10242            *cursor.column_mut() =
10243                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10244
10245            new_cursors.push((
10246                selection.id,
10247                buffer.anchor_after(cursor.to_point(&display_map)),
10248            ));
10249            edit_ranges.push(edit_start..edit_end);
10250        }
10251
10252        self.transact(window, cx, |this, window, cx| {
10253            let buffer = this.buffer.update(cx, |buffer, cx| {
10254                let empty_str: Arc<str> = Arc::default();
10255                buffer.edit(
10256                    edit_ranges
10257                        .into_iter()
10258                        .map(|range| (range, empty_str.clone())),
10259                    None,
10260                    cx,
10261                );
10262                buffer.snapshot(cx)
10263            });
10264            let new_selections = new_cursors
10265                .into_iter()
10266                .map(|(id, cursor)| {
10267                    let cursor = cursor.to_point(&buffer);
10268                    Selection {
10269                        id,
10270                        start: cursor,
10271                        end: cursor,
10272                        reversed: false,
10273                        goal: SelectionGoal::None,
10274                    }
10275                })
10276                .collect();
10277
10278            this.change_selections(Default::default(), window, cx, |s| {
10279                s.select(new_selections);
10280            });
10281        });
10282    }
10283
10284    pub fn join_lines_impl(
10285        &mut self,
10286        insert_whitespace: bool,
10287        window: &mut Window,
10288        cx: &mut Context<Self>,
10289    ) {
10290        if self.read_only(cx) {
10291            return;
10292        }
10293        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10294        for selection in self.selections.all::<Point>(cx) {
10295            let start = MultiBufferRow(selection.start.row);
10296            // Treat single line selections as if they include the next line. Otherwise this action
10297            // would do nothing for single line selections individual cursors.
10298            let end = if selection.start.row == selection.end.row {
10299                MultiBufferRow(selection.start.row + 1)
10300            } else {
10301                MultiBufferRow(selection.end.row)
10302            };
10303
10304            if let Some(last_row_range) = row_ranges.last_mut() {
10305                if start <= last_row_range.end {
10306                    last_row_range.end = end;
10307                    continue;
10308                }
10309            }
10310            row_ranges.push(start..end);
10311        }
10312
10313        let snapshot = self.buffer.read(cx).snapshot(cx);
10314        let mut cursor_positions = Vec::new();
10315        for row_range in &row_ranges {
10316            let anchor = snapshot.anchor_before(Point::new(
10317                row_range.end.previous_row().0,
10318                snapshot.line_len(row_range.end.previous_row()),
10319            ));
10320            cursor_positions.push(anchor..anchor);
10321        }
10322
10323        self.transact(window, cx, |this, window, cx| {
10324            for row_range in row_ranges.into_iter().rev() {
10325                for row in row_range.iter_rows().rev() {
10326                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10327                    let next_line_row = row.next_row();
10328                    let indent = snapshot.indent_size_for_line(next_line_row);
10329                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10330
10331                    let replace =
10332                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10333                            " "
10334                        } else {
10335                            ""
10336                        };
10337
10338                    this.buffer.update(cx, |buffer, cx| {
10339                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10340                    });
10341                }
10342            }
10343
10344            this.change_selections(Default::default(), window, cx, |s| {
10345                s.select_anchor_ranges(cursor_positions)
10346            });
10347        });
10348    }
10349
10350    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10352        self.join_lines_impl(true, window, cx);
10353    }
10354
10355    pub fn sort_lines_case_sensitive(
10356        &mut self,
10357        _: &SortLinesCaseSensitive,
10358        window: &mut Window,
10359        cx: &mut Context<Self>,
10360    ) {
10361        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10362    }
10363
10364    pub fn sort_lines_by_length(
10365        &mut self,
10366        _: &SortLinesByLength,
10367        window: &mut Window,
10368        cx: &mut Context<Self>,
10369    ) {
10370        self.manipulate_immutable_lines(window, cx, |lines| {
10371            lines.sort_by_key(|&line| line.chars().count())
10372        })
10373    }
10374
10375    pub fn sort_lines_case_insensitive(
10376        &mut self,
10377        _: &SortLinesCaseInsensitive,
10378        window: &mut Window,
10379        cx: &mut Context<Self>,
10380    ) {
10381        self.manipulate_immutable_lines(window, cx, |lines| {
10382            lines.sort_by_key(|line| line.to_lowercase())
10383        })
10384    }
10385
10386    pub fn unique_lines_case_insensitive(
10387        &mut self,
10388        _: &UniqueLinesCaseInsensitive,
10389        window: &mut Window,
10390        cx: &mut Context<Self>,
10391    ) {
10392        self.manipulate_immutable_lines(window, cx, |lines| {
10393            let mut seen = HashSet::default();
10394            lines.retain(|line| seen.insert(line.to_lowercase()));
10395        })
10396    }
10397
10398    pub fn unique_lines_case_sensitive(
10399        &mut self,
10400        _: &UniqueLinesCaseSensitive,
10401        window: &mut Window,
10402        cx: &mut Context<Self>,
10403    ) {
10404        self.manipulate_immutable_lines(window, cx, |lines| {
10405            let mut seen = HashSet::default();
10406            lines.retain(|line| seen.insert(*line));
10407        })
10408    }
10409
10410    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10411        let Some(project) = self.project.clone() else {
10412            return;
10413        };
10414        self.reload(project, window, cx)
10415            .detach_and_notify_err(window, cx);
10416    }
10417
10418    pub fn restore_file(
10419        &mut self,
10420        _: &::git::RestoreFile,
10421        window: &mut Window,
10422        cx: &mut Context<Self>,
10423    ) {
10424        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10425        let mut buffer_ids = HashSet::default();
10426        let snapshot = self.buffer().read(cx).snapshot(cx);
10427        for selection in self.selections.all::<usize>(cx) {
10428            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10429        }
10430
10431        let buffer = self.buffer().read(cx);
10432        let ranges = buffer_ids
10433            .into_iter()
10434            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10435            .collect::<Vec<_>>();
10436
10437        self.restore_hunks_in_ranges(ranges, window, cx);
10438    }
10439
10440    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10441        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10442        let selections = self
10443            .selections
10444            .all(cx)
10445            .into_iter()
10446            .map(|s| s.range())
10447            .collect();
10448        self.restore_hunks_in_ranges(selections, window, cx);
10449    }
10450
10451    pub fn restore_hunks_in_ranges(
10452        &mut self,
10453        ranges: Vec<Range<Point>>,
10454        window: &mut Window,
10455        cx: &mut Context<Editor>,
10456    ) {
10457        let mut revert_changes = HashMap::default();
10458        let chunk_by = self
10459            .snapshot(window, cx)
10460            .hunks_for_ranges(ranges)
10461            .into_iter()
10462            .chunk_by(|hunk| hunk.buffer_id);
10463        for (buffer_id, hunks) in &chunk_by {
10464            let hunks = hunks.collect::<Vec<_>>();
10465            for hunk in &hunks {
10466                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10467            }
10468            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10469        }
10470        drop(chunk_by);
10471        if !revert_changes.is_empty() {
10472            self.transact(window, cx, |editor, window, cx| {
10473                editor.restore(revert_changes, window, cx);
10474            });
10475        }
10476    }
10477
10478    pub fn open_active_item_in_terminal(
10479        &mut self,
10480        _: &OpenInTerminal,
10481        window: &mut Window,
10482        cx: &mut Context<Self>,
10483    ) {
10484        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10485            let project_path = buffer.read(cx).project_path(cx)?;
10486            let project = self.project.as_ref()?.read(cx);
10487            let entry = project.entry_for_path(&project_path, cx)?;
10488            let parent = match &entry.canonical_path {
10489                Some(canonical_path) => canonical_path.to_path_buf(),
10490                None => project.absolute_path(&project_path, cx)?,
10491            }
10492            .parent()?
10493            .to_path_buf();
10494            Some(parent)
10495        }) {
10496            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10497        }
10498    }
10499
10500    fn set_breakpoint_context_menu(
10501        &mut self,
10502        display_row: DisplayRow,
10503        position: Option<Anchor>,
10504        clicked_point: gpui::Point<Pixels>,
10505        window: &mut Window,
10506        cx: &mut Context<Self>,
10507    ) {
10508        let source = self
10509            .buffer
10510            .read(cx)
10511            .snapshot(cx)
10512            .anchor_before(Point::new(display_row.0, 0u32));
10513
10514        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10515
10516        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10517            self,
10518            source,
10519            clicked_point,
10520            context_menu,
10521            window,
10522            cx,
10523        );
10524    }
10525
10526    fn add_edit_breakpoint_block(
10527        &mut self,
10528        anchor: Anchor,
10529        breakpoint: &Breakpoint,
10530        edit_action: BreakpointPromptEditAction,
10531        window: &mut Window,
10532        cx: &mut Context<Self>,
10533    ) {
10534        let weak_editor = cx.weak_entity();
10535        let bp_prompt = cx.new(|cx| {
10536            BreakpointPromptEditor::new(
10537                weak_editor,
10538                anchor,
10539                breakpoint.clone(),
10540                edit_action,
10541                window,
10542                cx,
10543            )
10544        });
10545
10546        let height = bp_prompt.update(cx, |this, cx| {
10547            this.prompt
10548                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10549        });
10550        let cloned_prompt = bp_prompt.clone();
10551        let blocks = vec![BlockProperties {
10552            style: BlockStyle::Sticky,
10553            placement: BlockPlacement::Above(anchor),
10554            height: Some(height),
10555            render: Arc::new(move |cx| {
10556                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10557                cloned_prompt.clone().into_any_element()
10558            }),
10559            priority: 0,
10560        }];
10561
10562        let focus_handle = bp_prompt.focus_handle(cx);
10563        window.focus(&focus_handle);
10564
10565        let block_ids = self.insert_blocks(blocks, None, cx);
10566        bp_prompt.update(cx, |prompt, _| {
10567            prompt.add_block_ids(block_ids);
10568        });
10569    }
10570
10571    pub(crate) fn breakpoint_at_row(
10572        &self,
10573        row: u32,
10574        window: &mut Window,
10575        cx: &mut Context<Self>,
10576    ) -> Option<(Anchor, Breakpoint)> {
10577        let snapshot = self.snapshot(window, cx);
10578        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10579
10580        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10581    }
10582
10583    pub(crate) fn breakpoint_at_anchor(
10584        &self,
10585        breakpoint_position: Anchor,
10586        snapshot: &EditorSnapshot,
10587        cx: &mut Context<Self>,
10588    ) -> Option<(Anchor, Breakpoint)> {
10589        let project = self.project.clone()?;
10590
10591        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10592            snapshot
10593                .buffer_snapshot
10594                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10595        })?;
10596
10597        let enclosing_excerpt = breakpoint_position.excerpt_id;
10598        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10599        let buffer_snapshot = buffer.read(cx).snapshot();
10600
10601        let row = buffer_snapshot
10602            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10603            .row;
10604
10605        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10606        let anchor_end = snapshot
10607            .buffer_snapshot
10608            .anchor_after(Point::new(row, line_len));
10609
10610        let bp = self
10611            .breakpoint_store
10612            .as_ref()?
10613            .read_with(cx, |breakpoint_store, cx| {
10614                breakpoint_store
10615                    .breakpoints(
10616                        &buffer,
10617                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10618                        &buffer_snapshot,
10619                        cx,
10620                    )
10621                    .next()
10622                    .and_then(|(bp, _)| {
10623                        let breakpoint_row = buffer_snapshot
10624                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10625                            .row;
10626
10627                        if breakpoint_row == row {
10628                            snapshot
10629                                .buffer_snapshot
10630                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10631                                .map(|position| (position, bp.bp.clone()))
10632                        } else {
10633                            None
10634                        }
10635                    })
10636            });
10637        bp
10638    }
10639
10640    pub fn edit_log_breakpoint(
10641        &mut self,
10642        _: &EditLogBreakpoint,
10643        window: &mut Window,
10644        cx: &mut Context<Self>,
10645    ) {
10646        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10647            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10648                message: None,
10649                state: BreakpointState::Enabled,
10650                condition: None,
10651                hit_condition: None,
10652            });
10653
10654            self.add_edit_breakpoint_block(
10655                anchor,
10656                &breakpoint,
10657                BreakpointPromptEditAction::Log,
10658                window,
10659                cx,
10660            );
10661        }
10662    }
10663
10664    fn breakpoints_at_cursors(
10665        &self,
10666        window: &mut Window,
10667        cx: &mut Context<Self>,
10668    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10669        let snapshot = self.snapshot(window, cx);
10670        let cursors = self
10671            .selections
10672            .disjoint_anchors()
10673            .into_iter()
10674            .map(|selection| {
10675                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10676
10677                let breakpoint_position = self
10678                    .breakpoint_at_row(cursor_position.row, window, cx)
10679                    .map(|bp| bp.0)
10680                    .unwrap_or_else(|| {
10681                        snapshot
10682                            .display_snapshot
10683                            .buffer_snapshot
10684                            .anchor_after(Point::new(cursor_position.row, 0))
10685                    });
10686
10687                let breakpoint = self
10688                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10689                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10690
10691                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10692            })
10693            // 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.
10694            .collect::<HashMap<Anchor, _>>();
10695
10696        cursors.into_iter().collect()
10697    }
10698
10699    pub fn enable_breakpoint(
10700        &mut self,
10701        _: &crate::actions::EnableBreakpoint,
10702        window: &mut Window,
10703        cx: &mut Context<Self>,
10704    ) {
10705        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10706            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10707                continue;
10708            };
10709            self.edit_breakpoint_at_anchor(
10710                anchor,
10711                breakpoint,
10712                BreakpointEditAction::InvertState,
10713                cx,
10714            );
10715        }
10716    }
10717
10718    pub fn disable_breakpoint(
10719        &mut self,
10720        _: &crate::actions::DisableBreakpoint,
10721        window: &mut Window,
10722        cx: &mut Context<Self>,
10723    ) {
10724        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10725            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10726                continue;
10727            };
10728            self.edit_breakpoint_at_anchor(
10729                anchor,
10730                breakpoint,
10731                BreakpointEditAction::InvertState,
10732                cx,
10733            );
10734        }
10735    }
10736
10737    pub fn toggle_breakpoint(
10738        &mut self,
10739        _: &crate::actions::ToggleBreakpoint,
10740        window: &mut Window,
10741        cx: &mut Context<Self>,
10742    ) {
10743        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10744            if let Some(breakpoint) = breakpoint {
10745                self.edit_breakpoint_at_anchor(
10746                    anchor,
10747                    breakpoint,
10748                    BreakpointEditAction::Toggle,
10749                    cx,
10750                );
10751            } else {
10752                self.edit_breakpoint_at_anchor(
10753                    anchor,
10754                    Breakpoint::new_standard(),
10755                    BreakpointEditAction::Toggle,
10756                    cx,
10757                );
10758            }
10759        }
10760    }
10761
10762    pub fn edit_breakpoint_at_anchor(
10763        &mut self,
10764        breakpoint_position: Anchor,
10765        breakpoint: Breakpoint,
10766        edit_action: BreakpointEditAction,
10767        cx: &mut Context<Self>,
10768    ) {
10769        let Some(breakpoint_store) = &self.breakpoint_store else {
10770            return;
10771        };
10772
10773        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10774            if breakpoint_position == Anchor::min() {
10775                self.buffer()
10776                    .read(cx)
10777                    .excerpt_buffer_ids()
10778                    .into_iter()
10779                    .next()
10780            } else {
10781                None
10782            }
10783        }) else {
10784            return;
10785        };
10786
10787        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10788            return;
10789        };
10790
10791        breakpoint_store.update(cx, |breakpoint_store, cx| {
10792            breakpoint_store.toggle_breakpoint(
10793                buffer,
10794                BreakpointWithPosition {
10795                    position: breakpoint_position.text_anchor,
10796                    bp: breakpoint,
10797                },
10798                edit_action,
10799                cx,
10800            );
10801        });
10802
10803        cx.notify();
10804    }
10805
10806    #[cfg(any(test, feature = "test-support"))]
10807    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10808        self.breakpoint_store.clone()
10809    }
10810
10811    pub fn prepare_restore_change(
10812        &self,
10813        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10814        hunk: &MultiBufferDiffHunk,
10815        cx: &mut App,
10816    ) -> Option<()> {
10817        if hunk.is_created_file() {
10818            return None;
10819        }
10820        let buffer = self.buffer.read(cx);
10821        let diff = buffer.diff_for(hunk.buffer_id)?;
10822        let buffer = buffer.buffer(hunk.buffer_id)?;
10823        let buffer = buffer.read(cx);
10824        let original_text = diff
10825            .read(cx)
10826            .base_text()
10827            .as_rope()
10828            .slice(hunk.diff_base_byte_range.clone());
10829        let buffer_snapshot = buffer.snapshot();
10830        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10831        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10832            probe
10833                .0
10834                .start
10835                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10836                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10837        }) {
10838            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10839            Some(())
10840        } else {
10841            None
10842        }
10843    }
10844
10845    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10846        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10847    }
10848
10849    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10850        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10851    }
10852
10853    fn manipulate_lines<M>(
10854        &mut self,
10855        window: &mut Window,
10856        cx: &mut Context<Self>,
10857        mut manipulate: M,
10858    ) where
10859        M: FnMut(&str) -> LineManipulationResult,
10860    {
10861        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10862
10863        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10864        let buffer = self.buffer.read(cx).snapshot(cx);
10865
10866        let mut edits = Vec::new();
10867
10868        let selections = self.selections.all::<Point>(cx);
10869        let mut selections = selections.iter().peekable();
10870        let mut contiguous_row_selections = Vec::new();
10871        let mut new_selections = Vec::new();
10872        let mut added_lines = 0;
10873        let mut removed_lines = 0;
10874
10875        while let Some(selection) = selections.next() {
10876            let (start_row, end_row) = consume_contiguous_rows(
10877                &mut contiguous_row_selections,
10878                selection,
10879                &display_map,
10880                &mut selections,
10881            );
10882
10883            let start_point = Point::new(start_row.0, 0);
10884            let end_point = Point::new(
10885                end_row.previous_row().0,
10886                buffer.line_len(end_row.previous_row()),
10887            );
10888            let text = buffer
10889                .text_for_range(start_point..end_point)
10890                .collect::<String>();
10891
10892            let LineManipulationResult {
10893                new_text,
10894                line_count_before,
10895                line_count_after,
10896            } = manipulate(&text);
10897
10898            edits.push((start_point..end_point, new_text));
10899
10900            // Selections must change based on added and removed line count
10901            let start_row =
10902                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10903            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10904            new_selections.push(Selection {
10905                id: selection.id,
10906                start: start_row,
10907                end: end_row,
10908                goal: SelectionGoal::None,
10909                reversed: selection.reversed,
10910            });
10911
10912            if line_count_after > line_count_before {
10913                added_lines += line_count_after - line_count_before;
10914            } else if line_count_before > line_count_after {
10915                removed_lines += line_count_before - line_count_after;
10916            }
10917        }
10918
10919        self.transact(window, cx, |this, window, cx| {
10920            let buffer = this.buffer.update(cx, |buffer, cx| {
10921                buffer.edit(edits, None, cx);
10922                buffer.snapshot(cx)
10923            });
10924
10925            // Recalculate offsets on newly edited buffer
10926            let new_selections = new_selections
10927                .iter()
10928                .map(|s| {
10929                    let start_point = Point::new(s.start.0, 0);
10930                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10931                    Selection {
10932                        id: s.id,
10933                        start: buffer.point_to_offset(start_point),
10934                        end: buffer.point_to_offset(end_point),
10935                        goal: s.goal,
10936                        reversed: s.reversed,
10937                    }
10938                })
10939                .collect();
10940
10941            this.change_selections(Default::default(), window, cx, |s| {
10942                s.select(new_selections);
10943            });
10944
10945            this.request_autoscroll(Autoscroll::fit(), cx);
10946        });
10947    }
10948
10949    fn manipulate_immutable_lines<Fn>(
10950        &mut self,
10951        window: &mut Window,
10952        cx: &mut Context<Self>,
10953        mut callback: Fn,
10954    ) where
10955        Fn: FnMut(&mut Vec<&str>),
10956    {
10957        self.manipulate_lines(window, cx, |text| {
10958            let mut lines: Vec<&str> = text.split('\n').collect();
10959            let line_count_before = lines.len();
10960
10961            callback(&mut lines);
10962
10963            LineManipulationResult {
10964                new_text: lines.join("\n"),
10965                line_count_before,
10966                line_count_after: lines.len(),
10967            }
10968        });
10969    }
10970
10971    fn manipulate_mutable_lines<Fn>(
10972        &mut self,
10973        window: &mut Window,
10974        cx: &mut Context<Self>,
10975        mut callback: Fn,
10976    ) where
10977        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10978    {
10979        self.manipulate_lines(window, cx, |text| {
10980            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10981            let line_count_before = lines.len();
10982
10983            callback(&mut lines);
10984
10985            LineManipulationResult {
10986                new_text: lines.join("\n"),
10987                line_count_before,
10988                line_count_after: lines.len(),
10989            }
10990        });
10991    }
10992
10993    pub fn convert_indentation_to_spaces(
10994        &mut self,
10995        _: &ConvertIndentationToSpaces,
10996        window: &mut Window,
10997        cx: &mut Context<Self>,
10998    ) {
10999        let settings = self.buffer.read(cx).language_settings(cx);
11000        let tab_size = settings.tab_size.get() as usize;
11001
11002        self.manipulate_mutable_lines(window, cx, |lines| {
11003            // Allocates a reasonably sized scratch buffer once for the whole loop
11004            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11005            // Avoids recomputing spaces that could be inserted many times
11006            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11007                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11008                .collect();
11009
11010            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11011                let mut chars = line.as_ref().chars();
11012                let mut col = 0;
11013                let mut changed = false;
11014
11015                while let Some(ch) = chars.next() {
11016                    match ch {
11017                        ' ' => {
11018                            reindented_line.push(' ');
11019                            col += 1;
11020                        }
11021                        '\t' => {
11022                            // \t are converted to spaces depending on the current column
11023                            let spaces_len = tab_size - (col % tab_size);
11024                            reindented_line.extend(&space_cache[spaces_len - 1]);
11025                            col += spaces_len;
11026                            changed = true;
11027                        }
11028                        _ => {
11029                            // If we dont append before break, the character is consumed
11030                            reindented_line.push(ch);
11031                            break;
11032                        }
11033                    }
11034                }
11035
11036                if !changed {
11037                    reindented_line.clear();
11038                    continue;
11039                }
11040                // Append the rest of the line and replace old reference with new one
11041                reindented_line.extend(chars);
11042                *line = Cow::Owned(reindented_line.clone());
11043                reindented_line.clear();
11044            }
11045        });
11046    }
11047
11048    pub fn convert_indentation_to_tabs(
11049        &mut self,
11050        _: &ConvertIndentationToTabs,
11051        window: &mut Window,
11052        cx: &mut Context<Self>,
11053    ) {
11054        let settings = self.buffer.read(cx).language_settings(cx);
11055        let tab_size = settings.tab_size.get() as usize;
11056
11057        self.manipulate_mutable_lines(window, cx, |lines| {
11058            // Allocates a reasonably sized buffer once for the whole loop
11059            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11060            // Avoids recomputing spaces that could be inserted many times
11061            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11062                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11063                .collect();
11064
11065            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11066                let mut chars = line.chars();
11067                let mut spaces_count = 0;
11068                let mut first_non_indent_char = None;
11069                let mut changed = false;
11070
11071                while let Some(ch) = chars.next() {
11072                    match ch {
11073                        ' ' => {
11074                            // Keep track of spaces. Append \t when we reach tab_size
11075                            spaces_count += 1;
11076                            changed = true;
11077                            if spaces_count == tab_size {
11078                                reindented_line.push('\t');
11079                                spaces_count = 0;
11080                            }
11081                        }
11082                        '\t' => {
11083                            reindented_line.push('\t');
11084                            spaces_count = 0;
11085                        }
11086                        _ => {
11087                            // Dont append it yet, we might have remaining spaces
11088                            first_non_indent_char = Some(ch);
11089                            break;
11090                        }
11091                    }
11092                }
11093
11094                if !changed {
11095                    reindented_line.clear();
11096                    continue;
11097                }
11098                // Remaining spaces that didn't make a full tab stop
11099                if spaces_count > 0 {
11100                    reindented_line.extend(&space_cache[spaces_count - 1]);
11101                }
11102                // If we consume an extra character that was not indentation, add it back
11103                if let Some(extra_char) = first_non_indent_char {
11104                    reindented_line.push(extra_char);
11105                }
11106                // Append the rest of the line and replace old reference with new one
11107                reindented_line.extend(chars);
11108                *line = Cow::Owned(reindented_line.clone());
11109                reindented_line.clear();
11110            }
11111        });
11112    }
11113
11114    pub fn convert_to_upper_case(
11115        &mut self,
11116        _: &ConvertToUpperCase,
11117        window: &mut Window,
11118        cx: &mut Context<Self>,
11119    ) {
11120        self.manipulate_text(window, cx, |text| text.to_uppercase())
11121    }
11122
11123    pub fn convert_to_lower_case(
11124        &mut self,
11125        _: &ConvertToLowerCase,
11126        window: &mut Window,
11127        cx: &mut Context<Self>,
11128    ) {
11129        self.manipulate_text(window, cx, |text| text.to_lowercase())
11130    }
11131
11132    pub fn convert_to_title_case(
11133        &mut self,
11134        _: &ConvertToTitleCase,
11135        window: &mut Window,
11136        cx: &mut Context<Self>,
11137    ) {
11138        self.manipulate_text(window, cx, |text| {
11139            text.split('\n')
11140                .map(|line| line.to_case(Case::Title))
11141                .join("\n")
11142        })
11143    }
11144
11145    pub fn convert_to_snake_case(
11146        &mut self,
11147        _: &ConvertToSnakeCase,
11148        window: &mut Window,
11149        cx: &mut Context<Self>,
11150    ) {
11151        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11152    }
11153
11154    pub fn convert_to_kebab_case(
11155        &mut self,
11156        _: &ConvertToKebabCase,
11157        window: &mut Window,
11158        cx: &mut Context<Self>,
11159    ) {
11160        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11161    }
11162
11163    pub fn convert_to_upper_camel_case(
11164        &mut self,
11165        _: &ConvertToUpperCamelCase,
11166        window: &mut Window,
11167        cx: &mut Context<Self>,
11168    ) {
11169        self.manipulate_text(window, cx, |text| {
11170            text.split('\n')
11171                .map(|line| line.to_case(Case::UpperCamel))
11172                .join("\n")
11173        })
11174    }
11175
11176    pub fn convert_to_lower_camel_case(
11177        &mut self,
11178        _: &ConvertToLowerCamelCase,
11179        window: &mut Window,
11180        cx: &mut Context<Self>,
11181    ) {
11182        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11183    }
11184
11185    pub fn convert_to_opposite_case(
11186        &mut self,
11187        _: &ConvertToOppositeCase,
11188        window: &mut Window,
11189        cx: &mut Context<Self>,
11190    ) {
11191        self.manipulate_text(window, cx, |text| {
11192            text.chars()
11193                .fold(String::with_capacity(text.len()), |mut t, c| {
11194                    if c.is_uppercase() {
11195                        t.extend(c.to_lowercase());
11196                    } else {
11197                        t.extend(c.to_uppercase());
11198                    }
11199                    t
11200                })
11201        })
11202    }
11203
11204    pub fn convert_to_sentence_case(
11205        &mut self,
11206        _: &ConvertToSentenceCase,
11207        window: &mut Window,
11208        cx: &mut Context<Self>,
11209    ) {
11210        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11211    }
11212
11213    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11214        self.manipulate_text(window, cx, |text| {
11215            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11216            if has_upper_case_characters {
11217                text.to_lowercase()
11218            } else {
11219                text.to_uppercase()
11220            }
11221        })
11222    }
11223
11224    pub fn convert_to_rot13(
11225        &mut self,
11226        _: &ConvertToRot13,
11227        window: &mut Window,
11228        cx: &mut Context<Self>,
11229    ) {
11230        self.manipulate_text(window, cx, |text| {
11231            text.chars()
11232                .map(|c| match c {
11233                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11234                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11235                    _ => c,
11236                })
11237                .collect()
11238        })
11239    }
11240
11241    pub fn convert_to_rot47(
11242        &mut self,
11243        _: &ConvertToRot47,
11244        window: &mut Window,
11245        cx: &mut Context<Self>,
11246    ) {
11247        self.manipulate_text(window, cx, |text| {
11248            text.chars()
11249                .map(|c| {
11250                    let code_point = c as u32;
11251                    if code_point >= 33 && code_point <= 126 {
11252                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11253                    }
11254                    c
11255                })
11256                .collect()
11257        })
11258    }
11259
11260    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11261    where
11262        Fn: FnMut(&str) -> String,
11263    {
11264        let buffer = self.buffer.read(cx).snapshot(cx);
11265
11266        let mut new_selections = Vec::new();
11267        let mut edits = Vec::new();
11268        let mut selection_adjustment = 0i32;
11269
11270        for selection in self.selections.all::<usize>(cx) {
11271            let selection_is_empty = selection.is_empty();
11272
11273            let (start, end) = if selection_is_empty {
11274                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11275                (word_range.start, word_range.end)
11276            } else {
11277                (selection.start, selection.end)
11278            };
11279
11280            let text = buffer.text_for_range(start..end).collect::<String>();
11281            let old_length = text.len() as i32;
11282            let text = callback(&text);
11283
11284            new_selections.push(Selection {
11285                start: (start as i32 - selection_adjustment) as usize,
11286                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11287                goal: SelectionGoal::None,
11288                ..selection
11289            });
11290
11291            selection_adjustment += old_length - text.len() as i32;
11292
11293            edits.push((start..end, text));
11294        }
11295
11296        self.transact(window, cx, |this, window, cx| {
11297            this.buffer.update(cx, |buffer, cx| {
11298                buffer.edit(edits, None, cx);
11299            });
11300
11301            this.change_selections(Default::default(), window, cx, |s| {
11302                s.select(new_selections);
11303            });
11304
11305            this.request_autoscroll(Autoscroll::fit(), cx);
11306        });
11307    }
11308
11309    pub fn move_selection_on_drop(
11310        &mut self,
11311        selection: &Selection<Anchor>,
11312        target: DisplayPoint,
11313        is_cut: bool,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316    ) {
11317        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11318        let buffer = &display_map.buffer_snapshot;
11319        let mut edits = Vec::new();
11320        let insert_point = display_map
11321            .clip_point(target, Bias::Left)
11322            .to_point(&display_map);
11323        let text = buffer
11324            .text_for_range(selection.start..selection.end)
11325            .collect::<String>();
11326        if is_cut {
11327            edits.push(((selection.start..selection.end), String::new()));
11328        }
11329        let insert_anchor = buffer.anchor_before(insert_point);
11330        edits.push(((insert_anchor..insert_anchor), text));
11331        let last_edit_start = insert_anchor.bias_left(buffer);
11332        let last_edit_end = insert_anchor.bias_right(buffer);
11333        self.transact(window, cx, |this, window, cx| {
11334            this.buffer.update(cx, |buffer, cx| {
11335                buffer.edit(edits, None, cx);
11336            });
11337            this.change_selections(Default::default(), window, cx, |s| {
11338                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11339            });
11340        });
11341    }
11342
11343    pub fn clear_selection_drag_state(&mut self) {
11344        self.selection_drag_state = SelectionDragState::None;
11345    }
11346
11347    pub fn duplicate(
11348        &mut self,
11349        upwards: bool,
11350        whole_lines: bool,
11351        window: &mut Window,
11352        cx: &mut Context<Self>,
11353    ) {
11354        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11355
11356        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11357        let buffer = &display_map.buffer_snapshot;
11358        let selections = self.selections.all::<Point>(cx);
11359
11360        let mut edits = Vec::new();
11361        let mut selections_iter = selections.iter().peekable();
11362        while let Some(selection) = selections_iter.next() {
11363            let mut rows = selection.spanned_rows(false, &display_map);
11364            // duplicate line-wise
11365            if whole_lines || selection.start == selection.end {
11366                // Avoid duplicating the same lines twice.
11367                while let Some(next_selection) = selections_iter.peek() {
11368                    let next_rows = next_selection.spanned_rows(false, &display_map);
11369                    if next_rows.start < rows.end {
11370                        rows.end = next_rows.end;
11371                        selections_iter.next().unwrap();
11372                    } else {
11373                        break;
11374                    }
11375                }
11376
11377                // Copy the text from the selected row region and splice it either at the start
11378                // or end of the region.
11379                let start = Point::new(rows.start.0, 0);
11380                let end = Point::new(
11381                    rows.end.previous_row().0,
11382                    buffer.line_len(rows.end.previous_row()),
11383                );
11384                let text = buffer
11385                    .text_for_range(start..end)
11386                    .chain(Some("\n"))
11387                    .collect::<String>();
11388                let insert_location = if upwards {
11389                    Point::new(rows.end.0, 0)
11390                } else {
11391                    start
11392                };
11393                edits.push((insert_location..insert_location, text));
11394            } else {
11395                // duplicate character-wise
11396                let start = selection.start;
11397                let end = selection.end;
11398                let text = buffer.text_for_range(start..end).collect::<String>();
11399                edits.push((selection.end..selection.end, text));
11400            }
11401        }
11402
11403        self.transact(window, cx, |this, _, cx| {
11404            this.buffer.update(cx, |buffer, cx| {
11405                buffer.edit(edits, None, cx);
11406            });
11407
11408            this.request_autoscroll(Autoscroll::fit(), cx);
11409        });
11410    }
11411
11412    pub fn duplicate_line_up(
11413        &mut self,
11414        _: &DuplicateLineUp,
11415        window: &mut Window,
11416        cx: &mut Context<Self>,
11417    ) {
11418        self.duplicate(true, true, window, cx);
11419    }
11420
11421    pub fn duplicate_line_down(
11422        &mut self,
11423        _: &DuplicateLineDown,
11424        window: &mut Window,
11425        cx: &mut Context<Self>,
11426    ) {
11427        self.duplicate(false, true, window, cx);
11428    }
11429
11430    pub fn duplicate_selection(
11431        &mut self,
11432        _: &DuplicateSelection,
11433        window: &mut Window,
11434        cx: &mut Context<Self>,
11435    ) {
11436        self.duplicate(false, false, window, cx);
11437    }
11438
11439    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11440        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11441        if self.mode.is_single_line() {
11442            cx.propagate();
11443            return;
11444        }
11445
11446        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11447        let buffer = self.buffer.read(cx).snapshot(cx);
11448
11449        let mut edits = Vec::new();
11450        let mut unfold_ranges = Vec::new();
11451        let mut refold_creases = Vec::new();
11452
11453        let selections = self.selections.all::<Point>(cx);
11454        let mut selections = selections.iter().peekable();
11455        let mut contiguous_row_selections = Vec::new();
11456        let mut new_selections = Vec::new();
11457
11458        while let Some(selection) = selections.next() {
11459            // Find all the selections that span a contiguous row range
11460            let (start_row, end_row) = consume_contiguous_rows(
11461                &mut contiguous_row_selections,
11462                selection,
11463                &display_map,
11464                &mut selections,
11465            );
11466
11467            // Move the text spanned by the row range to be before the line preceding the row range
11468            if start_row.0 > 0 {
11469                let range_to_move = Point::new(
11470                    start_row.previous_row().0,
11471                    buffer.line_len(start_row.previous_row()),
11472                )
11473                    ..Point::new(
11474                        end_row.previous_row().0,
11475                        buffer.line_len(end_row.previous_row()),
11476                    );
11477                let insertion_point = display_map
11478                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11479                    .0;
11480
11481                // Don't move lines across excerpts
11482                if buffer
11483                    .excerpt_containing(insertion_point..range_to_move.end)
11484                    .is_some()
11485                {
11486                    let text = buffer
11487                        .text_for_range(range_to_move.clone())
11488                        .flat_map(|s| s.chars())
11489                        .skip(1)
11490                        .chain(['\n'])
11491                        .collect::<String>();
11492
11493                    edits.push((
11494                        buffer.anchor_after(range_to_move.start)
11495                            ..buffer.anchor_before(range_to_move.end),
11496                        String::new(),
11497                    ));
11498                    let insertion_anchor = buffer.anchor_after(insertion_point);
11499                    edits.push((insertion_anchor..insertion_anchor, text));
11500
11501                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11502
11503                    // Move selections up
11504                    new_selections.extend(contiguous_row_selections.drain(..).map(
11505                        |mut selection| {
11506                            selection.start.row -= row_delta;
11507                            selection.end.row -= row_delta;
11508                            selection
11509                        },
11510                    ));
11511
11512                    // Move folds up
11513                    unfold_ranges.push(range_to_move.clone());
11514                    for fold in display_map.folds_in_range(
11515                        buffer.anchor_before(range_to_move.start)
11516                            ..buffer.anchor_after(range_to_move.end),
11517                    ) {
11518                        let mut start = fold.range.start.to_point(&buffer);
11519                        let mut end = fold.range.end.to_point(&buffer);
11520                        start.row -= row_delta;
11521                        end.row -= row_delta;
11522                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11523                    }
11524                }
11525            }
11526
11527            // If we didn't move line(s), preserve the existing selections
11528            new_selections.append(&mut contiguous_row_selections);
11529        }
11530
11531        self.transact(window, cx, |this, window, cx| {
11532            this.unfold_ranges(&unfold_ranges, true, true, cx);
11533            this.buffer.update(cx, |buffer, cx| {
11534                for (range, text) in edits {
11535                    buffer.edit([(range, text)], None, cx);
11536                }
11537            });
11538            this.fold_creases(refold_creases, true, window, cx);
11539            this.change_selections(Default::default(), window, cx, |s| {
11540                s.select(new_selections);
11541            })
11542        });
11543    }
11544
11545    pub fn move_line_down(
11546        &mut self,
11547        _: &MoveLineDown,
11548        window: &mut Window,
11549        cx: &mut Context<Self>,
11550    ) {
11551        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11552        if self.mode.is_single_line() {
11553            cx.propagate();
11554            return;
11555        }
11556
11557        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11558        let buffer = self.buffer.read(cx).snapshot(cx);
11559
11560        let mut edits = Vec::new();
11561        let mut unfold_ranges = Vec::new();
11562        let mut refold_creases = Vec::new();
11563
11564        let selections = self.selections.all::<Point>(cx);
11565        let mut selections = selections.iter().peekable();
11566        let mut contiguous_row_selections = Vec::new();
11567        let mut new_selections = Vec::new();
11568
11569        while let Some(selection) = selections.next() {
11570            // Find all the selections that span a contiguous row range
11571            let (start_row, end_row) = consume_contiguous_rows(
11572                &mut contiguous_row_selections,
11573                selection,
11574                &display_map,
11575                &mut selections,
11576            );
11577
11578            // Move the text spanned by the row range to be after the last line of the row range
11579            if end_row.0 <= buffer.max_point().row {
11580                let range_to_move =
11581                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11582                let insertion_point = display_map
11583                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11584                    .0;
11585
11586                // Don't move lines across excerpt boundaries
11587                if buffer
11588                    .excerpt_containing(range_to_move.start..insertion_point)
11589                    .is_some()
11590                {
11591                    let mut text = String::from("\n");
11592                    text.extend(buffer.text_for_range(range_to_move.clone()));
11593                    text.pop(); // Drop trailing newline
11594                    edits.push((
11595                        buffer.anchor_after(range_to_move.start)
11596                            ..buffer.anchor_before(range_to_move.end),
11597                        String::new(),
11598                    ));
11599                    let insertion_anchor = buffer.anchor_after(insertion_point);
11600                    edits.push((insertion_anchor..insertion_anchor, text));
11601
11602                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11603
11604                    // Move selections down
11605                    new_selections.extend(contiguous_row_selections.drain(..).map(
11606                        |mut selection| {
11607                            selection.start.row += row_delta;
11608                            selection.end.row += row_delta;
11609                            selection
11610                        },
11611                    ));
11612
11613                    // Move folds down
11614                    unfold_ranges.push(range_to_move.clone());
11615                    for fold in display_map.folds_in_range(
11616                        buffer.anchor_before(range_to_move.start)
11617                            ..buffer.anchor_after(range_to_move.end),
11618                    ) {
11619                        let mut start = fold.range.start.to_point(&buffer);
11620                        let mut end = fold.range.end.to_point(&buffer);
11621                        start.row += row_delta;
11622                        end.row += row_delta;
11623                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11624                    }
11625                }
11626            }
11627
11628            // If we didn't move line(s), preserve the existing selections
11629            new_selections.append(&mut contiguous_row_selections);
11630        }
11631
11632        self.transact(window, cx, |this, window, cx| {
11633            this.unfold_ranges(&unfold_ranges, true, true, cx);
11634            this.buffer.update(cx, |buffer, cx| {
11635                for (range, text) in edits {
11636                    buffer.edit([(range, text)], None, cx);
11637                }
11638            });
11639            this.fold_creases(refold_creases, true, window, cx);
11640            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11641        });
11642    }
11643
11644    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11645        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11646        let text_layout_details = &self.text_layout_details(window);
11647        self.transact(window, cx, |this, window, cx| {
11648            let edits = this.change_selections(Default::default(), window, cx, |s| {
11649                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11650                s.move_with(|display_map, selection| {
11651                    if !selection.is_empty() {
11652                        return;
11653                    }
11654
11655                    let mut head = selection.head();
11656                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11657                    if head.column() == display_map.line_len(head.row()) {
11658                        transpose_offset = display_map
11659                            .buffer_snapshot
11660                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11661                    }
11662
11663                    if transpose_offset == 0 {
11664                        return;
11665                    }
11666
11667                    *head.column_mut() += 1;
11668                    head = display_map.clip_point(head, Bias::Right);
11669                    let goal = SelectionGoal::HorizontalPosition(
11670                        display_map
11671                            .x_for_display_point(head, text_layout_details)
11672                            .into(),
11673                    );
11674                    selection.collapse_to(head, goal);
11675
11676                    let transpose_start = display_map
11677                        .buffer_snapshot
11678                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11679                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11680                        let transpose_end = display_map
11681                            .buffer_snapshot
11682                            .clip_offset(transpose_offset + 1, Bias::Right);
11683                        if let Some(ch) =
11684                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11685                        {
11686                            edits.push((transpose_start..transpose_offset, String::new()));
11687                            edits.push((transpose_end..transpose_end, ch.to_string()));
11688                        }
11689                    }
11690                });
11691                edits
11692            });
11693            this.buffer
11694                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11695            let selections = this.selections.all::<usize>(cx);
11696            this.change_selections(Default::default(), window, cx, |s| {
11697                s.select(selections);
11698            });
11699        });
11700    }
11701
11702    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11703        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11704        if self.mode.is_single_line() {
11705            cx.propagate();
11706            return;
11707        }
11708
11709        self.rewrap_impl(RewrapOptions::default(), cx)
11710    }
11711
11712    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11713        let buffer = self.buffer.read(cx).snapshot(cx);
11714        let selections = self.selections.all::<Point>(cx);
11715
11716        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11717        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11718            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11719                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11720                .peekable();
11721
11722            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11723                row
11724            } else {
11725                return Vec::new();
11726            };
11727
11728            let language_settings = buffer.language_settings_at(selection.head(), cx);
11729            let language_scope = buffer.language_scope_at(selection.head());
11730
11731            let indent_and_prefix_for_row =
11732                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11733                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11734                    let (comment_prefix, rewrap_prefix) =
11735                        if let Some(language_scope) = &language_scope {
11736                            let indent_end = Point::new(row, indent.len);
11737                            let comment_prefix = language_scope
11738                                .line_comment_prefixes()
11739                                .iter()
11740                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11741                                .map(|prefix| prefix.to_string());
11742                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11743                            let line_text_after_indent = buffer
11744                                .text_for_range(indent_end..line_end)
11745                                .collect::<String>();
11746                            let rewrap_prefix = language_scope
11747                                .rewrap_prefixes()
11748                                .iter()
11749                                .find_map(|prefix_regex| {
11750                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11751                                        if mat.start() == 0 {
11752                                            Some(mat.as_str().to_string())
11753                                        } else {
11754                                            None
11755                                        }
11756                                    })
11757                                })
11758                                .flatten();
11759                            (comment_prefix, rewrap_prefix)
11760                        } else {
11761                            (None, None)
11762                        };
11763                    (indent, comment_prefix, rewrap_prefix)
11764                };
11765
11766            let mut ranges = Vec::new();
11767            let from_empty_selection = selection.is_empty();
11768
11769            let mut current_range_start = first_row;
11770            let mut prev_row = first_row;
11771            let (
11772                mut current_range_indent,
11773                mut current_range_comment_prefix,
11774                mut current_range_rewrap_prefix,
11775            ) = indent_and_prefix_for_row(first_row);
11776
11777            for row in non_blank_rows_iter.skip(1) {
11778                let has_paragraph_break = row > prev_row + 1;
11779
11780                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11781                    indent_and_prefix_for_row(row);
11782
11783                let has_indent_change = row_indent != current_range_indent;
11784                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11785
11786                let has_boundary_change = has_comment_change
11787                    || row_rewrap_prefix.is_some()
11788                    || (has_indent_change && current_range_comment_prefix.is_some());
11789
11790                if has_paragraph_break || has_boundary_change {
11791                    ranges.push((
11792                        language_settings.clone(),
11793                        Point::new(current_range_start, 0)
11794                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11795                        current_range_indent,
11796                        current_range_comment_prefix.clone(),
11797                        current_range_rewrap_prefix.clone(),
11798                        from_empty_selection,
11799                    ));
11800                    current_range_start = row;
11801                    current_range_indent = row_indent;
11802                    current_range_comment_prefix = row_comment_prefix;
11803                    current_range_rewrap_prefix = row_rewrap_prefix;
11804                }
11805                prev_row = row;
11806            }
11807
11808            ranges.push((
11809                language_settings.clone(),
11810                Point::new(current_range_start, 0)
11811                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11812                current_range_indent,
11813                current_range_comment_prefix,
11814                current_range_rewrap_prefix,
11815                from_empty_selection,
11816            ));
11817
11818            ranges
11819        });
11820
11821        let mut edits = Vec::new();
11822        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11823
11824        for (
11825            language_settings,
11826            wrap_range,
11827            indent_size,
11828            comment_prefix,
11829            rewrap_prefix,
11830            from_empty_selection,
11831        ) in wrap_ranges
11832        {
11833            let mut start_row = wrap_range.start.row;
11834            let mut end_row = wrap_range.end.row;
11835
11836            // Skip selections that overlap with a range that has already been rewrapped.
11837            let selection_range = start_row..end_row;
11838            if rewrapped_row_ranges
11839                .iter()
11840                .any(|range| range.overlaps(&selection_range))
11841            {
11842                continue;
11843            }
11844
11845            let tab_size = language_settings.tab_size;
11846
11847            let indent_prefix = indent_size.chars().collect::<String>();
11848            let mut line_prefix = indent_prefix.clone();
11849            let mut inside_comment = false;
11850            if let Some(prefix) = &comment_prefix {
11851                line_prefix.push_str(prefix);
11852                inside_comment = true;
11853            }
11854            if let Some(prefix) = &rewrap_prefix {
11855                line_prefix.push_str(prefix);
11856            }
11857
11858            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11859                RewrapBehavior::InComments => inside_comment,
11860                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11861                RewrapBehavior::Anywhere => true,
11862            };
11863
11864            let should_rewrap = options.override_language_settings
11865                || allow_rewrap_based_on_language
11866                || self.hard_wrap.is_some();
11867            if !should_rewrap {
11868                continue;
11869            }
11870
11871            if from_empty_selection {
11872                'expand_upwards: while start_row > 0 {
11873                    let prev_row = start_row - 1;
11874                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11875                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11876                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11877                    {
11878                        start_row = prev_row;
11879                    } else {
11880                        break 'expand_upwards;
11881                    }
11882                }
11883
11884                'expand_downwards: while end_row < buffer.max_point().row {
11885                    let next_row = end_row + 1;
11886                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11887                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11888                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11889                    {
11890                        end_row = next_row;
11891                    } else {
11892                        break 'expand_downwards;
11893                    }
11894                }
11895            }
11896
11897            let start = Point::new(start_row, 0);
11898            let start_offset = start.to_offset(&buffer);
11899            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11900            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11901            let Some(lines_without_prefixes) = selection_text
11902                .lines()
11903                .enumerate()
11904                .map(|(ix, line)| {
11905                    let line_trimmed = line.trim_start();
11906                    if rewrap_prefix.is_some() && ix > 0 {
11907                        Ok(line_trimmed)
11908                    } else {
11909                        line_trimmed
11910                            .strip_prefix(&line_prefix.trim_start())
11911                            .with_context(|| {
11912                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11913                            })
11914                    }
11915                })
11916                .collect::<Result<Vec<_>, _>>()
11917                .log_err()
11918            else {
11919                continue;
11920            };
11921
11922            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11923                buffer
11924                    .language_settings_at(Point::new(start_row, 0), cx)
11925                    .preferred_line_length as usize
11926            });
11927
11928            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11929                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11930            } else {
11931                line_prefix.clone()
11932            };
11933
11934            let wrapped_text = wrap_with_prefix(
11935                line_prefix,
11936                subsequent_lines_prefix,
11937                lines_without_prefixes.join("\n"),
11938                wrap_column,
11939                tab_size,
11940                options.preserve_existing_whitespace,
11941            );
11942
11943            // TODO: should always use char-based diff while still supporting cursor behavior that
11944            // matches vim.
11945            let mut diff_options = DiffOptions::default();
11946            if options.override_language_settings {
11947                diff_options.max_word_diff_len = 0;
11948                diff_options.max_word_diff_line_count = 0;
11949            } else {
11950                diff_options.max_word_diff_len = usize::MAX;
11951                diff_options.max_word_diff_line_count = usize::MAX;
11952            }
11953
11954            for (old_range, new_text) in
11955                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11956            {
11957                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11958                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11959                edits.push((edit_start..edit_end, new_text));
11960            }
11961
11962            rewrapped_row_ranges.push(start_row..=end_row);
11963        }
11964
11965        self.buffer
11966            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11967    }
11968
11969    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11970        let mut text = String::new();
11971        let buffer = self.buffer.read(cx).snapshot(cx);
11972        let mut selections = self.selections.all::<Point>(cx);
11973        let mut clipboard_selections = Vec::with_capacity(selections.len());
11974        {
11975            let max_point = buffer.max_point();
11976            let mut is_first = true;
11977            for selection in &mut selections {
11978                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11979                if is_entire_line {
11980                    selection.start = Point::new(selection.start.row, 0);
11981                    if !selection.is_empty() && selection.end.column == 0 {
11982                        selection.end = cmp::min(max_point, selection.end);
11983                    } else {
11984                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11985                    }
11986                    selection.goal = SelectionGoal::None;
11987                }
11988                if is_first {
11989                    is_first = false;
11990                } else {
11991                    text += "\n";
11992                }
11993                let mut len = 0;
11994                for chunk in buffer.text_for_range(selection.start..selection.end) {
11995                    text.push_str(chunk);
11996                    len += chunk.len();
11997                }
11998                clipboard_selections.push(ClipboardSelection {
11999                    len,
12000                    is_entire_line,
12001                    first_line_indent: buffer
12002                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12003                        .len,
12004                });
12005            }
12006        }
12007
12008        self.transact(window, cx, |this, window, cx| {
12009            this.change_selections(Default::default(), window, cx, |s| {
12010                s.select(selections);
12011            });
12012            this.insert("", window, cx);
12013        });
12014        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12015    }
12016
12017    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12019        let item = self.cut_common(window, cx);
12020        cx.write_to_clipboard(item);
12021    }
12022
12023    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12024        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12025        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12026            s.move_with(|snapshot, sel| {
12027                if sel.is_empty() {
12028                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12029                }
12030            });
12031        });
12032        let item = self.cut_common(window, cx);
12033        cx.set_global(KillRing(item))
12034    }
12035
12036    pub fn kill_ring_yank(
12037        &mut self,
12038        _: &KillRingYank,
12039        window: &mut Window,
12040        cx: &mut Context<Self>,
12041    ) {
12042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12043        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12044            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12045                (kill_ring.text().to_string(), kill_ring.metadata_json())
12046            } else {
12047                return;
12048            }
12049        } else {
12050            return;
12051        };
12052        self.do_paste(&text, metadata, false, window, cx);
12053    }
12054
12055    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12056        self.do_copy(true, cx);
12057    }
12058
12059    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12060        self.do_copy(false, cx);
12061    }
12062
12063    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12064        let selections = self.selections.all::<Point>(cx);
12065        let buffer = self.buffer.read(cx).read(cx);
12066        let mut text = String::new();
12067
12068        let mut clipboard_selections = Vec::with_capacity(selections.len());
12069        {
12070            let max_point = buffer.max_point();
12071            let mut is_first = true;
12072            for selection in &selections {
12073                let mut start = selection.start;
12074                let mut end = selection.end;
12075                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12076                if is_entire_line {
12077                    start = Point::new(start.row, 0);
12078                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12079                }
12080
12081                let mut trimmed_selections = Vec::new();
12082                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12083                    let row = MultiBufferRow(start.row);
12084                    let first_indent = buffer.indent_size_for_line(row);
12085                    if first_indent.len == 0 || start.column > first_indent.len {
12086                        trimmed_selections.push(start..end);
12087                    } else {
12088                        trimmed_selections.push(
12089                            Point::new(row.0, first_indent.len)
12090                                ..Point::new(row.0, buffer.line_len(row)),
12091                        );
12092                        for row in start.row + 1..=end.row {
12093                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12094                            if row == end.row {
12095                                line_len = end.column;
12096                            }
12097                            if line_len == 0 {
12098                                trimmed_selections
12099                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12100                                continue;
12101                            }
12102                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12103                            if row_indent_size.len >= first_indent.len {
12104                                trimmed_selections.push(
12105                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12106                                );
12107                            } else {
12108                                trimmed_selections.clear();
12109                                trimmed_selections.push(start..end);
12110                                break;
12111                            }
12112                        }
12113                    }
12114                } else {
12115                    trimmed_selections.push(start..end);
12116                }
12117
12118                for trimmed_range in trimmed_selections {
12119                    if is_first {
12120                        is_first = false;
12121                    } else {
12122                        text += "\n";
12123                    }
12124                    let mut len = 0;
12125                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12126                        text.push_str(chunk);
12127                        len += chunk.len();
12128                    }
12129                    clipboard_selections.push(ClipboardSelection {
12130                        len,
12131                        is_entire_line,
12132                        first_line_indent: buffer
12133                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12134                            .len,
12135                    });
12136                }
12137            }
12138        }
12139
12140        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12141            text,
12142            clipboard_selections,
12143        ));
12144    }
12145
12146    pub fn do_paste(
12147        &mut self,
12148        text: &String,
12149        clipboard_selections: Option<Vec<ClipboardSelection>>,
12150        handle_entire_lines: bool,
12151        window: &mut Window,
12152        cx: &mut Context<Self>,
12153    ) {
12154        if self.read_only(cx) {
12155            return;
12156        }
12157
12158        let clipboard_text = Cow::Borrowed(text);
12159
12160        self.transact(window, cx, |this, window, cx| {
12161            if let Some(mut clipboard_selections) = clipboard_selections {
12162                let old_selections = this.selections.all::<usize>(cx);
12163                let all_selections_were_entire_line =
12164                    clipboard_selections.iter().all(|s| s.is_entire_line);
12165                let first_selection_indent_column =
12166                    clipboard_selections.first().map(|s| s.first_line_indent);
12167                if clipboard_selections.len() != old_selections.len() {
12168                    clipboard_selections.drain(..);
12169                }
12170                let cursor_offset = this.selections.last::<usize>(cx).head();
12171                let mut auto_indent_on_paste = true;
12172
12173                this.buffer.update(cx, |buffer, cx| {
12174                    let snapshot = buffer.read(cx);
12175                    auto_indent_on_paste = snapshot
12176                        .language_settings_at(cursor_offset, cx)
12177                        .auto_indent_on_paste;
12178
12179                    let mut start_offset = 0;
12180                    let mut edits = Vec::new();
12181                    let mut original_indent_columns = Vec::new();
12182                    for (ix, selection) in old_selections.iter().enumerate() {
12183                        let to_insert;
12184                        let entire_line;
12185                        let original_indent_column;
12186                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12187                            let end_offset = start_offset + clipboard_selection.len;
12188                            to_insert = &clipboard_text[start_offset..end_offset];
12189                            entire_line = clipboard_selection.is_entire_line;
12190                            start_offset = end_offset + 1;
12191                            original_indent_column = Some(clipboard_selection.first_line_indent);
12192                        } else {
12193                            to_insert = clipboard_text.as_str();
12194                            entire_line = all_selections_were_entire_line;
12195                            original_indent_column = first_selection_indent_column
12196                        }
12197
12198                        // If the corresponding selection was empty when this slice of the
12199                        // clipboard text was written, then the entire line containing the
12200                        // selection was copied. If this selection is also currently empty,
12201                        // then paste the line before the current line of the buffer.
12202                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12203                            let column = selection.start.to_point(&snapshot).column as usize;
12204                            let line_start = selection.start - column;
12205                            line_start..line_start
12206                        } else {
12207                            selection.range()
12208                        };
12209
12210                        edits.push((range, to_insert));
12211                        original_indent_columns.push(original_indent_column);
12212                    }
12213                    drop(snapshot);
12214
12215                    buffer.edit(
12216                        edits,
12217                        if auto_indent_on_paste {
12218                            Some(AutoindentMode::Block {
12219                                original_indent_columns,
12220                            })
12221                        } else {
12222                            None
12223                        },
12224                        cx,
12225                    );
12226                });
12227
12228                let selections = this.selections.all::<usize>(cx);
12229                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12230            } else {
12231                this.insert(&clipboard_text, window, cx);
12232            }
12233        });
12234    }
12235
12236    pub fn diff_clipboard_with_selection(
12237        &mut self,
12238        _: &DiffClipboardWithSelection,
12239        window: &mut Window,
12240        cx: &mut Context<Self>,
12241    ) {
12242        let selections = self.selections.all::<usize>(cx);
12243
12244        if selections.is_empty() {
12245            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12246            return;
12247        };
12248
12249        let clipboard_text = match cx.read_from_clipboard() {
12250            Some(item) => match item.entries().first() {
12251                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12252                _ => None,
12253            },
12254            None => None,
12255        };
12256
12257        let Some(clipboard_text) = clipboard_text else {
12258            log::warn!("Clipboard doesn't contain text.");
12259            return;
12260        };
12261
12262        window.dispatch_action(
12263            Box::new(DiffClipboardWithSelectionData {
12264                clipboard_text,
12265                editor: cx.entity(),
12266            }),
12267            cx,
12268        );
12269    }
12270
12271    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12272        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12273        if let Some(item) = cx.read_from_clipboard() {
12274            let entries = item.entries();
12275
12276            match entries.first() {
12277                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12278                // of all the pasted entries.
12279                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12280                    .do_paste(
12281                        clipboard_string.text(),
12282                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12283                        true,
12284                        window,
12285                        cx,
12286                    ),
12287                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12288            }
12289        }
12290    }
12291
12292    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12293        if self.read_only(cx) {
12294            return;
12295        }
12296
12297        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12298
12299        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12300            if let Some((selections, _)) =
12301                self.selection_history.transaction(transaction_id).cloned()
12302            {
12303                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12304                    s.select_anchors(selections.to_vec());
12305                });
12306            } else {
12307                log::error!(
12308                    "No entry in selection_history found for undo. \
12309                     This may correspond to a bug where undo does not update the selection. \
12310                     If this is occurring, please add details to \
12311                     https://github.com/zed-industries/zed/issues/22692"
12312                );
12313            }
12314            self.request_autoscroll(Autoscroll::fit(), cx);
12315            self.unmark_text(window, cx);
12316            self.refresh_edit_prediction(true, false, window, cx);
12317            cx.emit(EditorEvent::Edited { transaction_id });
12318            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12319        }
12320    }
12321
12322    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12323        if self.read_only(cx) {
12324            return;
12325        }
12326
12327        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12328
12329        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12330            if let Some((_, Some(selections))) =
12331                self.selection_history.transaction(transaction_id).cloned()
12332            {
12333                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12334                    s.select_anchors(selections.to_vec());
12335                });
12336            } else {
12337                log::error!(
12338                    "No entry in selection_history found for redo. \
12339                     This may correspond to a bug where undo does not update the selection. \
12340                     If this is occurring, please add details to \
12341                     https://github.com/zed-industries/zed/issues/22692"
12342                );
12343            }
12344            self.request_autoscroll(Autoscroll::fit(), cx);
12345            self.unmark_text(window, cx);
12346            self.refresh_edit_prediction(true, false, window, cx);
12347            cx.emit(EditorEvent::Edited { transaction_id });
12348        }
12349    }
12350
12351    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12352        self.buffer
12353            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12354    }
12355
12356    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12357        self.buffer
12358            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12359    }
12360
12361    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12363        self.change_selections(Default::default(), window, cx, |s| {
12364            s.move_with(|map, selection| {
12365                let cursor = if selection.is_empty() {
12366                    movement::left(map, selection.start)
12367                } else {
12368                    selection.start
12369                };
12370                selection.collapse_to(cursor, SelectionGoal::None);
12371            });
12372        })
12373    }
12374
12375    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12377        self.change_selections(Default::default(), window, cx, |s| {
12378            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12379        })
12380    }
12381
12382    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12383        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12384        self.change_selections(Default::default(), window, cx, |s| {
12385            s.move_with(|map, selection| {
12386                let cursor = if selection.is_empty() {
12387                    movement::right(map, selection.end)
12388                } else {
12389                    selection.end
12390                };
12391                selection.collapse_to(cursor, SelectionGoal::None)
12392            });
12393        })
12394    }
12395
12396    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12398        self.change_selections(Default::default(), window, cx, |s| {
12399            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12400        })
12401    }
12402
12403    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12404        if self.take_rename(true, window, cx).is_some() {
12405            return;
12406        }
12407
12408        if self.mode.is_single_line() {
12409            cx.propagate();
12410            return;
12411        }
12412
12413        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12414
12415        let text_layout_details = &self.text_layout_details(window);
12416        let selection_count = self.selections.count();
12417        let first_selection = self.selections.first_anchor();
12418
12419        self.change_selections(Default::default(), window, cx, |s| {
12420            s.move_with(|map, selection| {
12421                if !selection.is_empty() {
12422                    selection.goal = SelectionGoal::None;
12423                }
12424                let (cursor, goal) = movement::up(
12425                    map,
12426                    selection.start,
12427                    selection.goal,
12428                    false,
12429                    text_layout_details,
12430                );
12431                selection.collapse_to(cursor, goal);
12432            });
12433        });
12434
12435        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12436        {
12437            cx.propagate();
12438        }
12439    }
12440
12441    pub fn move_up_by_lines(
12442        &mut self,
12443        action: &MoveUpByLines,
12444        window: &mut Window,
12445        cx: &mut Context<Self>,
12446    ) {
12447        if self.take_rename(true, window, cx).is_some() {
12448            return;
12449        }
12450
12451        if self.mode.is_single_line() {
12452            cx.propagate();
12453            return;
12454        }
12455
12456        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12457
12458        let text_layout_details = &self.text_layout_details(window);
12459
12460        self.change_selections(Default::default(), window, cx, |s| {
12461            s.move_with(|map, selection| {
12462                if !selection.is_empty() {
12463                    selection.goal = SelectionGoal::None;
12464                }
12465                let (cursor, goal) = movement::up_by_rows(
12466                    map,
12467                    selection.start,
12468                    action.lines,
12469                    selection.goal,
12470                    false,
12471                    text_layout_details,
12472                );
12473                selection.collapse_to(cursor, goal);
12474            });
12475        })
12476    }
12477
12478    pub fn move_down_by_lines(
12479        &mut self,
12480        action: &MoveDownByLines,
12481        window: &mut Window,
12482        cx: &mut Context<Self>,
12483    ) {
12484        if self.take_rename(true, window, cx).is_some() {
12485            return;
12486        }
12487
12488        if self.mode.is_single_line() {
12489            cx.propagate();
12490            return;
12491        }
12492
12493        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12494
12495        let text_layout_details = &self.text_layout_details(window);
12496
12497        self.change_selections(Default::default(), window, cx, |s| {
12498            s.move_with(|map, selection| {
12499                if !selection.is_empty() {
12500                    selection.goal = SelectionGoal::None;
12501                }
12502                let (cursor, goal) = movement::down_by_rows(
12503                    map,
12504                    selection.start,
12505                    action.lines,
12506                    selection.goal,
12507                    false,
12508                    text_layout_details,
12509                );
12510                selection.collapse_to(cursor, goal);
12511            });
12512        })
12513    }
12514
12515    pub fn select_down_by_lines(
12516        &mut self,
12517        action: &SelectDownByLines,
12518        window: &mut Window,
12519        cx: &mut Context<Self>,
12520    ) {
12521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12522        let text_layout_details = &self.text_layout_details(window);
12523        self.change_selections(Default::default(), window, cx, |s| {
12524            s.move_heads_with(|map, head, goal| {
12525                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12526            })
12527        })
12528    }
12529
12530    pub fn select_up_by_lines(
12531        &mut self,
12532        action: &SelectUpByLines,
12533        window: &mut Window,
12534        cx: &mut Context<Self>,
12535    ) {
12536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12537        let text_layout_details = &self.text_layout_details(window);
12538        self.change_selections(Default::default(), window, cx, |s| {
12539            s.move_heads_with(|map, head, goal| {
12540                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12541            })
12542        })
12543    }
12544
12545    pub fn select_page_up(
12546        &mut self,
12547        _: &SelectPageUp,
12548        window: &mut Window,
12549        cx: &mut Context<Self>,
12550    ) {
12551        let Some(row_count) = self.visible_row_count() else {
12552            return;
12553        };
12554
12555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12556
12557        let text_layout_details = &self.text_layout_details(window);
12558
12559        self.change_selections(Default::default(), window, cx, |s| {
12560            s.move_heads_with(|map, head, goal| {
12561                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12562            })
12563        })
12564    }
12565
12566    pub fn move_page_up(
12567        &mut self,
12568        action: &MovePageUp,
12569        window: &mut Window,
12570        cx: &mut Context<Self>,
12571    ) {
12572        if self.take_rename(true, window, cx).is_some() {
12573            return;
12574        }
12575
12576        if self
12577            .context_menu
12578            .borrow_mut()
12579            .as_mut()
12580            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12581            .unwrap_or(false)
12582        {
12583            return;
12584        }
12585
12586        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12587            cx.propagate();
12588            return;
12589        }
12590
12591        let Some(row_count) = self.visible_row_count() else {
12592            return;
12593        };
12594
12595        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12596
12597        let effects = if action.center_cursor {
12598            SelectionEffects::scroll(Autoscroll::center())
12599        } else {
12600            SelectionEffects::default()
12601        };
12602
12603        let text_layout_details = &self.text_layout_details(window);
12604
12605        self.change_selections(effects, window, cx, |s| {
12606            s.move_with(|map, selection| {
12607                if !selection.is_empty() {
12608                    selection.goal = SelectionGoal::None;
12609                }
12610                let (cursor, goal) = movement::up_by_rows(
12611                    map,
12612                    selection.end,
12613                    row_count,
12614                    selection.goal,
12615                    false,
12616                    text_layout_details,
12617                );
12618                selection.collapse_to(cursor, goal);
12619            });
12620        });
12621    }
12622
12623    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12624        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12625        let text_layout_details = &self.text_layout_details(window);
12626        self.change_selections(Default::default(), window, cx, |s| {
12627            s.move_heads_with(|map, head, goal| {
12628                movement::up(map, head, goal, false, text_layout_details)
12629            })
12630        })
12631    }
12632
12633    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12634        self.take_rename(true, window, cx);
12635
12636        if self.mode.is_single_line() {
12637            cx.propagate();
12638            return;
12639        }
12640
12641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12642
12643        let text_layout_details = &self.text_layout_details(window);
12644        let selection_count = self.selections.count();
12645        let first_selection = self.selections.first_anchor();
12646
12647        self.change_selections(Default::default(), window, cx, |s| {
12648            s.move_with(|map, selection| {
12649                if !selection.is_empty() {
12650                    selection.goal = SelectionGoal::None;
12651                }
12652                let (cursor, goal) = movement::down(
12653                    map,
12654                    selection.end,
12655                    selection.goal,
12656                    false,
12657                    text_layout_details,
12658                );
12659                selection.collapse_to(cursor, goal);
12660            });
12661        });
12662
12663        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12664        {
12665            cx.propagate();
12666        }
12667    }
12668
12669    pub fn select_page_down(
12670        &mut self,
12671        _: &SelectPageDown,
12672        window: &mut Window,
12673        cx: &mut Context<Self>,
12674    ) {
12675        let Some(row_count) = self.visible_row_count() else {
12676            return;
12677        };
12678
12679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12680
12681        let text_layout_details = &self.text_layout_details(window);
12682
12683        self.change_selections(Default::default(), window, cx, |s| {
12684            s.move_heads_with(|map, head, goal| {
12685                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12686            })
12687        })
12688    }
12689
12690    pub fn move_page_down(
12691        &mut self,
12692        action: &MovePageDown,
12693        window: &mut Window,
12694        cx: &mut Context<Self>,
12695    ) {
12696        if self.take_rename(true, window, cx).is_some() {
12697            return;
12698        }
12699
12700        if self
12701            .context_menu
12702            .borrow_mut()
12703            .as_mut()
12704            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12705            .unwrap_or(false)
12706        {
12707            return;
12708        }
12709
12710        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12711            cx.propagate();
12712            return;
12713        }
12714
12715        let Some(row_count) = self.visible_row_count() else {
12716            return;
12717        };
12718
12719        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12720
12721        let effects = if action.center_cursor {
12722            SelectionEffects::scroll(Autoscroll::center())
12723        } else {
12724            SelectionEffects::default()
12725        };
12726
12727        let text_layout_details = &self.text_layout_details(window);
12728        self.change_selections(effects, window, cx, |s| {
12729            s.move_with(|map, selection| {
12730                if !selection.is_empty() {
12731                    selection.goal = SelectionGoal::None;
12732                }
12733                let (cursor, goal) = movement::down_by_rows(
12734                    map,
12735                    selection.end,
12736                    row_count,
12737                    selection.goal,
12738                    false,
12739                    text_layout_details,
12740                );
12741                selection.collapse_to(cursor, goal);
12742            });
12743        });
12744    }
12745
12746    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12748        let text_layout_details = &self.text_layout_details(window);
12749        self.change_selections(Default::default(), window, cx, |s| {
12750            s.move_heads_with(|map, head, goal| {
12751                movement::down(map, head, goal, false, text_layout_details)
12752            })
12753        });
12754    }
12755
12756    pub fn context_menu_first(
12757        &mut self,
12758        _: &ContextMenuFirst,
12759        window: &mut Window,
12760        cx: &mut Context<Self>,
12761    ) {
12762        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12763            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12764        }
12765    }
12766
12767    pub fn context_menu_prev(
12768        &mut self,
12769        _: &ContextMenuPrevious,
12770        window: &mut Window,
12771        cx: &mut Context<Self>,
12772    ) {
12773        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12774            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12775        }
12776    }
12777
12778    pub fn context_menu_next(
12779        &mut self,
12780        _: &ContextMenuNext,
12781        window: &mut Window,
12782        cx: &mut Context<Self>,
12783    ) {
12784        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12785            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12786        }
12787    }
12788
12789    pub fn context_menu_last(
12790        &mut self,
12791        _: &ContextMenuLast,
12792        window: &mut Window,
12793        cx: &mut Context<Self>,
12794    ) {
12795        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12796            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12797        }
12798    }
12799
12800    pub fn signature_help_prev(
12801        &mut self,
12802        _: &SignatureHelpPrevious,
12803        _: &mut Window,
12804        cx: &mut Context<Self>,
12805    ) {
12806        if let Some(popover) = self.signature_help_state.popover_mut() {
12807            if popover.current_signature == 0 {
12808                popover.current_signature = popover.signatures.len() - 1;
12809            } else {
12810                popover.current_signature -= 1;
12811            }
12812            cx.notify();
12813        }
12814    }
12815
12816    pub fn signature_help_next(
12817        &mut self,
12818        _: &SignatureHelpNext,
12819        _: &mut Window,
12820        cx: &mut Context<Self>,
12821    ) {
12822        if let Some(popover) = self.signature_help_state.popover_mut() {
12823            if popover.current_signature + 1 == popover.signatures.len() {
12824                popover.current_signature = 0;
12825            } else {
12826                popover.current_signature += 1;
12827            }
12828            cx.notify();
12829        }
12830    }
12831
12832    pub fn move_to_previous_word_start(
12833        &mut self,
12834        _: &MoveToPreviousWordStart,
12835        window: &mut Window,
12836        cx: &mut Context<Self>,
12837    ) {
12838        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12839        self.change_selections(Default::default(), window, cx, |s| {
12840            s.move_cursors_with(|map, head, _| {
12841                (
12842                    movement::previous_word_start(map, head),
12843                    SelectionGoal::None,
12844                )
12845            });
12846        })
12847    }
12848
12849    pub fn move_to_previous_subword_start(
12850        &mut self,
12851        _: &MoveToPreviousSubwordStart,
12852        window: &mut Window,
12853        cx: &mut Context<Self>,
12854    ) {
12855        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12856        self.change_selections(Default::default(), window, cx, |s| {
12857            s.move_cursors_with(|map, head, _| {
12858                (
12859                    movement::previous_subword_start(map, head),
12860                    SelectionGoal::None,
12861                )
12862            });
12863        })
12864    }
12865
12866    pub fn select_to_previous_word_start(
12867        &mut self,
12868        _: &SelectToPreviousWordStart,
12869        window: &mut Window,
12870        cx: &mut Context<Self>,
12871    ) {
12872        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12873        self.change_selections(Default::default(), window, cx, |s| {
12874            s.move_heads_with(|map, head, _| {
12875                (
12876                    movement::previous_word_start(map, head),
12877                    SelectionGoal::None,
12878                )
12879            });
12880        })
12881    }
12882
12883    pub fn select_to_previous_subword_start(
12884        &mut self,
12885        _: &SelectToPreviousSubwordStart,
12886        window: &mut Window,
12887        cx: &mut Context<Self>,
12888    ) {
12889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12890        self.change_selections(Default::default(), window, cx, |s| {
12891            s.move_heads_with(|map, head, _| {
12892                (
12893                    movement::previous_subword_start(map, head),
12894                    SelectionGoal::None,
12895                )
12896            });
12897        })
12898    }
12899
12900    pub fn delete_to_previous_word_start(
12901        &mut self,
12902        action: &DeleteToPreviousWordStart,
12903        window: &mut Window,
12904        cx: &mut Context<Self>,
12905    ) {
12906        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12907        self.transact(window, cx, |this, window, cx| {
12908            this.select_autoclose_pair(window, cx);
12909            this.change_selections(Default::default(), window, cx, |s| {
12910                s.move_with(|map, selection| {
12911                    if selection.is_empty() {
12912                        let cursor = if action.ignore_newlines {
12913                            movement::previous_word_start(map, selection.head())
12914                        } else {
12915                            movement::previous_word_start_or_newline(map, selection.head())
12916                        };
12917                        selection.set_head(cursor, SelectionGoal::None);
12918                    }
12919                });
12920            });
12921            this.insert("", window, cx);
12922        });
12923    }
12924
12925    pub fn delete_to_previous_subword_start(
12926        &mut self,
12927        _: &DeleteToPreviousSubwordStart,
12928        window: &mut Window,
12929        cx: &mut Context<Self>,
12930    ) {
12931        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12932        self.transact(window, cx, |this, window, cx| {
12933            this.select_autoclose_pair(window, cx);
12934            this.change_selections(Default::default(), window, cx, |s| {
12935                s.move_with(|map, selection| {
12936                    if selection.is_empty() {
12937                        let cursor = movement::previous_subword_start(map, selection.head());
12938                        selection.set_head(cursor, SelectionGoal::None);
12939                    }
12940                });
12941            });
12942            this.insert("", window, cx);
12943        });
12944    }
12945
12946    pub fn move_to_next_word_end(
12947        &mut self,
12948        _: &MoveToNextWordEnd,
12949        window: &mut Window,
12950        cx: &mut Context<Self>,
12951    ) {
12952        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12953        self.change_selections(Default::default(), window, cx, |s| {
12954            s.move_cursors_with(|map, head, _| {
12955                (movement::next_word_end(map, head), SelectionGoal::None)
12956            });
12957        })
12958    }
12959
12960    pub fn move_to_next_subword_end(
12961        &mut self,
12962        _: &MoveToNextSubwordEnd,
12963        window: &mut Window,
12964        cx: &mut Context<Self>,
12965    ) {
12966        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12967        self.change_selections(Default::default(), window, cx, |s| {
12968            s.move_cursors_with(|map, head, _| {
12969                (movement::next_subword_end(map, head), SelectionGoal::None)
12970            });
12971        })
12972    }
12973
12974    pub fn select_to_next_word_end(
12975        &mut self,
12976        _: &SelectToNextWordEnd,
12977        window: &mut Window,
12978        cx: &mut Context<Self>,
12979    ) {
12980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12981        self.change_selections(Default::default(), window, cx, |s| {
12982            s.move_heads_with(|map, head, _| {
12983                (movement::next_word_end(map, head), SelectionGoal::None)
12984            });
12985        })
12986    }
12987
12988    pub fn select_to_next_subword_end(
12989        &mut self,
12990        _: &SelectToNextSubwordEnd,
12991        window: &mut Window,
12992        cx: &mut Context<Self>,
12993    ) {
12994        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12995        self.change_selections(Default::default(), window, cx, |s| {
12996            s.move_heads_with(|map, head, _| {
12997                (movement::next_subword_end(map, head), SelectionGoal::None)
12998            });
12999        })
13000    }
13001
13002    pub fn delete_to_next_word_end(
13003        &mut self,
13004        action: &DeleteToNextWordEnd,
13005        window: &mut Window,
13006        cx: &mut Context<Self>,
13007    ) {
13008        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13009        self.transact(window, cx, |this, window, cx| {
13010            this.change_selections(Default::default(), window, cx, |s| {
13011                s.move_with(|map, selection| {
13012                    if selection.is_empty() {
13013                        let cursor = if action.ignore_newlines {
13014                            movement::next_word_end(map, selection.head())
13015                        } else {
13016                            movement::next_word_end_or_newline(map, selection.head())
13017                        };
13018                        selection.set_head(cursor, SelectionGoal::None);
13019                    }
13020                });
13021            });
13022            this.insert("", window, cx);
13023        });
13024    }
13025
13026    pub fn delete_to_next_subword_end(
13027        &mut self,
13028        _: &DeleteToNextSubwordEnd,
13029        window: &mut Window,
13030        cx: &mut Context<Self>,
13031    ) {
13032        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13033        self.transact(window, cx, |this, window, cx| {
13034            this.change_selections(Default::default(), window, cx, |s| {
13035                s.move_with(|map, selection| {
13036                    if selection.is_empty() {
13037                        let cursor = movement::next_subword_end(map, selection.head());
13038                        selection.set_head(cursor, SelectionGoal::None);
13039                    }
13040                });
13041            });
13042            this.insert("", window, cx);
13043        });
13044    }
13045
13046    pub fn move_to_beginning_of_line(
13047        &mut self,
13048        action: &MoveToBeginningOfLine,
13049        window: &mut Window,
13050        cx: &mut Context<Self>,
13051    ) {
13052        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13053        self.change_selections(Default::default(), window, cx, |s| {
13054            s.move_cursors_with(|map, head, _| {
13055                (
13056                    movement::indented_line_beginning(
13057                        map,
13058                        head,
13059                        action.stop_at_soft_wraps,
13060                        action.stop_at_indent,
13061                    ),
13062                    SelectionGoal::None,
13063                )
13064            });
13065        })
13066    }
13067
13068    pub fn select_to_beginning_of_line(
13069        &mut self,
13070        action: &SelectToBeginningOfLine,
13071        window: &mut Window,
13072        cx: &mut Context<Self>,
13073    ) {
13074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13075        self.change_selections(Default::default(), window, cx, |s| {
13076            s.move_heads_with(|map, head, _| {
13077                (
13078                    movement::indented_line_beginning(
13079                        map,
13080                        head,
13081                        action.stop_at_soft_wraps,
13082                        action.stop_at_indent,
13083                    ),
13084                    SelectionGoal::None,
13085                )
13086            });
13087        });
13088    }
13089
13090    pub fn delete_to_beginning_of_line(
13091        &mut self,
13092        action: &DeleteToBeginningOfLine,
13093        window: &mut Window,
13094        cx: &mut Context<Self>,
13095    ) {
13096        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13097        self.transact(window, cx, |this, window, cx| {
13098            this.change_selections(Default::default(), window, cx, |s| {
13099                s.move_with(|_, selection| {
13100                    selection.reversed = true;
13101                });
13102            });
13103
13104            this.select_to_beginning_of_line(
13105                &SelectToBeginningOfLine {
13106                    stop_at_soft_wraps: false,
13107                    stop_at_indent: action.stop_at_indent,
13108                },
13109                window,
13110                cx,
13111            );
13112            this.backspace(&Backspace, window, cx);
13113        });
13114    }
13115
13116    pub fn move_to_end_of_line(
13117        &mut self,
13118        action: &MoveToEndOfLine,
13119        window: &mut Window,
13120        cx: &mut Context<Self>,
13121    ) {
13122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13123        self.change_selections(Default::default(), window, cx, |s| {
13124            s.move_cursors_with(|map, head, _| {
13125                (
13126                    movement::line_end(map, head, action.stop_at_soft_wraps),
13127                    SelectionGoal::None,
13128                )
13129            });
13130        })
13131    }
13132
13133    pub fn select_to_end_of_line(
13134        &mut self,
13135        action: &SelectToEndOfLine,
13136        window: &mut Window,
13137        cx: &mut Context<Self>,
13138    ) {
13139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13140        self.change_selections(Default::default(), window, cx, |s| {
13141            s.move_heads_with(|map, head, _| {
13142                (
13143                    movement::line_end(map, head, action.stop_at_soft_wraps),
13144                    SelectionGoal::None,
13145                )
13146            });
13147        })
13148    }
13149
13150    pub fn delete_to_end_of_line(
13151        &mut self,
13152        _: &DeleteToEndOfLine,
13153        window: &mut Window,
13154        cx: &mut Context<Self>,
13155    ) {
13156        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13157        self.transact(window, cx, |this, window, cx| {
13158            this.select_to_end_of_line(
13159                &SelectToEndOfLine {
13160                    stop_at_soft_wraps: false,
13161                },
13162                window,
13163                cx,
13164            );
13165            this.delete(&Delete, window, cx);
13166        });
13167    }
13168
13169    pub fn cut_to_end_of_line(
13170        &mut self,
13171        _: &CutToEndOfLine,
13172        window: &mut Window,
13173        cx: &mut Context<Self>,
13174    ) {
13175        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13176        self.transact(window, cx, |this, window, cx| {
13177            this.select_to_end_of_line(
13178                &SelectToEndOfLine {
13179                    stop_at_soft_wraps: false,
13180                },
13181                window,
13182                cx,
13183            );
13184            this.cut(&Cut, window, cx);
13185        });
13186    }
13187
13188    pub fn move_to_start_of_paragraph(
13189        &mut self,
13190        _: &MoveToStartOfParagraph,
13191        window: &mut Window,
13192        cx: &mut Context<Self>,
13193    ) {
13194        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13195            cx.propagate();
13196            return;
13197        }
13198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13199        self.change_selections(Default::default(), window, cx, |s| {
13200            s.move_with(|map, selection| {
13201                selection.collapse_to(
13202                    movement::start_of_paragraph(map, selection.head(), 1),
13203                    SelectionGoal::None,
13204                )
13205            });
13206        })
13207    }
13208
13209    pub fn move_to_end_of_paragraph(
13210        &mut self,
13211        _: &MoveToEndOfParagraph,
13212        window: &mut Window,
13213        cx: &mut Context<Self>,
13214    ) {
13215        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13216            cx.propagate();
13217            return;
13218        }
13219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13220        self.change_selections(Default::default(), window, cx, |s| {
13221            s.move_with(|map, selection| {
13222                selection.collapse_to(
13223                    movement::end_of_paragraph(map, selection.head(), 1),
13224                    SelectionGoal::None,
13225                )
13226            });
13227        })
13228    }
13229
13230    pub fn select_to_start_of_paragraph(
13231        &mut self,
13232        _: &SelectToStartOfParagraph,
13233        window: &mut Window,
13234        cx: &mut Context<Self>,
13235    ) {
13236        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13237            cx.propagate();
13238            return;
13239        }
13240        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13241        self.change_selections(Default::default(), window, cx, |s| {
13242            s.move_heads_with(|map, head, _| {
13243                (
13244                    movement::start_of_paragraph(map, head, 1),
13245                    SelectionGoal::None,
13246                )
13247            });
13248        })
13249    }
13250
13251    pub fn select_to_end_of_paragraph(
13252        &mut self,
13253        _: &SelectToEndOfParagraph,
13254        window: &mut Window,
13255        cx: &mut Context<Self>,
13256    ) {
13257        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13258            cx.propagate();
13259            return;
13260        }
13261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13262        self.change_selections(Default::default(), window, cx, |s| {
13263            s.move_heads_with(|map, head, _| {
13264                (
13265                    movement::end_of_paragraph(map, head, 1),
13266                    SelectionGoal::None,
13267                )
13268            });
13269        })
13270    }
13271
13272    pub fn move_to_start_of_excerpt(
13273        &mut self,
13274        _: &MoveToStartOfExcerpt,
13275        window: &mut Window,
13276        cx: &mut Context<Self>,
13277    ) {
13278        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13279            cx.propagate();
13280            return;
13281        }
13282        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13283        self.change_selections(Default::default(), window, cx, |s| {
13284            s.move_with(|map, selection| {
13285                selection.collapse_to(
13286                    movement::start_of_excerpt(
13287                        map,
13288                        selection.head(),
13289                        workspace::searchable::Direction::Prev,
13290                    ),
13291                    SelectionGoal::None,
13292                )
13293            });
13294        })
13295    }
13296
13297    pub fn move_to_start_of_next_excerpt(
13298        &mut self,
13299        _: &MoveToStartOfNextExcerpt,
13300        window: &mut Window,
13301        cx: &mut Context<Self>,
13302    ) {
13303        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13304            cx.propagate();
13305            return;
13306        }
13307
13308        self.change_selections(Default::default(), window, cx, |s| {
13309            s.move_with(|map, selection| {
13310                selection.collapse_to(
13311                    movement::start_of_excerpt(
13312                        map,
13313                        selection.head(),
13314                        workspace::searchable::Direction::Next,
13315                    ),
13316                    SelectionGoal::None,
13317                )
13318            });
13319        })
13320    }
13321
13322    pub fn move_to_end_of_excerpt(
13323        &mut self,
13324        _: &MoveToEndOfExcerpt,
13325        window: &mut Window,
13326        cx: &mut Context<Self>,
13327    ) {
13328        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13329            cx.propagate();
13330            return;
13331        }
13332        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13333        self.change_selections(Default::default(), window, cx, |s| {
13334            s.move_with(|map, selection| {
13335                selection.collapse_to(
13336                    movement::end_of_excerpt(
13337                        map,
13338                        selection.head(),
13339                        workspace::searchable::Direction::Next,
13340                    ),
13341                    SelectionGoal::None,
13342                )
13343            });
13344        })
13345    }
13346
13347    pub fn move_to_end_of_previous_excerpt(
13348        &mut self,
13349        _: &MoveToEndOfPreviousExcerpt,
13350        window: &mut Window,
13351        cx: &mut Context<Self>,
13352    ) {
13353        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13354            cx.propagate();
13355            return;
13356        }
13357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13358        self.change_selections(Default::default(), window, cx, |s| {
13359            s.move_with(|map, selection| {
13360                selection.collapse_to(
13361                    movement::end_of_excerpt(
13362                        map,
13363                        selection.head(),
13364                        workspace::searchable::Direction::Prev,
13365                    ),
13366                    SelectionGoal::None,
13367                )
13368            });
13369        })
13370    }
13371
13372    pub fn select_to_start_of_excerpt(
13373        &mut self,
13374        _: &SelectToStartOfExcerpt,
13375        window: &mut Window,
13376        cx: &mut Context<Self>,
13377    ) {
13378        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13379            cx.propagate();
13380            return;
13381        }
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13383        self.change_selections(Default::default(), window, cx, |s| {
13384            s.move_heads_with(|map, head, _| {
13385                (
13386                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13387                    SelectionGoal::None,
13388                )
13389            });
13390        })
13391    }
13392
13393    pub fn select_to_start_of_next_excerpt(
13394        &mut self,
13395        _: &SelectToStartOfNextExcerpt,
13396        window: &mut Window,
13397        cx: &mut Context<Self>,
13398    ) {
13399        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13400            cx.propagate();
13401            return;
13402        }
13403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13404        self.change_selections(Default::default(), window, cx, |s| {
13405            s.move_heads_with(|map, head, _| {
13406                (
13407                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13408                    SelectionGoal::None,
13409                )
13410            });
13411        })
13412    }
13413
13414    pub fn select_to_end_of_excerpt(
13415        &mut self,
13416        _: &SelectToEndOfExcerpt,
13417        window: &mut Window,
13418        cx: &mut Context<Self>,
13419    ) {
13420        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13421            cx.propagate();
13422            return;
13423        }
13424        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13425        self.change_selections(Default::default(), window, cx, |s| {
13426            s.move_heads_with(|map, head, _| {
13427                (
13428                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13429                    SelectionGoal::None,
13430                )
13431            });
13432        })
13433    }
13434
13435    pub fn select_to_end_of_previous_excerpt(
13436        &mut self,
13437        _: &SelectToEndOfPreviousExcerpt,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13442            cx.propagate();
13443            return;
13444        }
13445        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13446        self.change_selections(Default::default(), window, cx, |s| {
13447            s.move_heads_with(|map, head, _| {
13448                (
13449                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13450                    SelectionGoal::None,
13451                )
13452            });
13453        })
13454    }
13455
13456    pub fn move_to_beginning(
13457        &mut self,
13458        _: &MoveToBeginning,
13459        window: &mut Window,
13460        cx: &mut Context<Self>,
13461    ) {
13462        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13463            cx.propagate();
13464            return;
13465        }
13466        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13467        self.change_selections(Default::default(), window, cx, |s| {
13468            s.select_ranges(vec![0..0]);
13469        });
13470    }
13471
13472    pub fn select_to_beginning(
13473        &mut self,
13474        _: &SelectToBeginning,
13475        window: &mut Window,
13476        cx: &mut Context<Self>,
13477    ) {
13478        let mut selection = self.selections.last::<Point>(cx);
13479        selection.set_head(Point::zero(), SelectionGoal::None);
13480        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13481        self.change_selections(Default::default(), window, cx, |s| {
13482            s.select(vec![selection]);
13483        });
13484    }
13485
13486    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13487        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13488            cx.propagate();
13489            return;
13490        }
13491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13492        let cursor = self.buffer.read(cx).read(cx).len();
13493        self.change_selections(Default::default(), window, cx, |s| {
13494            s.select_ranges(vec![cursor..cursor])
13495        });
13496    }
13497
13498    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13499        self.nav_history = nav_history;
13500    }
13501
13502    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13503        self.nav_history.as_ref()
13504    }
13505
13506    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13507        self.push_to_nav_history(
13508            self.selections.newest_anchor().head(),
13509            None,
13510            false,
13511            true,
13512            cx,
13513        );
13514    }
13515
13516    fn push_to_nav_history(
13517        &mut self,
13518        cursor_anchor: Anchor,
13519        new_position: Option<Point>,
13520        is_deactivate: bool,
13521        always: bool,
13522        cx: &mut Context<Self>,
13523    ) {
13524        if let Some(nav_history) = self.nav_history.as_mut() {
13525            let buffer = self.buffer.read(cx).read(cx);
13526            let cursor_position = cursor_anchor.to_point(&buffer);
13527            let scroll_state = self.scroll_manager.anchor();
13528            let scroll_top_row = scroll_state.top_row(&buffer);
13529            drop(buffer);
13530
13531            if let Some(new_position) = new_position {
13532                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13533                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13534                    return;
13535                }
13536            }
13537
13538            nav_history.push(
13539                Some(NavigationData {
13540                    cursor_anchor,
13541                    cursor_position,
13542                    scroll_anchor: scroll_state,
13543                    scroll_top_row,
13544                }),
13545                cx,
13546            );
13547            cx.emit(EditorEvent::PushedToNavHistory {
13548                anchor: cursor_anchor,
13549                is_deactivate,
13550            })
13551        }
13552    }
13553
13554    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13556        let buffer = self.buffer.read(cx).snapshot(cx);
13557        let mut selection = self.selections.first::<usize>(cx);
13558        selection.set_head(buffer.len(), SelectionGoal::None);
13559        self.change_selections(Default::default(), window, cx, |s| {
13560            s.select(vec![selection]);
13561        });
13562    }
13563
13564    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13566        let end = self.buffer.read(cx).read(cx).len();
13567        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13568            s.select_ranges(vec![0..end]);
13569        });
13570    }
13571
13572    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13573        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13574        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13575        let mut selections = self.selections.all::<Point>(cx);
13576        let max_point = display_map.buffer_snapshot.max_point();
13577        for selection in &mut selections {
13578            let rows = selection.spanned_rows(true, &display_map);
13579            selection.start = Point::new(rows.start.0, 0);
13580            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13581            selection.reversed = false;
13582        }
13583        self.change_selections(Default::default(), window, cx, |s| {
13584            s.select(selections);
13585        });
13586    }
13587
13588    pub fn split_selection_into_lines(
13589        &mut self,
13590        _: &SplitSelectionIntoLines,
13591        window: &mut Window,
13592        cx: &mut Context<Self>,
13593    ) {
13594        let selections = self
13595            .selections
13596            .all::<Point>(cx)
13597            .into_iter()
13598            .map(|selection| selection.start..selection.end)
13599            .collect::<Vec<_>>();
13600        self.unfold_ranges(&selections, true, true, cx);
13601
13602        let mut new_selection_ranges = Vec::new();
13603        {
13604            let buffer = self.buffer.read(cx).read(cx);
13605            for selection in selections {
13606                for row in selection.start.row..selection.end.row {
13607                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13608                    new_selection_ranges.push(cursor..cursor);
13609                }
13610
13611                let is_multiline_selection = selection.start.row != selection.end.row;
13612                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13613                // so this action feels more ergonomic when paired with other selection operations
13614                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13615                if !should_skip_last {
13616                    new_selection_ranges.push(selection.end..selection.end);
13617                }
13618            }
13619        }
13620        self.change_selections(Default::default(), window, cx, |s| {
13621            s.select_ranges(new_selection_ranges);
13622        });
13623    }
13624
13625    pub fn add_selection_above(
13626        &mut self,
13627        _: &AddSelectionAbove,
13628        window: &mut Window,
13629        cx: &mut Context<Self>,
13630    ) {
13631        self.add_selection(true, window, cx);
13632    }
13633
13634    pub fn add_selection_below(
13635        &mut self,
13636        _: &AddSelectionBelow,
13637        window: &mut Window,
13638        cx: &mut Context<Self>,
13639    ) {
13640        self.add_selection(false, window, cx);
13641    }
13642
13643    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13644        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13645
13646        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13647        let all_selections = self.selections.all::<Point>(cx);
13648        let text_layout_details = self.text_layout_details(window);
13649
13650        let (mut columnar_selections, new_selections_to_columnarize) = {
13651            if let Some(state) = self.add_selections_state.as_ref() {
13652                let columnar_selection_ids: HashSet<_> = state
13653                    .groups
13654                    .iter()
13655                    .flat_map(|group| group.stack.iter())
13656                    .copied()
13657                    .collect();
13658
13659                all_selections
13660                    .into_iter()
13661                    .partition(|s| columnar_selection_ids.contains(&s.id))
13662            } else {
13663                (Vec::new(), all_selections)
13664            }
13665        };
13666
13667        let mut state = self
13668            .add_selections_state
13669            .take()
13670            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13671
13672        for selection in new_selections_to_columnarize {
13673            let range = selection.display_range(&display_map).sorted();
13674            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13675            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13676            let positions = start_x.min(end_x)..start_x.max(end_x);
13677            let mut stack = Vec::new();
13678            for row in range.start.row().0..=range.end.row().0 {
13679                if let Some(selection) = self.selections.build_columnar_selection(
13680                    &display_map,
13681                    DisplayRow(row),
13682                    &positions,
13683                    selection.reversed,
13684                    &text_layout_details,
13685                ) {
13686                    stack.push(selection.id);
13687                    columnar_selections.push(selection);
13688                }
13689            }
13690            if !stack.is_empty() {
13691                if above {
13692                    stack.reverse();
13693                }
13694                state.groups.push(AddSelectionsGroup { above, stack });
13695            }
13696        }
13697
13698        let mut final_selections = Vec::new();
13699        let end_row = if above {
13700            DisplayRow(0)
13701        } else {
13702            display_map.max_point().row()
13703        };
13704
13705        let mut last_added_item_per_group = HashMap::default();
13706        for group in state.groups.iter_mut() {
13707            if let Some(last_id) = group.stack.last() {
13708                last_added_item_per_group.insert(*last_id, group);
13709            }
13710        }
13711
13712        for selection in columnar_selections {
13713            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13714                if above == group.above {
13715                    let range = selection.display_range(&display_map).sorted();
13716                    debug_assert_eq!(range.start.row(), range.end.row());
13717                    let mut row = range.start.row();
13718                    let positions =
13719                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13720                            px(start)..px(end)
13721                        } else {
13722                            let start_x =
13723                                display_map.x_for_display_point(range.start, &text_layout_details);
13724                            let end_x =
13725                                display_map.x_for_display_point(range.end, &text_layout_details);
13726                            start_x.min(end_x)..start_x.max(end_x)
13727                        };
13728
13729                    let mut maybe_new_selection = None;
13730                    while row != end_row {
13731                        if above {
13732                            row.0 -= 1;
13733                        } else {
13734                            row.0 += 1;
13735                        }
13736                        if let Some(new_selection) = self.selections.build_columnar_selection(
13737                            &display_map,
13738                            row,
13739                            &positions,
13740                            selection.reversed,
13741                            &text_layout_details,
13742                        ) {
13743                            maybe_new_selection = Some(new_selection);
13744                            break;
13745                        }
13746                    }
13747
13748                    if let Some(new_selection) = maybe_new_selection {
13749                        group.stack.push(new_selection.id);
13750                        if above {
13751                            final_selections.push(new_selection);
13752                            final_selections.push(selection);
13753                        } else {
13754                            final_selections.push(selection);
13755                            final_selections.push(new_selection);
13756                        }
13757                    } else {
13758                        final_selections.push(selection);
13759                    }
13760                } else {
13761                    group.stack.pop();
13762                }
13763            } else {
13764                final_selections.push(selection);
13765            }
13766        }
13767
13768        self.change_selections(Default::default(), window, cx, |s| {
13769            s.select(final_selections);
13770        });
13771
13772        let final_selection_ids: HashSet<_> = self
13773            .selections
13774            .all::<Point>(cx)
13775            .iter()
13776            .map(|s| s.id)
13777            .collect();
13778        state.groups.retain_mut(|group| {
13779            // selections might get merged above so we remove invalid items from stacks
13780            group.stack.retain(|id| final_selection_ids.contains(id));
13781
13782            // single selection in stack can be treated as initial state
13783            group.stack.len() > 1
13784        });
13785
13786        if !state.groups.is_empty() {
13787            self.add_selections_state = Some(state);
13788        }
13789    }
13790
13791    fn select_match_ranges(
13792        &mut self,
13793        range: Range<usize>,
13794        reversed: bool,
13795        replace_newest: bool,
13796        auto_scroll: Option<Autoscroll>,
13797        window: &mut Window,
13798        cx: &mut Context<Editor>,
13799    ) {
13800        self.unfold_ranges(
13801            std::slice::from_ref(&range),
13802            false,
13803            auto_scroll.is_some(),
13804            cx,
13805        );
13806        let effects = if let Some(scroll) = auto_scroll {
13807            SelectionEffects::scroll(scroll)
13808        } else {
13809            SelectionEffects::no_scroll()
13810        };
13811        self.change_selections(effects, window, cx, |s| {
13812            if replace_newest {
13813                s.delete(s.newest_anchor().id);
13814            }
13815            if reversed {
13816                s.insert_range(range.end..range.start);
13817            } else {
13818                s.insert_range(range);
13819            }
13820        });
13821    }
13822
13823    pub fn select_next_match_internal(
13824        &mut self,
13825        display_map: &DisplaySnapshot,
13826        replace_newest: bool,
13827        autoscroll: Option<Autoscroll>,
13828        window: &mut Window,
13829        cx: &mut Context<Self>,
13830    ) -> Result<()> {
13831        let buffer = &display_map.buffer_snapshot;
13832        let mut selections = self.selections.all::<usize>(cx);
13833        if let Some(mut select_next_state) = self.select_next_state.take() {
13834            let query = &select_next_state.query;
13835            if !select_next_state.done {
13836                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13837                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13838                let mut next_selected_range = None;
13839
13840                let bytes_after_last_selection =
13841                    buffer.bytes_in_range(last_selection.end..buffer.len());
13842                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13843                let query_matches = query
13844                    .stream_find_iter(bytes_after_last_selection)
13845                    .map(|result| (last_selection.end, result))
13846                    .chain(
13847                        query
13848                            .stream_find_iter(bytes_before_first_selection)
13849                            .map(|result| (0, result)),
13850                    );
13851
13852                for (start_offset, query_match) in query_matches {
13853                    let query_match = query_match.unwrap(); // can only fail due to I/O
13854                    let offset_range =
13855                        start_offset + query_match.start()..start_offset + query_match.end();
13856
13857                    if !select_next_state.wordwise
13858                        || (!buffer.is_inside_word(offset_range.start, false)
13859                            && !buffer.is_inside_word(offset_range.end, false))
13860                    {
13861                        // TODO: This is n^2, because we might check all the selections
13862                        if !selections
13863                            .iter()
13864                            .any(|selection| selection.range().overlaps(&offset_range))
13865                        {
13866                            next_selected_range = Some(offset_range);
13867                            break;
13868                        }
13869                    }
13870                }
13871
13872                if let Some(next_selected_range) = next_selected_range {
13873                    self.select_match_ranges(
13874                        next_selected_range,
13875                        last_selection.reversed,
13876                        replace_newest,
13877                        autoscroll,
13878                        window,
13879                        cx,
13880                    );
13881                } else {
13882                    select_next_state.done = true;
13883                }
13884            }
13885
13886            self.select_next_state = Some(select_next_state);
13887        } else {
13888            let mut only_carets = true;
13889            let mut same_text_selected = true;
13890            let mut selected_text = None;
13891
13892            let mut selections_iter = selections.iter().peekable();
13893            while let Some(selection) = selections_iter.next() {
13894                if selection.start != selection.end {
13895                    only_carets = false;
13896                }
13897
13898                if same_text_selected {
13899                    if selected_text.is_none() {
13900                        selected_text =
13901                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13902                    }
13903
13904                    if let Some(next_selection) = selections_iter.peek() {
13905                        if next_selection.range().len() == selection.range().len() {
13906                            let next_selected_text = buffer
13907                                .text_for_range(next_selection.range())
13908                                .collect::<String>();
13909                            if Some(next_selected_text) != selected_text {
13910                                same_text_selected = false;
13911                                selected_text = None;
13912                            }
13913                        } else {
13914                            same_text_selected = false;
13915                            selected_text = None;
13916                        }
13917                    }
13918                }
13919            }
13920
13921            if only_carets {
13922                for selection in &mut selections {
13923                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13924                    selection.start = word_range.start;
13925                    selection.end = word_range.end;
13926                    selection.goal = SelectionGoal::None;
13927                    selection.reversed = false;
13928                    self.select_match_ranges(
13929                        selection.start..selection.end,
13930                        selection.reversed,
13931                        replace_newest,
13932                        autoscroll,
13933                        window,
13934                        cx,
13935                    );
13936                }
13937
13938                if selections.len() == 1 {
13939                    let selection = selections
13940                        .last()
13941                        .expect("ensured that there's only one selection");
13942                    let query = buffer
13943                        .text_for_range(selection.start..selection.end)
13944                        .collect::<String>();
13945                    let is_empty = query.is_empty();
13946                    let select_state = SelectNextState {
13947                        query: AhoCorasick::new(&[query])?,
13948                        wordwise: true,
13949                        done: is_empty,
13950                    };
13951                    self.select_next_state = Some(select_state);
13952                } else {
13953                    self.select_next_state = None;
13954                }
13955            } else if let Some(selected_text) = selected_text {
13956                self.select_next_state = Some(SelectNextState {
13957                    query: AhoCorasick::new(&[selected_text])?,
13958                    wordwise: false,
13959                    done: false,
13960                });
13961                self.select_next_match_internal(
13962                    display_map,
13963                    replace_newest,
13964                    autoscroll,
13965                    window,
13966                    cx,
13967                )?;
13968            }
13969        }
13970        Ok(())
13971    }
13972
13973    pub fn select_all_matches(
13974        &mut self,
13975        _action: &SelectAllMatches,
13976        window: &mut Window,
13977        cx: &mut Context<Self>,
13978    ) -> Result<()> {
13979        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13980
13981        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13982
13983        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13984        let Some(select_next_state) = self.select_next_state.as_mut() else {
13985            return Ok(());
13986        };
13987        if select_next_state.done {
13988            return Ok(());
13989        }
13990
13991        let mut new_selections = Vec::new();
13992
13993        let reversed = self.selections.oldest::<usize>(cx).reversed;
13994        let buffer = &display_map.buffer_snapshot;
13995        let query_matches = select_next_state
13996            .query
13997            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13998
13999        for query_match in query_matches.into_iter() {
14000            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14001            let offset_range = if reversed {
14002                query_match.end()..query_match.start()
14003            } else {
14004                query_match.start()..query_match.end()
14005            };
14006
14007            if !select_next_state.wordwise
14008                || (!buffer.is_inside_word(offset_range.start, false)
14009                    && !buffer.is_inside_word(offset_range.end, false))
14010            {
14011                new_selections.push(offset_range.start..offset_range.end);
14012            }
14013        }
14014
14015        select_next_state.done = true;
14016
14017        if new_selections.is_empty() {
14018            log::error!("bug: new_selections is empty in select_all_matches");
14019            return Ok(());
14020        }
14021
14022        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14023        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14024            selections.select_ranges(new_selections)
14025        });
14026
14027        Ok(())
14028    }
14029
14030    pub fn select_next(
14031        &mut self,
14032        action: &SelectNext,
14033        window: &mut Window,
14034        cx: &mut Context<Self>,
14035    ) -> Result<()> {
14036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14037        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14038        self.select_next_match_internal(
14039            &display_map,
14040            action.replace_newest,
14041            Some(Autoscroll::newest()),
14042            window,
14043            cx,
14044        )?;
14045        Ok(())
14046    }
14047
14048    pub fn select_previous(
14049        &mut self,
14050        action: &SelectPrevious,
14051        window: &mut Window,
14052        cx: &mut Context<Self>,
14053    ) -> Result<()> {
14054        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14055        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14056        let buffer = &display_map.buffer_snapshot;
14057        let mut selections = self.selections.all::<usize>(cx);
14058        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14059            let query = &select_prev_state.query;
14060            if !select_prev_state.done {
14061                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14062                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14063                let mut next_selected_range = None;
14064                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14065                let bytes_before_last_selection =
14066                    buffer.reversed_bytes_in_range(0..last_selection.start);
14067                let bytes_after_first_selection =
14068                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14069                let query_matches = query
14070                    .stream_find_iter(bytes_before_last_selection)
14071                    .map(|result| (last_selection.start, result))
14072                    .chain(
14073                        query
14074                            .stream_find_iter(bytes_after_first_selection)
14075                            .map(|result| (buffer.len(), result)),
14076                    );
14077                for (end_offset, query_match) in query_matches {
14078                    let query_match = query_match.unwrap(); // can only fail due to I/O
14079                    let offset_range =
14080                        end_offset - query_match.end()..end_offset - query_match.start();
14081
14082                    if !select_prev_state.wordwise
14083                        || (!buffer.is_inside_word(offset_range.start, false)
14084                            && !buffer.is_inside_word(offset_range.end, false))
14085                    {
14086                        next_selected_range = Some(offset_range);
14087                        break;
14088                    }
14089                }
14090
14091                if let Some(next_selected_range) = next_selected_range {
14092                    self.select_match_ranges(
14093                        next_selected_range,
14094                        last_selection.reversed,
14095                        action.replace_newest,
14096                        Some(Autoscroll::newest()),
14097                        window,
14098                        cx,
14099                    );
14100                } else {
14101                    select_prev_state.done = true;
14102                }
14103            }
14104
14105            self.select_prev_state = Some(select_prev_state);
14106        } else {
14107            let mut only_carets = true;
14108            let mut same_text_selected = true;
14109            let mut selected_text = None;
14110
14111            let mut selections_iter = selections.iter().peekable();
14112            while let Some(selection) = selections_iter.next() {
14113                if selection.start != selection.end {
14114                    only_carets = false;
14115                }
14116
14117                if same_text_selected {
14118                    if selected_text.is_none() {
14119                        selected_text =
14120                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14121                    }
14122
14123                    if let Some(next_selection) = selections_iter.peek() {
14124                        if next_selection.range().len() == selection.range().len() {
14125                            let next_selected_text = buffer
14126                                .text_for_range(next_selection.range())
14127                                .collect::<String>();
14128                            if Some(next_selected_text) != selected_text {
14129                                same_text_selected = false;
14130                                selected_text = None;
14131                            }
14132                        } else {
14133                            same_text_selected = false;
14134                            selected_text = None;
14135                        }
14136                    }
14137                }
14138            }
14139
14140            if only_carets {
14141                for selection in &mut selections {
14142                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14143                    selection.start = word_range.start;
14144                    selection.end = word_range.end;
14145                    selection.goal = SelectionGoal::None;
14146                    selection.reversed = false;
14147                    self.select_match_ranges(
14148                        selection.start..selection.end,
14149                        selection.reversed,
14150                        action.replace_newest,
14151                        Some(Autoscroll::newest()),
14152                        window,
14153                        cx,
14154                    );
14155                }
14156                if selections.len() == 1 {
14157                    let selection = selections
14158                        .last()
14159                        .expect("ensured that there's only one selection");
14160                    let query = buffer
14161                        .text_for_range(selection.start..selection.end)
14162                        .collect::<String>();
14163                    let is_empty = query.is_empty();
14164                    let select_state = SelectNextState {
14165                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14166                        wordwise: true,
14167                        done: is_empty,
14168                    };
14169                    self.select_prev_state = Some(select_state);
14170                } else {
14171                    self.select_prev_state = None;
14172                }
14173            } else if let Some(selected_text) = selected_text {
14174                self.select_prev_state = Some(SelectNextState {
14175                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14176                    wordwise: false,
14177                    done: false,
14178                });
14179                self.select_previous(action, window, cx)?;
14180            }
14181        }
14182        Ok(())
14183    }
14184
14185    pub fn find_next_match(
14186        &mut self,
14187        _: &FindNextMatch,
14188        window: &mut Window,
14189        cx: &mut Context<Self>,
14190    ) -> Result<()> {
14191        let selections = self.selections.disjoint_anchors();
14192        match selections.first() {
14193            Some(first) if selections.len() >= 2 => {
14194                self.change_selections(Default::default(), window, cx, |s| {
14195                    s.select_ranges([first.range()]);
14196                });
14197            }
14198            _ => self.select_next(
14199                &SelectNext {
14200                    replace_newest: true,
14201                },
14202                window,
14203                cx,
14204            )?,
14205        }
14206        Ok(())
14207    }
14208
14209    pub fn find_previous_match(
14210        &mut self,
14211        _: &FindPreviousMatch,
14212        window: &mut Window,
14213        cx: &mut Context<Self>,
14214    ) -> Result<()> {
14215        let selections = self.selections.disjoint_anchors();
14216        match selections.last() {
14217            Some(last) if selections.len() >= 2 => {
14218                self.change_selections(Default::default(), window, cx, |s| {
14219                    s.select_ranges([last.range()]);
14220                });
14221            }
14222            _ => self.select_previous(
14223                &SelectPrevious {
14224                    replace_newest: true,
14225                },
14226                window,
14227                cx,
14228            )?,
14229        }
14230        Ok(())
14231    }
14232
14233    pub fn toggle_comments(
14234        &mut self,
14235        action: &ToggleComments,
14236        window: &mut Window,
14237        cx: &mut Context<Self>,
14238    ) {
14239        if self.read_only(cx) {
14240            return;
14241        }
14242        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14243        let text_layout_details = &self.text_layout_details(window);
14244        self.transact(window, cx, |this, window, cx| {
14245            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14246            let mut edits = Vec::new();
14247            let mut selection_edit_ranges = Vec::new();
14248            let mut last_toggled_row = None;
14249            let snapshot = this.buffer.read(cx).read(cx);
14250            let empty_str: Arc<str> = Arc::default();
14251            let mut suffixes_inserted = Vec::new();
14252            let ignore_indent = action.ignore_indent;
14253
14254            fn comment_prefix_range(
14255                snapshot: &MultiBufferSnapshot,
14256                row: MultiBufferRow,
14257                comment_prefix: &str,
14258                comment_prefix_whitespace: &str,
14259                ignore_indent: bool,
14260            ) -> Range<Point> {
14261                let indent_size = if ignore_indent {
14262                    0
14263                } else {
14264                    snapshot.indent_size_for_line(row).len
14265                };
14266
14267                let start = Point::new(row.0, indent_size);
14268
14269                let mut line_bytes = snapshot
14270                    .bytes_in_range(start..snapshot.max_point())
14271                    .flatten()
14272                    .copied();
14273
14274                // If this line currently begins with the line comment prefix, then record
14275                // the range containing the prefix.
14276                if line_bytes
14277                    .by_ref()
14278                    .take(comment_prefix.len())
14279                    .eq(comment_prefix.bytes())
14280                {
14281                    // Include any whitespace that matches the comment prefix.
14282                    let matching_whitespace_len = line_bytes
14283                        .zip(comment_prefix_whitespace.bytes())
14284                        .take_while(|(a, b)| a == b)
14285                        .count() as u32;
14286                    let end = Point::new(
14287                        start.row,
14288                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14289                    );
14290                    start..end
14291                } else {
14292                    start..start
14293                }
14294            }
14295
14296            fn comment_suffix_range(
14297                snapshot: &MultiBufferSnapshot,
14298                row: MultiBufferRow,
14299                comment_suffix: &str,
14300                comment_suffix_has_leading_space: bool,
14301            ) -> Range<Point> {
14302                let end = Point::new(row.0, snapshot.line_len(row));
14303                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14304
14305                let mut line_end_bytes = snapshot
14306                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14307                    .flatten()
14308                    .copied();
14309
14310                let leading_space_len = if suffix_start_column > 0
14311                    && line_end_bytes.next() == Some(b' ')
14312                    && comment_suffix_has_leading_space
14313                {
14314                    1
14315                } else {
14316                    0
14317                };
14318
14319                // If this line currently begins with the line comment prefix, then record
14320                // the range containing the prefix.
14321                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14322                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14323                    start..end
14324                } else {
14325                    end..end
14326                }
14327            }
14328
14329            // TODO: Handle selections that cross excerpts
14330            for selection in &mut selections {
14331                let start_column = snapshot
14332                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14333                    .len;
14334                let language = if let Some(language) =
14335                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14336                {
14337                    language
14338                } else {
14339                    continue;
14340                };
14341
14342                selection_edit_ranges.clear();
14343
14344                // If multiple selections contain a given row, avoid processing that
14345                // row more than once.
14346                let mut start_row = MultiBufferRow(selection.start.row);
14347                if last_toggled_row == Some(start_row) {
14348                    start_row = start_row.next_row();
14349                }
14350                let end_row =
14351                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14352                        MultiBufferRow(selection.end.row - 1)
14353                    } else {
14354                        MultiBufferRow(selection.end.row)
14355                    };
14356                last_toggled_row = Some(end_row);
14357
14358                if start_row > end_row {
14359                    continue;
14360                }
14361
14362                // If the language has line comments, toggle those.
14363                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14364
14365                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14366                if ignore_indent {
14367                    full_comment_prefixes = full_comment_prefixes
14368                        .into_iter()
14369                        .map(|s| Arc::from(s.trim_end()))
14370                        .collect();
14371                }
14372
14373                if !full_comment_prefixes.is_empty() {
14374                    let first_prefix = full_comment_prefixes
14375                        .first()
14376                        .expect("prefixes is non-empty");
14377                    let prefix_trimmed_lengths = full_comment_prefixes
14378                        .iter()
14379                        .map(|p| p.trim_end_matches(' ').len())
14380                        .collect::<SmallVec<[usize; 4]>>();
14381
14382                    let mut all_selection_lines_are_comments = true;
14383
14384                    for row in start_row.0..=end_row.0 {
14385                        let row = MultiBufferRow(row);
14386                        if start_row < end_row && snapshot.is_line_blank(row) {
14387                            continue;
14388                        }
14389
14390                        let prefix_range = full_comment_prefixes
14391                            .iter()
14392                            .zip(prefix_trimmed_lengths.iter().copied())
14393                            .map(|(prefix, trimmed_prefix_len)| {
14394                                comment_prefix_range(
14395                                    snapshot.deref(),
14396                                    row,
14397                                    &prefix[..trimmed_prefix_len],
14398                                    &prefix[trimmed_prefix_len..],
14399                                    ignore_indent,
14400                                )
14401                            })
14402                            .max_by_key(|range| range.end.column - range.start.column)
14403                            .expect("prefixes is non-empty");
14404
14405                        if prefix_range.is_empty() {
14406                            all_selection_lines_are_comments = false;
14407                        }
14408
14409                        selection_edit_ranges.push(prefix_range);
14410                    }
14411
14412                    if all_selection_lines_are_comments {
14413                        edits.extend(
14414                            selection_edit_ranges
14415                                .iter()
14416                                .cloned()
14417                                .map(|range| (range, empty_str.clone())),
14418                        );
14419                    } else {
14420                        let min_column = selection_edit_ranges
14421                            .iter()
14422                            .map(|range| range.start.column)
14423                            .min()
14424                            .unwrap_or(0);
14425                        edits.extend(selection_edit_ranges.iter().map(|range| {
14426                            let position = Point::new(range.start.row, min_column);
14427                            (position..position, first_prefix.clone())
14428                        }));
14429                    }
14430                } else if let Some(BlockCommentConfig {
14431                    start: full_comment_prefix,
14432                    end: comment_suffix,
14433                    ..
14434                }) = language.block_comment()
14435                {
14436                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14437                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14438                    let prefix_range = comment_prefix_range(
14439                        snapshot.deref(),
14440                        start_row,
14441                        comment_prefix,
14442                        comment_prefix_whitespace,
14443                        ignore_indent,
14444                    );
14445                    let suffix_range = comment_suffix_range(
14446                        snapshot.deref(),
14447                        end_row,
14448                        comment_suffix.trim_start_matches(' '),
14449                        comment_suffix.starts_with(' '),
14450                    );
14451
14452                    if prefix_range.is_empty() || suffix_range.is_empty() {
14453                        edits.push((
14454                            prefix_range.start..prefix_range.start,
14455                            full_comment_prefix.clone(),
14456                        ));
14457                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14458                        suffixes_inserted.push((end_row, comment_suffix.len()));
14459                    } else {
14460                        edits.push((prefix_range, empty_str.clone()));
14461                        edits.push((suffix_range, empty_str.clone()));
14462                    }
14463                } else {
14464                    continue;
14465                }
14466            }
14467
14468            drop(snapshot);
14469            this.buffer.update(cx, |buffer, cx| {
14470                buffer.edit(edits, None, cx);
14471            });
14472
14473            // Adjust selections so that they end before any comment suffixes that
14474            // were inserted.
14475            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14476            let mut selections = this.selections.all::<Point>(cx);
14477            let snapshot = this.buffer.read(cx).read(cx);
14478            for selection in &mut selections {
14479                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14480                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14481                        Ordering::Less => {
14482                            suffixes_inserted.next();
14483                            continue;
14484                        }
14485                        Ordering::Greater => break,
14486                        Ordering::Equal => {
14487                            if selection.end.column == snapshot.line_len(row) {
14488                                if selection.is_empty() {
14489                                    selection.start.column -= suffix_len as u32;
14490                                }
14491                                selection.end.column -= suffix_len as u32;
14492                            }
14493                            break;
14494                        }
14495                    }
14496                }
14497            }
14498
14499            drop(snapshot);
14500            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14501
14502            let selections = this.selections.all::<Point>(cx);
14503            let selections_on_single_row = selections.windows(2).all(|selections| {
14504                selections[0].start.row == selections[1].start.row
14505                    && selections[0].end.row == selections[1].end.row
14506                    && selections[0].start.row == selections[0].end.row
14507            });
14508            let selections_selecting = selections
14509                .iter()
14510                .any(|selection| selection.start != selection.end);
14511            let advance_downwards = action.advance_downwards
14512                && selections_on_single_row
14513                && !selections_selecting
14514                && !matches!(this.mode, EditorMode::SingleLine { .. });
14515
14516            if advance_downwards {
14517                let snapshot = this.buffer.read(cx).snapshot(cx);
14518
14519                this.change_selections(Default::default(), window, cx, |s| {
14520                    s.move_cursors_with(|display_snapshot, display_point, _| {
14521                        let mut point = display_point.to_point(display_snapshot);
14522                        point.row += 1;
14523                        point = snapshot.clip_point(point, Bias::Left);
14524                        let display_point = point.to_display_point(display_snapshot);
14525                        let goal = SelectionGoal::HorizontalPosition(
14526                            display_snapshot
14527                                .x_for_display_point(display_point, text_layout_details)
14528                                .into(),
14529                        );
14530                        (display_point, goal)
14531                    })
14532                });
14533            }
14534        });
14535    }
14536
14537    pub fn select_enclosing_symbol(
14538        &mut self,
14539        _: &SelectEnclosingSymbol,
14540        window: &mut Window,
14541        cx: &mut Context<Self>,
14542    ) {
14543        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14544
14545        let buffer = self.buffer.read(cx).snapshot(cx);
14546        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14547
14548        fn update_selection(
14549            selection: &Selection<usize>,
14550            buffer_snap: &MultiBufferSnapshot,
14551        ) -> Option<Selection<usize>> {
14552            let cursor = selection.head();
14553            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14554            for symbol in symbols.iter().rev() {
14555                let start = symbol.range.start.to_offset(buffer_snap);
14556                let end = symbol.range.end.to_offset(buffer_snap);
14557                let new_range = start..end;
14558                if start < selection.start || end > selection.end {
14559                    return Some(Selection {
14560                        id: selection.id,
14561                        start: new_range.start,
14562                        end: new_range.end,
14563                        goal: SelectionGoal::None,
14564                        reversed: selection.reversed,
14565                    });
14566                }
14567            }
14568            None
14569        }
14570
14571        let mut selected_larger_symbol = false;
14572        let new_selections = old_selections
14573            .iter()
14574            .map(|selection| match update_selection(selection, &buffer) {
14575                Some(new_selection) => {
14576                    if new_selection.range() != selection.range() {
14577                        selected_larger_symbol = true;
14578                    }
14579                    new_selection
14580                }
14581                None => selection.clone(),
14582            })
14583            .collect::<Vec<_>>();
14584
14585        if selected_larger_symbol {
14586            self.change_selections(Default::default(), window, cx, |s| {
14587                s.select(new_selections);
14588            });
14589        }
14590    }
14591
14592    pub fn select_larger_syntax_node(
14593        &mut self,
14594        _: &SelectLargerSyntaxNode,
14595        window: &mut Window,
14596        cx: &mut Context<Self>,
14597    ) {
14598        let Some(visible_row_count) = self.visible_row_count() else {
14599            return;
14600        };
14601        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14602        if old_selections.is_empty() {
14603            return;
14604        }
14605
14606        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14607
14608        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14609        let buffer = self.buffer.read(cx).snapshot(cx);
14610
14611        let mut selected_larger_node = false;
14612        let mut new_selections = old_selections
14613            .iter()
14614            .map(|selection| {
14615                let old_range = selection.start..selection.end;
14616
14617                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14618                    // manually select word at selection
14619                    if ["string_content", "inline"].contains(&node.kind()) {
14620                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14621                        // ignore if word is already selected
14622                        if !word_range.is_empty() && old_range != word_range {
14623                            let (last_word_range, _) =
14624                                buffer.surrounding_word(old_range.end, false);
14625                            // only select word if start and end point belongs to same word
14626                            if word_range == last_word_range {
14627                                selected_larger_node = true;
14628                                return Selection {
14629                                    id: selection.id,
14630                                    start: word_range.start,
14631                                    end: word_range.end,
14632                                    goal: SelectionGoal::None,
14633                                    reversed: selection.reversed,
14634                                };
14635                            }
14636                        }
14637                    }
14638                }
14639
14640                let mut new_range = old_range.clone();
14641                while let Some((_node, containing_range)) =
14642                    buffer.syntax_ancestor(new_range.clone())
14643                {
14644                    new_range = match containing_range {
14645                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14646                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14647                    };
14648                    if !display_map.intersects_fold(new_range.start)
14649                        && !display_map.intersects_fold(new_range.end)
14650                    {
14651                        break;
14652                    }
14653                }
14654
14655                selected_larger_node |= new_range != old_range;
14656                Selection {
14657                    id: selection.id,
14658                    start: new_range.start,
14659                    end: new_range.end,
14660                    goal: SelectionGoal::None,
14661                    reversed: selection.reversed,
14662                }
14663            })
14664            .collect::<Vec<_>>();
14665
14666        if !selected_larger_node {
14667            return; // don't put this call in the history
14668        }
14669
14670        // scroll based on transformation done to the last selection created by the user
14671        let (last_old, last_new) = old_selections
14672            .last()
14673            .zip(new_selections.last().cloned())
14674            .expect("old_selections isn't empty");
14675
14676        // revert selection
14677        let is_selection_reversed = {
14678            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14679            new_selections.last_mut().expect("checked above").reversed =
14680                should_newest_selection_be_reversed;
14681            should_newest_selection_be_reversed
14682        };
14683
14684        if selected_larger_node {
14685            self.select_syntax_node_history.disable_clearing = true;
14686            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14687                s.select(new_selections.clone());
14688            });
14689            self.select_syntax_node_history.disable_clearing = false;
14690        }
14691
14692        let start_row = last_new.start.to_display_point(&display_map).row().0;
14693        let end_row = last_new.end.to_display_point(&display_map).row().0;
14694        let selection_height = end_row - start_row + 1;
14695        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14696
14697        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14698        let scroll_behavior = if fits_on_the_screen {
14699            self.request_autoscroll(Autoscroll::fit(), cx);
14700            SelectSyntaxNodeScrollBehavior::FitSelection
14701        } else if is_selection_reversed {
14702            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14703            SelectSyntaxNodeScrollBehavior::CursorTop
14704        } else {
14705            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14706            SelectSyntaxNodeScrollBehavior::CursorBottom
14707        };
14708
14709        self.select_syntax_node_history.push((
14710            old_selections,
14711            scroll_behavior,
14712            is_selection_reversed,
14713        ));
14714    }
14715
14716    pub fn select_smaller_syntax_node(
14717        &mut self,
14718        _: &SelectSmallerSyntaxNode,
14719        window: &mut Window,
14720        cx: &mut Context<Self>,
14721    ) {
14722        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14723
14724        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14725            self.select_syntax_node_history.pop()
14726        {
14727            if let Some(selection) = selections.last_mut() {
14728                selection.reversed = is_selection_reversed;
14729            }
14730
14731            self.select_syntax_node_history.disable_clearing = true;
14732            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14733                s.select(selections.to_vec());
14734            });
14735            self.select_syntax_node_history.disable_clearing = false;
14736
14737            match scroll_behavior {
14738                SelectSyntaxNodeScrollBehavior::CursorTop => {
14739                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14740                }
14741                SelectSyntaxNodeScrollBehavior::FitSelection => {
14742                    self.request_autoscroll(Autoscroll::fit(), cx);
14743                }
14744                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14745                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14746                }
14747            }
14748        }
14749    }
14750
14751    pub fn unwrap_syntax_node(
14752        &mut self,
14753        _: &UnwrapSyntaxNode,
14754        window: &mut Window,
14755        cx: &mut Context<Self>,
14756    ) {
14757        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14758
14759        let buffer = self.buffer.read(cx).snapshot(cx);
14760        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14761
14762        let edits = old_selections
14763            .iter()
14764            // only consider the first selection for now
14765            .take(1)
14766            .map(|selection| {
14767                // Only requires two branches once if-let-chains stabilize (#53667)
14768                let selection_range = if !selection.is_empty() {
14769                    selection.range()
14770                } else if let Some((_, ancestor_range)) =
14771                    buffer.syntax_ancestor(selection.start..selection.end)
14772                {
14773                    match ancestor_range {
14774                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14775                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14776                    }
14777                } else {
14778                    selection.range()
14779                };
14780
14781                let mut new_range = selection_range.clone();
14782                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(new_range.clone()) {
14783                    new_range = match ancestor_range {
14784                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14785                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14786                    };
14787                    if new_range.start < selection_range.start
14788                        || new_range.end > selection_range.end
14789                    {
14790                        break;
14791                    }
14792                }
14793
14794                (selection, selection_range, new_range)
14795            })
14796            .collect::<Vec<_>>();
14797
14798        self.transact(window, cx, |editor, window, cx| {
14799            for (_, child, parent) in &edits {
14800                let text = buffer.text_for_range(child.clone()).collect::<String>();
14801                editor.replace_text_in_range(Some(parent.clone()), &text, window, cx);
14802            }
14803
14804            editor.change_selections(
14805                SelectionEffects::scroll(Autoscroll::fit()),
14806                window,
14807                cx,
14808                |s| {
14809                    s.select(
14810                        edits
14811                            .iter()
14812                            .map(|(s, old, new)| Selection {
14813                                id: s.id,
14814                                start: new.start,
14815                                end: new.start + old.len(),
14816                                goal: SelectionGoal::None,
14817                                reversed: s.reversed,
14818                            })
14819                            .collect(),
14820                    );
14821                },
14822            );
14823        });
14824    }
14825
14826    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14827        if !EditorSettings::get_global(cx).gutter.runnables {
14828            self.clear_tasks();
14829            return Task::ready(());
14830        }
14831        let project = self.project.as_ref().map(Entity::downgrade);
14832        let task_sources = self.lsp_task_sources(cx);
14833        let multi_buffer = self.buffer.downgrade();
14834        cx.spawn_in(window, async move |editor, cx| {
14835            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14836            let Some(project) = project.and_then(|p| p.upgrade()) else {
14837                return;
14838            };
14839            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14840                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14841            }) else {
14842                return;
14843            };
14844
14845            let hide_runnables = project
14846                .update(cx, |project, cx| {
14847                    // Do not display any test indicators in non-dev server remote projects.
14848                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14849                })
14850                .unwrap_or(true);
14851            if hide_runnables {
14852                return;
14853            }
14854            let new_rows =
14855                cx.background_spawn({
14856                    let snapshot = display_snapshot.clone();
14857                    async move {
14858                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14859                    }
14860                })
14861                    .await;
14862            let Ok(lsp_tasks) =
14863                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14864            else {
14865                return;
14866            };
14867            let lsp_tasks = lsp_tasks.await;
14868
14869            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14870                lsp_tasks
14871                    .into_iter()
14872                    .flat_map(|(kind, tasks)| {
14873                        tasks.into_iter().filter_map(move |(location, task)| {
14874                            Some((kind.clone(), location?, task))
14875                        })
14876                    })
14877                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14878                        let buffer = location.target.buffer;
14879                        let buffer_snapshot = buffer.read(cx).snapshot();
14880                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14881                            |(excerpt_id, snapshot, _)| {
14882                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14883                                    display_snapshot
14884                                        .buffer_snapshot
14885                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14886                                } else {
14887                                    None
14888                                }
14889                            },
14890                        );
14891                        if let Some(offset) = offset {
14892                            let task_buffer_range =
14893                                location.target.range.to_point(&buffer_snapshot);
14894                            let context_buffer_range =
14895                                task_buffer_range.to_offset(&buffer_snapshot);
14896                            let context_range = BufferOffset(context_buffer_range.start)
14897                                ..BufferOffset(context_buffer_range.end);
14898
14899                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14900                                .or_insert_with(|| RunnableTasks {
14901                                    templates: Vec::new(),
14902                                    offset,
14903                                    column: task_buffer_range.start.column,
14904                                    extra_variables: HashMap::default(),
14905                                    context_range,
14906                                })
14907                                .templates
14908                                .push((kind, task.original_task().clone()));
14909                        }
14910
14911                        acc
14912                    })
14913            }) else {
14914                return;
14915            };
14916
14917            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14918                buffer.language_settings(cx).tasks.prefer_lsp
14919            }) else {
14920                return;
14921            };
14922
14923            let rows = Self::runnable_rows(
14924                project,
14925                display_snapshot,
14926                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14927                new_rows,
14928                cx.clone(),
14929            )
14930            .await;
14931            editor
14932                .update(cx, |editor, _| {
14933                    editor.clear_tasks();
14934                    for (key, mut value) in rows {
14935                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14936                            value.templates.extend(lsp_tasks.templates);
14937                        }
14938
14939                        editor.insert_tasks(key, value);
14940                    }
14941                    for (key, value) in lsp_tasks_by_rows {
14942                        editor.insert_tasks(key, value);
14943                    }
14944                })
14945                .ok();
14946        })
14947    }
14948    fn fetch_runnable_ranges(
14949        snapshot: &DisplaySnapshot,
14950        range: Range<Anchor>,
14951    ) -> Vec<language::RunnableRange> {
14952        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14953    }
14954
14955    fn runnable_rows(
14956        project: Entity<Project>,
14957        snapshot: DisplaySnapshot,
14958        prefer_lsp: bool,
14959        runnable_ranges: Vec<RunnableRange>,
14960        cx: AsyncWindowContext,
14961    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14962        cx.spawn(async move |cx| {
14963            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14964            for mut runnable in runnable_ranges {
14965                let Some(tasks) = cx
14966                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14967                    .ok()
14968                else {
14969                    continue;
14970                };
14971                let mut tasks = tasks.await;
14972
14973                if prefer_lsp {
14974                    tasks.retain(|(task_kind, _)| {
14975                        !matches!(task_kind, TaskSourceKind::Language { .. })
14976                    });
14977                }
14978                if tasks.is_empty() {
14979                    continue;
14980                }
14981
14982                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14983                let Some(row) = snapshot
14984                    .buffer_snapshot
14985                    .buffer_line_for_row(MultiBufferRow(point.row))
14986                    .map(|(_, range)| range.start.row)
14987                else {
14988                    continue;
14989                };
14990
14991                let context_range =
14992                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14993                runnable_rows.push((
14994                    (runnable.buffer_id, row),
14995                    RunnableTasks {
14996                        templates: tasks,
14997                        offset: snapshot
14998                            .buffer_snapshot
14999                            .anchor_before(runnable.run_range.start),
15000                        context_range,
15001                        column: point.column,
15002                        extra_variables: runnable.extra_captures,
15003                    },
15004                ));
15005            }
15006            runnable_rows
15007        })
15008    }
15009
15010    fn templates_with_tags(
15011        project: &Entity<Project>,
15012        runnable: &mut Runnable,
15013        cx: &mut App,
15014    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15015        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15016            let (worktree_id, file) = project
15017                .buffer_for_id(runnable.buffer, cx)
15018                .and_then(|buffer| buffer.read(cx).file())
15019                .map(|file| (file.worktree_id(cx), file.clone()))
15020                .unzip();
15021
15022            (
15023                project.task_store().read(cx).task_inventory().cloned(),
15024                worktree_id,
15025                file,
15026            )
15027        });
15028
15029        let tags = mem::take(&mut runnable.tags);
15030        let language = runnable.language.clone();
15031        cx.spawn(async move |cx| {
15032            let mut templates_with_tags = Vec::new();
15033            if let Some(inventory) = inventory {
15034                for RunnableTag(tag) in tags {
15035                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15036                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15037                    }) else {
15038                        return templates_with_tags;
15039                    };
15040                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15041                        move |(_, template)| {
15042                            template.tags.iter().any(|source_tag| source_tag == &tag)
15043                        },
15044                    ));
15045                }
15046            }
15047            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15048
15049            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15050                // Strongest source wins; if we have worktree tag binding, prefer that to
15051                // global and language bindings;
15052                // if we have a global binding, prefer that to language binding.
15053                let first_mismatch = templates_with_tags
15054                    .iter()
15055                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15056                if let Some(index) = first_mismatch {
15057                    templates_with_tags.truncate(index);
15058                }
15059            }
15060
15061            templates_with_tags
15062        })
15063    }
15064
15065    pub fn move_to_enclosing_bracket(
15066        &mut self,
15067        _: &MoveToEnclosingBracket,
15068        window: &mut Window,
15069        cx: &mut Context<Self>,
15070    ) {
15071        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15072        self.change_selections(Default::default(), window, cx, |s| {
15073            s.move_offsets_with(|snapshot, selection| {
15074                let Some(enclosing_bracket_ranges) =
15075                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15076                else {
15077                    return;
15078                };
15079
15080                let mut best_length = usize::MAX;
15081                let mut best_inside = false;
15082                let mut best_in_bracket_range = false;
15083                let mut best_destination = None;
15084                for (open, close) in enclosing_bracket_ranges {
15085                    let close = close.to_inclusive();
15086                    let length = close.end() - open.start;
15087                    let inside = selection.start >= open.end && selection.end <= *close.start();
15088                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15089                        || close.contains(&selection.head());
15090
15091                    // If best is next to a bracket and current isn't, skip
15092                    if !in_bracket_range && best_in_bracket_range {
15093                        continue;
15094                    }
15095
15096                    // Prefer smaller lengths unless best is inside and current isn't
15097                    if length > best_length && (best_inside || !inside) {
15098                        continue;
15099                    }
15100
15101                    best_length = length;
15102                    best_inside = inside;
15103                    best_in_bracket_range = in_bracket_range;
15104                    best_destination = Some(
15105                        if close.contains(&selection.start) && close.contains(&selection.end) {
15106                            if inside { open.end } else { open.start }
15107                        } else if inside {
15108                            *close.start()
15109                        } else {
15110                            *close.end()
15111                        },
15112                    );
15113                }
15114
15115                if let Some(destination) = best_destination {
15116                    selection.collapse_to(destination, SelectionGoal::None);
15117                }
15118            })
15119        });
15120    }
15121
15122    pub fn undo_selection(
15123        &mut self,
15124        _: &UndoSelection,
15125        window: &mut Window,
15126        cx: &mut Context<Self>,
15127    ) {
15128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15129        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15130            self.selection_history.mode = SelectionHistoryMode::Undoing;
15131            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15132                this.end_selection(window, cx);
15133                this.change_selections(
15134                    SelectionEffects::scroll(Autoscroll::newest()),
15135                    window,
15136                    cx,
15137                    |s| s.select_anchors(entry.selections.to_vec()),
15138                );
15139            });
15140            self.selection_history.mode = SelectionHistoryMode::Normal;
15141
15142            self.select_next_state = entry.select_next_state;
15143            self.select_prev_state = entry.select_prev_state;
15144            self.add_selections_state = entry.add_selections_state;
15145        }
15146    }
15147
15148    pub fn redo_selection(
15149        &mut self,
15150        _: &RedoSelection,
15151        window: &mut Window,
15152        cx: &mut Context<Self>,
15153    ) {
15154        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15155        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15156            self.selection_history.mode = SelectionHistoryMode::Redoing;
15157            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15158                this.end_selection(window, cx);
15159                this.change_selections(
15160                    SelectionEffects::scroll(Autoscroll::newest()),
15161                    window,
15162                    cx,
15163                    |s| s.select_anchors(entry.selections.to_vec()),
15164                );
15165            });
15166            self.selection_history.mode = SelectionHistoryMode::Normal;
15167
15168            self.select_next_state = entry.select_next_state;
15169            self.select_prev_state = entry.select_prev_state;
15170            self.add_selections_state = entry.add_selections_state;
15171        }
15172    }
15173
15174    pub fn expand_excerpts(
15175        &mut self,
15176        action: &ExpandExcerpts,
15177        _: &mut Window,
15178        cx: &mut Context<Self>,
15179    ) {
15180        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15181    }
15182
15183    pub fn expand_excerpts_down(
15184        &mut self,
15185        action: &ExpandExcerptsDown,
15186        _: &mut Window,
15187        cx: &mut Context<Self>,
15188    ) {
15189        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15190    }
15191
15192    pub fn expand_excerpts_up(
15193        &mut self,
15194        action: &ExpandExcerptsUp,
15195        _: &mut Window,
15196        cx: &mut Context<Self>,
15197    ) {
15198        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15199    }
15200
15201    pub fn expand_excerpts_for_direction(
15202        &mut self,
15203        lines: u32,
15204        direction: ExpandExcerptDirection,
15205
15206        cx: &mut Context<Self>,
15207    ) {
15208        let selections = self.selections.disjoint_anchors();
15209
15210        let lines = if lines == 0 {
15211            EditorSettings::get_global(cx).expand_excerpt_lines
15212        } else {
15213            lines
15214        };
15215
15216        self.buffer.update(cx, |buffer, cx| {
15217            let snapshot = buffer.snapshot(cx);
15218            let mut excerpt_ids = selections
15219                .iter()
15220                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15221                .collect::<Vec<_>>();
15222            excerpt_ids.sort();
15223            excerpt_ids.dedup();
15224            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15225        })
15226    }
15227
15228    pub fn expand_excerpt(
15229        &mut self,
15230        excerpt: ExcerptId,
15231        direction: ExpandExcerptDirection,
15232        window: &mut Window,
15233        cx: &mut Context<Self>,
15234    ) {
15235        let current_scroll_position = self.scroll_position(cx);
15236        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15237        let mut should_scroll_up = false;
15238
15239        if direction == ExpandExcerptDirection::Down {
15240            let multi_buffer = self.buffer.read(cx);
15241            let snapshot = multi_buffer.snapshot(cx);
15242            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15243                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15244                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15245                        let buffer_snapshot = buffer.read(cx).snapshot();
15246                        let excerpt_end_row =
15247                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15248                        let last_row = buffer_snapshot.max_point().row;
15249                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15250                        should_scroll_up = lines_below >= lines_to_expand;
15251                    }
15252                }
15253            }
15254        }
15255
15256        self.buffer.update(cx, |buffer, cx| {
15257            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15258        });
15259
15260        if should_scroll_up {
15261            let new_scroll_position =
15262                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15263            self.set_scroll_position(new_scroll_position, window, cx);
15264        }
15265    }
15266
15267    pub fn go_to_singleton_buffer_point(
15268        &mut self,
15269        point: Point,
15270        window: &mut Window,
15271        cx: &mut Context<Self>,
15272    ) {
15273        self.go_to_singleton_buffer_range(point..point, window, cx);
15274    }
15275
15276    pub fn go_to_singleton_buffer_range(
15277        &mut self,
15278        range: Range<Point>,
15279        window: &mut Window,
15280        cx: &mut Context<Self>,
15281    ) {
15282        let multibuffer = self.buffer().read(cx);
15283        let Some(buffer) = multibuffer.as_singleton() else {
15284            return;
15285        };
15286        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15287            return;
15288        };
15289        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15290            return;
15291        };
15292        self.change_selections(
15293            SelectionEffects::default().nav_history(true),
15294            window,
15295            cx,
15296            |s| s.select_anchor_ranges([start..end]),
15297        );
15298    }
15299
15300    pub fn go_to_diagnostic(
15301        &mut self,
15302        action: &GoToDiagnostic,
15303        window: &mut Window,
15304        cx: &mut Context<Self>,
15305    ) {
15306        if !self.diagnostics_enabled() {
15307            return;
15308        }
15309        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15310        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15311    }
15312
15313    pub fn go_to_prev_diagnostic(
15314        &mut self,
15315        action: &GoToPreviousDiagnostic,
15316        window: &mut Window,
15317        cx: &mut Context<Self>,
15318    ) {
15319        if !self.diagnostics_enabled() {
15320            return;
15321        }
15322        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15323        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15324    }
15325
15326    pub fn go_to_diagnostic_impl(
15327        &mut self,
15328        direction: Direction,
15329        severity: GoToDiagnosticSeverityFilter,
15330        window: &mut Window,
15331        cx: &mut Context<Self>,
15332    ) {
15333        let buffer = self.buffer.read(cx).snapshot(cx);
15334        let selection = self.selections.newest::<usize>(cx);
15335
15336        let mut active_group_id = None;
15337        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15338            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15339                active_group_id = Some(active_group.group_id);
15340            }
15341        }
15342
15343        fn filtered(
15344            snapshot: EditorSnapshot,
15345            severity: GoToDiagnosticSeverityFilter,
15346            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15347        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15348            diagnostics
15349                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15350                .filter(|entry| entry.range.start != entry.range.end)
15351                .filter(|entry| !entry.diagnostic.is_unnecessary)
15352                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15353        }
15354
15355        let snapshot = self.snapshot(window, cx);
15356        let before = filtered(
15357            snapshot.clone(),
15358            severity,
15359            buffer
15360                .diagnostics_in_range(0..selection.start)
15361                .filter(|entry| entry.range.start <= selection.start),
15362        );
15363        let after = filtered(
15364            snapshot,
15365            severity,
15366            buffer
15367                .diagnostics_in_range(selection.start..buffer.len())
15368                .filter(|entry| entry.range.start >= selection.start),
15369        );
15370
15371        let mut found: Option<DiagnosticEntry<usize>> = None;
15372        if direction == Direction::Prev {
15373            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15374            {
15375                for diagnostic in prev_diagnostics.into_iter().rev() {
15376                    if diagnostic.range.start != selection.start
15377                        || active_group_id
15378                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15379                    {
15380                        found = Some(diagnostic);
15381                        break 'outer;
15382                    }
15383                }
15384            }
15385        } else {
15386            for diagnostic in after.chain(before) {
15387                if diagnostic.range.start != selection.start
15388                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15389                {
15390                    found = Some(diagnostic);
15391                    break;
15392                }
15393            }
15394        }
15395        let Some(next_diagnostic) = found else {
15396            return;
15397        };
15398
15399        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15400            return;
15401        };
15402        self.change_selections(Default::default(), window, cx, |s| {
15403            s.select_ranges(vec![
15404                next_diagnostic.range.start..next_diagnostic.range.start,
15405            ])
15406        });
15407        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15408        self.refresh_edit_prediction(false, true, window, cx);
15409    }
15410
15411    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15412        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15413        let snapshot = self.snapshot(window, cx);
15414        let selection = self.selections.newest::<Point>(cx);
15415        self.go_to_hunk_before_or_after_position(
15416            &snapshot,
15417            selection.head(),
15418            Direction::Next,
15419            window,
15420            cx,
15421        );
15422    }
15423
15424    pub fn go_to_hunk_before_or_after_position(
15425        &mut self,
15426        snapshot: &EditorSnapshot,
15427        position: Point,
15428        direction: Direction,
15429        window: &mut Window,
15430        cx: &mut Context<Editor>,
15431    ) {
15432        let row = if direction == Direction::Next {
15433            self.hunk_after_position(snapshot, position)
15434                .map(|hunk| hunk.row_range.start)
15435        } else {
15436            self.hunk_before_position(snapshot, position)
15437        };
15438
15439        if let Some(row) = row {
15440            let destination = Point::new(row.0, 0);
15441            let autoscroll = Autoscroll::center();
15442
15443            self.unfold_ranges(&[destination..destination], false, false, cx);
15444            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15445                s.select_ranges([destination..destination]);
15446            });
15447        }
15448    }
15449
15450    fn hunk_after_position(
15451        &mut self,
15452        snapshot: &EditorSnapshot,
15453        position: Point,
15454    ) -> Option<MultiBufferDiffHunk> {
15455        snapshot
15456            .buffer_snapshot
15457            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15458            .find(|hunk| hunk.row_range.start.0 > position.row)
15459            .or_else(|| {
15460                snapshot
15461                    .buffer_snapshot
15462                    .diff_hunks_in_range(Point::zero()..position)
15463                    .find(|hunk| hunk.row_range.end.0 < position.row)
15464            })
15465    }
15466
15467    fn go_to_prev_hunk(
15468        &mut self,
15469        _: &GoToPreviousHunk,
15470        window: &mut Window,
15471        cx: &mut Context<Self>,
15472    ) {
15473        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15474        let snapshot = self.snapshot(window, cx);
15475        let selection = self.selections.newest::<Point>(cx);
15476        self.go_to_hunk_before_or_after_position(
15477            &snapshot,
15478            selection.head(),
15479            Direction::Prev,
15480            window,
15481            cx,
15482        );
15483    }
15484
15485    fn hunk_before_position(
15486        &mut self,
15487        snapshot: &EditorSnapshot,
15488        position: Point,
15489    ) -> Option<MultiBufferRow> {
15490        snapshot
15491            .buffer_snapshot
15492            .diff_hunk_before(position)
15493            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15494    }
15495
15496    fn go_to_next_change(
15497        &mut self,
15498        _: &GoToNextChange,
15499        window: &mut Window,
15500        cx: &mut Context<Self>,
15501    ) {
15502        if let Some(selections) = self
15503            .change_list
15504            .next_change(1, Direction::Next)
15505            .map(|s| s.to_vec())
15506        {
15507            self.change_selections(Default::default(), window, cx, |s| {
15508                let map = s.display_map();
15509                s.select_display_ranges(selections.iter().map(|a| {
15510                    let point = a.to_display_point(&map);
15511                    point..point
15512                }))
15513            })
15514        }
15515    }
15516
15517    fn go_to_previous_change(
15518        &mut self,
15519        _: &GoToPreviousChange,
15520        window: &mut Window,
15521        cx: &mut Context<Self>,
15522    ) {
15523        if let Some(selections) = self
15524            .change_list
15525            .next_change(1, Direction::Prev)
15526            .map(|s| s.to_vec())
15527        {
15528            self.change_selections(Default::default(), window, cx, |s| {
15529                let map = s.display_map();
15530                s.select_display_ranges(selections.iter().map(|a| {
15531                    let point = a.to_display_point(&map);
15532                    point..point
15533                }))
15534            })
15535        }
15536    }
15537
15538    fn go_to_line<T: 'static>(
15539        &mut self,
15540        position: Anchor,
15541        highlight_color: Option<Hsla>,
15542        window: &mut Window,
15543        cx: &mut Context<Self>,
15544    ) {
15545        let snapshot = self.snapshot(window, cx).display_snapshot;
15546        let position = position.to_point(&snapshot.buffer_snapshot);
15547        let start = snapshot
15548            .buffer_snapshot
15549            .clip_point(Point::new(position.row, 0), Bias::Left);
15550        let end = start + Point::new(1, 0);
15551        let start = snapshot.buffer_snapshot.anchor_before(start);
15552        let end = snapshot.buffer_snapshot.anchor_before(end);
15553
15554        self.highlight_rows::<T>(
15555            start..end,
15556            highlight_color
15557                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15558            Default::default(),
15559            cx,
15560        );
15561
15562        if self.buffer.read(cx).is_singleton() {
15563            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15564        }
15565    }
15566
15567    pub fn go_to_definition(
15568        &mut self,
15569        _: &GoToDefinition,
15570        window: &mut Window,
15571        cx: &mut Context<Self>,
15572    ) -> Task<Result<Navigated>> {
15573        let definition =
15574            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15575        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15576        cx.spawn_in(window, async move |editor, cx| {
15577            if definition.await? == Navigated::Yes {
15578                return Ok(Navigated::Yes);
15579            }
15580            match fallback_strategy {
15581                GoToDefinitionFallback::None => Ok(Navigated::No),
15582                GoToDefinitionFallback::FindAllReferences => {
15583                    match editor.update_in(cx, |editor, window, cx| {
15584                        editor.find_all_references(&FindAllReferences, window, cx)
15585                    })? {
15586                        Some(references) => references.await,
15587                        None => Ok(Navigated::No),
15588                    }
15589                }
15590            }
15591        })
15592    }
15593
15594    pub fn go_to_declaration(
15595        &mut self,
15596        _: &GoToDeclaration,
15597        window: &mut Window,
15598        cx: &mut Context<Self>,
15599    ) -> Task<Result<Navigated>> {
15600        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15601    }
15602
15603    pub fn go_to_declaration_split(
15604        &mut self,
15605        _: &GoToDeclaration,
15606        window: &mut Window,
15607        cx: &mut Context<Self>,
15608    ) -> Task<Result<Navigated>> {
15609        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15610    }
15611
15612    pub fn go_to_implementation(
15613        &mut self,
15614        _: &GoToImplementation,
15615        window: &mut Window,
15616        cx: &mut Context<Self>,
15617    ) -> Task<Result<Navigated>> {
15618        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15619    }
15620
15621    pub fn go_to_implementation_split(
15622        &mut self,
15623        _: &GoToImplementationSplit,
15624        window: &mut Window,
15625        cx: &mut Context<Self>,
15626    ) -> Task<Result<Navigated>> {
15627        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15628    }
15629
15630    pub fn go_to_type_definition(
15631        &mut self,
15632        _: &GoToTypeDefinition,
15633        window: &mut Window,
15634        cx: &mut Context<Self>,
15635    ) -> Task<Result<Navigated>> {
15636        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15637    }
15638
15639    pub fn go_to_definition_split(
15640        &mut self,
15641        _: &GoToDefinitionSplit,
15642        window: &mut Window,
15643        cx: &mut Context<Self>,
15644    ) -> Task<Result<Navigated>> {
15645        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15646    }
15647
15648    pub fn go_to_type_definition_split(
15649        &mut self,
15650        _: &GoToTypeDefinitionSplit,
15651        window: &mut Window,
15652        cx: &mut Context<Self>,
15653    ) -> Task<Result<Navigated>> {
15654        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15655    }
15656
15657    fn go_to_definition_of_kind(
15658        &mut self,
15659        kind: GotoDefinitionKind,
15660        split: bool,
15661        window: &mut Window,
15662        cx: &mut Context<Self>,
15663    ) -> Task<Result<Navigated>> {
15664        let Some(provider) = self.semantics_provider.clone() else {
15665            return Task::ready(Ok(Navigated::No));
15666        };
15667        let head = self.selections.newest::<usize>(cx).head();
15668        let buffer = self.buffer.read(cx);
15669        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15670            return Task::ready(Ok(Navigated::No));
15671        };
15672        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15673            return Task::ready(Ok(Navigated::No));
15674        };
15675
15676        cx.spawn_in(window, async move |editor, cx| {
15677            let definitions = definitions.await?;
15678            let navigated = editor
15679                .update_in(cx, |editor, window, cx| {
15680                    editor.navigate_to_hover_links(
15681                        Some(kind),
15682                        definitions
15683                            .into_iter()
15684                            .filter(|location| {
15685                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15686                            })
15687                            .map(HoverLink::Text)
15688                            .collect::<Vec<_>>(),
15689                        split,
15690                        window,
15691                        cx,
15692                    )
15693                })?
15694                .await?;
15695            anyhow::Ok(navigated)
15696        })
15697    }
15698
15699    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15700        let selection = self.selections.newest_anchor();
15701        let head = selection.head();
15702        let tail = selection.tail();
15703
15704        let Some((buffer, start_position)) =
15705            self.buffer.read(cx).text_anchor_for_position(head, cx)
15706        else {
15707            return;
15708        };
15709
15710        let end_position = if head != tail {
15711            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15712                return;
15713            };
15714            Some(pos)
15715        } else {
15716            None
15717        };
15718
15719        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15720            let url = if let Some(end_pos) = end_position {
15721                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15722            } else {
15723                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15724            };
15725
15726            if let Some(url) = url {
15727                editor.update(cx, |_, cx| {
15728                    cx.open_url(&url);
15729                })
15730            } else {
15731                Ok(())
15732            }
15733        });
15734
15735        url_finder.detach();
15736    }
15737
15738    pub fn open_selected_filename(
15739        &mut self,
15740        _: &OpenSelectedFilename,
15741        window: &mut Window,
15742        cx: &mut Context<Self>,
15743    ) {
15744        let Some(workspace) = self.workspace() else {
15745            return;
15746        };
15747
15748        let position = self.selections.newest_anchor().head();
15749
15750        let Some((buffer, buffer_position)) =
15751            self.buffer.read(cx).text_anchor_for_position(position, cx)
15752        else {
15753            return;
15754        };
15755
15756        let project = self.project.clone();
15757
15758        cx.spawn_in(window, async move |_, cx| {
15759            let result = find_file(&buffer, project, buffer_position, cx).await;
15760
15761            if let Some((_, path)) = result {
15762                workspace
15763                    .update_in(cx, |workspace, window, cx| {
15764                        workspace.open_resolved_path(path, window, cx)
15765                    })?
15766                    .await?;
15767            }
15768            anyhow::Ok(())
15769        })
15770        .detach();
15771    }
15772
15773    pub(crate) fn navigate_to_hover_links(
15774        &mut self,
15775        kind: Option<GotoDefinitionKind>,
15776        definitions: Vec<HoverLink>,
15777        split: bool,
15778        window: &mut Window,
15779        cx: &mut Context<Editor>,
15780    ) -> Task<Result<Navigated>> {
15781        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15782        let mut first_url_or_file = None;
15783        let definitions: Vec<_> = definitions
15784            .into_iter()
15785            .filter_map(|def| match def {
15786                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15787                HoverLink::InlayHint(lsp_location, server_id) => {
15788                    let computation =
15789                        self.compute_target_location(lsp_location, server_id, window, cx);
15790                    Some(cx.background_spawn(computation))
15791                }
15792                HoverLink::Url(url) => {
15793                    first_url_or_file = Some(Either::Left(url));
15794                    None
15795                }
15796                HoverLink::File(path) => {
15797                    first_url_or_file = Some(Either::Right(path));
15798                    None
15799                }
15800            })
15801            .collect();
15802
15803        let workspace = self.workspace();
15804
15805        cx.spawn_in(window, async move |editor, acx| {
15806            let mut locations: Vec<Location> = future::join_all(definitions)
15807                .await
15808                .into_iter()
15809                .filter_map(|location| location.transpose())
15810                .collect::<Result<_>>()
15811                .context("location tasks")?;
15812
15813            if locations.len() > 1 {
15814                let Some(workspace) = workspace else {
15815                    return Ok(Navigated::No);
15816                };
15817
15818                let tab_kind = match kind {
15819                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15820                    _ => "Definitions",
15821                };
15822                let title = editor
15823                    .update_in(acx, |_, _, cx| {
15824                        let origin = locations.first().unwrap();
15825                        let buffer = origin.buffer.read(cx);
15826                        format!(
15827                            "{} for {}",
15828                            tab_kind,
15829                            buffer
15830                                .text_for_range(origin.range.clone())
15831                                .collect::<String>()
15832                        )
15833                    })
15834                    .context("buffer title")?;
15835
15836                let opened = workspace
15837                    .update_in(acx, |workspace, window, cx| {
15838                        Self::open_locations_in_multibuffer(
15839                            workspace,
15840                            locations,
15841                            title,
15842                            split,
15843                            MultibufferSelectionMode::First,
15844                            window,
15845                            cx,
15846                        )
15847                    })
15848                    .is_ok();
15849
15850                anyhow::Ok(Navigated::from_bool(opened))
15851            } else if locations.is_empty() {
15852                // If there is one definition, just open it directly
15853                match first_url_or_file {
15854                    Some(Either::Left(url)) => {
15855                        acx.update(|_, cx| cx.open_url(&url))?;
15856                        Ok(Navigated::Yes)
15857                    }
15858                    Some(Either::Right(path)) => {
15859                        let Some(workspace) = workspace else {
15860                            return Ok(Navigated::No);
15861                        };
15862
15863                        workspace
15864                            .update_in(acx, |workspace, window, cx| {
15865                                workspace.open_resolved_path(path, window, cx)
15866                            })?
15867                            .await?;
15868                        Ok(Navigated::Yes)
15869                    }
15870                    None => Ok(Navigated::No),
15871                }
15872            } else {
15873                let Some(workspace) = workspace else {
15874                    return Ok(Navigated::No);
15875                };
15876
15877                let target = locations.pop().unwrap();
15878                editor.update_in(acx, |editor, window, cx| {
15879                    let pane = workspace.read(cx).active_pane().clone();
15880
15881                    let range = target.range.to_point(target.buffer.read(cx));
15882                    let range = editor.range_for_match(&range);
15883                    let range = collapse_multiline_range(range);
15884
15885                    if !split
15886                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15887                    {
15888                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15889                    } else {
15890                        window.defer(cx, move |window, cx| {
15891                            let target_editor: Entity<Self> =
15892                                workspace.update(cx, |workspace, cx| {
15893                                    let pane = if split {
15894                                        workspace.adjacent_pane(window, cx)
15895                                    } else {
15896                                        workspace.active_pane().clone()
15897                                    };
15898
15899                                    workspace.open_project_item(
15900                                        pane,
15901                                        target.buffer.clone(),
15902                                        true,
15903                                        true,
15904                                        window,
15905                                        cx,
15906                                    )
15907                                });
15908                            target_editor.update(cx, |target_editor, cx| {
15909                                // When selecting a definition in a different buffer, disable the nav history
15910                                // to avoid creating a history entry at the previous cursor location.
15911                                pane.update(cx, |pane, _| pane.disable_history());
15912                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15913                                pane.update(cx, |pane, _| pane.enable_history());
15914                            });
15915                        });
15916                    }
15917                    Navigated::Yes
15918                })
15919            }
15920        })
15921    }
15922
15923    fn compute_target_location(
15924        &self,
15925        lsp_location: lsp::Location,
15926        server_id: LanguageServerId,
15927        window: &mut Window,
15928        cx: &mut Context<Self>,
15929    ) -> Task<anyhow::Result<Option<Location>>> {
15930        let Some(project) = self.project.clone() else {
15931            return Task::ready(Ok(None));
15932        };
15933
15934        cx.spawn_in(window, async move |editor, cx| {
15935            let location_task = editor.update(cx, |_, cx| {
15936                project.update(cx, |project, cx| {
15937                    let language_server_name = project
15938                        .language_server_statuses(cx)
15939                        .find(|(id, _)| server_id == *id)
15940                        .map(|(_, status)| status.name.clone());
15941                    language_server_name.map(|language_server_name| {
15942                        project.open_local_buffer_via_lsp(
15943                            lsp_location.uri.clone(),
15944                            server_id,
15945                            language_server_name,
15946                            cx,
15947                        )
15948                    })
15949                })
15950            })?;
15951            let location = match location_task {
15952                Some(task) => Some({
15953                    let target_buffer_handle = task.await.context("open local buffer")?;
15954                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15955                        let target_start = target_buffer
15956                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15957                        let target_end = target_buffer
15958                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15959                        target_buffer.anchor_after(target_start)
15960                            ..target_buffer.anchor_before(target_end)
15961                    })?;
15962                    Location {
15963                        buffer: target_buffer_handle,
15964                        range,
15965                    }
15966                }),
15967                None => None,
15968            };
15969            Ok(location)
15970        })
15971    }
15972
15973    pub fn find_all_references(
15974        &mut self,
15975        _: &FindAllReferences,
15976        window: &mut Window,
15977        cx: &mut Context<Self>,
15978    ) -> Option<Task<Result<Navigated>>> {
15979        let selection = self.selections.newest::<usize>(cx);
15980        let multi_buffer = self.buffer.read(cx);
15981        let head = selection.head();
15982
15983        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15984        let head_anchor = multi_buffer_snapshot.anchor_at(
15985            head,
15986            if head < selection.tail() {
15987                Bias::Right
15988            } else {
15989                Bias::Left
15990            },
15991        );
15992
15993        match self
15994            .find_all_references_task_sources
15995            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15996        {
15997            Ok(_) => {
15998                log::info!(
15999                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16000                );
16001                return None;
16002            }
16003            Err(i) => {
16004                self.find_all_references_task_sources.insert(i, head_anchor);
16005            }
16006        }
16007
16008        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16009        let workspace = self.workspace()?;
16010        let project = workspace.read(cx).project().clone();
16011        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16012        Some(cx.spawn_in(window, async move |editor, cx| {
16013            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16014                if let Ok(i) = editor
16015                    .find_all_references_task_sources
16016                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16017                {
16018                    editor.find_all_references_task_sources.remove(i);
16019                }
16020            });
16021
16022            let locations = references.await?;
16023            if locations.is_empty() {
16024                return anyhow::Ok(Navigated::No);
16025            }
16026
16027            workspace.update_in(cx, |workspace, window, cx| {
16028                let title = locations
16029                    .first()
16030                    .as_ref()
16031                    .map(|location| {
16032                        let buffer = location.buffer.read(cx);
16033                        format!(
16034                            "References to `{}`",
16035                            buffer
16036                                .text_for_range(location.range.clone())
16037                                .collect::<String>()
16038                        )
16039                    })
16040                    .unwrap();
16041                Self::open_locations_in_multibuffer(
16042                    workspace,
16043                    locations,
16044                    title,
16045                    false,
16046                    MultibufferSelectionMode::First,
16047                    window,
16048                    cx,
16049                );
16050                Navigated::Yes
16051            })
16052        }))
16053    }
16054
16055    /// Opens a multibuffer with the given project locations in it
16056    pub fn open_locations_in_multibuffer(
16057        workspace: &mut Workspace,
16058        mut locations: Vec<Location>,
16059        title: String,
16060        split: bool,
16061        multibuffer_selection_mode: MultibufferSelectionMode,
16062        window: &mut Window,
16063        cx: &mut Context<Workspace>,
16064    ) {
16065        if locations.is_empty() {
16066            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16067            return;
16068        }
16069
16070        // If there are multiple definitions, open them in a multibuffer
16071        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16072        let mut locations = locations.into_iter().peekable();
16073        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16074        let capability = workspace.project().read(cx).capability();
16075
16076        let excerpt_buffer = cx.new(|cx| {
16077            let mut multibuffer = MultiBuffer::new(capability);
16078            while let Some(location) = locations.next() {
16079                let buffer = location.buffer.read(cx);
16080                let mut ranges_for_buffer = Vec::new();
16081                let range = location.range.to_point(buffer);
16082                ranges_for_buffer.push(range.clone());
16083
16084                while let Some(next_location) = locations.peek() {
16085                    if next_location.buffer == location.buffer {
16086                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16087                        locations.next();
16088                    } else {
16089                        break;
16090                    }
16091                }
16092
16093                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16094                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16095                    PathKey::for_buffer(&location.buffer, cx),
16096                    location.buffer.clone(),
16097                    ranges_for_buffer,
16098                    DEFAULT_MULTIBUFFER_CONTEXT,
16099                    cx,
16100                );
16101                ranges.extend(new_ranges)
16102            }
16103
16104            multibuffer.with_title(title)
16105        });
16106
16107        let editor = cx.new(|cx| {
16108            Editor::for_multibuffer(
16109                excerpt_buffer,
16110                Some(workspace.project().clone()),
16111                window,
16112                cx,
16113            )
16114        });
16115        editor.update(cx, |editor, cx| {
16116            match multibuffer_selection_mode {
16117                MultibufferSelectionMode::First => {
16118                    if let Some(first_range) = ranges.first() {
16119                        editor.change_selections(
16120                            SelectionEffects::no_scroll(),
16121                            window,
16122                            cx,
16123                            |selections| {
16124                                selections.clear_disjoint();
16125                                selections
16126                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16127                            },
16128                        );
16129                    }
16130                    editor.highlight_background::<Self>(
16131                        &ranges,
16132                        |theme| theme.colors().editor_highlighted_line_background,
16133                        cx,
16134                    );
16135                }
16136                MultibufferSelectionMode::All => {
16137                    editor.change_selections(
16138                        SelectionEffects::no_scroll(),
16139                        window,
16140                        cx,
16141                        |selections| {
16142                            selections.clear_disjoint();
16143                            selections.select_anchor_ranges(ranges);
16144                        },
16145                    );
16146                }
16147            }
16148            editor.register_buffers_with_language_servers(cx);
16149        });
16150
16151        let item = Box::new(editor);
16152        let item_id = item.item_id();
16153
16154        if split {
16155            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16156        } else {
16157            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16158                let (preview_item_id, preview_item_idx) =
16159                    workspace.active_pane().read_with(cx, |pane, _| {
16160                        (pane.preview_item_id(), pane.preview_item_idx())
16161                    });
16162
16163                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16164
16165                if let Some(preview_item_id) = preview_item_id {
16166                    workspace.active_pane().update(cx, |pane, cx| {
16167                        pane.remove_item(preview_item_id, false, false, window, cx);
16168                    });
16169                }
16170            } else {
16171                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16172            }
16173        }
16174        workspace.active_pane().update(cx, |pane, cx| {
16175            pane.set_preview_item_id(Some(item_id), cx);
16176        });
16177    }
16178
16179    pub fn rename(
16180        &mut self,
16181        _: &Rename,
16182        window: &mut Window,
16183        cx: &mut Context<Self>,
16184    ) -> Option<Task<Result<()>>> {
16185        use language::ToOffset as _;
16186
16187        let provider = self.semantics_provider.clone()?;
16188        let selection = self.selections.newest_anchor().clone();
16189        let (cursor_buffer, cursor_buffer_position) = self
16190            .buffer
16191            .read(cx)
16192            .text_anchor_for_position(selection.head(), cx)?;
16193        let (tail_buffer, cursor_buffer_position_end) = self
16194            .buffer
16195            .read(cx)
16196            .text_anchor_for_position(selection.tail(), cx)?;
16197        if tail_buffer != cursor_buffer {
16198            return None;
16199        }
16200
16201        let snapshot = cursor_buffer.read(cx).snapshot();
16202        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16203        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16204        let prepare_rename = provider
16205            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16206            .unwrap_or_else(|| Task::ready(Ok(None)));
16207        drop(snapshot);
16208
16209        Some(cx.spawn_in(window, async move |this, cx| {
16210            let rename_range = if let Some(range) = prepare_rename.await? {
16211                Some(range)
16212            } else {
16213                this.update(cx, |this, cx| {
16214                    let buffer = this.buffer.read(cx).snapshot(cx);
16215                    let mut buffer_highlights = this
16216                        .document_highlights_for_position(selection.head(), &buffer)
16217                        .filter(|highlight| {
16218                            highlight.start.excerpt_id == selection.head().excerpt_id
16219                                && highlight.end.excerpt_id == selection.head().excerpt_id
16220                        });
16221                    buffer_highlights
16222                        .next()
16223                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16224                })?
16225            };
16226            if let Some(rename_range) = rename_range {
16227                this.update_in(cx, |this, window, cx| {
16228                    let snapshot = cursor_buffer.read(cx).snapshot();
16229                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16230                    let cursor_offset_in_rename_range =
16231                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16232                    let cursor_offset_in_rename_range_end =
16233                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16234
16235                    this.take_rename(false, window, cx);
16236                    let buffer = this.buffer.read(cx).read(cx);
16237                    let cursor_offset = selection.head().to_offset(&buffer);
16238                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16239                    let rename_end = rename_start + rename_buffer_range.len();
16240                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16241                    let mut old_highlight_id = None;
16242                    let old_name: Arc<str> = buffer
16243                        .chunks(rename_start..rename_end, true)
16244                        .map(|chunk| {
16245                            if old_highlight_id.is_none() {
16246                                old_highlight_id = chunk.syntax_highlight_id;
16247                            }
16248                            chunk.text
16249                        })
16250                        .collect::<String>()
16251                        .into();
16252
16253                    drop(buffer);
16254
16255                    // Position the selection in the rename editor so that it matches the current selection.
16256                    this.show_local_selections = false;
16257                    let rename_editor = cx.new(|cx| {
16258                        let mut editor = Editor::single_line(window, cx);
16259                        editor.buffer.update(cx, |buffer, cx| {
16260                            buffer.edit([(0..0, old_name.clone())], None, cx)
16261                        });
16262                        let rename_selection_range = match cursor_offset_in_rename_range
16263                            .cmp(&cursor_offset_in_rename_range_end)
16264                        {
16265                            Ordering::Equal => {
16266                                editor.select_all(&SelectAll, window, cx);
16267                                return editor;
16268                            }
16269                            Ordering::Less => {
16270                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16271                            }
16272                            Ordering::Greater => {
16273                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16274                            }
16275                        };
16276                        if rename_selection_range.end > old_name.len() {
16277                            editor.select_all(&SelectAll, window, cx);
16278                        } else {
16279                            editor.change_selections(Default::default(), window, cx, |s| {
16280                                s.select_ranges([rename_selection_range]);
16281                            });
16282                        }
16283                        editor
16284                    });
16285                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16286                        if e == &EditorEvent::Focused {
16287                            cx.emit(EditorEvent::FocusedIn)
16288                        }
16289                    })
16290                    .detach();
16291
16292                    let write_highlights =
16293                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16294                    let read_highlights =
16295                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16296                    let ranges = write_highlights
16297                        .iter()
16298                        .flat_map(|(_, ranges)| ranges.iter())
16299                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16300                        .cloned()
16301                        .collect();
16302
16303                    this.highlight_text::<Rename>(
16304                        ranges,
16305                        HighlightStyle {
16306                            fade_out: Some(0.6),
16307                            ..Default::default()
16308                        },
16309                        cx,
16310                    );
16311                    let rename_focus_handle = rename_editor.focus_handle(cx);
16312                    window.focus(&rename_focus_handle);
16313                    let block_id = this.insert_blocks(
16314                        [BlockProperties {
16315                            style: BlockStyle::Flex,
16316                            placement: BlockPlacement::Below(range.start),
16317                            height: Some(1),
16318                            render: Arc::new({
16319                                let rename_editor = rename_editor.clone();
16320                                move |cx: &mut BlockContext| {
16321                                    let mut text_style = cx.editor_style.text.clone();
16322                                    if let Some(highlight_style) = old_highlight_id
16323                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16324                                    {
16325                                        text_style = text_style.highlight(highlight_style);
16326                                    }
16327                                    div()
16328                                        .block_mouse_except_scroll()
16329                                        .pl(cx.anchor_x)
16330                                        .child(EditorElement::new(
16331                                            &rename_editor,
16332                                            EditorStyle {
16333                                                background: cx.theme().system().transparent,
16334                                                local_player: cx.editor_style.local_player,
16335                                                text: text_style,
16336                                                scrollbar_width: cx.editor_style.scrollbar_width,
16337                                                syntax: cx.editor_style.syntax.clone(),
16338                                                status: cx.editor_style.status.clone(),
16339                                                inlay_hints_style: HighlightStyle {
16340                                                    font_weight: Some(FontWeight::BOLD),
16341                                                    ..make_inlay_hints_style(cx.app)
16342                                                },
16343                                                edit_prediction_styles: make_suggestion_styles(
16344                                                    cx.app,
16345                                                ),
16346                                                ..EditorStyle::default()
16347                                            },
16348                                        ))
16349                                        .into_any_element()
16350                                }
16351                            }),
16352                            priority: 0,
16353                        }],
16354                        Some(Autoscroll::fit()),
16355                        cx,
16356                    )[0];
16357                    this.pending_rename = Some(RenameState {
16358                        range,
16359                        old_name,
16360                        editor: rename_editor,
16361                        block_id,
16362                    });
16363                })?;
16364            }
16365
16366            Ok(())
16367        }))
16368    }
16369
16370    pub fn confirm_rename(
16371        &mut self,
16372        _: &ConfirmRename,
16373        window: &mut Window,
16374        cx: &mut Context<Self>,
16375    ) -> Option<Task<Result<()>>> {
16376        let rename = self.take_rename(false, window, cx)?;
16377        let workspace = self.workspace()?.downgrade();
16378        let (buffer, start) = self
16379            .buffer
16380            .read(cx)
16381            .text_anchor_for_position(rename.range.start, cx)?;
16382        let (end_buffer, _) = self
16383            .buffer
16384            .read(cx)
16385            .text_anchor_for_position(rename.range.end, cx)?;
16386        if buffer != end_buffer {
16387            return None;
16388        }
16389
16390        let old_name = rename.old_name;
16391        let new_name = rename.editor.read(cx).text(cx);
16392
16393        let rename = self.semantics_provider.as_ref()?.perform_rename(
16394            &buffer,
16395            start,
16396            new_name.clone(),
16397            cx,
16398        )?;
16399
16400        Some(cx.spawn_in(window, async move |editor, cx| {
16401            let project_transaction = rename.await?;
16402            Self::open_project_transaction(
16403                &editor,
16404                workspace,
16405                project_transaction,
16406                format!("Rename: {}{}", old_name, new_name),
16407                cx,
16408            )
16409            .await?;
16410
16411            editor.update(cx, |editor, cx| {
16412                editor.refresh_document_highlights(cx);
16413            })?;
16414            Ok(())
16415        }))
16416    }
16417
16418    fn take_rename(
16419        &mut self,
16420        moving_cursor: bool,
16421        window: &mut Window,
16422        cx: &mut Context<Self>,
16423    ) -> Option<RenameState> {
16424        let rename = self.pending_rename.take()?;
16425        if rename.editor.focus_handle(cx).is_focused(window) {
16426            window.focus(&self.focus_handle);
16427        }
16428
16429        self.remove_blocks(
16430            [rename.block_id].into_iter().collect(),
16431            Some(Autoscroll::fit()),
16432            cx,
16433        );
16434        self.clear_highlights::<Rename>(cx);
16435        self.show_local_selections = true;
16436
16437        if moving_cursor {
16438            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16439                editor.selections.newest::<usize>(cx).head()
16440            });
16441
16442            // Update the selection to match the position of the selection inside
16443            // the rename editor.
16444            let snapshot = self.buffer.read(cx).read(cx);
16445            let rename_range = rename.range.to_offset(&snapshot);
16446            let cursor_in_editor = snapshot
16447                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16448                .min(rename_range.end);
16449            drop(snapshot);
16450
16451            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16452                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16453            });
16454        } else {
16455            self.refresh_document_highlights(cx);
16456        }
16457
16458        Some(rename)
16459    }
16460
16461    pub fn pending_rename(&self) -> Option<&RenameState> {
16462        self.pending_rename.as_ref()
16463    }
16464
16465    fn format(
16466        &mut self,
16467        _: &Format,
16468        window: &mut Window,
16469        cx: &mut Context<Self>,
16470    ) -> Option<Task<Result<()>>> {
16471        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16472
16473        let project = match &self.project {
16474            Some(project) => project.clone(),
16475            None => return None,
16476        };
16477
16478        Some(self.perform_format(
16479            project,
16480            FormatTrigger::Manual,
16481            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16482            window,
16483            cx,
16484        ))
16485    }
16486
16487    fn format_selections(
16488        &mut self,
16489        _: &FormatSelections,
16490        window: &mut Window,
16491        cx: &mut Context<Self>,
16492    ) -> Option<Task<Result<()>>> {
16493        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16494
16495        let project = match &self.project {
16496            Some(project) => project.clone(),
16497            None => return None,
16498        };
16499
16500        let ranges = self
16501            .selections
16502            .all_adjusted(cx)
16503            .into_iter()
16504            .map(|selection| selection.range())
16505            .collect_vec();
16506
16507        Some(self.perform_format(
16508            project,
16509            FormatTrigger::Manual,
16510            FormatTarget::Ranges(ranges),
16511            window,
16512            cx,
16513        ))
16514    }
16515
16516    fn perform_format(
16517        &mut self,
16518        project: Entity<Project>,
16519        trigger: FormatTrigger,
16520        target: FormatTarget,
16521        window: &mut Window,
16522        cx: &mut Context<Self>,
16523    ) -> Task<Result<()>> {
16524        let buffer = self.buffer.clone();
16525        let (buffers, target) = match target {
16526            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16527            FormatTarget::Ranges(selection_ranges) => {
16528                let multi_buffer = buffer.read(cx);
16529                let snapshot = multi_buffer.read(cx);
16530                let mut buffers = HashSet::default();
16531                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16532                    BTreeMap::new();
16533                for selection_range in selection_ranges {
16534                    for (buffer, buffer_range, _) in
16535                        snapshot.range_to_buffer_ranges(selection_range)
16536                    {
16537                        let buffer_id = buffer.remote_id();
16538                        let start = buffer.anchor_before(buffer_range.start);
16539                        let end = buffer.anchor_after(buffer_range.end);
16540                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16541                        buffer_id_to_ranges
16542                            .entry(buffer_id)
16543                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16544                            .or_insert_with(|| vec![start..end]);
16545                    }
16546                }
16547                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16548            }
16549        };
16550
16551        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16552        let selections_prev = transaction_id_prev
16553            .and_then(|transaction_id_prev| {
16554                // default to selections as they were after the last edit, if we have them,
16555                // instead of how they are now.
16556                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16557                // will take you back to where you made the last edit, instead of staying where you scrolled
16558                self.selection_history
16559                    .transaction(transaction_id_prev)
16560                    .map(|t| t.0.clone())
16561            })
16562            .unwrap_or_else(|| {
16563                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16564                self.selections.disjoint_anchors()
16565            });
16566
16567        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16568        let format = project.update(cx, |project, cx| {
16569            project.format(buffers, target, true, trigger, cx)
16570        });
16571
16572        cx.spawn_in(window, async move |editor, cx| {
16573            let transaction = futures::select_biased! {
16574                transaction = format.log_err().fuse() => transaction,
16575                () = timeout => {
16576                    log::warn!("timed out waiting for formatting");
16577                    None
16578                }
16579            };
16580
16581            buffer
16582                .update(cx, |buffer, cx| {
16583                    if let Some(transaction) = transaction {
16584                        if !buffer.is_singleton() {
16585                            buffer.push_transaction(&transaction.0, cx);
16586                        }
16587                    }
16588                    cx.notify();
16589                })
16590                .ok();
16591
16592            if let Some(transaction_id_now) =
16593                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16594            {
16595                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16596                if has_new_transaction {
16597                    _ = editor.update(cx, |editor, _| {
16598                        editor
16599                            .selection_history
16600                            .insert_transaction(transaction_id_now, selections_prev);
16601                    });
16602                }
16603            }
16604
16605            Ok(())
16606        })
16607    }
16608
16609    fn organize_imports(
16610        &mut self,
16611        _: &OrganizeImports,
16612        window: &mut Window,
16613        cx: &mut Context<Self>,
16614    ) -> Option<Task<Result<()>>> {
16615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16616        let project = match &self.project {
16617            Some(project) => project.clone(),
16618            None => return None,
16619        };
16620        Some(self.perform_code_action_kind(
16621            project,
16622            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16623            window,
16624            cx,
16625        ))
16626    }
16627
16628    fn perform_code_action_kind(
16629        &mut self,
16630        project: Entity<Project>,
16631        kind: CodeActionKind,
16632        window: &mut Window,
16633        cx: &mut Context<Self>,
16634    ) -> Task<Result<()>> {
16635        let buffer = self.buffer.clone();
16636        let buffers = buffer.read(cx).all_buffers();
16637        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16638        let apply_action = project.update(cx, |project, cx| {
16639            project.apply_code_action_kind(buffers, kind, true, cx)
16640        });
16641        cx.spawn_in(window, async move |_, cx| {
16642            let transaction = futures::select_biased! {
16643                () = timeout => {
16644                    log::warn!("timed out waiting for executing code action");
16645                    None
16646                }
16647                transaction = apply_action.log_err().fuse() => transaction,
16648            };
16649            buffer
16650                .update(cx, |buffer, cx| {
16651                    // check if we need this
16652                    if let Some(transaction) = transaction {
16653                        if !buffer.is_singleton() {
16654                            buffer.push_transaction(&transaction.0, cx);
16655                        }
16656                    }
16657                    cx.notify();
16658                })
16659                .ok();
16660            Ok(())
16661        })
16662    }
16663
16664    pub fn restart_language_server(
16665        &mut self,
16666        _: &RestartLanguageServer,
16667        _: &mut Window,
16668        cx: &mut Context<Self>,
16669    ) {
16670        if let Some(project) = self.project.clone() {
16671            self.buffer.update(cx, |multi_buffer, cx| {
16672                project.update(cx, |project, cx| {
16673                    project.restart_language_servers_for_buffers(
16674                        multi_buffer.all_buffers().into_iter().collect(),
16675                        HashSet::default(),
16676                        cx,
16677                    );
16678                });
16679            })
16680        }
16681    }
16682
16683    pub fn stop_language_server(
16684        &mut self,
16685        _: &StopLanguageServer,
16686        _: &mut Window,
16687        cx: &mut Context<Self>,
16688    ) {
16689        if let Some(project) = self.project.clone() {
16690            self.buffer.update(cx, |multi_buffer, cx| {
16691                project.update(cx, |project, cx| {
16692                    project.stop_language_servers_for_buffers(
16693                        multi_buffer.all_buffers().into_iter().collect(),
16694                        HashSet::default(),
16695                        cx,
16696                    );
16697                    cx.emit(project::Event::RefreshInlayHints);
16698                });
16699            });
16700        }
16701    }
16702
16703    fn cancel_language_server_work(
16704        workspace: &mut Workspace,
16705        _: &actions::CancelLanguageServerWork,
16706        _: &mut Window,
16707        cx: &mut Context<Workspace>,
16708    ) {
16709        let project = workspace.project();
16710        let buffers = workspace
16711            .active_item(cx)
16712            .and_then(|item| item.act_as::<Editor>(cx))
16713            .map_or(HashSet::default(), |editor| {
16714                editor.read(cx).buffer.read(cx).all_buffers()
16715            });
16716        project.update(cx, |project, cx| {
16717            project.cancel_language_server_work_for_buffers(buffers, cx);
16718        });
16719    }
16720
16721    fn show_character_palette(
16722        &mut self,
16723        _: &ShowCharacterPalette,
16724        window: &mut Window,
16725        _: &mut Context<Self>,
16726    ) {
16727        window.show_character_palette();
16728    }
16729
16730    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16731        if !self.diagnostics_enabled() {
16732            return;
16733        }
16734
16735        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16736            let buffer = self.buffer.read(cx).snapshot(cx);
16737            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16738            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16739            let is_valid = buffer
16740                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16741                .any(|entry| {
16742                    entry.diagnostic.is_primary
16743                        && !entry.range.is_empty()
16744                        && entry.range.start == primary_range_start
16745                        && entry.diagnostic.message == active_diagnostics.active_message
16746                });
16747
16748            if !is_valid {
16749                self.dismiss_diagnostics(cx);
16750            }
16751        }
16752    }
16753
16754    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16755        match &self.active_diagnostics {
16756            ActiveDiagnostic::Group(group) => Some(group),
16757            _ => None,
16758        }
16759    }
16760
16761    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16762        if !self.diagnostics_enabled() {
16763            return;
16764        }
16765        self.dismiss_diagnostics(cx);
16766        self.active_diagnostics = ActiveDiagnostic::All;
16767    }
16768
16769    fn activate_diagnostics(
16770        &mut self,
16771        buffer_id: BufferId,
16772        diagnostic: DiagnosticEntry<usize>,
16773        window: &mut Window,
16774        cx: &mut Context<Self>,
16775    ) {
16776        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16777            return;
16778        }
16779        self.dismiss_diagnostics(cx);
16780        let snapshot = self.snapshot(window, cx);
16781        let buffer = self.buffer.read(cx).snapshot(cx);
16782        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16783            return;
16784        };
16785
16786        let diagnostic_group = buffer
16787            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16788            .collect::<Vec<_>>();
16789
16790        let blocks =
16791            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16792
16793        let blocks = self.display_map.update(cx, |display_map, cx| {
16794            display_map.insert_blocks(blocks, cx).into_iter().collect()
16795        });
16796        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16797            active_range: buffer.anchor_before(diagnostic.range.start)
16798                ..buffer.anchor_after(diagnostic.range.end),
16799            active_message: diagnostic.diagnostic.message.clone(),
16800            group_id: diagnostic.diagnostic.group_id,
16801            blocks,
16802        });
16803        cx.notify();
16804    }
16805
16806    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16807        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16808            return;
16809        };
16810
16811        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16812        if let ActiveDiagnostic::Group(group) = prev {
16813            self.display_map.update(cx, |display_map, cx| {
16814                display_map.remove_blocks(group.blocks, cx);
16815            });
16816            cx.notify();
16817        }
16818    }
16819
16820    /// Disable inline diagnostics rendering for this editor.
16821    pub fn disable_inline_diagnostics(&mut self) {
16822        self.inline_diagnostics_enabled = false;
16823        self.inline_diagnostics_update = Task::ready(());
16824        self.inline_diagnostics.clear();
16825    }
16826
16827    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16828        self.diagnostics_enabled = false;
16829        self.dismiss_diagnostics(cx);
16830        self.inline_diagnostics_update = Task::ready(());
16831        self.inline_diagnostics.clear();
16832    }
16833
16834    pub fn diagnostics_enabled(&self) -> bool {
16835        self.diagnostics_enabled && self.mode.is_full()
16836    }
16837
16838    pub fn inline_diagnostics_enabled(&self) -> bool {
16839        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16840    }
16841
16842    pub fn show_inline_diagnostics(&self) -> bool {
16843        self.show_inline_diagnostics
16844    }
16845
16846    pub fn toggle_inline_diagnostics(
16847        &mut self,
16848        _: &ToggleInlineDiagnostics,
16849        window: &mut Window,
16850        cx: &mut Context<Editor>,
16851    ) {
16852        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16853        self.refresh_inline_diagnostics(false, window, cx);
16854    }
16855
16856    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16857        self.diagnostics_max_severity = severity;
16858        self.display_map.update(cx, |display_map, _| {
16859            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16860        });
16861    }
16862
16863    pub fn toggle_diagnostics(
16864        &mut self,
16865        _: &ToggleDiagnostics,
16866        window: &mut Window,
16867        cx: &mut Context<Editor>,
16868    ) {
16869        if !self.diagnostics_enabled() {
16870            return;
16871        }
16872
16873        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16874            EditorSettings::get_global(cx)
16875                .diagnostics_max_severity
16876                .filter(|severity| severity != &DiagnosticSeverity::Off)
16877                .unwrap_or(DiagnosticSeverity::Hint)
16878        } else {
16879            DiagnosticSeverity::Off
16880        };
16881        self.set_max_diagnostics_severity(new_severity, cx);
16882        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16883            self.active_diagnostics = ActiveDiagnostic::None;
16884            self.inline_diagnostics_update = Task::ready(());
16885            self.inline_diagnostics.clear();
16886        } else {
16887            self.refresh_inline_diagnostics(false, window, cx);
16888        }
16889
16890        cx.notify();
16891    }
16892
16893    pub fn toggle_minimap(
16894        &mut self,
16895        _: &ToggleMinimap,
16896        window: &mut Window,
16897        cx: &mut Context<Editor>,
16898    ) {
16899        if self.supports_minimap(cx) {
16900            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16901        }
16902    }
16903
16904    fn refresh_inline_diagnostics(
16905        &mut self,
16906        debounce: bool,
16907        window: &mut Window,
16908        cx: &mut Context<Self>,
16909    ) {
16910        let max_severity = ProjectSettings::get_global(cx)
16911            .diagnostics
16912            .inline
16913            .max_severity
16914            .unwrap_or(self.diagnostics_max_severity);
16915
16916        if !self.inline_diagnostics_enabled()
16917            || !self.show_inline_diagnostics
16918            || max_severity == DiagnosticSeverity::Off
16919        {
16920            self.inline_diagnostics_update = Task::ready(());
16921            self.inline_diagnostics.clear();
16922            return;
16923        }
16924
16925        let debounce_ms = ProjectSettings::get_global(cx)
16926            .diagnostics
16927            .inline
16928            .update_debounce_ms;
16929        let debounce = if debounce && debounce_ms > 0 {
16930            Some(Duration::from_millis(debounce_ms))
16931        } else {
16932            None
16933        };
16934        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16935            if let Some(debounce) = debounce {
16936                cx.background_executor().timer(debounce).await;
16937            }
16938            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16939                editor
16940                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16941                    .ok()
16942            }) else {
16943                return;
16944            };
16945
16946            let new_inline_diagnostics = cx
16947                .background_spawn(async move {
16948                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16949                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16950                        let message = diagnostic_entry
16951                            .diagnostic
16952                            .message
16953                            .split_once('\n')
16954                            .map(|(line, _)| line)
16955                            .map(SharedString::new)
16956                            .unwrap_or_else(|| {
16957                                SharedString::from(diagnostic_entry.diagnostic.message)
16958                            });
16959                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16960                        let (Ok(i) | Err(i)) = inline_diagnostics
16961                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16962                        inline_diagnostics.insert(
16963                            i,
16964                            (
16965                                start_anchor,
16966                                InlineDiagnostic {
16967                                    message,
16968                                    group_id: diagnostic_entry.diagnostic.group_id,
16969                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16970                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16971                                    severity: diagnostic_entry.diagnostic.severity,
16972                                },
16973                            ),
16974                        );
16975                    }
16976                    inline_diagnostics
16977                })
16978                .await;
16979
16980            editor
16981                .update(cx, |editor, cx| {
16982                    editor.inline_diagnostics = new_inline_diagnostics;
16983                    cx.notify();
16984                })
16985                .ok();
16986        });
16987    }
16988
16989    fn pull_diagnostics(
16990        &mut self,
16991        buffer_id: Option<BufferId>,
16992        window: &Window,
16993        cx: &mut Context<Self>,
16994    ) -> Option<()> {
16995        if !self.mode().is_full() {
16996            return None;
16997        }
16998        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16999            .diagnostics
17000            .lsp_pull_diagnostics;
17001        if !pull_diagnostics_settings.enabled {
17002            return None;
17003        }
17004        let project = self.project.as_ref()?.downgrade();
17005        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17006        let mut buffers = self.buffer.read(cx).all_buffers();
17007        if let Some(buffer_id) = buffer_id {
17008            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17009        }
17010
17011        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17012            cx.background_executor().timer(debounce).await;
17013
17014            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17015                buffers
17016                    .into_iter()
17017                    .filter_map(|buffer| {
17018                        project
17019                            .update(cx, |project, cx| {
17020                                project.lsp_store().update(cx, |lsp_store, cx| {
17021                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17022                                })
17023                            })
17024                            .ok()
17025                    })
17026                    .collect::<FuturesUnordered<_>>()
17027            }) else {
17028                return;
17029            };
17030
17031            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17032                match pull_task {
17033                    Ok(()) => {
17034                        if editor
17035                            .update_in(cx, |editor, window, cx| {
17036                                editor.update_diagnostics_state(window, cx);
17037                            })
17038                            .is_err()
17039                        {
17040                            return;
17041                        }
17042                    }
17043                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17044                }
17045            }
17046        });
17047
17048        Some(())
17049    }
17050
17051    pub fn set_selections_from_remote(
17052        &mut self,
17053        selections: Vec<Selection<Anchor>>,
17054        pending_selection: Option<Selection<Anchor>>,
17055        window: &mut Window,
17056        cx: &mut Context<Self>,
17057    ) {
17058        let old_cursor_position = self.selections.newest_anchor().head();
17059        self.selections.change_with(cx, |s| {
17060            s.select_anchors(selections);
17061            if let Some(pending_selection) = pending_selection {
17062                s.set_pending(pending_selection, SelectMode::Character);
17063            } else {
17064                s.clear_pending();
17065            }
17066        });
17067        self.selections_did_change(
17068            false,
17069            &old_cursor_position,
17070            SelectionEffects::default(),
17071            window,
17072            cx,
17073        );
17074    }
17075
17076    pub fn transact(
17077        &mut self,
17078        window: &mut Window,
17079        cx: &mut Context<Self>,
17080        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17081    ) -> Option<TransactionId> {
17082        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17083            this.start_transaction_at(Instant::now(), window, cx);
17084            update(this, window, cx);
17085            this.end_transaction_at(Instant::now(), cx)
17086        })
17087    }
17088
17089    pub fn start_transaction_at(
17090        &mut self,
17091        now: Instant,
17092        window: &mut Window,
17093        cx: &mut Context<Self>,
17094    ) -> Option<TransactionId> {
17095        self.end_selection(window, cx);
17096        if let Some(tx_id) = self
17097            .buffer
17098            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17099        {
17100            self.selection_history
17101                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17102            cx.emit(EditorEvent::TransactionBegun {
17103                transaction_id: tx_id,
17104            });
17105            Some(tx_id)
17106        } else {
17107            None
17108        }
17109    }
17110
17111    pub fn end_transaction_at(
17112        &mut self,
17113        now: Instant,
17114        cx: &mut Context<Self>,
17115    ) -> Option<TransactionId> {
17116        if let Some(transaction_id) = self
17117            .buffer
17118            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17119        {
17120            if let Some((_, end_selections)) =
17121                self.selection_history.transaction_mut(transaction_id)
17122            {
17123                *end_selections = Some(self.selections.disjoint_anchors());
17124            } else {
17125                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17126            }
17127
17128            cx.emit(EditorEvent::Edited { transaction_id });
17129            Some(transaction_id)
17130        } else {
17131            None
17132        }
17133    }
17134
17135    pub fn modify_transaction_selection_history(
17136        &mut self,
17137        transaction_id: TransactionId,
17138        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17139    ) -> bool {
17140        self.selection_history
17141            .transaction_mut(transaction_id)
17142            .map(modify)
17143            .is_some()
17144    }
17145
17146    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17147        if self.selection_mark_mode {
17148            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17149                s.move_with(|_, sel| {
17150                    sel.collapse_to(sel.head(), SelectionGoal::None);
17151                });
17152            })
17153        }
17154        self.selection_mark_mode = true;
17155        cx.notify();
17156    }
17157
17158    pub fn swap_selection_ends(
17159        &mut self,
17160        _: &actions::SwapSelectionEnds,
17161        window: &mut Window,
17162        cx: &mut Context<Self>,
17163    ) {
17164        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17165            s.move_with(|_, sel| {
17166                if sel.start != sel.end {
17167                    sel.reversed = !sel.reversed
17168                }
17169            });
17170        });
17171        self.request_autoscroll(Autoscroll::newest(), cx);
17172        cx.notify();
17173    }
17174
17175    pub fn toggle_focus(
17176        workspace: &mut Workspace,
17177        _: &actions::ToggleFocus,
17178        window: &mut Window,
17179        cx: &mut Context<Workspace>,
17180    ) {
17181        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17182            return;
17183        };
17184        workspace.activate_item(&item, true, true, window, cx);
17185    }
17186
17187    pub fn toggle_fold(
17188        &mut self,
17189        _: &actions::ToggleFold,
17190        window: &mut Window,
17191        cx: &mut Context<Self>,
17192    ) {
17193        if self.is_singleton(cx) {
17194            let selection = self.selections.newest::<Point>(cx);
17195
17196            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17197            let range = if selection.is_empty() {
17198                let point = selection.head().to_display_point(&display_map);
17199                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17200                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17201                    .to_point(&display_map);
17202                start..end
17203            } else {
17204                selection.range()
17205            };
17206            if display_map.folds_in_range(range).next().is_some() {
17207                self.unfold_lines(&Default::default(), window, cx)
17208            } else {
17209                self.fold(&Default::default(), window, cx)
17210            }
17211        } else {
17212            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17213            let buffer_ids: HashSet<_> = self
17214                .selections
17215                .disjoint_anchor_ranges()
17216                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17217                .collect();
17218
17219            let should_unfold = buffer_ids
17220                .iter()
17221                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17222
17223            for buffer_id in buffer_ids {
17224                if should_unfold {
17225                    self.unfold_buffer(buffer_id, cx);
17226                } else {
17227                    self.fold_buffer(buffer_id, cx);
17228                }
17229            }
17230        }
17231    }
17232
17233    pub fn toggle_fold_recursive(
17234        &mut self,
17235        _: &actions::ToggleFoldRecursive,
17236        window: &mut Window,
17237        cx: &mut Context<Self>,
17238    ) {
17239        let selection = self.selections.newest::<Point>(cx);
17240
17241        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17242        let range = if selection.is_empty() {
17243            let point = selection.head().to_display_point(&display_map);
17244            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17245            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17246                .to_point(&display_map);
17247            start..end
17248        } else {
17249            selection.range()
17250        };
17251        if display_map.folds_in_range(range).next().is_some() {
17252            self.unfold_recursive(&Default::default(), window, cx)
17253        } else {
17254            self.fold_recursive(&Default::default(), window, cx)
17255        }
17256    }
17257
17258    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17259        if self.is_singleton(cx) {
17260            let mut to_fold = Vec::new();
17261            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17262            let selections = self.selections.all_adjusted(cx);
17263
17264            for selection in selections {
17265                let range = selection.range().sorted();
17266                let buffer_start_row = range.start.row;
17267
17268                if range.start.row != range.end.row {
17269                    let mut found = false;
17270                    let mut row = range.start.row;
17271                    while row <= range.end.row {
17272                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17273                        {
17274                            found = true;
17275                            row = crease.range().end.row + 1;
17276                            to_fold.push(crease);
17277                        } else {
17278                            row += 1
17279                        }
17280                    }
17281                    if found {
17282                        continue;
17283                    }
17284                }
17285
17286                for row in (0..=range.start.row).rev() {
17287                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17288                        if crease.range().end.row >= buffer_start_row {
17289                            to_fold.push(crease);
17290                            if row <= range.start.row {
17291                                break;
17292                            }
17293                        }
17294                    }
17295                }
17296            }
17297
17298            self.fold_creases(to_fold, true, window, cx);
17299        } else {
17300            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17301            let buffer_ids = self
17302                .selections
17303                .disjoint_anchor_ranges()
17304                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17305                .collect::<HashSet<_>>();
17306            for buffer_id in buffer_ids {
17307                self.fold_buffer(buffer_id, cx);
17308            }
17309        }
17310    }
17311
17312    pub fn toggle_fold_all(
17313        &mut self,
17314        _: &actions::ToggleFoldAll,
17315        window: &mut Window,
17316        cx: &mut Context<Self>,
17317    ) {
17318        if self.buffer.read(cx).is_singleton() {
17319            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17320            let has_folds = display_map
17321                .folds_in_range(0..display_map.buffer_snapshot.len())
17322                .next()
17323                .is_some();
17324
17325            if has_folds {
17326                self.unfold_all(&actions::UnfoldAll, window, cx);
17327            } else {
17328                self.fold_all(&actions::FoldAll, window, cx);
17329            }
17330        } else {
17331            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17332            let should_unfold = buffer_ids
17333                .iter()
17334                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17335
17336            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17337                editor
17338                    .update_in(cx, |editor, _, cx| {
17339                        for buffer_id in buffer_ids {
17340                            if should_unfold {
17341                                editor.unfold_buffer(buffer_id, cx);
17342                            } else {
17343                                editor.fold_buffer(buffer_id, cx);
17344                            }
17345                        }
17346                    })
17347                    .ok();
17348            });
17349        }
17350    }
17351
17352    fn fold_at_level(
17353        &mut self,
17354        fold_at: &FoldAtLevel,
17355        window: &mut Window,
17356        cx: &mut Context<Self>,
17357    ) {
17358        if !self.buffer.read(cx).is_singleton() {
17359            return;
17360        }
17361
17362        let fold_at_level = fold_at.0;
17363        let snapshot = self.buffer.read(cx).snapshot(cx);
17364        let mut to_fold = Vec::new();
17365        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17366
17367        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17368            while start_row < end_row {
17369                match self
17370                    .snapshot(window, cx)
17371                    .crease_for_buffer_row(MultiBufferRow(start_row))
17372                {
17373                    Some(crease) => {
17374                        let nested_start_row = crease.range().start.row + 1;
17375                        let nested_end_row = crease.range().end.row;
17376
17377                        if current_level < fold_at_level {
17378                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17379                        } else if current_level == fold_at_level {
17380                            to_fold.push(crease);
17381                        }
17382
17383                        start_row = nested_end_row + 1;
17384                    }
17385                    None => start_row += 1,
17386                }
17387            }
17388        }
17389
17390        self.fold_creases(to_fold, true, window, cx);
17391    }
17392
17393    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17394        if self.buffer.read(cx).is_singleton() {
17395            let mut fold_ranges = Vec::new();
17396            let snapshot = self.buffer.read(cx).snapshot(cx);
17397
17398            for row in 0..snapshot.max_row().0 {
17399                if let Some(foldable_range) = self
17400                    .snapshot(window, cx)
17401                    .crease_for_buffer_row(MultiBufferRow(row))
17402                {
17403                    fold_ranges.push(foldable_range);
17404                }
17405            }
17406
17407            self.fold_creases(fold_ranges, true, window, cx);
17408        } else {
17409            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17410                editor
17411                    .update_in(cx, |editor, _, cx| {
17412                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17413                            editor.fold_buffer(buffer_id, cx);
17414                        }
17415                    })
17416                    .ok();
17417            });
17418        }
17419    }
17420
17421    pub fn fold_function_bodies(
17422        &mut self,
17423        _: &actions::FoldFunctionBodies,
17424        window: &mut Window,
17425        cx: &mut Context<Self>,
17426    ) {
17427        let snapshot = self.buffer.read(cx).snapshot(cx);
17428
17429        let ranges = snapshot
17430            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17431            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17432            .collect::<Vec<_>>();
17433
17434        let creases = ranges
17435            .into_iter()
17436            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17437            .collect();
17438
17439        self.fold_creases(creases, true, window, cx);
17440    }
17441
17442    pub fn fold_recursive(
17443        &mut self,
17444        _: &actions::FoldRecursive,
17445        window: &mut Window,
17446        cx: &mut Context<Self>,
17447    ) {
17448        let mut to_fold = Vec::new();
17449        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17450        let selections = self.selections.all_adjusted(cx);
17451
17452        for selection in selections {
17453            let range = selection.range().sorted();
17454            let buffer_start_row = range.start.row;
17455
17456            if range.start.row != range.end.row {
17457                let mut found = false;
17458                for row in range.start.row..=range.end.row {
17459                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17460                        found = true;
17461                        to_fold.push(crease);
17462                    }
17463                }
17464                if found {
17465                    continue;
17466                }
17467            }
17468
17469            for row in (0..=range.start.row).rev() {
17470                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17471                    if crease.range().end.row >= buffer_start_row {
17472                        to_fold.push(crease);
17473                    } else {
17474                        break;
17475                    }
17476                }
17477            }
17478        }
17479
17480        self.fold_creases(to_fold, true, window, cx);
17481    }
17482
17483    pub fn fold_at(
17484        &mut self,
17485        buffer_row: MultiBufferRow,
17486        window: &mut Window,
17487        cx: &mut Context<Self>,
17488    ) {
17489        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17490
17491        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17492            let autoscroll = self
17493                .selections
17494                .all::<Point>(cx)
17495                .iter()
17496                .any(|selection| crease.range().overlaps(&selection.range()));
17497
17498            self.fold_creases(vec![crease], autoscroll, window, cx);
17499        }
17500    }
17501
17502    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17503        if self.is_singleton(cx) {
17504            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17505            let buffer = &display_map.buffer_snapshot;
17506            let selections = self.selections.all::<Point>(cx);
17507            let ranges = selections
17508                .iter()
17509                .map(|s| {
17510                    let range = s.display_range(&display_map).sorted();
17511                    let mut start = range.start.to_point(&display_map);
17512                    let mut end = range.end.to_point(&display_map);
17513                    start.column = 0;
17514                    end.column = buffer.line_len(MultiBufferRow(end.row));
17515                    start..end
17516                })
17517                .collect::<Vec<_>>();
17518
17519            self.unfold_ranges(&ranges, true, true, cx);
17520        } else {
17521            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17522            let buffer_ids = self
17523                .selections
17524                .disjoint_anchor_ranges()
17525                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17526                .collect::<HashSet<_>>();
17527            for buffer_id in buffer_ids {
17528                self.unfold_buffer(buffer_id, cx);
17529            }
17530        }
17531    }
17532
17533    pub fn unfold_recursive(
17534        &mut self,
17535        _: &UnfoldRecursive,
17536        _window: &mut Window,
17537        cx: &mut Context<Self>,
17538    ) {
17539        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17540        let selections = self.selections.all::<Point>(cx);
17541        let ranges = selections
17542            .iter()
17543            .map(|s| {
17544                let mut range = s.display_range(&display_map).sorted();
17545                *range.start.column_mut() = 0;
17546                *range.end.column_mut() = display_map.line_len(range.end.row());
17547                let start = range.start.to_point(&display_map);
17548                let end = range.end.to_point(&display_map);
17549                start..end
17550            })
17551            .collect::<Vec<_>>();
17552
17553        self.unfold_ranges(&ranges, true, true, cx);
17554    }
17555
17556    pub fn unfold_at(
17557        &mut self,
17558        buffer_row: MultiBufferRow,
17559        _window: &mut Window,
17560        cx: &mut Context<Self>,
17561    ) {
17562        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17563
17564        let intersection_range = Point::new(buffer_row.0, 0)
17565            ..Point::new(
17566                buffer_row.0,
17567                display_map.buffer_snapshot.line_len(buffer_row),
17568            );
17569
17570        let autoscroll = self
17571            .selections
17572            .all::<Point>(cx)
17573            .iter()
17574            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17575
17576        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17577    }
17578
17579    pub fn unfold_all(
17580        &mut self,
17581        _: &actions::UnfoldAll,
17582        _window: &mut Window,
17583        cx: &mut Context<Self>,
17584    ) {
17585        if self.buffer.read(cx).is_singleton() {
17586            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17587            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17588        } else {
17589            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17590                editor
17591                    .update(cx, |editor, cx| {
17592                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17593                            editor.unfold_buffer(buffer_id, cx);
17594                        }
17595                    })
17596                    .ok();
17597            });
17598        }
17599    }
17600
17601    pub fn fold_selected_ranges(
17602        &mut self,
17603        _: &FoldSelectedRanges,
17604        window: &mut Window,
17605        cx: &mut Context<Self>,
17606    ) {
17607        let selections = self.selections.all_adjusted(cx);
17608        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17609        let ranges = selections
17610            .into_iter()
17611            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17612            .collect::<Vec<_>>();
17613        self.fold_creases(ranges, true, window, cx);
17614    }
17615
17616    pub fn fold_ranges<T: ToOffset + Clone>(
17617        &mut self,
17618        ranges: Vec<Range<T>>,
17619        auto_scroll: bool,
17620        window: &mut Window,
17621        cx: &mut Context<Self>,
17622    ) {
17623        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17624        let ranges = ranges
17625            .into_iter()
17626            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17627            .collect::<Vec<_>>();
17628        self.fold_creases(ranges, auto_scroll, window, cx);
17629    }
17630
17631    pub fn fold_creases<T: ToOffset + Clone>(
17632        &mut self,
17633        creases: Vec<Crease<T>>,
17634        auto_scroll: bool,
17635        _window: &mut Window,
17636        cx: &mut Context<Self>,
17637    ) {
17638        if creases.is_empty() {
17639            return;
17640        }
17641
17642        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17643
17644        if auto_scroll {
17645            self.request_autoscroll(Autoscroll::fit(), cx);
17646        }
17647
17648        cx.notify();
17649
17650        self.scrollbar_marker_state.dirty = true;
17651        self.folds_did_change(cx);
17652    }
17653
17654    /// Removes any folds whose ranges intersect any of the given ranges.
17655    pub fn unfold_ranges<T: ToOffset + Clone>(
17656        &mut self,
17657        ranges: &[Range<T>],
17658        inclusive: bool,
17659        auto_scroll: bool,
17660        cx: &mut Context<Self>,
17661    ) {
17662        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17663            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17664        });
17665        self.folds_did_change(cx);
17666    }
17667
17668    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17669        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17670            return;
17671        }
17672        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17673        self.display_map.update(cx, |display_map, cx| {
17674            display_map.fold_buffers([buffer_id], cx)
17675        });
17676        cx.emit(EditorEvent::BufferFoldToggled {
17677            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17678            folded: true,
17679        });
17680        cx.notify();
17681    }
17682
17683    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17684        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17685            return;
17686        }
17687        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17688        self.display_map.update(cx, |display_map, cx| {
17689            display_map.unfold_buffers([buffer_id], cx);
17690        });
17691        cx.emit(EditorEvent::BufferFoldToggled {
17692            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17693            folded: false,
17694        });
17695        cx.notify();
17696    }
17697
17698    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17699        self.display_map.read(cx).is_buffer_folded(buffer)
17700    }
17701
17702    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17703        self.display_map.read(cx).folded_buffers()
17704    }
17705
17706    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17707        self.display_map.update(cx, |display_map, cx| {
17708            display_map.disable_header_for_buffer(buffer_id, cx);
17709        });
17710        cx.notify();
17711    }
17712
17713    /// Removes any folds with the given ranges.
17714    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17715        &mut self,
17716        ranges: &[Range<T>],
17717        type_id: TypeId,
17718        auto_scroll: bool,
17719        cx: &mut Context<Self>,
17720    ) {
17721        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17722            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17723        });
17724        self.folds_did_change(cx);
17725    }
17726
17727    fn remove_folds_with<T: ToOffset + Clone>(
17728        &mut self,
17729        ranges: &[Range<T>],
17730        auto_scroll: bool,
17731        cx: &mut Context<Self>,
17732        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17733    ) {
17734        if ranges.is_empty() {
17735            return;
17736        }
17737
17738        let mut buffers_affected = HashSet::default();
17739        let multi_buffer = self.buffer().read(cx);
17740        for range in ranges {
17741            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17742                buffers_affected.insert(buffer.read(cx).remote_id());
17743            };
17744        }
17745
17746        self.display_map.update(cx, update);
17747
17748        if auto_scroll {
17749            self.request_autoscroll(Autoscroll::fit(), cx);
17750        }
17751
17752        cx.notify();
17753        self.scrollbar_marker_state.dirty = true;
17754        self.active_indent_guides_state.dirty = true;
17755    }
17756
17757    pub fn update_renderer_widths(
17758        &mut self,
17759        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17760        cx: &mut Context<Self>,
17761    ) -> bool {
17762        self.display_map
17763            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17764    }
17765
17766    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17767        self.display_map.read(cx).fold_placeholder.clone()
17768    }
17769
17770    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17771        self.buffer.update(cx, |buffer, cx| {
17772            buffer.set_all_diff_hunks_expanded(cx);
17773        });
17774    }
17775
17776    pub fn expand_all_diff_hunks(
17777        &mut self,
17778        _: &ExpandAllDiffHunks,
17779        _window: &mut Window,
17780        cx: &mut Context<Self>,
17781    ) {
17782        self.buffer.update(cx, |buffer, cx| {
17783            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17784        });
17785    }
17786
17787    pub fn toggle_selected_diff_hunks(
17788        &mut self,
17789        _: &ToggleSelectedDiffHunks,
17790        _window: &mut Window,
17791        cx: &mut Context<Self>,
17792    ) {
17793        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17794        self.toggle_diff_hunks_in_ranges(ranges, cx);
17795    }
17796
17797    pub fn diff_hunks_in_ranges<'a>(
17798        &'a self,
17799        ranges: &'a [Range<Anchor>],
17800        buffer: &'a MultiBufferSnapshot,
17801    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17802        ranges.iter().flat_map(move |range| {
17803            let end_excerpt_id = range.end.excerpt_id;
17804            let range = range.to_point(buffer);
17805            let mut peek_end = range.end;
17806            if range.end.row < buffer.max_row().0 {
17807                peek_end = Point::new(range.end.row + 1, 0);
17808            }
17809            buffer
17810                .diff_hunks_in_range(range.start..peek_end)
17811                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17812        })
17813    }
17814
17815    pub fn has_stageable_diff_hunks_in_ranges(
17816        &self,
17817        ranges: &[Range<Anchor>],
17818        snapshot: &MultiBufferSnapshot,
17819    ) -> bool {
17820        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17821        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17822    }
17823
17824    pub fn toggle_staged_selected_diff_hunks(
17825        &mut self,
17826        _: &::git::ToggleStaged,
17827        _: &mut Window,
17828        cx: &mut Context<Self>,
17829    ) {
17830        let snapshot = self.buffer.read(cx).snapshot(cx);
17831        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17832        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17833        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17834    }
17835
17836    pub fn set_render_diff_hunk_controls(
17837        &mut self,
17838        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17839        cx: &mut Context<Self>,
17840    ) {
17841        self.render_diff_hunk_controls = render_diff_hunk_controls;
17842        cx.notify();
17843    }
17844
17845    pub fn stage_and_next(
17846        &mut self,
17847        _: &::git::StageAndNext,
17848        window: &mut Window,
17849        cx: &mut Context<Self>,
17850    ) {
17851        self.do_stage_or_unstage_and_next(true, window, cx);
17852    }
17853
17854    pub fn unstage_and_next(
17855        &mut self,
17856        _: &::git::UnstageAndNext,
17857        window: &mut Window,
17858        cx: &mut Context<Self>,
17859    ) {
17860        self.do_stage_or_unstage_and_next(false, window, cx);
17861    }
17862
17863    pub fn stage_or_unstage_diff_hunks(
17864        &mut self,
17865        stage: bool,
17866        ranges: Vec<Range<Anchor>>,
17867        cx: &mut Context<Self>,
17868    ) {
17869        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17870        cx.spawn(async move |this, cx| {
17871            task.await?;
17872            this.update(cx, |this, cx| {
17873                let snapshot = this.buffer.read(cx).snapshot(cx);
17874                let chunk_by = this
17875                    .diff_hunks_in_ranges(&ranges, &snapshot)
17876                    .chunk_by(|hunk| hunk.buffer_id);
17877                for (buffer_id, hunks) in &chunk_by {
17878                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17879                }
17880            })
17881        })
17882        .detach_and_log_err(cx);
17883    }
17884
17885    fn save_buffers_for_ranges_if_needed(
17886        &mut self,
17887        ranges: &[Range<Anchor>],
17888        cx: &mut Context<Editor>,
17889    ) -> Task<Result<()>> {
17890        let multibuffer = self.buffer.read(cx);
17891        let snapshot = multibuffer.read(cx);
17892        let buffer_ids: HashSet<_> = ranges
17893            .iter()
17894            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17895            .collect();
17896        drop(snapshot);
17897
17898        let mut buffers = HashSet::default();
17899        for buffer_id in buffer_ids {
17900            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17901                let buffer = buffer_entity.read(cx);
17902                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17903                {
17904                    buffers.insert(buffer_entity);
17905                }
17906            }
17907        }
17908
17909        if let Some(project) = &self.project {
17910            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17911        } else {
17912            Task::ready(Ok(()))
17913        }
17914    }
17915
17916    fn do_stage_or_unstage_and_next(
17917        &mut self,
17918        stage: bool,
17919        window: &mut Window,
17920        cx: &mut Context<Self>,
17921    ) {
17922        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17923
17924        if ranges.iter().any(|range| range.start != range.end) {
17925            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17926            return;
17927        }
17928
17929        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17930        let snapshot = self.snapshot(window, cx);
17931        let position = self.selections.newest::<Point>(cx).head();
17932        let mut row = snapshot
17933            .buffer_snapshot
17934            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17935            .find(|hunk| hunk.row_range.start.0 > position.row)
17936            .map(|hunk| hunk.row_range.start);
17937
17938        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17939        // Outside of the project diff editor, wrap around to the beginning.
17940        if !all_diff_hunks_expanded {
17941            row = row.or_else(|| {
17942                snapshot
17943                    .buffer_snapshot
17944                    .diff_hunks_in_range(Point::zero()..position)
17945                    .find(|hunk| hunk.row_range.end.0 < position.row)
17946                    .map(|hunk| hunk.row_range.start)
17947            });
17948        }
17949
17950        if let Some(row) = row {
17951            let destination = Point::new(row.0, 0);
17952            let autoscroll = Autoscroll::center();
17953
17954            self.unfold_ranges(&[destination..destination], false, false, cx);
17955            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17956                s.select_ranges([destination..destination]);
17957            });
17958        }
17959    }
17960
17961    fn do_stage_or_unstage(
17962        &self,
17963        stage: bool,
17964        buffer_id: BufferId,
17965        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17966        cx: &mut App,
17967    ) -> Option<()> {
17968        let project = self.project.as_ref()?;
17969        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17970        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17971        let buffer_snapshot = buffer.read(cx).snapshot();
17972        let file_exists = buffer_snapshot
17973            .file()
17974            .is_some_and(|file| file.disk_state().exists());
17975        diff.update(cx, |diff, cx| {
17976            diff.stage_or_unstage_hunks(
17977                stage,
17978                &hunks
17979                    .map(|hunk| buffer_diff::DiffHunk {
17980                        buffer_range: hunk.buffer_range,
17981                        diff_base_byte_range: hunk.diff_base_byte_range,
17982                        secondary_status: hunk.secondary_status,
17983                        range: Point::zero()..Point::zero(), // unused
17984                    })
17985                    .collect::<Vec<_>>(),
17986                &buffer_snapshot,
17987                file_exists,
17988                cx,
17989            )
17990        });
17991        None
17992    }
17993
17994    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17995        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17996        self.buffer
17997            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17998    }
17999
18000    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18001        self.buffer.update(cx, |buffer, cx| {
18002            let ranges = vec![Anchor::min()..Anchor::max()];
18003            if !buffer.all_diff_hunks_expanded()
18004                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18005            {
18006                buffer.collapse_diff_hunks(ranges, cx);
18007                true
18008            } else {
18009                false
18010            }
18011        })
18012    }
18013
18014    fn toggle_diff_hunks_in_ranges(
18015        &mut self,
18016        ranges: Vec<Range<Anchor>>,
18017        cx: &mut Context<Editor>,
18018    ) {
18019        self.buffer.update(cx, |buffer, cx| {
18020            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18021            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18022        })
18023    }
18024
18025    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18026        self.buffer.update(cx, |buffer, cx| {
18027            let snapshot = buffer.snapshot(cx);
18028            let excerpt_id = range.end.excerpt_id;
18029            let point_range = range.to_point(&snapshot);
18030            let expand = !buffer.single_hunk_is_expanded(range, cx);
18031            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18032        })
18033    }
18034
18035    pub(crate) fn apply_all_diff_hunks(
18036        &mut self,
18037        _: &ApplyAllDiffHunks,
18038        window: &mut Window,
18039        cx: &mut Context<Self>,
18040    ) {
18041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18042
18043        let buffers = self.buffer.read(cx).all_buffers();
18044        for branch_buffer in buffers {
18045            branch_buffer.update(cx, |branch_buffer, cx| {
18046                branch_buffer.merge_into_base(Vec::new(), cx);
18047            });
18048        }
18049
18050        if let Some(project) = self.project.clone() {
18051            self.save(
18052                SaveOptions {
18053                    format: true,
18054                    autosave: false,
18055                },
18056                project,
18057                window,
18058                cx,
18059            )
18060            .detach_and_log_err(cx);
18061        }
18062    }
18063
18064    pub(crate) fn apply_selected_diff_hunks(
18065        &mut self,
18066        _: &ApplyDiffHunk,
18067        window: &mut Window,
18068        cx: &mut Context<Self>,
18069    ) {
18070        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18071        let snapshot = self.snapshot(window, cx);
18072        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18073        let mut ranges_by_buffer = HashMap::default();
18074        self.transact(window, cx, |editor, _window, cx| {
18075            for hunk in hunks {
18076                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18077                    ranges_by_buffer
18078                        .entry(buffer.clone())
18079                        .or_insert_with(Vec::new)
18080                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18081                }
18082            }
18083
18084            for (buffer, ranges) in ranges_by_buffer {
18085                buffer.update(cx, |buffer, cx| {
18086                    buffer.merge_into_base(ranges, cx);
18087                });
18088            }
18089        });
18090
18091        if let Some(project) = self.project.clone() {
18092            self.save(
18093                SaveOptions {
18094                    format: true,
18095                    autosave: false,
18096                },
18097                project,
18098                window,
18099                cx,
18100            )
18101            .detach_and_log_err(cx);
18102        }
18103    }
18104
18105    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18106        if hovered != self.gutter_hovered {
18107            self.gutter_hovered = hovered;
18108            cx.notify();
18109        }
18110    }
18111
18112    pub fn insert_blocks(
18113        &mut self,
18114        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18115        autoscroll: Option<Autoscroll>,
18116        cx: &mut Context<Self>,
18117    ) -> Vec<CustomBlockId> {
18118        let blocks = self
18119            .display_map
18120            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18121        if let Some(autoscroll) = autoscroll {
18122            self.request_autoscroll(autoscroll, cx);
18123        }
18124        cx.notify();
18125        blocks
18126    }
18127
18128    pub fn resize_blocks(
18129        &mut self,
18130        heights: HashMap<CustomBlockId, u32>,
18131        autoscroll: Option<Autoscroll>,
18132        cx: &mut Context<Self>,
18133    ) {
18134        self.display_map
18135            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18136        if let Some(autoscroll) = autoscroll {
18137            self.request_autoscroll(autoscroll, cx);
18138        }
18139        cx.notify();
18140    }
18141
18142    pub fn replace_blocks(
18143        &mut self,
18144        renderers: HashMap<CustomBlockId, RenderBlock>,
18145        autoscroll: Option<Autoscroll>,
18146        cx: &mut Context<Self>,
18147    ) {
18148        self.display_map
18149            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18150        if let Some(autoscroll) = autoscroll {
18151            self.request_autoscroll(autoscroll, cx);
18152        }
18153        cx.notify();
18154    }
18155
18156    pub fn remove_blocks(
18157        &mut self,
18158        block_ids: HashSet<CustomBlockId>,
18159        autoscroll: Option<Autoscroll>,
18160        cx: &mut Context<Self>,
18161    ) {
18162        self.display_map.update(cx, |display_map, cx| {
18163            display_map.remove_blocks(block_ids, cx)
18164        });
18165        if let Some(autoscroll) = autoscroll {
18166            self.request_autoscroll(autoscroll, cx);
18167        }
18168        cx.notify();
18169    }
18170
18171    pub fn row_for_block(
18172        &self,
18173        block_id: CustomBlockId,
18174        cx: &mut Context<Self>,
18175    ) -> Option<DisplayRow> {
18176        self.display_map
18177            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18178    }
18179
18180    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18181        self.focused_block = Some(focused_block);
18182    }
18183
18184    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18185        self.focused_block.take()
18186    }
18187
18188    pub fn insert_creases(
18189        &mut self,
18190        creases: impl IntoIterator<Item = Crease<Anchor>>,
18191        cx: &mut Context<Self>,
18192    ) -> Vec<CreaseId> {
18193        self.display_map
18194            .update(cx, |map, cx| map.insert_creases(creases, cx))
18195    }
18196
18197    pub fn remove_creases(
18198        &mut self,
18199        ids: impl IntoIterator<Item = CreaseId>,
18200        cx: &mut Context<Self>,
18201    ) -> Vec<(CreaseId, Range<Anchor>)> {
18202        self.display_map
18203            .update(cx, |map, cx| map.remove_creases(ids, cx))
18204    }
18205
18206    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18207        self.display_map
18208            .update(cx, |map, cx| map.snapshot(cx))
18209            .longest_row()
18210    }
18211
18212    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18213        self.display_map
18214            .update(cx, |map, cx| map.snapshot(cx))
18215            .max_point()
18216    }
18217
18218    pub fn text(&self, cx: &App) -> String {
18219        self.buffer.read(cx).read(cx).text()
18220    }
18221
18222    pub fn is_empty(&self, cx: &App) -> bool {
18223        self.buffer.read(cx).read(cx).is_empty()
18224    }
18225
18226    pub fn text_option(&self, cx: &App) -> Option<String> {
18227        let text = self.text(cx);
18228        let text = text.trim();
18229
18230        if text.is_empty() {
18231            return None;
18232        }
18233
18234        Some(text.to_string())
18235    }
18236
18237    pub fn set_text(
18238        &mut self,
18239        text: impl Into<Arc<str>>,
18240        window: &mut Window,
18241        cx: &mut Context<Self>,
18242    ) {
18243        self.transact(window, cx, |this, _, cx| {
18244            this.buffer
18245                .read(cx)
18246                .as_singleton()
18247                .expect("you can only call set_text on editors for singleton buffers")
18248                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18249        });
18250    }
18251
18252    pub fn display_text(&self, cx: &mut App) -> String {
18253        self.display_map
18254            .update(cx, |map, cx| map.snapshot(cx))
18255            .text()
18256    }
18257
18258    fn create_minimap(
18259        &self,
18260        minimap_settings: MinimapSettings,
18261        window: &mut Window,
18262        cx: &mut Context<Self>,
18263    ) -> Option<Entity<Self>> {
18264        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18265            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18266    }
18267
18268    fn initialize_new_minimap(
18269        &self,
18270        minimap_settings: MinimapSettings,
18271        window: &mut Window,
18272        cx: &mut Context<Self>,
18273    ) -> Entity<Self> {
18274        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18275
18276        let mut minimap = Editor::new_internal(
18277            EditorMode::Minimap {
18278                parent: cx.weak_entity(),
18279            },
18280            self.buffer.clone(),
18281            None,
18282            Some(self.display_map.clone()),
18283            window,
18284            cx,
18285        );
18286        minimap.scroll_manager.clone_state(&self.scroll_manager);
18287        minimap.set_text_style_refinement(TextStyleRefinement {
18288            font_size: Some(MINIMAP_FONT_SIZE),
18289            font_weight: Some(MINIMAP_FONT_WEIGHT),
18290            ..Default::default()
18291        });
18292        minimap.update_minimap_configuration(minimap_settings, cx);
18293        cx.new(|_| minimap)
18294    }
18295
18296    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18297        let current_line_highlight = minimap_settings
18298            .current_line_highlight
18299            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18300        self.set_current_line_highlight(Some(current_line_highlight));
18301    }
18302
18303    pub fn minimap(&self) -> Option<&Entity<Self>> {
18304        self.minimap
18305            .as_ref()
18306            .filter(|_| self.minimap_visibility.visible())
18307    }
18308
18309    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18310        let mut wrap_guides = smallvec![];
18311
18312        if self.show_wrap_guides == Some(false) {
18313            return wrap_guides;
18314        }
18315
18316        let settings = self.buffer.read(cx).language_settings(cx);
18317        if settings.show_wrap_guides {
18318            match self.soft_wrap_mode(cx) {
18319                SoftWrap::Column(soft_wrap) => {
18320                    wrap_guides.push((soft_wrap as usize, true));
18321                }
18322                SoftWrap::Bounded(soft_wrap) => {
18323                    wrap_guides.push((soft_wrap as usize, true));
18324                }
18325                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18326            }
18327            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18328        }
18329
18330        wrap_guides
18331    }
18332
18333    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18334        let settings = self.buffer.read(cx).language_settings(cx);
18335        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18336        match mode {
18337            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18338                SoftWrap::None
18339            }
18340            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18341            language_settings::SoftWrap::PreferredLineLength => {
18342                SoftWrap::Column(settings.preferred_line_length)
18343            }
18344            language_settings::SoftWrap::Bounded => {
18345                SoftWrap::Bounded(settings.preferred_line_length)
18346            }
18347        }
18348    }
18349
18350    pub fn set_soft_wrap_mode(
18351        &mut self,
18352        mode: language_settings::SoftWrap,
18353
18354        cx: &mut Context<Self>,
18355    ) {
18356        self.soft_wrap_mode_override = Some(mode);
18357        cx.notify();
18358    }
18359
18360    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18361        self.hard_wrap = hard_wrap;
18362        cx.notify();
18363    }
18364
18365    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18366        self.text_style_refinement = Some(style);
18367    }
18368
18369    /// called by the Element so we know what style we were most recently rendered with.
18370    pub(crate) fn set_style(
18371        &mut self,
18372        style: EditorStyle,
18373        window: &mut Window,
18374        cx: &mut Context<Self>,
18375    ) {
18376        // We intentionally do not inform the display map about the minimap style
18377        // so that wrapping is not recalculated and stays consistent for the editor
18378        // and its linked minimap.
18379        if !self.mode.is_minimap() {
18380            let rem_size = window.rem_size();
18381            self.display_map.update(cx, |map, cx| {
18382                map.set_font(
18383                    style.text.font(),
18384                    style.text.font_size.to_pixels(rem_size),
18385                    cx,
18386                )
18387            });
18388        }
18389        self.style = Some(style);
18390    }
18391
18392    pub fn style(&self) -> Option<&EditorStyle> {
18393        self.style.as_ref()
18394    }
18395
18396    // Called by the element. This method is not designed to be called outside of the editor
18397    // element's layout code because it does not notify when rewrapping is computed synchronously.
18398    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18399        self.display_map
18400            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18401    }
18402
18403    pub fn set_soft_wrap(&mut self) {
18404        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18405    }
18406
18407    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18408        if self.soft_wrap_mode_override.is_some() {
18409            self.soft_wrap_mode_override.take();
18410        } else {
18411            let soft_wrap = match self.soft_wrap_mode(cx) {
18412                SoftWrap::GitDiff => return,
18413                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18414                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18415                    language_settings::SoftWrap::None
18416                }
18417            };
18418            self.soft_wrap_mode_override = Some(soft_wrap);
18419        }
18420        cx.notify();
18421    }
18422
18423    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18424        let Some(workspace) = self.workspace() else {
18425            return;
18426        };
18427        let fs = workspace.read(cx).app_state().fs.clone();
18428        let current_show = TabBarSettings::get_global(cx).show;
18429        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18430            setting.show = Some(!current_show);
18431        });
18432    }
18433
18434    pub fn toggle_indent_guides(
18435        &mut self,
18436        _: &ToggleIndentGuides,
18437        _: &mut Window,
18438        cx: &mut Context<Self>,
18439    ) {
18440        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18441            self.buffer
18442                .read(cx)
18443                .language_settings(cx)
18444                .indent_guides
18445                .enabled
18446        });
18447        self.show_indent_guides = Some(!currently_enabled);
18448        cx.notify();
18449    }
18450
18451    fn should_show_indent_guides(&self) -> Option<bool> {
18452        self.show_indent_guides
18453    }
18454
18455    pub fn toggle_line_numbers(
18456        &mut self,
18457        _: &ToggleLineNumbers,
18458        _: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        let mut editor_settings = EditorSettings::get_global(cx).clone();
18462        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18463        EditorSettings::override_global(editor_settings, cx);
18464    }
18465
18466    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18467        if let Some(show_line_numbers) = self.show_line_numbers {
18468            return show_line_numbers;
18469        }
18470        EditorSettings::get_global(cx).gutter.line_numbers
18471    }
18472
18473    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18474        self.use_relative_line_numbers
18475            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18476    }
18477
18478    pub fn toggle_relative_line_numbers(
18479        &mut self,
18480        _: &ToggleRelativeLineNumbers,
18481        _: &mut Window,
18482        cx: &mut Context<Self>,
18483    ) {
18484        let is_relative = self.should_use_relative_line_numbers(cx);
18485        self.set_relative_line_number(Some(!is_relative), cx)
18486    }
18487
18488    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18489        self.use_relative_line_numbers = is_relative;
18490        cx.notify();
18491    }
18492
18493    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18494        self.show_gutter = show_gutter;
18495        cx.notify();
18496    }
18497
18498    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18499        self.show_scrollbars = ScrollbarAxes {
18500            horizontal: show,
18501            vertical: show,
18502        };
18503        cx.notify();
18504    }
18505
18506    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18507        self.show_scrollbars.vertical = show;
18508        cx.notify();
18509    }
18510
18511    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18512        self.show_scrollbars.horizontal = show;
18513        cx.notify();
18514    }
18515
18516    pub fn set_minimap_visibility(
18517        &mut self,
18518        minimap_visibility: MinimapVisibility,
18519        window: &mut Window,
18520        cx: &mut Context<Self>,
18521    ) {
18522        if self.minimap_visibility != minimap_visibility {
18523            if minimap_visibility.visible() && self.minimap.is_none() {
18524                let minimap_settings = EditorSettings::get_global(cx).minimap;
18525                self.minimap =
18526                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18527            }
18528            self.minimap_visibility = minimap_visibility;
18529            cx.notify();
18530        }
18531    }
18532
18533    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18534        self.set_show_scrollbars(false, cx);
18535        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18536    }
18537
18538    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18539        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18540    }
18541
18542    /// Normally the text in full mode and auto height editors is padded on the
18543    /// left side by roughly half a character width for improved hit testing.
18544    ///
18545    /// Use this method to disable this for cases where this is not wanted (e.g.
18546    /// if you want to align the editor text with some other text above or below)
18547    /// or if you want to add this padding to single-line editors.
18548    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18549        self.offset_content = offset_content;
18550        cx.notify();
18551    }
18552
18553    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18554        self.show_line_numbers = Some(show_line_numbers);
18555        cx.notify();
18556    }
18557
18558    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18559        self.disable_expand_excerpt_buttons = true;
18560        cx.notify();
18561    }
18562
18563    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18564        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18565        cx.notify();
18566    }
18567
18568    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18569        self.show_code_actions = Some(show_code_actions);
18570        cx.notify();
18571    }
18572
18573    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18574        self.show_runnables = Some(show_runnables);
18575        cx.notify();
18576    }
18577
18578    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18579        self.show_breakpoints = Some(show_breakpoints);
18580        cx.notify();
18581    }
18582
18583    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18584        if self.display_map.read(cx).masked != masked {
18585            self.display_map.update(cx, |map, _| map.masked = masked);
18586        }
18587        cx.notify()
18588    }
18589
18590    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18591        self.show_wrap_guides = Some(show_wrap_guides);
18592        cx.notify();
18593    }
18594
18595    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18596        self.show_indent_guides = Some(show_indent_guides);
18597        cx.notify();
18598    }
18599
18600    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18601        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18602            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18603                if let Some(dir) = file.abs_path(cx).parent() {
18604                    return Some(dir.to_owned());
18605                }
18606            }
18607
18608            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18609                return Some(project_path.path.to_path_buf());
18610            }
18611        }
18612
18613        None
18614    }
18615
18616    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18617        self.active_excerpt(cx)?
18618            .1
18619            .read(cx)
18620            .file()
18621            .and_then(|f| f.as_local())
18622    }
18623
18624    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18625        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18626            let buffer = buffer.read(cx);
18627            if let Some(project_path) = buffer.project_path(cx) {
18628                let project = self.project.as_ref()?.read(cx);
18629                project.absolute_path(&project_path, cx)
18630            } else {
18631                buffer
18632                    .file()
18633                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18634            }
18635        })
18636    }
18637
18638    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18639        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18640            let project_path = buffer.read(cx).project_path(cx)?;
18641            let project = self.project.as_ref()?.read(cx);
18642            let entry = project.entry_for_path(&project_path, cx)?;
18643            let path = entry.path.to_path_buf();
18644            Some(path)
18645        })
18646    }
18647
18648    pub fn reveal_in_finder(
18649        &mut self,
18650        _: &RevealInFileManager,
18651        _window: &mut Window,
18652        cx: &mut Context<Self>,
18653    ) {
18654        if let Some(target) = self.target_file(cx) {
18655            cx.reveal_path(&target.abs_path(cx));
18656        }
18657    }
18658
18659    pub fn copy_path(
18660        &mut self,
18661        _: &zed_actions::workspace::CopyPath,
18662        _window: &mut Window,
18663        cx: &mut Context<Self>,
18664    ) {
18665        if let Some(path) = self.target_file_abs_path(cx) {
18666            if let Some(path) = path.to_str() {
18667                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18668            }
18669        }
18670    }
18671
18672    pub fn copy_relative_path(
18673        &mut self,
18674        _: &zed_actions::workspace::CopyRelativePath,
18675        _window: &mut Window,
18676        cx: &mut Context<Self>,
18677    ) {
18678        if let Some(path) = self.target_file_path(cx) {
18679            if let Some(path) = path.to_str() {
18680                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18681            }
18682        }
18683    }
18684
18685    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18686        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18687            buffer.read(cx).project_path(cx)
18688        } else {
18689            None
18690        }
18691    }
18692
18693    // Returns true if the editor handled a go-to-line request
18694    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18695        maybe!({
18696            let breakpoint_store = self.breakpoint_store.as_ref()?;
18697
18698            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18699            else {
18700                self.clear_row_highlights::<ActiveDebugLine>();
18701                return None;
18702            };
18703
18704            let position = active_stack_frame.position;
18705            let buffer_id = position.buffer_id?;
18706            let snapshot = self
18707                .project
18708                .as_ref()?
18709                .read(cx)
18710                .buffer_for_id(buffer_id, cx)?
18711                .read(cx)
18712                .snapshot();
18713
18714            let mut handled = false;
18715            for (id, ExcerptRange { context, .. }) in
18716                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18717            {
18718                if context.start.cmp(&position, &snapshot).is_ge()
18719                    || context.end.cmp(&position, &snapshot).is_lt()
18720                {
18721                    continue;
18722                }
18723                let snapshot = self.buffer.read(cx).snapshot(cx);
18724                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18725
18726                handled = true;
18727                self.clear_row_highlights::<ActiveDebugLine>();
18728
18729                self.go_to_line::<ActiveDebugLine>(
18730                    multibuffer_anchor,
18731                    Some(cx.theme().colors().editor_debugger_active_line_background),
18732                    window,
18733                    cx,
18734                );
18735
18736                cx.notify();
18737            }
18738
18739            handled.then_some(())
18740        })
18741        .is_some()
18742    }
18743
18744    pub fn copy_file_name_without_extension(
18745        &mut self,
18746        _: &CopyFileNameWithoutExtension,
18747        _: &mut Window,
18748        cx: &mut Context<Self>,
18749    ) {
18750        if let Some(file) = self.target_file(cx) {
18751            if let Some(file_stem) = file.path().file_stem() {
18752                if let Some(name) = file_stem.to_str() {
18753                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18754                }
18755            }
18756        }
18757    }
18758
18759    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18760        if let Some(file) = self.target_file(cx) {
18761            if let Some(file_name) = file.path().file_name() {
18762                if let Some(name) = file_name.to_str() {
18763                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18764                }
18765            }
18766        }
18767    }
18768
18769    pub fn toggle_git_blame(
18770        &mut self,
18771        _: &::git::Blame,
18772        window: &mut Window,
18773        cx: &mut Context<Self>,
18774    ) {
18775        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18776
18777        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18778            self.start_git_blame(true, window, cx);
18779        }
18780
18781        cx.notify();
18782    }
18783
18784    pub fn toggle_git_blame_inline(
18785        &mut self,
18786        _: &ToggleGitBlameInline,
18787        window: &mut Window,
18788        cx: &mut Context<Self>,
18789    ) {
18790        self.toggle_git_blame_inline_internal(true, window, cx);
18791        cx.notify();
18792    }
18793
18794    pub fn open_git_blame_commit(
18795        &mut self,
18796        _: &OpenGitBlameCommit,
18797        window: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) {
18800        self.open_git_blame_commit_internal(window, cx);
18801    }
18802
18803    fn open_git_blame_commit_internal(
18804        &mut self,
18805        window: &mut Window,
18806        cx: &mut Context<Self>,
18807    ) -> Option<()> {
18808        let blame = self.blame.as_ref()?;
18809        let snapshot = self.snapshot(window, cx);
18810        let cursor = self.selections.newest::<Point>(cx).head();
18811        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18812        let blame_entry = blame
18813            .update(cx, |blame, cx| {
18814                blame
18815                    .blame_for_rows(
18816                        &[RowInfo {
18817                            buffer_id: Some(buffer.remote_id()),
18818                            buffer_row: Some(point.row),
18819                            ..Default::default()
18820                        }],
18821                        cx,
18822                    )
18823                    .next()
18824            })
18825            .flatten()?;
18826        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18827        let repo = blame.read(cx).repository(cx)?;
18828        let workspace = self.workspace()?.downgrade();
18829        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18830        None
18831    }
18832
18833    pub fn git_blame_inline_enabled(&self) -> bool {
18834        self.git_blame_inline_enabled
18835    }
18836
18837    pub fn toggle_selection_menu(
18838        &mut self,
18839        _: &ToggleSelectionMenu,
18840        _: &mut Window,
18841        cx: &mut Context<Self>,
18842    ) {
18843        self.show_selection_menu = self
18844            .show_selection_menu
18845            .map(|show_selections_menu| !show_selections_menu)
18846            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18847
18848        cx.notify();
18849    }
18850
18851    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18852        self.show_selection_menu
18853            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18854    }
18855
18856    fn start_git_blame(
18857        &mut self,
18858        user_triggered: bool,
18859        window: &mut Window,
18860        cx: &mut Context<Self>,
18861    ) {
18862        if let Some(project) = self.project.as_ref() {
18863            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18864                return;
18865            };
18866
18867            if buffer.read(cx).file().is_none() {
18868                return;
18869            }
18870
18871            let focused = self.focus_handle(cx).contains_focused(window, cx);
18872
18873            let project = project.clone();
18874            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18875            self.blame_subscription =
18876                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18877            self.blame = Some(blame);
18878        }
18879    }
18880
18881    fn toggle_git_blame_inline_internal(
18882        &mut self,
18883        user_triggered: bool,
18884        window: &mut Window,
18885        cx: &mut Context<Self>,
18886    ) {
18887        if self.git_blame_inline_enabled {
18888            self.git_blame_inline_enabled = false;
18889            self.show_git_blame_inline = false;
18890            self.show_git_blame_inline_delay_task.take();
18891        } else {
18892            self.git_blame_inline_enabled = true;
18893            self.start_git_blame_inline(user_triggered, window, cx);
18894        }
18895
18896        cx.notify();
18897    }
18898
18899    fn start_git_blame_inline(
18900        &mut self,
18901        user_triggered: bool,
18902        window: &mut Window,
18903        cx: &mut Context<Self>,
18904    ) {
18905        self.start_git_blame(user_triggered, window, cx);
18906
18907        if ProjectSettings::get_global(cx)
18908            .git
18909            .inline_blame_delay()
18910            .is_some()
18911        {
18912            self.start_inline_blame_timer(window, cx);
18913        } else {
18914            self.show_git_blame_inline = true
18915        }
18916    }
18917
18918    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18919        self.blame.as_ref()
18920    }
18921
18922    pub fn show_git_blame_gutter(&self) -> bool {
18923        self.show_git_blame_gutter
18924    }
18925
18926    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18927        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18928    }
18929
18930    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18931        self.show_git_blame_inline
18932            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18933            && !self.newest_selection_head_on_empty_line(cx)
18934            && self.has_blame_entries(cx)
18935    }
18936
18937    fn has_blame_entries(&self, cx: &App) -> bool {
18938        self.blame()
18939            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18940    }
18941
18942    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18943        let cursor_anchor = self.selections.newest_anchor().head();
18944
18945        let snapshot = self.buffer.read(cx).snapshot(cx);
18946        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18947
18948        snapshot.line_len(buffer_row) == 0
18949    }
18950
18951    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18952        let buffer_and_selection = maybe!({
18953            let selection = self.selections.newest::<Point>(cx);
18954            let selection_range = selection.range();
18955
18956            let multi_buffer = self.buffer().read(cx);
18957            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18958            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18959
18960            let (buffer, range, _) = if selection.reversed {
18961                buffer_ranges.first()
18962            } else {
18963                buffer_ranges.last()
18964            }?;
18965
18966            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18967                ..text::ToPoint::to_point(&range.end, &buffer).row;
18968            Some((
18969                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18970                selection,
18971            ))
18972        });
18973
18974        let Some((buffer, selection)) = buffer_and_selection else {
18975            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18976        };
18977
18978        let Some(project) = self.project.as_ref() else {
18979            return Task::ready(Err(anyhow!("editor does not have project")));
18980        };
18981
18982        project.update(cx, |project, cx| {
18983            project.get_permalink_to_line(&buffer, selection, cx)
18984        })
18985    }
18986
18987    pub fn copy_permalink_to_line(
18988        &mut self,
18989        _: &CopyPermalinkToLine,
18990        window: &mut Window,
18991        cx: &mut Context<Self>,
18992    ) {
18993        let permalink_task = self.get_permalink_to_line(cx);
18994        let workspace = self.workspace();
18995
18996        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18997            Ok(permalink) => {
18998                cx.update(|_, cx| {
18999                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19000                })
19001                .ok();
19002            }
19003            Err(err) => {
19004                let message = format!("Failed to copy permalink: {err}");
19005
19006                anyhow::Result::<()>::Err(err).log_err();
19007
19008                if let Some(workspace) = workspace {
19009                    workspace
19010                        .update_in(cx, |workspace, _, cx| {
19011                            struct CopyPermalinkToLine;
19012
19013                            workspace.show_toast(
19014                                Toast::new(
19015                                    NotificationId::unique::<CopyPermalinkToLine>(),
19016                                    message,
19017                                ),
19018                                cx,
19019                            )
19020                        })
19021                        .ok();
19022                }
19023            }
19024        })
19025        .detach();
19026    }
19027
19028    pub fn copy_file_location(
19029        &mut self,
19030        _: &CopyFileLocation,
19031        _: &mut Window,
19032        cx: &mut Context<Self>,
19033    ) {
19034        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19035        if let Some(file) = self.target_file(cx) {
19036            if let Some(path) = file.path().to_str() {
19037                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19038            }
19039        }
19040    }
19041
19042    pub fn open_permalink_to_line(
19043        &mut self,
19044        _: &OpenPermalinkToLine,
19045        window: &mut Window,
19046        cx: &mut Context<Self>,
19047    ) {
19048        let permalink_task = self.get_permalink_to_line(cx);
19049        let workspace = self.workspace();
19050
19051        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19052            Ok(permalink) => {
19053                cx.update(|_, cx| {
19054                    cx.open_url(permalink.as_ref());
19055                })
19056                .ok();
19057            }
19058            Err(err) => {
19059                let message = format!("Failed to open permalink: {err}");
19060
19061                anyhow::Result::<()>::Err(err).log_err();
19062
19063                if let Some(workspace) = workspace {
19064                    workspace
19065                        .update(cx, |workspace, cx| {
19066                            struct OpenPermalinkToLine;
19067
19068                            workspace.show_toast(
19069                                Toast::new(
19070                                    NotificationId::unique::<OpenPermalinkToLine>(),
19071                                    message,
19072                                ),
19073                                cx,
19074                            )
19075                        })
19076                        .ok();
19077                }
19078            }
19079        })
19080        .detach();
19081    }
19082
19083    pub fn insert_uuid_v4(
19084        &mut self,
19085        _: &InsertUuidV4,
19086        window: &mut Window,
19087        cx: &mut Context<Self>,
19088    ) {
19089        self.insert_uuid(UuidVersion::V4, window, cx);
19090    }
19091
19092    pub fn insert_uuid_v7(
19093        &mut self,
19094        _: &InsertUuidV7,
19095        window: &mut Window,
19096        cx: &mut Context<Self>,
19097    ) {
19098        self.insert_uuid(UuidVersion::V7, window, cx);
19099    }
19100
19101    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19102        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19103        self.transact(window, cx, |this, window, cx| {
19104            let edits = this
19105                .selections
19106                .all::<Point>(cx)
19107                .into_iter()
19108                .map(|selection| {
19109                    let uuid = match version {
19110                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19111                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19112                    };
19113
19114                    (selection.range(), uuid.to_string())
19115                });
19116            this.edit(edits, cx);
19117            this.refresh_edit_prediction(true, false, window, cx);
19118        });
19119    }
19120
19121    pub fn open_selections_in_multibuffer(
19122        &mut self,
19123        _: &OpenSelectionsInMultibuffer,
19124        window: &mut Window,
19125        cx: &mut Context<Self>,
19126    ) {
19127        let multibuffer = self.buffer.read(cx);
19128
19129        let Some(buffer) = multibuffer.as_singleton() else {
19130            return;
19131        };
19132
19133        let Some(workspace) = self.workspace() else {
19134            return;
19135        };
19136
19137        let title = multibuffer.title(cx).to_string();
19138
19139        let locations = self
19140            .selections
19141            .all_anchors(cx)
19142            .into_iter()
19143            .map(|selection| Location {
19144                buffer: buffer.clone(),
19145                range: selection.start.text_anchor..selection.end.text_anchor,
19146            })
19147            .collect::<Vec<_>>();
19148
19149        cx.spawn_in(window, async move |_, cx| {
19150            workspace.update_in(cx, |workspace, window, cx| {
19151                Self::open_locations_in_multibuffer(
19152                    workspace,
19153                    locations,
19154                    format!("Selections for '{title}'"),
19155                    false,
19156                    MultibufferSelectionMode::All,
19157                    window,
19158                    cx,
19159                );
19160            })
19161        })
19162        .detach();
19163    }
19164
19165    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19166    /// last highlight added will be used.
19167    ///
19168    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19169    pub fn highlight_rows<T: 'static>(
19170        &mut self,
19171        range: Range<Anchor>,
19172        color: Hsla,
19173        options: RowHighlightOptions,
19174        cx: &mut Context<Self>,
19175    ) {
19176        let snapshot = self.buffer().read(cx).snapshot(cx);
19177        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19178        let ix = row_highlights.binary_search_by(|highlight| {
19179            Ordering::Equal
19180                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19181                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19182        });
19183
19184        if let Err(mut ix) = ix {
19185            let index = post_inc(&mut self.highlight_order);
19186
19187            // If this range intersects with the preceding highlight, then merge it with
19188            // the preceding highlight. Otherwise insert a new highlight.
19189            let mut merged = false;
19190            if ix > 0 {
19191                let prev_highlight = &mut row_highlights[ix - 1];
19192                if prev_highlight
19193                    .range
19194                    .end
19195                    .cmp(&range.start, &snapshot)
19196                    .is_ge()
19197                {
19198                    ix -= 1;
19199                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19200                        prev_highlight.range.end = range.end;
19201                    }
19202                    merged = true;
19203                    prev_highlight.index = index;
19204                    prev_highlight.color = color;
19205                    prev_highlight.options = options;
19206                }
19207            }
19208
19209            if !merged {
19210                row_highlights.insert(
19211                    ix,
19212                    RowHighlight {
19213                        range: range.clone(),
19214                        index,
19215                        color,
19216                        options,
19217                        type_id: TypeId::of::<T>(),
19218                    },
19219                );
19220            }
19221
19222            // If any of the following highlights intersect with this one, merge them.
19223            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19224                let highlight = &row_highlights[ix];
19225                if next_highlight
19226                    .range
19227                    .start
19228                    .cmp(&highlight.range.end, &snapshot)
19229                    .is_le()
19230                {
19231                    if next_highlight
19232                        .range
19233                        .end
19234                        .cmp(&highlight.range.end, &snapshot)
19235                        .is_gt()
19236                    {
19237                        row_highlights[ix].range.end = next_highlight.range.end;
19238                    }
19239                    row_highlights.remove(ix + 1);
19240                } else {
19241                    break;
19242                }
19243            }
19244        }
19245    }
19246
19247    /// Remove any highlighted row ranges of the given type that intersect the
19248    /// given ranges.
19249    pub fn remove_highlighted_rows<T: 'static>(
19250        &mut self,
19251        ranges_to_remove: Vec<Range<Anchor>>,
19252        cx: &mut Context<Self>,
19253    ) {
19254        let snapshot = self.buffer().read(cx).snapshot(cx);
19255        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19256        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19257        row_highlights.retain(|highlight| {
19258            while let Some(range_to_remove) = ranges_to_remove.peek() {
19259                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19260                    Ordering::Less | Ordering::Equal => {
19261                        ranges_to_remove.next();
19262                    }
19263                    Ordering::Greater => {
19264                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19265                            Ordering::Less | Ordering::Equal => {
19266                                return false;
19267                            }
19268                            Ordering::Greater => break,
19269                        }
19270                    }
19271                }
19272            }
19273
19274            true
19275        })
19276    }
19277
19278    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19279    pub fn clear_row_highlights<T: 'static>(&mut self) {
19280        self.highlighted_rows.remove(&TypeId::of::<T>());
19281    }
19282
19283    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19284    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19285        self.highlighted_rows
19286            .get(&TypeId::of::<T>())
19287            .map_or(&[] as &[_], |vec| vec.as_slice())
19288            .iter()
19289            .map(|highlight| (highlight.range.clone(), highlight.color))
19290    }
19291
19292    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19293    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19294    /// Allows to ignore certain kinds of highlights.
19295    pub fn highlighted_display_rows(
19296        &self,
19297        window: &mut Window,
19298        cx: &mut App,
19299    ) -> BTreeMap<DisplayRow, LineHighlight> {
19300        let snapshot = self.snapshot(window, cx);
19301        let mut used_highlight_orders = HashMap::default();
19302        self.highlighted_rows
19303            .iter()
19304            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19305            .fold(
19306                BTreeMap::<DisplayRow, LineHighlight>::new(),
19307                |mut unique_rows, highlight| {
19308                    let start = highlight.range.start.to_display_point(&snapshot);
19309                    let end = highlight.range.end.to_display_point(&snapshot);
19310                    let start_row = start.row().0;
19311                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19312                        && end.column() == 0
19313                    {
19314                        end.row().0.saturating_sub(1)
19315                    } else {
19316                        end.row().0
19317                    };
19318                    for row in start_row..=end_row {
19319                        let used_index =
19320                            used_highlight_orders.entry(row).or_insert(highlight.index);
19321                        if highlight.index >= *used_index {
19322                            *used_index = highlight.index;
19323                            unique_rows.insert(
19324                                DisplayRow(row),
19325                                LineHighlight {
19326                                    include_gutter: highlight.options.include_gutter,
19327                                    border: None,
19328                                    background: highlight.color.into(),
19329                                    type_id: Some(highlight.type_id),
19330                                },
19331                            );
19332                        }
19333                    }
19334                    unique_rows
19335                },
19336            )
19337    }
19338
19339    pub fn highlighted_display_row_for_autoscroll(
19340        &self,
19341        snapshot: &DisplaySnapshot,
19342    ) -> Option<DisplayRow> {
19343        self.highlighted_rows
19344            .values()
19345            .flat_map(|highlighted_rows| highlighted_rows.iter())
19346            .filter_map(|highlight| {
19347                if highlight.options.autoscroll {
19348                    Some(highlight.range.start.to_display_point(snapshot).row())
19349                } else {
19350                    None
19351                }
19352            })
19353            .min()
19354    }
19355
19356    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19357        self.highlight_background::<SearchWithinRange>(
19358            ranges,
19359            |colors| colors.colors().editor_document_highlight_read_background,
19360            cx,
19361        )
19362    }
19363
19364    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19365        self.breadcrumb_header = Some(new_header);
19366    }
19367
19368    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19369        self.clear_background_highlights::<SearchWithinRange>(cx);
19370    }
19371
19372    pub fn highlight_background<T: 'static>(
19373        &mut self,
19374        ranges: &[Range<Anchor>],
19375        color_fetcher: fn(&Theme) -> Hsla,
19376        cx: &mut Context<Self>,
19377    ) {
19378        self.background_highlights.insert(
19379            HighlightKey::Type(TypeId::of::<T>()),
19380            (color_fetcher, Arc::from(ranges)),
19381        );
19382        self.scrollbar_marker_state.dirty = true;
19383        cx.notify();
19384    }
19385
19386    pub fn highlight_background_key<T: 'static>(
19387        &mut self,
19388        key: usize,
19389        ranges: &[Range<Anchor>],
19390        color_fetcher: fn(&Theme) -> Hsla,
19391        cx: &mut Context<Self>,
19392    ) {
19393        self.background_highlights.insert(
19394            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19395            (color_fetcher, Arc::from(ranges)),
19396        );
19397        self.scrollbar_marker_state.dirty = true;
19398        cx.notify();
19399    }
19400
19401    pub fn clear_background_highlights<T: 'static>(
19402        &mut self,
19403        cx: &mut Context<Self>,
19404    ) -> Option<BackgroundHighlight> {
19405        let text_highlights = self
19406            .background_highlights
19407            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19408        if !text_highlights.1.is_empty() {
19409            self.scrollbar_marker_state.dirty = true;
19410            cx.notify();
19411        }
19412        Some(text_highlights)
19413    }
19414
19415    pub fn highlight_gutter<T: 'static>(
19416        &mut self,
19417        ranges: impl Into<Vec<Range<Anchor>>>,
19418        color_fetcher: fn(&App) -> Hsla,
19419        cx: &mut Context<Self>,
19420    ) {
19421        self.gutter_highlights
19422            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19423        cx.notify();
19424    }
19425
19426    pub fn clear_gutter_highlights<T: 'static>(
19427        &mut self,
19428        cx: &mut Context<Self>,
19429    ) -> Option<GutterHighlight> {
19430        cx.notify();
19431        self.gutter_highlights.remove(&TypeId::of::<T>())
19432    }
19433
19434    pub fn insert_gutter_highlight<T: 'static>(
19435        &mut self,
19436        range: Range<Anchor>,
19437        color_fetcher: fn(&App) -> Hsla,
19438        cx: &mut Context<Self>,
19439    ) {
19440        let snapshot = self.buffer().read(cx).snapshot(cx);
19441        let mut highlights = self
19442            .gutter_highlights
19443            .remove(&TypeId::of::<T>())
19444            .map(|(_, highlights)| highlights)
19445            .unwrap_or_default();
19446        let ix = highlights.binary_search_by(|highlight| {
19447            Ordering::Equal
19448                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19449                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19450        });
19451        if let Err(ix) = ix {
19452            highlights.insert(ix, range);
19453        }
19454        self.gutter_highlights
19455            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19456    }
19457
19458    pub fn remove_gutter_highlights<T: 'static>(
19459        &mut self,
19460        ranges_to_remove: Vec<Range<Anchor>>,
19461        cx: &mut Context<Self>,
19462    ) {
19463        let snapshot = self.buffer().read(cx).snapshot(cx);
19464        let Some((color_fetcher, mut gutter_highlights)) =
19465            self.gutter_highlights.remove(&TypeId::of::<T>())
19466        else {
19467            return;
19468        };
19469        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19470        gutter_highlights.retain(|highlight| {
19471            while let Some(range_to_remove) = ranges_to_remove.peek() {
19472                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19473                    Ordering::Less | Ordering::Equal => {
19474                        ranges_to_remove.next();
19475                    }
19476                    Ordering::Greater => {
19477                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19478                            Ordering::Less | Ordering::Equal => {
19479                                return false;
19480                            }
19481                            Ordering::Greater => break,
19482                        }
19483                    }
19484                }
19485            }
19486
19487            true
19488        });
19489        self.gutter_highlights
19490            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19491    }
19492
19493    #[cfg(feature = "test-support")]
19494    pub fn all_text_highlights(
19495        &self,
19496        window: &mut Window,
19497        cx: &mut Context<Self>,
19498    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19499        let snapshot = self.snapshot(window, cx);
19500        self.display_map.update(cx, |display_map, _| {
19501            display_map
19502                .all_text_highlights()
19503                .map(|highlight| {
19504                    let (style, ranges) = highlight.as_ref();
19505                    (
19506                        *style,
19507                        ranges
19508                            .iter()
19509                            .map(|range| range.clone().to_display_points(&snapshot))
19510                            .collect(),
19511                    )
19512                })
19513                .collect()
19514        })
19515    }
19516
19517    #[cfg(feature = "test-support")]
19518    pub fn all_text_background_highlights(
19519        &self,
19520        window: &mut Window,
19521        cx: &mut Context<Self>,
19522    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19523        let snapshot = self.snapshot(window, cx);
19524        let buffer = &snapshot.buffer_snapshot;
19525        let start = buffer.anchor_before(0);
19526        let end = buffer.anchor_after(buffer.len());
19527        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19528    }
19529
19530    #[cfg(feature = "test-support")]
19531    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19532        let snapshot = self.buffer().read(cx).snapshot(cx);
19533
19534        let highlights = self
19535            .background_highlights
19536            .get(&HighlightKey::Type(TypeId::of::<
19537                items::BufferSearchHighlights,
19538            >()));
19539
19540        if let Some((_color, ranges)) = highlights {
19541            ranges
19542                .iter()
19543                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19544                .collect_vec()
19545        } else {
19546            vec![]
19547        }
19548    }
19549
19550    fn document_highlights_for_position<'a>(
19551        &'a self,
19552        position: Anchor,
19553        buffer: &'a MultiBufferSnapshot,
19554    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19555        let read_highlights = self
19556            .background_highlights
19557            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19558            .map(|h| &h.1);
19559        let write_highlights = self
19560            .background_highlights
19561            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19562            .map(|h| &h.1);
19563        let left_position = position.bias_left(buffer);
19564        let right_position = position.bias_right(buffer);
19565        read_highlights
19566            .into_iter()
19567            .chain(write_highlights)
19568            .flat_map(move |ranges| {
19569                let start_ix = match ranges.binary_search_by(|probe| {
19570                    let cmp = probe.end.cmp(&left_position, buffer);
19571                    if cmp.is_ge() {
19572                        Ordering::Greater
19573                    } else {
19574                        Ordering::Less
19575                    }
19576                }) {
19577                    Ok(i) | Err(i) => i,
19578                };
19579
19580                ranges[start_ix..]
19581                    .iter()
19582                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19583            })
19584    }
19585
19586    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19587        self.background_highlights
19588            .get(&HighlightKey::Type(TypeId::of::<T>()))
19589            .map_or(false, |(_, highlights)| !highlights.is_empty())
19590    }
19591
19592    pub fn background_highlights_in_range(
19593        &self,
19594        search_range: Range<Anchor>,
19595        display_snapshot: &DisplaySnapshot,
19596        theme: &Theme,
19597    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19598        let mut results = Vec::new();
19599        for (color_fetcher, ranges) in self.background_highlights.values() {
19600            let color = color_fetcher(theme);
19601            let start_ix = match ranges.binary_search_by(|probe| {
19602                let cmp = probe
19603                    .end
19604                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19605                if cmp.is_gt() {
19606                    Ordering::Greater
19607                } else {
19608                    Ordering::Less
19609                }
19610            }) {
19611                Ok(i) | Err(i) => i,
19612            };
19613            for range in &ranges[start_ix..] {
19614                if range
19615                    .start
19616                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19617                    .is_ge()
19618                {
19619                    break;
19620                }
19621
19622                let start = range.start.to_display_point(display_snapshot);
19623                let end = range.end.to_display_point(display_snapshot);
19624                results.push((start..end, color))
19625            }
19626        }
19627        results
19628    }
19629
19630    pub fn background_highlight_row_ranges<T: 'static>(
19631        &self,
19632        search_range: Range<Anchor>,
19633        display_snapshot: &DisplaySnapshot,
19634        count: usize,
19635    ) -> Vec<RangeInclusive<DisplayPoint>> {
19636        let mut results = Vec::new();
19637        let Some((_, ranges)) = self
19638            .background_highlights
19639            .get(&HighlightKey::Type(TypeId::of::<T>()))
19640        else {
19641            return vec![];
19642        };
19643
19644        let start_ix = match ranges.binary_search_by(|probe| {
19645            let cmp = probe
19646                .end
19647                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19648            if cmp.is_gt() {
19649                Ordering::Greater
19650            } else {
19651                Ordering::Less
19652            }
19653        }) {
19654            Ok(i) | Err(i) => i,
19655        };
19656        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19657            if let (Some(start_display), Some(end_display)) = (start, end) {
19658                results.push(
19659                    start_display.to_display_point(display_snapshot)
19660                        ..=end_display.to_display_point(display_snapshot),
19661                );
19662            }
19663        };
19664        let mut start_row: Option<Point> = None;
19665        let mut end_row: Option<Point> = None;
19666        if ranges.len() > count {
19667            return Vec::new();
19668        }
19669        for range in &ranges[start_ix..] {
19670            if range
19671                .start
19672                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19673                .is_ge()
19674            {
19675                break;
19676            }
19677            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19678            if let Some(current_row) = &end_row {
19679                if end.row == current_row.row {
19680                    continue;
19681                }
19682            }
19683            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19684            if start_row.is_none() {
19685                assert_eq!(end_row, None);
19686                start_row = Some(start);
19687                end_row = Some(end);
19688                continue;
19689            }
19690            if let Some(current_end) = end_row.as_mut() {
19691                if start.row > current_end.row + 1 {
19692                    push_region(start_row, end_row);
19693                    start_row = Some(start);
19694                    end_row = Some(end);
19695                } else {
19696                    // Merge two hunks.
19697                    *current_end = end;
19698                }
19699            } else {
19700                unreachable!();
19701            }
19702        }
19703        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19704        push_region(start_row, end_row);
19705        results
19706    }
19707
19708    pub fn gutter_highlights_in_range(
19709        &self,
19710        search_range: Range<Anchor>,
19711        display_snapshot: &DisplaySnapshot,
19712        cx: &App,
19713    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19714        let mut results = Vec::new();
19715        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19716            let color = color_fetcher(cx);
19717            let start_ix = match ranges.binary_search_by(|probe| {
19718                let cmp = probe
19719                    .end
19720                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19721                if cmp.is_gt() {
19722                    Ordering::Greater
19723                } else {
19724                    Ordering::Less
19725                }
19726            }) {
19727                Ok(i) | Err(i) => i,
19728            };
19729            for range in &ranges[start_ix..] {
19730                if range
19731                    .start
19732                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19733                    .is_ge()
19734                {
19735                    break;
19736                }
19737
19738                let start = range.start.to_display_point(display_snapshot);
19739                let end = range.end.to_display_point(display_snapshot);
19740                results.push((start..end, color))
19741            }
19742        }
19743        results
19744    }
19745
19746    /// Get the text ranges corresponding to the redaction query
19747    pub fn redacted_ranges(
19748        &self,
19749        search_range: Range<Anchor>,
19750        display_snapshot: &DisplaySnapshot,
19751        cx: &App,
19752    ) -> Vec<Range<DisplayPoint>> {
19753        display_snapshot
19754            .buffer_snapshot
19755            .redacted_ranges(search_range, |file| {
19756                if let Some(file) = file {
19757                    file.is_private()
19758                        && EditorSettings::get(
19759                            Some(SettingsLocation {
19760                                worktree_id: file.worktree_id(cx),
19761                                path: file.path().as_ref(),
19762                            }),
19763                            cx,
19764                        )
19765                        .redact_private_values
19766                } else {
19767                    false
19768                }
19769            })
19770            .map(|range| {
19771                range.start.to_display_point(display_snapshot)
19772                    ..range.end.to_display_point(display_snapshot)
19773            })
19774            .collect()
19775    }
19776
19777    pub fn highlight_text_key<T: 'static>(
19778        &mut self,
19779        key: usize,
19780        ranges: Vec<Range<Anchor>>,
19781        style: HighlightStyle,
19782        cx: &mut Context<Self>,
19783    ) {
19784        self.display_map.update(cx, |map, _| {
19785            map.highlight_text(
19786                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19787                ranges,
19788                style,
19789            );
19790        });
19791        cx.notify();
19792    }
19793
19794    pub fn highlight_text<T: 'static>(
19795        &mut self,
19796        ranges: Vec<Range<Anchor>>,
19797        style: HighlightStyle,
19798        cx: &mut Context<Self>,
19799    ) {
19800        self.display_map.update(cx, |map, _| {
19801            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19802        });
19803        cx.notify();
19804    }
19805
19806    pub(crate) fn highlight_inlays<T: 'static>(
19807        &mut self,
19808        highlights: Vec<InlayHighlight>,
19809        style: HighlightStyle,
19810        cx: &mut Context<Self>,
19811    ) {
19812        self.display_map.update(cx, |map, _| {
19813            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19814        });
19815        cx.notify();
19816    }
19817
19818    pub fn text_highlights<'a, T: 'static>(
19819        &'a self,
19820        cx: &'a App,
19821    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19822        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19823    }
19824
19825    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19826        let cleared = self
19827            .display_map
19828            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19829        if cleared {
19830            cx.notify();
19831        }
19832    }
19833
19834    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19835        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19836            && self.focus_handle.is_focused(window)
19837    }
19838
19839    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19840        self.show_cursor_when_unfocused = is_enabled;
19841        cx.notify();
19842    }
19843
19844    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19845        cx.notify();
19846    }
19847
19848    fn on_debug_session_event(
19849        &mut self,
19850        _session: Entity<Session>,
19851        event: &SessionEvent,
19852        cx: &mut Context<Self>,
19853    ) {
19854        match event {
19855            SessionEvent::InvalidateInlineValue => {
19856                self.refresh_inline_values(cx);
19857            }
19858            _ => {}
19859        }
19860    }
19861
19862    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19863        let Some(project) = self.project.clone() else {
19864            return;
19865        };
19866
19867        if !self.inline_value_cache.enabled {
19868            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19869            self.splice_inlays(&inlays, Vec::new(), cx);
19870            return;
19871        }
19872
19873        let current_execution_position = self
19874            .highlighted_rows
19875            .get(&TypeId::of::<ActiveDebugLine>())
19876            .and_then(|lines| lines.last().map(|line| line.range.end));
19877
19878        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19879            let inline_values = editor
19880                .update(cx, |editor, cx| {
19881                    let Some(current_execution_position) = current_execution_position else {
19882                        return Some(Task::ready(Ok(Vec::new())));
19883                    };
19884
19885                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19886                        let snapshot = buffer.snapshot(cx);
19887
19888                        let excerpt = snapshot.excerpt_containing(
19889                            current_execution_position..current_execution_position,
19890                        )?;
19891
19892                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19893                    })?;
19894
19895                    let range =
19896                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19897
19898                    project.inline_values(buffer, range, cx)
19899                })
19900                .ok()
19901                .flatten()?
19902                .await
19903                .context("refreshing debugger inlays")
19904                .log_err()?;
19905
19906            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19907
19908            for (buffer_id, inline_value) in inline_values
19909                .into_iter()
19910                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19911            {
19912                buffer_inline_values
19913                    .entry(buffer_id)
19914                    .or_default()
19915                    .push(inline_value);
19916            }
19917
19918            editor
19919                .update(cx, |editor, cx| {
19920                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19921                    let mut new_inlays = Vec::default();
19922
19923                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19924                        let buffer_id = buffer_snapshot.remote_id();
19925                        buffer_inline_values
19926                            .get(&buffer_id)
19927                            .into_iter()
19928                            .flatten()
19929                            .for_each(|hint| {
19930                                let inlay = Inlay::debugger(
19931                                    post_inc(&mut editor.next_inlay_id),
19932                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19933                                    hint.text(),
19934                                );
19935                                if !inlay.text.chars().contains(&'\n') {
19936                                    new_inlays.push(inlay);
19937                                }
19938                            });
19939                    }
19940
19941                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19942                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19943
19944                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19945                })
19946                .ok()?;
19947            Some(())
19948        });
19949    }
19950
19951    fn on_buffer_event(
19952        &mut self,
19953        multibuffer: &Entity<MultiBuffer>,
19954        event: &multi_buffer::Event,
19955        window: &mut Window,
19956        cx: &mut Context<Self>,
19957    ) {
19958        match event {
19959            multi_buffer::Event::Edited {
19960                singleton_buffer_edited,
19961                edited_buffer,
19962            } => {
19963                self.scrollbar_marker_state.dirty = true;
19964                self.active_indent_guides_state.dirty = true;
19965                self.refresh_active_diagnostics(cx);
19966                self.refresh_code_actions(window, cx);
19967                self.refresh_selected_text_highlights(true, window, cx);
19968                self.refresh_single_line_folds(window, cx);
19969                refresh_matching_bracket_highlights(self, window, cx);
19970                if self.has_active_edit_prediction() {
19971                    self.update_visible_edit_prediction(window, cx);
19972                }
19973                if let Some(project) = self.project.as_ref() {
19974                    if let Some(edited_buffer) = edited_buffer {
19975                        project.update(cx, |project, cx| {
19976                            self.registered_buffers
19977                                .entry(edited_buffer.read(cx).remote_id())
19978                                .or_insert_with(|| {
19979                                    project
19980                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19981                                });
19982                        });
19983                    }
19984                }
19985                cx.emit(EditorEvent::BufferEdited);
19986                cx.emit(SearchEvent::MatchesInvalidated);
19987
19988                if let Some(buffer) = edited_buffer {
19989                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19990                }
19991
19992                if *singleton_buffer_edited {
19993                    if let Some(buffer) = edited_buffer {
19994                        if buffer.read(cx).file().is_none() {
19995                            cx.emit(EditorEvent::TitleChanged);
19996                        }
19997                    }
19998                    if let Some(project) = &self.project {
19999                        #[allow(clippy::mutable_key_type)]
20000                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20001                            multibuffer
20002                                .all_buffers()
20003                                .into_iter()
20004                                .filter_map(|buffer| {
20005                                    buffer.update(cx, |buffer, cx| {
20006                                        let language = buffer.language()?;
20007                                        let should_discard = project.update(cx, |project, cx| {
20008                                            project.is_local()
20009                                                && !project.has_language_servers_for(buffer, cx)
20010                                        });
20011                                        should_discard.not().then_some(language.clone())
20012                                    })
20013                                })
20014                                .collect::<HashSet<_>>()
20015                        });
20016                        if !languages_affected.is_empty() {
20017                            self.refresh_inlay_hints(
20018                                InlayHintRefreshReason::BufferEdited(languages_affected),
20019                                cx,
20020                            );
20021                        }
20022                    }
20023                }
20024
20025                let Some(project) = &self.project else { return };
20026                let (telemetry, is_via_ssh) = {
20027                    let project = project.read(cx);
20028                    let telemetry = project.client().telemetry().clone();
20029                    let is_via_ssh = project.is_via_ssh();
20030                    (telemetry, is_via_ssh)
20031                };
20032                refresh_linked_ranges(self, window, cx);
20033                telemetry.log_edit_event("editor", is_via_ssh);
20034            }
20035            multi_buffer::Event::ExcerptsAdded {
20036                buffer,
20037                predecessor,
20038                excerpts,
20039            } => {
20040                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20041                let buffer_id = buffer.read(cx).remote_id();
20042                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
20043                    if let Some(project) = &self.project {
20044                        update_uncommitted_diff_for_buffer(
20045                            cx.entity(),
20046                            project,
20047                            [buffer.clone()],
20048                            self.buffer.clone(),
20049                            cx,
20050                        )
20051                        .detach();
20052                    }
20053                }
20054                self.update_lsp_data(false, Some(buffer_id), window, cx);
20055                cx.emit(EditorEvent::ExcerptsAdded {
20056                    buffer: buffer.clone(),
20057                    predecessor: *predecessor,
20058                    excerpts: excerpts.clone(),
20059                });
20060                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20061            }
20062            multi_buffer::Event::ExcerptsRemoved {
20063                ids,
20064                removed_buffer_ids,
20065            } => {
20066                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20067                let buffer = self.buffer.read(cx);
20068                self.registered_buffers
20069                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20070                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20071                cx.emit(EditorEvent::ExcerptsRemoved {
20072                    ids: ids.clone(),
20073                    removed_buffer_ids: removed_buffer_ids.clone(),
20074                });
20075            }
20076            multi_buffer::Event::ExcerptsEdited {
20077                excerpt_ids,
20078                buffer_ids,
20079            } => {
20080                self.display_map.update(cx, |map, cx| {
20081                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20082                });
20083                cx.emit(EditorEvent::ExcerptsEdited {
20084                    ids: excerpt_ids.clone(),
20085                });
20086            }
20087            multi_buffer::Event::ExcerptsExpanded { ids } => {
20088                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20089                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20090            }
20091            multi_buffer::Event::Reparsed(buffer_id) => {
20092                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20093                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20094
20095                cx.emit(EditorEvent::Reparsed(*buffer_id));
20096            }
20097            multi_buffer::Event::DiffHunksToggled => {
20098                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20099            }
20100            multi_buffer::Event::LanguageChanged(buffer_id) => {
20101                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20102                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20103                cx.emit(EditorEvent::Reparsed(*buffer_id));
20104                cx.notify();
20105            }
20106            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20107            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20108            multi_buffer::Event::FileHandleChanged
20109            | multi_buffer::Event::Reloaded
20110            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20111            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20112            multi_buffer::Event::DiagnosticsUpdated => {
20113                self.update_diagnostics_state(window, cx);
20114            }
20115            _ => {}
20116        };
20117    }
20118
20119    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20120        if !self.diagnostics_enabled() {
20121            return;
20122        }
20123        self.refresh_active_diagnostics(cx);
20124        self.refresh_inline_diagnostics(true, window, cx);
20125        self.scrollbar_marker_state.dirty = true;
20126        cx.notify();
20127    }
20128
20129    pub fn start_temporary_diff_override(&mut self) {
20130        self.load_diff_task.take();
20131        self.temporary_diff_override = true;
20132    }
20133
20134    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20135        self.temporary_diff_override = false;
20136        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20137        self.buffer.update(cx, |buffer, cx| {
20138            buffer.set_all_diff_hunks_collapsed(cx);
20139        });
20140
20141        if let Some(project) = self.project.clone() {
20142            self.load_diff_task = Some(
20143                update_uncommitted_diff_for_buffer(
20144                    cx.entity(),
20145                    &project,
20146                    self.buffer.read(cx).all_buffers(),
20147                    self.buffer.clone(),
20148                    cx,
20149                )
20150                .shared(),
20151            );
20152        }
20153    }
20154
20155    fn on_display_map_changed(
20156        &mut self,
20157        _: Entity<DisplayMap>,
20158        _: &mut Window,
20159        cx: &mut Context<Self>,
20160    ) {
20161        cx.notify();
20162    }
20163
20164    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20165        if self.diagnostics_enabled() {
20166            let new_severity = EditorSettings::get_global(cx)
20167                .diagnostics_max_severity
20168                .unwrap_or(DiagnosticSeverity::Hint);
20169            self.set_max_diagnostics_severity(new_severity, cx);
20170        }
20171        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20172        self.update_edit_prediction_settings(cx);
20173        self.refresh_edit_prediction(true, false, window, cx);
20174        self.refresh_inline_values(cx);
20175        self.refresh_inlay_hints(
20176            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20177                self.selections.newest_anchor().head(),
20178                &self.buffer.read(cx).snapshot(cx),
20179                cx,
20180            )),
20181            cx,
20182        );
20183
20184        let old_cursor_shape = self.cursor_shape;
20185
20186        {
20187            let editor_settings = EditorSettings::get_global(cx);
20188            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20189            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20190            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20191            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20192        }
20193
20194        if old_cursor_shape != self.cursor_shape {
20195            cx.emit(EditorEvent::CursorShapeChanged);
20196        }
20197
20198        let project_settings = ProjectSettings::get_global(cx);
20199        self.serialize_dirty_buffers =
20200            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20201
20202        if self.mode.is_full() {
20203            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20204            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20205            if self.show_inline_diagnostics != show_inline_diagnostics {
20206                self.show_inline_diagnostics = show_inline_diagnostics;
20207                self.refresh_inline_diagnostics(false, window, cx);
20208            }
20209
20210            if self.git_blame_inline_enabled != inline_blame_enabled {
20211                self.toggle_git_blame_inline_internal(false, window, cx);
20212            }
20213
20214            let minimap_settings = EditorSettings::get_global(cx).minimap;
20215            if self.minimap_visibility != MinimapVisibility::Disabled {
20216                if self.minimap_visibility.settings_visibility()
20217                    != minimap_settings.minimap_enabled()
20218                {
20219                    self.set_minimap_visibility(
20220                        MinimapVisibility::for_mode(self.mode(), cx),
20221                        window,
20222                        cx,
20223                    );
20224                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20225                    minimap_entity.update(cx, |minimap_editor, cx| {
20226                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20227                    })
20228                }
20229            }
20230        }
20231
20232        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20233            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20234        }) {
20235            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20236                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20237            }
20238            self.refresh_colors(false, None, window, cx);
20239        }
20240
20241        cx.notify();
20242    }
20243
20244    pub fn set_searchable(&mut self, searchable: bool) {
20245        self.searchable = searchable;
20246    }
20247
20248    pub fn searchable(&self) -> bool {
20249        self.searchable
20250    }
20251
20252    fn open_proposed_changes_editor(
20253        &mut self,
20254        _: &OpenProposedChangesEditor,
20255        window: &mut Window,
20256        cx: &mut Context<Self>,
20257    ) {
20258        let Some(workspace) = self.workspace() else {
20259            cx.propagate();
20260            return;
20261        };
20262
20263        let selections = self.selections.all::<usize>(cx);
20264        let multi_buffer = self.buffer.read(cx);
20265        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20266        let mut new_selections_by_buffer = HashMap::default();
20267        for selection in selections {
20268            for (buffer, range, _) in
20269                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20270            {
20271                let mut range = range.to_point(buffer);
20272                range.start.column = 0;
20273                range.end.column = buffer.line_len(range.end.row);
20274                new_selections_by_buffer
20275                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20276                    .or_insert(Vec::new())
20277                    .push(range)
20278            }
20279        }
20280
20281        let proposed_changes_buffers = new_selections_by_buffer
20282            .into_iter()
20283            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20284            .collect::<Vec<_>>();
20285        let proposed_changes_editor = cx.new(|cx| {
20286            ProposedChangesEditor::new(
20287                "Proposed changes",
20288                proposed_changes_buffers,
20289                self.project.clone(),
20290                window,
20291                cx,
20292            )
20293        });
20294
20295        window.defer(cx, move |window, cx| {
20296            workspace.update(cx, |workspace, cx| {
20297                workspace.active_pane().update(cx, |pane, cx| {
20298                    pane.add_item(
20299                        Box::new(proposed_changes_editor),
20300                        true,
20301                        true,
20302                        None,
20303                        window,
20304                        cx,
20305                    );
20306                });
20307            });
20308        });
20309    }
20310
20311    pub fn open_excerpts_in_split(
20312        &mut self,
20313        _: &OpenExcerptsSplit,
20314        window: &mut Window,
20315        cx: &mut Context<Self>,
20316    ) {
20317        self.open_excerpts_common(None, true, window, cx)
20318    }
20319
20320    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20321        self.open_excerpts_common(None, false, window, cx)
20322    }
20323
20324    fn open_excerpts_common(
20325        &mut self,
20326        jump_data: Option<JumpData>,
20327        split: bool,
20328        window: &mut Window,
20329        cx: &mut Context<Self>,
20330    ) {
20331        let Some(workspace) = self.workspace() else {
20332            cx.propagate();
20333            return;
20334        };
20335
20336        if self.buffer.read(cx).is_singleton() {
20337            cx.propagate();
20338            return;
20339        }
20340
20341        let mut new_selections_by_buffer = HashMap::default();
20342        match &jump_data {
20343            Some(JumpData::MultiBufferPoint {
20344                excerpt_id,
20345                position,
20346                anchor,
20347                line_offset_from_top,
20348            }) => {
20349                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20350                if let Some(buffer) = multi_buffer_snapshot
20351                    .buffer_id_for_excerpt(*excerpt_id)
20352                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20353                {
20354                    let buffer_snapshot = buffer.read(cx).snapshot();
20355                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20356                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20357                    } else {
20358                        buffer_snapshot.clip_point(*position, Bias::Left)
20359                    };
20360                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20361                    new_selections_by_buffer.insert(
20362                        buffer,
20363                        (
20364                            vec![jump_to_offset..jump_to_offset],
20365                            Some(*line_offset_from_top),
20366                        ),
20367                    );
20368                }
20369            }
20370            Some(JumpData::MultiBufferRow {
20371                row,
20372                line_offset_from_top,
20373            }) => {
20374                let point = MultiBufferPoint::new(row.0, 0);
20375                if let Some((buffer, buffer_point, _)) =
20376                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20377                {
20378                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20379                    new_selections_by_buffer
20380                        .entry(buffer)
20381                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20382                        .0
20383                        .push(buffer_offset..buffer_offset)
20384                }
20385            }
20386            None => {
20387                let selections = self.selections.all::<usize>(cx);
20388                let multi_buffer = self.buffer.read(cx);
20389                for selection in selections {
20390                    for (snapshot, range, _, anchor) in multi_buffer
20391                        .snapshot(cx)
20392                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20393                    {
20394                        if let Some(anchor) = anchor {
20395                            // selection is in a deleted hunk
20396                            let Some(buffer_id) = anchor.buffer_id else {
20397                                continue;
20398                            };
20399                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20400                                continue;
20401                            };
20402                            let offset = text::ToOffset::to_offset(
20403                                &anchor.text_anchor,
20404                                &buffer_handle.read(cx).snapshot(),
20405                            );
20406                            let range = offset..offset;
20407                            new_selections_by_buffer
20408                                .entry(buffer_handle)
20409                                .or_insert((Vec::new(), None))
20410                                .0
20411                                .push(range)
20412                        } else {
20413                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20414                            else {
20415                                continue;
20416                            };
20417                            new_selections_by_buffer
20418                                .entry(buffer_handle)
20419                                .or_insert((Vec::new(), None))
20420                                .0
20421                                .push(range)
20422                        }
20423                    }
20424                }
20425            }
20426        }
20427
20428        new_selections_by_buffer
20429            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20430
20431        if new_selections_by_buffer.is_empty() {
20432            return;
20433        }
20434
20435        // We defer the pane interaction because we ourselves are a workspace item
20436        // and activating a new item causes the pane to call a method on us reentrantly,
20437        // which panics if we're on the stack.
20438        window.defer(cx, move |window, cx| {
20439            workspace.update(cx, |workspace, cx| {
20440                let pane = if split {
20441                    workspace.adjacent_pane(window, cx)
20442                } else {
20443                    workspace.active_pane().clone()
20444                };
20445
20446                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20447                    let editor = buffer
20448                        .read(cx)
20449                        .file()
20450                        .is_none()
20451                        .then(|| {
20452                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20453                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20454                            // Instead, we try to activate the existing editor in the pane first.
20455                            let (editor, pane_item_index) =
20456                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20457                                    let editor = item.downcast::<Editor>()?;
20458                                    let singleton_buffer =
20459                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20460                                    if singleton_buffer == buffer {
20461                                        Some((editor, i))
20462                                    } else {
20463                                        None
20464                                    }
20465                                })?;
20466                            pane.update(cx, |pane, cx| {
20467                                pane.activate_item(pane_item_index, true, true, window, cx)
20468                            });
20469                            Some(editor)
20470                        })
20471                        .flatten()
20472                        .unwrap_or_else(|| {
20473                            workspace.open_project_item::<Self>(
20474                                pane.clone(),
20475                                buffer,
20476                                true,
20477                                true,
20478                                window,
20479                                cx,
20480                            )
20481                        });
20482
20483                    editor.update(cx, |editor, cx| {
20484                        let autoscroll = match scroll_offset {
20485                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20486                            None => Autoscroll::newest(),
20487                        };
20488                        let nav_history = editor.nav_history.take();
20489                        editor.change_selections(
20490                            SelectionEffects::scroll(autoscroll),
20491                            window,
20492                            cx,
20493                            |s| {
20494                                s.select_ranges(ranges);
20495                            },
20496                        );
20497                        editor.nav_history = nav_history;
20498                    });
20499                }
20500            })
20501        });
20502    }
20503
20504    // For now, don't allow opening excerpts in buffers that aren't backed by
20505    // regular project files.
20506    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20507        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20508    }
20509
20510    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20511        let snapshot = self.buffer.read(cx).read(cx);
20512        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20513        Some(
20514            ranges
20515                .iter()
20516                .map(move |range| {
20517                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20518                })
20519                .collect(),
20520        )
20521    }
20522
20523    fn selection_replacement_ranges(
20524        &self,
20525        range: Range<OffsetUtf16>,
20526        cx: &mut App,
20527    ) -> Vec<Range<OffsetUtf16>> {
20528        let selections = self.selections.all::<OffsetUtf16>(cx);
20529        let newest_selection = selections
20530            .iter()
20531            .max_by_key(|selection| selection.id)
20532            .unwrap();
20533        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20534        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20535        let snapshot = self.buffer.read(cx).read(cx);
20536        selections
20537            .into_iter()
20538            .map(|mut selection| {
20539                selection.start.0 =
20540                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20541                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20542                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20543                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20544            })
20545            .collect()
20546    }
20547
20548    fn report_editor_event(
20549        &self,
20550        event_type: &'static str,
20551        file_extension: Option<String>,
20552        cx: &App,
20553    ) {
20554        if cfg!(any(test, feature = "test-support")) {
20555            return;
20556        }
20557
20558        let Some(project) = &self.project else { return };
20559
20560        // If None, we are in a file without an extension
20561        let file = self
20562            .buffer
20563            .read(cx)
20564            .as_singleton()
20565            .and_then(|b| b.read(cx).file());
20566        let file_extension = file_extension.or(file
20567            .as_ref()
20568            .and_then(|file| Path::new(file.file_name(cx)).extension())
20569            .and_then(|e| e.to_str())
20570            .map(|a| a.to_string()));
20571
20572        let vim_mode = vim_enabled(cx);
20573
20574        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20575        let copilot_enabled = edit_predictions_provider
20576            == language::language_settings::EditPredictionProvider::Copilot;
20577        let copilot_enabled_for_language = self
20578            .buffer
20579            .read(cx)
20580            .language_settings(cx)
20581            .show_edit_predictions;
20582
20583        let project = project.read(cx);
20584        telemetry::event!(
20585            event_type,
20586            file_extension,
20587            vim_mode,
20588            copilot_enabled,
20589            copilot_enabled_for_language,
20590            edit_predictions_provider,
20591            is_via_ssh = project.is_via_ssh(),
20592        );
20593    }
20594
20595    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20596    /// with each line being an array of {text, highlight} objects.
20597    fn copy_highlight_json(
20598        &mut self,
20599        _: &CopyHighlightJson,
20600        window: &mut Window,
20601        cx: &mut Context<Self>,
20602    ) {
20603        #[derive(Serialize)]
20604        struct Chunk<'a> {
20605            text: String,
20606            highlight: Option<&'a str>,
20607        }
20608
20609        let snapshot = self.buffer.read(cx).snapshot(cx);
20610        let range = self
20611            .selected_text_range(false, window, cx)
20612            .and_then(|selection| {
20613                if selection.range.is_empty() {
20614                    None
20615                } else {
20616                    Some(selection.range)
20617                }
20618            })
20619            .unwrap_or_else(|| 0..snapshot.len());
20620
20621        let chunks = snapshot.chunks(range, true);
20622        let mut lines = Vec::new();
20623        let mut line: VecDeque<Chunk> = VecDeque::new();
20624
20625        let Some(style) = self.style.as_ref() else {
20626            return;
20627        };
20628
20629        for chunk in chunks {
20630            let highlight = chunk
20631                .syntax_highlight_id
20632                .and_then(|id| id.name(&style.syntax));
20633            let mut chunk_lines = chunk.text.split('\n').peekable();
20634            while let Some(text) = chunk_lines.next() {
20635                let mut merged_with_last_token = false;
20636                if let Some(last_token) = line.back_mut() {
20637                    if last_token.highlight == highlight {
20638                        last_token.text.push_str(text);
20639                        merged_with_last_token = true;
20640                    }
20641                }
20642
20643                if !merged_with_last_token {
20644                    line.push_back(Chunk {
20645                        text: text.into(),
20646                        highlight,
20647                    });
20648                }
20649
20650                if chunk_lines.peek().is_some() {
20651                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20652                        line.pop_front();
20653                    }
20654                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20655                        line.pop_back();
20656                    }
20657
20658                    lines.push(mem::take(&mut line));
20659                }
20660            }
20661        }
20662
20663        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20664            return;
20665        };
20666        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20667    }
20668
20669    pub fn open_context_menu(
20670        &mut self,
20671        _: &OpenContextMenu,
20672        window: &mut Window,
20673        cx: &mut Context<Self>,
20674    ) {
20675        self.request_autoscroll(Autoscroll::newest(), cx);
20676        let position = self.selections.newest_display(cx).start;
20677        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20678    }
20679
20680    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20681        &self.inlay_hint_cache
20682    }
20683
20684    pub fn replay_insert_event(
20685        &mut self,
20686        text: &str,
20687        relative_utf16_range: Option<Range<isize>>,
20688        window: &mut Window,
20689        cx: &mut Context<Self>,
20690    ) {
20691        if !self.input_enabled {
20692            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20693            return;
20694        }
20695        if let Some(relative_utf16_range) = relative_utf16_range {
20696            let selections = self.selections.all::<OffsetUtf16>(cx);
20697            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20698                let new_ranges = selections.into_iter().map(|range| {
20699                    let start = OffsetUtf16(
20700                        range
20701                            .head()
20702                            .0
20703                            .saturating_add_signed(relative_utf16_range.start),
20704                    );
20705                    let end = OffsetUtf16(
20706                        range
20707                            .head()
20708                            .0
20709                            .saturating_add_signed(relative_utf16_range.end),
20710                    );
20711                    start..end
20712                });
20713                s.select_ranges(new_ranges);
20714            });
20715        }
20716
20717        self.handle_input(text, window, cx);
20718    }
20719
20720    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20721        let Some(provider) = self.semantics_provider.as_ref() else {
20722            return false;
20723        };
20724
20725        let mut supports = false;
20726        self.buffer().update(cx, |this, cx| {
20727            this.for_each_buffer(|buffer| {
20728                supports |= provider.supports_inlay_hints(buffer, cx);
20729            });
20730        });
20731
20732        supports
20733    }
20734
20735    pub fn is_focused(&self, window: &Window) -> bool {
20736        self.focus_handle.is_focused(window)
20737    }
20738
20739    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20740        cx.emit(EditorEvent::Focused);
20741
20742        if let Some(descendant) = self
20743            .last_focused_descendant
20744            .take()
20745            .and_then(|descendant| descendant.upgrade())
20746        {
20747            window.focus(&descendant);
20748        } else {
20749            if let Some(blame) = self.blame.as_ref() {
20750                blame.update(cx, GitBlame::focus)
20751            }
20752
20753            self.blink_manager.update(cx, BlinkManager::enable);
20754            self.show_cursor_names(window, cx);
20755            self.buffer.update(cx, |buffer, cx| {
20756                buffer.finalize_last_transaction(cx);
20757                if self.leader_id.is_none() {
20758                    buffer.set_active_selections(
20759                        &self.selections.disjoint_anchors(),
20760                        self.selections.line_mode,
20761                        self.cursor_shape,
20762                        cx,
20763                    );
20764                }
20765            });
20766        }
20767    }
20768
20769    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20770        cx.emit(EditorEvent::FocusedIn)
20771    }
20772
20773    fn handle_focus_out(
20774        &mut self,
20775        event: FocusOutEvent,
20776        _window: &mut Window,
20777        cx: &mut Context<Self>,
20778    ) {
20779        if event.blurred != self.focus_handle {
20780            self.last_focused_descendant = Some(event.blurred);
20781        }
20782        self.selection_drag_state = SelectionDragState::None;
20783        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20784    }
20785
20786    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20787        self.blink_manager.update(cx, BlinkManager::disable);
20788        self.buffer
20789            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20790
20791        if let Some(blame) = self.blame.as_ref() {
20792            blame.update(cx, GitBlame::blur)
20793        }
20794        if !self.hover_state.focused(window, cx) {
20795            hide_hover(self, cx);
20796        }
20797        if !self
20798            .context_menu
20799            .borrow()
20800            .as_ref()
20801            .is_some_and(|context_menu| context_menu.focused(window, cx))
20802        {
20803            self.hide_context_menu(window, cx);
20804        }
20805        self.discard_edit_prediction(false, cx);
20806        cx.emit(EditorEvent::Blurred);
20807        cx.notify();
20808    }
20809
20810    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20811        let mut pending: String = window
20812            .pending_input_keystrokes()
20813            .into_iter()
20814            .flatten()
20815            .filter_map(|keystroke| {
20816                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20817                    keystroke.key_char.clone()
20818                } else {
20819                    None
20820                }
20821            })
20822            .collect();
20823
20824        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20825            pending = "".to_string();
20826        }
20827
20828        let existing_pending = self
20829            .text_highlights::<PendingInput>(cx)
20830            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20831        if existing_pending.is_none() && pending.is_empty() {
20832            return;
20833        }
20834        let transaction =
20835            self.transact(window, cx, |this, window, cx| {
20836                let selections = this.selections.all::<usize>(cx);
20837                let edits = selections
20838                    .iter()
20839                    .map(|selection| (selection.end..selection.end, pending.clone()));
20840                this.edit(edits, cx);
20841                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20842                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20843                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20844                    }));
20845                });
20846                if let Some(existing_ranges) = existing_pending {
20847                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20848                    this.edit(edits, cx);
20849                }
20850            });
20851
20852        let snapshot = self.snapshot(window, cx);
20853        let ranges = self
20854            .selections
20855            .all::<usize>(cx)
20856            .into_iter()
20857            .map(|selection| {
20858                snapshot.buffer_snapshot.anchor_after(selection.end)
20859                    ..snapshot
20860                        .buffer_snapshot
20861                        .anchor_before(selection.end + pending.len())
20862            })
20863            .collect();
20864
20865        if pending.is_empty() {
20866            self.clear_highlights::<PendingInput>(cx);
20867        } else {
20868            self.highlight_text::<PendingInput>(
20869                ranges,
20870                HighlightStyle {
20871                    underline: Some(UnderlineStyle {
20872                        thickness: px(1.),
20873                        color: None,
20874                        wavy: false,
20875                    }),
20876                    ..Default::default()
20877                },
20878                cx,
20879            );
20880        }
20881
20882        self.ime_transaction = self.ime_transaction.or(transaction);
20883        if let Some(transaction) = self.ime_transaction {
20884            self.buffer.update(cx, |buffer, cx| {
20885                buffer.group_until_transaction(transaction, cx);
20886            });
20887        }
20888
20889        if self.text_highlights::<PendingInput>(cx).is_none() {
20890            self.ime_transaction.take();
20891        }
20892    }
20893
20894    pub fn register_action_renderer(
20895        &mut self,
20896        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20897    ) -> Subscription {
20898        let id = self.next_editor_action_id.post_inc();
20899        self.editor_actions
20900            .borrow_mut()
20901            .insert(id, Box::new(listener));
20902
20903        let editor_actions = self.editor_actions.clone();
20904        Subscription::new(move || {
20905            editor_actions.borrow_mut().remove(&id);
20906        })
20907    }
20908
20909    pub fn register_action<A: Action>(
20910        &mut self,
20911        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20912    ) -> Subscription {
20913        let id = self.next_editor_action_id.post_inc();
20914        let listener = Arc::new(listener);
20915        self.editor_actions.borrow_mut().insert(
20916            id,
20917            Box::new(move |_, window, _| {
20918                let listener = listener.clone();
20919                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20920                    let action = action.downcast_ref().unwrap();
20921                    if phase == DispatchPhase::Bubble {
20922                        listener(action, window, cx)
20923                    }
20924                })
20925            }),
20926        );
20927
20928        let editor_actions = self.editor_actions.clone();
20929        Subscription::new(move || {
20930            editor_actions.borrow_mut().remove(&id);
20931        })
20932    }
20933
20934    pub fn file_header_size(&self) -> u32 {
20935        FILE_HEADER_HEIGHT
20936    }
20937
20938    pub fn restore(
20939        &mut self,
20940        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20941        window: &mut Window,
20942        cx: &mut Context<Self>,
20943    ) {
20944        let workspace = self.workspace();
20945        let project = self.project.as_ref();
20946        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20947            let mut tasks = Vec::new();
20948            for (buffer_id, changes) in revert_changes {
20949                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20950                    buffer.update(cx, |buffer, cx| {
20951                        buffer.edit(
20952                            changes
20953                                .into_iter()
20954                                .map(|(range, text)| (range, text.to_string())),
20955                            None,
20956                            cx,
20957                        );
20958                    });
20959
20960                    if let Some(project) =
20961                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20962                    {
20963                        project.update(cx, |project, cx| {
20964                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20965                        })
20966                    }
20967                }
20968            }
20969            tasks
20970        });
20971        cx.spawn_in(window, async move |_, cx| {
20972            for (buffer, task) in save_tasks {
20973                let result = task.await;
20974                if result.is_err() {
20975                    let Some(path) = buffer
20976                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20977                        .ok()
20978                    else {
20979                        continue;
20980                    };
20981                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20982                        let Some(task) = cx
20983                            .update_window_entity(&workspace, |workspace, window, cx| {
20984                                workspace
20985                                    .open_path_preview(path, None, false, false, false, window, cx)
20986                            })
20987                            .ok()
20988                        else {
20989                            continue;
20990                        };
20991                        task.await.log_err();
20992                    }
20993                }
20994            }
20995        })
20996        .detach();
20997        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20998            selections.refresh()
20999        });
21000    }
21001
21002    pub fn to_pixel_point(
21003        &self,
21004        source: multi_buffer::Anchor,
21005        editor_snapshot: &EditorSnapshot,
21006        window: &mut Window,
21007    ) -> Option<gpui::Point<Pixels>> {
21008        let source_point = source.to_display_point(editor_snapshot);
21009        self.display_to_pixel_point(source_point, editor_snapshot, window)
21010    }
21011
21012    pub fn display_to_pixel_point(
21013        &self,
21014        source: DisplayPoint,
21015        editor_snapshot: &EditorSnapshot,
21016        window: &mut Window,
21017    ) -> Option<gpui::Point<Pixels>> {
21018        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21019        let text_layout_details = self.text_layout_details(window);
21020        let scroll_top = text_layout_details
21021            .scroll_anchor
21022            .scroll_position(editor_snapshot)
21023            .y;
21024
21025        if source.row().as_f32() < scroll_top.floor() {
21026            return None;
21027        }
21028        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21029        let source_y = line_height * (source.row().as_f32() - scroll_top);
21030        Some(gpui::Point::new(source_x, source_y))
21031    }
21032
21033    pub fn has_visible_completions_menu(&self) -> bool {
21034        !self.edit_prediction_preview_is_active()
21035            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
21036                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21037            })
21038    }
21039
21040    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21041        if self.mode.is_minimap() {
21042            return;
21043        }
21044        self.addons
21045            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21046    }
21047
21048    pub fn unregister_addon<T: Addon>(&mut self) {
21049        self.addons.remove(&std::any::TypeId::of::<T>());
21050    }
21051
21052    pub fn addon<T: Addon>(&self) -> Option<&T> {
21053        let type_id = std::any::TypeId::of::<T>();
21054        self.addons
21055            .get(&type_id)
21056            .and_then(|item| item.to_any().downcast_ref::<T>())
21057    }
21058
21059    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21060        let type_id = std::any::TypeId::of::<T>();
21061        self.addons
21062            .get_mut(&type_id)
21063            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21064    }
21065
21066    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21067        let text_layout_details = self.text_layout_details(window);
21068        let style = &text_layout_details.editor_style;
21069        let font_id = window.text_system().resolve_font(&style.text.font());
21070        let font_size = style.text.font_size.to_pixels(window.rem_size());
21071        let line_height = style.text.line_height_in_pixels(window.rem_size());
21072        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21073        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21074
21075        CharacterDimensions {
21076            em_width,
21077            em_advance,
21078            line_height,
21079        }
21080    }
21081
21082    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21083        self.load_diff_task.clone()
21084    }
21085
21086    fn read_metadata_from_db(
21087        &mut self,
21088        item_id: u64,
21089        workspace_id: WorkspaceId,
21090        window: &mut Window,
21091        cx: &mut Context<Editor>,
21092    ) {
21093        if self.is_singleton(cx)
21094            && !self.mode.is_minimap()
21095            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21096        {
21097            let buffer_snapshot = OnceCell::new();
21098
21099            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21100                if !folds.is_empty() {
21101                    let snapshot =
21102                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21103                    self.fold_ranges(
21104                        folds
21105                            .into_iter()
21106                            .map(|(start, end)| {
21107                                snapshot.clip_offset(start, Bias::Left)
21108                                    ..snapshot.clip_offset(end, Bias::Right)
21109                            })
21110                            .collect(),
21111                        false,
21112                        window,
21113                        cx,
21114                    );
21115                }
21116            }
21117
21118            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21119                if !selections.is_empty() {
21120                    let snapshot =
21121                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21122                    // skip adding the initial selection to selection history
21123                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21124                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21125                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21126                            snapshot.clip_offset(start, Bias::Left)
21127                                ..snapshot.clip_offset(end, Bias::Right)
21128                        }));
21129                    });
21130                    self.selection_history.mode = SelectionHistoryMode::Normal;
21131                }
21132            };
21133        }
21134
21135        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21136    }
21137
21138    fn update_lsp_data(
21139        &mut self,
21140        ignore_cache: bool,
21141        for_buffer: Option<BufferId>,
21142        window: &mut Window,
21143        cx: &mut Context<'_, Self>,
21144    ) {
21145        self.pull_diagnostics(for_buffer, window, cx);
21146        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21147    }
21148}
21149
21150fn vim_enabled(cx: &App) -> bool {
21151    cx.global::<SettingsStore>()
21152        .raw_user_settings()
21153        .get("vim_mode")
21154        == Some(&serde_json::Value::Bool(true))
21155}
21156
21157fn process_completion_for_edit(
21158    completion: &Completion,
21159    intent: CompletionIntent,
21160    buffer: &Entity<Buffer>,
21161    cursor_position: &text::Anchor,
21162    cx: &mut Context<Editor>,
21163) -> CompletionEdit {
21164    let buffer = buffer.read(cx);
21165    let buffer_snapshot = buffer.snapshot();
21166    let (snippet, new_text) = if completion.is_snippet() {
21167        // Workaround for typescript language server issues so that methods don't expand within
21168        // strings and functions with type expressions. The previous point is used because the query
21169        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21170        let mut snippet_source = completion.new_text.clone();
21171        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21172        previous_point.column = previous_point.column.saturating_sub(1);
21173        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21174            if scope.prefers_label_for_snippet_in_completion() {
21175                if let Some(label) = completion.label() {
21176                    if matches!(
21177                        completion.kind(),
21178                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21179                    ) {
21180                        snippet_source = label;
21181                    }
21182                }
21183            }
21184        }
21185        match Snippet::parse(&snippet_source).log_err() {
21186            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21187            None => (None, completion.new_text.clone()),
21188        }
21189    } else {
21190        (None, completion.new_text.clone())
21191    };
21192
21193    let mut range_to_replace = {
21194        let replace_range = &completion.replace_range;
21195        if let CompletionSource::Lsp {
21196            insert_range: Some(insert_range),
21197            ..
21198        } = &completion.source
21199        {
21200            debug_assert_eq!(
21201                insert_range.start, replace_range.start,
21202                "insert_range and replace_range should start at the same position"
21203            );
21204            debug_assert!(
21205                insert_range
21206                    .start
21207                    .cmp(&cursor_position, &buffer_snapshot)
21208                    .is_le(),
21209                "insert_range should start before or at cursor position"
21210            );
21211            debug_assert!(
21212                replace_range
21213                    .start
21214                    .cmp(&cursor_position, &buffer_snapshot)
21215                    .is_le(),
21216                "replace_range should start before or at cursor position"
21217            );
21218
21219            let should_replace = match intent {
21220                CompletionIntent::CompleteWithInsert => false,
21221                CompletionIntent::CompleteWithReplace => true,
21222                CompletionIntent::Complete | CompletionIntent::Compose => {
21223                    let insert_mode =
21224                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21225                            .completions
21226                            .lsp_insert_mode;
21227                    match insert_mode {
21228                        LspInsertMode::Insert => false,
21229                        LspInsertMode::Replace => true,
21230                        LspInsertMode::ReplaceSubsequence => {
21231                            let mut text_to_replace = buffer.chars_for_range(
21232                                buffer.anchor_before(replace_range.start)
21233                                    ..buffer.anchor_after(replace_range.end),
21234                            );
21235                            let mut current_needle = text_to_replace.next();
21236                            for haystack_ch in completion.label.text.chars() {
21237                                if let Some(needle_ch) = current_needle {
21238                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21239                                        current_needle = text_to_replace.next();
21240                                    }
21241                                }
21242                            }
21243                            current_needle.is_none()
21244                        }
21245                        LspInsertMode::ReplaceSuffix => {
21246                            if replace_range
21247                                .end
21248                                .cmp(&cursor_position, &buffer_snapshot)
21249                                .is_gt()
21250                            {
21251                                let range_after_cursor = *cursor_position..replace_range.end;
21252                                let text_after_cursor = buffer
21253                                    .text_for_range(
21254                                        buffer.anchor_before(range_after_cursor.start)
21255                                            ..buffer.anchor_after(range_after_cursor.end),
21256                                    )
21257                                    .collect::<String>()
21258                                    .to_ascii_lowercase();
21259                                completion
21260                                    .label
21261                                    .text
21262                                    .to_ascii_lowercase()
21263                                    .ends_with(&text_after_cursor)
21264                            } else {
21265                                true
21266                            }
21267                        }
21268                    }
21269                }
21270            };
21271
21272            if should_replace {
21273                replace_range.clone()
21274            } else {
21275                insert_range.clone()
21276            }
21277        } else {
21278            replace_range.clone()
21279        }
21280    };
21281
21282    if range_to_replace
21283        .end
21284        .cmp(&cursor_position, &buffer_snapshot)
21285        .is_lt()
21286    {
21287        range_to_replace.end = *cursor_position;
21288    }
21289
21290    CompletionEdit {
21291        new_text,
21292        replace_range: range_to_replace.to_offset(&buffer),
21293        snippet,
21294    }
21295}
21296
21297struct CompletionEdit {
21298    new_text: String,
21299    replace_range: Range<usize>,
21300    snippet: Option<Snippet>,
21301}
21302
21303fn insert_extra_newline_brackets(
21304    buffer: &MultiBufferSnapshot,
21305    range: Range<usize>,
21306    language: &language::LanguageScope,
21307) -> bool {
21308    let leading_whitespace_len = buffer
21309        .reversed_chars_at(range.start)
21310        .take_while(|c| c.is_whitespace() && *c != '\n')
21311        .map(|c| c.len_utf8())
21312        .sum::<usize>();
21313    let trailing_whitespace_len = buffer
21314        .chars_at(range.end)
21315        .take_while(|c| c.is_whitespace() && *c != '\n')
21316        .map(|c| c.len_utf8())
21317        .sum::<usize>();
21318    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21319
21320    language.brackets().any(|(pair, enabled)| {
21321        let pair_start = pair.start.trim_end();
21322        let pair_end = pair.end.trim_start();
21323
21324        enabled
21325            && pair.newline
21326            && buffer.contains_str_at(range.end, pair_end)
21327            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21328    })
21329}
21330
21331fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21332    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21333        [(buffer, range, _)] => (*buffer, range.clone()),
21334        _ => return false,
21335    };
21336    let pair = {
21337        let mut result: Option<BracketMatch> = None;
21338
21339        for pair in buffer
21340            .all_bracket_ranges(range.clone())
21341            .filter(move |pair| {
21342                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21343            })
21344        {
21345            let len = pair.close_range.end - pair.open_range.start;
21346
21347            if let Some(existing) = &result {
21348                let existing_len = existing.close_range.end - existing.open_range.start;
21349                if len > existing_len {
21350                    continue;
21351                }
21352            }
21353
21354            result = Some(pair);
21355        }
21356
21357        result
21358    };
21359    let Some(pair) = pair else {
21360        return false;
21361    };
21362    pair.newline_only
21363        && buffer
21364            .chars_for_range(pair.open_range.end..range.start)
21365            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21366            .all(|c| c.is_whitespace() && c != '\n')
21367}
21368
21369fn update_uncommitted_diff_for_buffer(
21370    editor: Entity<Editor>,
21371    project: &Entity<Project>,
21372    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21373    buffer: Entity<MultiBuffer>,
21374    cx: &mut App,
21375) -> Task<()> {
21376    let mut tasks = Vec::new();
21377    project.update(cx, |project, cx| {
21378        for buffer in buffers {
21379            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21380                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21381            }
21382        }
21383    });
21384    cx.spawn(async move |cx| {
21385        let diffs = future::join_all(tasks).await;
21386        if editor
21387            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21388            .unwrap_or(false)
21389        {
21390            return;
21391        }
21392
21393        buffer
21394            .update(cx, |buffer, cx| {
21395                for diff in diffs.into_iter().flatten() {
21396                    buffer.add_diff(diff, cx);
21397                }
21398            })
21399            .ok();
21400    })
21401}
21402
21403fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21404    let tab_size = tab_size.get() as usize;
21405    let mut width = offset;
21406
21407    for ch in text.chars() {
21408        width += if ch == '\t' {
21409            tab_size - (width % tab_size)
21410        } else {
21411            1
21412        };
21413    }
21414
21415    width - offset
21416}
21417
21418#[cfg(test)]
21419mod tests {
21420    use super::*;
21421
21422    #[test]
21423    fn test_string_size_with_expanded_tabs() {
21424        let nz = |val| NonZeroU32::new(val).unwrap();
21425        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21426        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21427        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21428        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21429        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21430        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21431        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21432        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21433    }
21434}
21435
21436/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21437struct WordBreakingTokenizer<'a> {
21438    input: &'a str,
21439}
21440
21441impl<'a> WordBreakingTokenizer<'a> {
21442    fn new(input: &'a str) -> Self {
21443        Self { input }
21444    }
21445}
21446
21447fn is_char_ideographic(ch: char) -> bool {
21448    use unicode_script::Script::*;
21449    use unicode_script::UnicodeScript;
21450    matches!(ch.script(), Han | Tangut | Yi)
21451}
21452
21453fn is_grapheme_ideographic(text: &str) -> bool {
21454    text.chars().any(is_char_ideographic)
21455}
21456
21457fn is_grapheme_whitespace(text: &str) -> bool {
21458    text.chars().any(|x| x.is_whitespace())
21459}
21460
21461fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21462    text.chars().next().map_or(false, |ch| {
21463        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21464    })
21465}
21466
21467#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21468enum WordBreakToken<'a> {
21469    Word { token: &'a str, grapheme_len: usize },
21470    InlineWhitespace { token: &'a str, grapheme_len: usize },
21471    Newline,
21472}
21473
21474impl<'a> Iterator for WordBreakingTokenizer<'a> {
21475    /// Yields a span, the count of graphemes in the token, and whether it was
21476    /// whitespace. Note that it also breaks at word boundaries.
21477    type Item = WordBreakToken<'a>;
21478
21479    fn next(&mut self) -> Option<Self::Item> {
21480        use unicode_segmentation::UnicodeSegmentation;
21481        if self.input.is_empty() {
21482            return None;
21483        }
21484
21485        let mut iter = self.input.graphemes(true).peekable();
21486        let mut offset = 0;
21487        let mut grapheme_len = 0;
21488        if let Some(first_grapheme) = iter.next() {
21489            let is_newline = first_grapheme == "\n";
21490            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21491            offset += first_grapheme.len();
21492            grapheme_len += 1;
21493            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21494                if let Some(grapheme) = iter.peek().copied() {
21495                    if should_stay_with_preceding_ideograph(grapheme) {
21496                        offset += grapheme.len();
21497                        grapheme_len += 1;
21498                    }
21499                }
21500            } else {
21501                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21502                let mut next_word_bound = words.peek().copied();
21503                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21504                    next_word_bound = words.next();
21505                }
21506                while let Some(grapheme) = iter.peek().copied() {
21507                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21508                        break;
21509                    };
21510                    if is_grapheme_whitespace(grapheme) != is_whitespace
21511                        || (grapheme == "\n") != is_newline
21512                    {
21513                        break;
21514                    };
21515                    offset += grapheme.len();
21516                    grapheme_len += 1;
21517                    iter.next();
21518                }
21519            }
21520            let token = &self.input[..offset];
21521            self.input = &self.input[offset..];
21522            if token == "\n" {
21523                Some(WordBreakToken::Newline)
21524            } else if is_whitespace {
21525                Some(WordBreakToken::InlineWhitespace {
21526                    token,
21527                    grapheme_len,
21528                })
21529            } else {
21530                Some(WordBreakToken::Word {
21531                    token,
21532                    grapheme_len,
21533                })
21534            }
21535        } else {
21536            None
21537        }
21538    }
21539}
21540
21541#[test]
21542fn test_word_breaking_tokenizer() {
21543    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21544        ("", &[]),
21545        ("  ", &[whitespace("  ", 2)]),
21546        ("Ʒ", &[word("Ʒ", 1)]),
21547        ("Ǽ", &[word("Ǽ", 1)]),
21548        ("", &[word("", 1)]),
21549        ("⋑⋑", &[word("⋑⋑", 2)]),
21550        (
21551            "原理,进而",
21552            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21553        ),
21554        (
21555            "hello world",
21556            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21557        ),
21558        (
21559            "hello, world",
21560            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21561        ),
21562        (
21563            "  hello world",
21564            &[
21565                whitespace("  ", 2),
21566                word("hello", 5),
21567                whitespace(" ", 1),
21568                word("world", 5),
21569            ],
21570        ),
21571        (
21572            "这是什么 \n 钢笔",
21573            &[
21574                word("", 1),
21575                word("", 1),
21576                word("", 1),
21577                word("", 1),
21578                whitespace(" ", 1),
21579                newline(),
21580                whitespace(" ", 1),
21581                word("", 1),
21582                word("", 1),
21583            ],
21584        ),
21585        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21586    ];
21587
21588    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21589        WordBreakToken::Word {
21590            token,
21591            grapheme_len,
21592        }
21593    }
21594
21595    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21596        WordBreakToken::InlineWhitespace {
21597            token,
21598            grapheme_len,
21599        }
21600    }
21601
21602    fn newline() -> WordBreakToken<'static> {
21603        WordBreakToken::Newline
21604    }
21605
21606    for (input, result) in tests {
21607        assert_eq!(
21608            WordBreakingTokenizer::new(input)
21609                .collect::<Vec<_>>()
21610                .as_slice(),
21611            *result,
21612        );
21613    }
21614}
21615
21616fn wrap_with_prefix(
21617    first_line_prefix: String,
21618    subsequent_lines_prefix: String,
21619    unwrapped_text: String,
21620    wrap_column: usize,
21621    tab_size: NonZeroU32,
21622    preserve_existing_whitespace: bool,
21623) -> String {
21624    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21625    let subsequent_lines_prefix_len =
21626        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21627    let mut wrapped_text = String::new();
21628    let mut current_line = first_line_prefix.clone();
21629    let mut is_first_line = true;
21630
21631    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21632    let mut current_line_len = first_line_prefix_len;
21633    let mut in_whitespace = false;
21634    for token in tokenizer {
21635        let have_preceding_whitespace = in_whitespace;
21636        match token {
21637            WordBreakToken::Word {
21638                token,
21639                grapheme_len,
21640            } => {
21641                in_whitespace = false;
21642                let current_prefix_len = if is_first_line {
21643                    first_line_prefix_len
21644                } else {
21645                    subsequent_lines_prefix_len
21646                };
21647                if current_line_len + grapheme_len > wrap_column
21648                    && current_line_len != current_prefix_len
21649                {
21650                    wrapped_text.push_str(current_line.trim_end());
21651                    wrapped_text.push('\n');
21652                    is_first_line = false;
21653                    current_line = subsequent_lines_prefix.clone();
21654                    current_line_len = subsequent_lines_prefix_len;
21655                }
21656                current_line.push_str(token);
21657                current_line_len += grapheme_len;
21658            }
21659            WordBreakToken::InlineWhitespace {
21660                mut token,
21661                mut grapheme_len,
21662            } => {
21663                in_whitespace = true;
21664                if have_preceding_whitespace && !preserve_existing_whitespace {
21665                    continue;
21666                }
21667                if !preserve_existing_whitespace {
21668                    token = " ";
21669                    grapheme_len = 1;
21670                }
21671                let current_prefix_len = if is_first_line {
21672                    first_line_prefix_len
21673                } else {
21674                    subsequent_lines_prefix_len
21675                };
21676                if current_line_len + grapheme_len > wrap_column {
21677                    wrapped_text.push_str(current_line.trim_end());
21678                    wrapped_text.push('\n');
21679                    is_first_line = false;
21680                    current_line = subsequent_lines_prefix.clone();
21681                    current_line_len = subsequent_lines_prefix_len;
21682                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21683                    current_line.push_str(token);
21684                    current_line_len += grapheme_len;
21685                }
21686            }
21687            WordBreakToken::Newline => {
21688                in_whitespace = true;
21689                let current_prefix_len = if is_first_line {
21690                    first_line_prefix_len
21691                } else {
21692                    subsequent_lines_prefix_len
21693                };
21694                if preserve_existing_whitespace {
21695                    wrapped_text.push_str(current_line.trim_end());
21696                    wrapped_text.push('\n');
21697                    is_first_line = false;
21698                    current_line = subsequent_lines_prefix.clone();
21699                    current_line_len = subsequent_lines_prefix_len;
21700                } else if have_preceding_whitespace {
21701                    continue;
21702                } else if current_line_len + 1 > wrap_column
21703                    && current_line_len != current_prefix_len
21704                {
21705                    wrapped_text.push_str(current_line.trim_end());
21706                    wrapped_text.push('\n');
21707                    is_first_line = false;
21708                    current_line = subsequent_lines_prefix.clone();
21709                    current_line_len = subsequent_lines_prefix_len;
21710                } else if current_line_len != current_prefix_len {
21711                    current_line.push(' ');
21712                    current_line_len += 1;
21713                }
21714            }
21715        }
21716    }
21717
21718    if !current_line.is_empty() {
21719        wrapped_text.push_str(&current_line);
21720    }
21721    wrapped_text
21722}
21723
21724#[test]
21725fn test_wrap_with_prefix() {
21726    assert_eq!(
21727        wrap_with_prefix(
21728            "# ".to_string(),
21729            "# ".to_string(),
21730            "abcdefg".to_string(),
21731            4,
21732            NonZeroU32::new(4).unwrap(),
21733            false,
21734        ),
21735        "# abcdefg"
21736    );
21737    assert_eq!(
21738        wrap_with_prefix(
21739            "".to_string(),
21740            "".to_string(),
21741            "\thello world".to_string(),
21742            8,
21743            NonZeroU32::new(4).unwrap(),
21744            false,
21745        ),
21746        "hello\nworld"
21747    );
21748    assert_eq!(
21749        wrap_with_prefix(
21750            "// ".to_string(),
21751            "// ".to_string(),
21752            "xx \nyy zz aa bb cc".to_string(),
21753            12,
21754            NonZeroU32::new(4).unwrap(),
21755            false,
21756        ),
21757        "// xx yy zz\n// aa bb cc"
21758    );
21759    assert_eq!(
21760        wrap_with_prefix(
21761            String::new(),
21762            String::new(),
21763            "这是什么 \n 钢笔".to_string(),
21764            3,
21765            NonZeroU32::new(4).unwrap(),
21766            false,
21767        ),
21768        "这是什\n么 钢\n"
21769    );
21770}
21771
21772pub trait CollaborationHub {
21773    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21774    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21775    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21776}
21777
21778impl CollaborationHub for Entity<Project> {
21779    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21780        self.read(cx).collaborators()
21781    }
21782
21783    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21784        self.read(cx).user_store().read(cx).participant_indices()
21785    }
21786
21787    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21788        let this = self.read(cx);
21789        let user_ids = this.collaborators().values().map(|c| c.user_id);
21790        this.user_store().read(cx).participant_names(user_ids, cx)
21791    }
21792}
21793
21794pub trait SemanticsProvider {
21795    fn hover(
21796        &self,
21797        buffer: &Entity<Buffer>,
21798        position: text::Anchor,
21799        cx: &mut App,
21800    ) -> Option<Task<Vec<project::Hover>>>;
21801
21802    fn inline_values(
21803        &self,
21804        buffer_handle: Entity<Buffer>,
21805        range: Range<text::Anchor>,
21806        cx: &mut App,
21807    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21808
21809    fn inlay_hints(
21810        &self,
21811        buffer_handle: Entity<Buffer>,
21812        range: Range<text::Anchor>,
21813        cx: &mut App,
21814    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21815
21816    fn resolve_inlay_hint(
21817        &self,
21818        hint: InlayHint,
21819        buffer_handle: Entity<Buffer>,
21820        server_id: LanguageServerId,
21821        cx: &mut App,
21822    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21823
21824    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21825
21826    fn document_highlights(
21827        &self,
21828        buffer: &Entity<Buffer>,
21829        position: text::Anchor,
21830        cx: &mut App,
21831    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21832
21833    fn definitions(
21834        &self,
21835        buffer: &Entity<Buffer>,
21836        position: text::Anchor,
21837        kind: GotoDefinitionKind,
21838        cx: &mut App,
21839    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21840
21841    fn range_for_rename(
21842        &self,
21843        buffer: &Entity<Buffer>,
21844        position: text::Anchor,
21845        cx: &mut App,
21846    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21847
21848    fn perform_rename(
21849        &self,
21850        buffer: &Entity<Buffer>,
21851        position: text::Anchor,
21852        new_name: String,
21853        cx: &mut App,
21854    ) -> Option<Task<Result<ProjectTransaction>>>;
21855}
21856
21857pub trait CompletionProvider {
21858    fn completions(
21859        &self,
21860        excerpt_id: ExcerptId,
21861        buffer: &Entity<Buffer>,
21862        buffer_position: text::Anchor,
21863        trigger: CompletionContext,
21864        window: &mut Window,
21865        cx: &mut Context<Editor>,
21866    ) -> Task<Result<Vec<CompletionResponse>>>;
21867
21868    fn resolve_completions(
21869        &self,
21870        _buffer: Entity<Buffer>,
21871        _completion_indices: Vec<usize>,
21872        _completions: Rc<RefCell<Box<[Completion]>>>,
21873        _cx: &mut Context<Editor>,
21874    ) -> Task<Result<bool>> {
21875        Task::ready(Ok(false))
21876    }
21877
21878    fn apply_additional_edits_for_completion(
21879        &self,
21880        _buffer: Entity<Buffer>,
21881        _completions: Rc<RefCell<Box<[Completion]>>>,
21882        _completion_index: usize,
21883        _push_to_history: bool,
21884        _cx: &mut Context<Editor>,
21885    ) -> Task<Result<Option<language::Transaction>>> {
21886        Task::ready(Ok(None))
21887    }
21888
21889    fn is_completion_trigger(
21890        &self,
21891        buffer: &Entity<Buffer>,
21892        position: language::Anchor,
21893        text: &str,
21894        trigger_in_words: bool,
21895        menu_is_open: bool,
21896        cx: &mut Context<Editor>,
21897    ) -> bool;
21898
21899    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21900
21901    fn sort_completions(&self) -> bool {
21902        true
21903    }
21904
21905    fn filter_completions(&self) -> bool {
21906        true
21907    }
21908}
21909
21910pub trait CodeActionProvider {
21911    fn id(&self) -> Arc<str>;
21912
21913    fn code_actions(
21914        &self,
21915        buffer: &Entity<Buffer>,
21916        range: Range<text::Anchor>,
21917        window: &mut Window,
21918        cx: &mut App,
21919    ) -> Task<Result<Vec<CodeAction>>>;
21920
21921    fn apply_code_action(
21922        &self,
21923        buffer_handle: Entity<Buffer>,
21924        action: CodeAction,
21925        excerpt_id: ExcerptId,
21926        push_to_history: bool,
21927        window: &mut Window,
21928        cx: &mut App,
21929    ) -> Task<Result<ProjectTransaction>>;
21930}
21931
21932impl CodeActionProvider for Entity<Project> {
21933    fn id(&self) -> Arc<str> {
21934        "project".into()
21935    }
21936
21937    fn code_actions(
21938        &self,
21939        buffer: &Entity<Buffer>,
21940        range: Range<text::Anchor>,
21941        _window: &mut Window,
21942        cx: &mut App,
21943    ) -> Task<Result<Vec<CodeAction>>> {
21944        self.update(cx, |project, cx| {
21945            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21946            let code_actions = project.code_actions(buffer, range, None, cx);
21947            cx.background_spawn(async move {
21948                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21949                Ok(code_lens_actions
21950                    .context("code lens fetch")?
21951                    .into_iter()
21952                    .chain(code_actions.context("code action fetch")?)
21953                    .collect())
21954            })
21955        })
21956    }
21957
21958    fn apply_code_action(
21959        &self,
21960        buffer_handle: Entity<Buffer>,
21961        action: CodeAction,
21962        _excerpt_id: ExcerptId,
21963        push_to_history: bool,
21964        _window: &mut Window,
21965        cx: &mut App,
21966    ) -> Task<Result<ProjectTransaction>> {
21967        self.update(cx, |project, cx| {
21968            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21969        })
21970    }
21971}
21972
21973fn snippet_completions(
21974    project: &Project,
21975    buffer: &Entity<Buffer>,
21976    buffer_position: text::Anchor,
21977    cx: &mut App,
21978) -> Task<Result<CompletionResponse>> {
21979    let languages = buffer.read(cx).languages_at(buffer_position);
21980    let snippet_store = project.snippets().read(cx);
21981
21982    let scopes: Vec<_> = languages
21983        .iter()
21984        .filter_map(|language| {
21985            let language_name = language.lsp_id();
21986            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21987
21988            if snippets.is_empty() {
21989                None
21990            } else {
21991                Some((language.default_scope(), snippets))
21992            }
21993        })
21994        .collect();
21995
21996    if scopes.is_empty() {
21997        return Task::ready(Ok(CompletionResponse {
21998            completions: vec![],
21999            is_incomplete: false,
22000        }));
22001    }
22002
22003    let snapshot = buffer.read(cx).text_snapshot();
22004    let chars: String = snapshot
22005        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22006        .collect();
22007    let executor = cx.background_executor().clone();
22008
22009    cx.background_spawn(async move {
22010        let mut is_incomplete = false;
22011        let mut completions: Vec<Completion> = Vec::new();
22012        for (scope, snippets) in scopes.into_iter() {
22013            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22014            let mut last_word = chars
22015                .chars()
22016                .take_while(|c| classifier.is_word(*c))
22017                .collect::<String>();
22018            last_word = last_word.chars().rev().collect();
22019
22020            if last_word.is_empty() {
22021                return Ok(CompletionResponse {
22022                    completions: vec![],
22023                    is_incomplete: true,
22024                });
22025            }
22026
22027            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22028            let to_lsp = |point: &text::Anchor| {
22029                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22030                point_to_lsp(end)
22031            };
22032            let lsp_end = to_lsp(&buffer_position);
22033
22034            let candidates = snippets
22035                .iter()
22036                .enumerate()
22037                .flat_map(|(ix, snippet)| {
22038                    snippet
22039                        .prefix
22040                        .iter()
22041                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
22042                })
22043                .collect::<Vec<StringMatchCandidate>>();
22044
22045            const MAX_RESULTS: usize = 100;
22046            let mut matches = fuzzy::match_strings(
22047                &candidates,
22048                &last_word,
22049                last_word.chars().any(|c| c.is_uppercase()),
22050                true,
22051                MAX_RESULTS,
22052                &Default::default(),
22053                executor.clone(),
22054            )
22055            .await;
22056
22057            if matches.len() >= MAX_RESULTS {
22058                is_incomplete = true;
22059            }
22060
22061            // Remove all candidates where the query's start does not match the start of any word in the candidate
22062            if let Some(query_start) = last_word.chars().next() {
22063                matches.retain(|string_match| {
22064                    split_words(&string_match.string).any(|word| {
22065                        // Check that the first codepoint of the word as lowercase matches the first
22066                        // codepoint of the query as lowercase
22067                        word.chars()
22068                            .flat_map(|codepoint| codepoint.to_lowercase())
22069                            .zip(query_start.to_lowercase())
22070                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22071                    })
22072                });
22073            }
22074
22075            let matched_strings = matches
22076                .into_iter()
22077                .map(|m| m.string)
22078                .collect::<HashSet<_>>();
22079
22080            completions.extend(snippets.iter().filter_map(|snippet| {
22081                let matching_prefix = snippet
22082                    .prefix
22083                    .iter()
22084                    .find(|prefix| matched_strings.contains(*prefix))?;
22085                let start = as_offset - last_word.len();
22086                let start = snapshot.anchor_before(start);
22087                let range = start..buffer_position;
22088                let lsp_start = to_lsp(&start);
22089                let lsp_range = lsp::Range {
22090                    start: lsp_start,
22091                    end: lsp_end,
22092                };
22093                Some(Completion {
22094                    replace_range: range,
22095                    new_text: snippet.body.clone(),
22096                    source: CompletionSource::Lsp {
22097                        insert_range: None,
22098                        server_id: LanguageServerId(usize::MAX),
22099                        resolved: true,
22100                        lsp_completion: Box::new(lsp::CompletionItem {
22101                            label: snippet.prefix.first().unwrap().clone(),
22102                            kind: Some(CompletionItemKind::SNIPPET),
22103                            label_details: snippet.description.as_ref().map(|description| {
22104                                lsp::CompletionItemLabelDetails {
22105                                    detail: Some(description.clone()),
22106                                    description: None,
22107                                }
22108                            }),
22109                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22110                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22111                                lsp::InsertReplaceEdit {
22112                                    new_text: snippet.body.clone(),
22113                                    insert: lsp_range,
22114                                    replace: lsp_range,
22115                                },
22116                            )),
22117                            filter_text: Some(snippet.body.clone()),
22118                            sort_text: Some(char::MAX.to_string()),
22119                            ..lsp::CompletionItem::default()
22120                        }),
22121                        lsp_defaults: None,
22122                    },
22123                    label: CodeLabel {
22124                        text: matching_prefix.clone(),
22125                        runs: Vec::new(),
22126                        filter_range: 0..matching_prefix.len(),
22127                    },
22128                    icon_path: None,
22129                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22130                        single_line: snippet.name.clone().into(),
22131                        plain_text: snippet
22132                            .description
22133                            .clone()
22134                            .map(|description| description.into()),
22135                    }),
22136                    insert_text_mode: None,
22137                    confirm: None,
22138                })
22139            }))
22140        }
22141
22142        Ok(CompletionResponse {
22143            completions,
22144            is_incomplete,
22145        })
22146    })
22147}
22148
22149impl CompletionProvider for Entity<Project> {
22150    fn completions(
22151        &self,
22152        _excerpt_id: ExcerptId,
22153        buffer: &Entity<Buffer>,
22154        buffer_position: text::Anchor,
22155        options: CompletionContext,
22156        _window: &mut Window,
22157        cx: &mut Context<Editor>,
22158    ) -> Task<Result<Vec<CompletionResponse>>> {
22159        self.update(cx, |project, cx| {
22160            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22161            let project_completions = project.completions(buffer, buffer_position, options, cx);
22162            cx.background_spawn(async move {
22163                let mut responses = project_completions.await?;
22164                let snippets = snippets.await?;
22165                if !snippets.completions.is_empty() {
22166                    responses.push(snippets);
22167                }
22168                Ok(responses)
22169            })
22170        })
22171    }
22172
22173    fn resolve_completions(
22174        &self,
22175        buffer: Entity<Buffer>,
22176        completion_indices: Vec<usize>,
22177        completions: Rc<RefCell<Box<[Completion]>>>,
22178        cx: &mut Context<Editor>,
22179    ) -> Task<Result<bool>> {
22180        self.update(cx, |project, cx| {
22181            project.lsp_store().update(cx, |lsp_store, cx| {
22182                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22183            })
22184        })
22185    }
22186
22187    fn apply_additional_edits_for_completion(
22188        &self,
22189        buffer: Entity<Buffer>,
22190        completions: Rc<RefCell<Box<[Completion]>>>,
22191        completion_index: usize,
22192        push_to_history: bool,
22193        cx: &mut Context<Editor>,
22194    ) -> Task<Result<Option<language::Transaction>>> {
22195        self.update(cx, |project, cx| {
22196            project.lsp_store().update(cx, |lsp_store, cx| {
22197                lsp_store.apply_additional_edits_for_completion(
22198                    buffer,
22199                    completions,
22200                    completion_index,
22201                    push_to_history,
22202                    cx,
22203                )
22204            })
22205        })
22206    }
22207
22208    fn is_completion_trigger(
22209        &self,
22210        buffer: &Entity<Buffer>,
22211        position: language::Anchor,
22212        text: &str,
22213        trigger_in_words: bool,
22214        menu_is_open: bool,
22215        cx: &mut Context<Editor>,
22216    ) -> bool {
22217        let mut chars = text.chars();
22218        let char = if let Some(char) = chars.next() {
22219            char
22220        } else {
22221            return false;
22222        };
22223        if chars.next().is_some() {
22224            return false;
22225        }
22226
22227        let buffer = buffer.read(cx);
22228        let snapshot = buffer.snapshot();
22229        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22230            return false;
22231        }
22232        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22233        if trigger_in_words && classifier.is_word(char) {
22234            return true;
22235        }
22236
22237        buffer.completion_triggers().contains(text)
22238    }
22239}
22240
22241impl SemanticsProvider for Entity<Project> {
22242    fn hover(
22243        &self,
22244        buffer: &Entity<Buffer>,
22245        position: text::Anchor,
22246        cx: &mut App,
22247    ) -> Option<Task<Vec<project::Hover>>> {
22248        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22249    }
22250
22251    fn document_highlights(
22252        &self,
22253        buffer: &Entity<Buffer>,
22254        position: text::Anchor,
22255        cx: &mut App,
22256    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22257        Some(self.update(cx, |project, cx| {
22258            project.document_highlights(buffer, position, cx)
22259        }))
22260    }
22261
22262    fn definitions(
22263        &self,
22264        buffer: &Entity<Buffer>,
22265        position: text::Anchor,
22266        kind: GotoDefinitionKind,
22267        cx: &mut App,
22268    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22269        Some(self.update(cx, |project, cx| match kind {
22270            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22271            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22272            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22273            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22274        }))
22275    }
22276
22277    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22278        self.update(cx, |project, cx| {
22279            if project
22280                .active_debug_session(cx)
22281                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22282            {
22283                return true;
22284            }
22285
22286            buffer.update(cx, |buffer, cx| {
22287                project.any_language_server_supports_inlay_hints(buffer, cx)
22288            })
22289        })
22290    }
22291
22292    fn inline_values(
22293        &self,
22294        buffer_handle: Entity<Buffer>,
22295        range: Range<text::Anchor>,
22296        cx: &mut App,
22297    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22298        self.update(cx, |project, cx| {
22299            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22300
22301            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22302        })
22303    }
22304
22305    fn inlay_hints(
22306        &self,
22307        buffer_handle: Entity<Buffer>,
22308        range: Range<text::Anchor>,
22309        cx: &mut App,
22310    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22311        Some(self.update(cx, |project, cx| {
22312            project.inlay_hints(buffer_handle, range, cx)
22313        }))
22314    }
22315
22316    fn resolve_inlay_hint(
22317        &self,
22318        hint: InlayHint,
22319        buffer_handle: Entity<Buffer>,
22320        server_id: LanguageServerId,
22321        cx: &mut App,
22322    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22323        Some(self.update(cx, |project, cx| {
22324            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22325        }))
22326    }
22327
22328    fn range_for_rename(
22329        &self,
22330        buffer: &Entity<Buffer>,
22331        position: text::Anchor,
22332        cx: &mut App,
22333    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22334        Some(self.update(cx, |project, cx| {
22335            let buffer = buffer.clone();
22336            let task = project.prepare_rename(buffer.clone(), position, cx);
22337            cx.spawn(async move |_, cx| {
22338                Ok(match task.await? {
22339                    PrepareRenameResponse::Success(range) => Some(range),
22340                    PrepareRenameResponse::InvalidPosition => None,
22341                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22342                        // Fallback on using TreeSitter info to determine identifier range
22343                        buffer.read_with(cx, |buffer, _| {
22344                            let snapshot = buffer.snapshot();
22345                            let (range, kind) = snapshot.surrounding_word(position, false);
22346                            if kind != Some(CharKind::Word) {
22347                                return None;
22348                            }
22349                            Some(
22350                                snapshot.anchor_before(range.start)
22351                                    ..snapshot.anchor_after(range.end),
22352                            )
22353                        })?
22354                    }
22355                })
22356            })
22357        }))
22358    }
22359
22360    fn perform_rename(
22361        &self,
22362        buffer: &Entity<Buffer>,
22363        position: text::Anchor,
22364        new_name: String,
22365        cx: &mut App,
22366    ) -> Option<Task<Result<ProjectTransaction>>> {
22367        Some(self.update(cx, |project, cx| {
22368            project.perform_rename(buffer.clone(), position, new_name, cx)
22369        }))
22370    }
22371}
22372
22373fn inlay_hint_settings(
22374    location: Anchor,
22375    snapshot: &MultiBufferSnapshot,
22376    cx: &mut Context<Editor>,
22377) -> InlayHintSettings {
22378    let file = snapshot.file_at(location);
22379    let language = snapshot.language_at(location).map(|l| l.name());
22380    language_settings(language, file, cx).inlay_hints
22381}
22382
22383fn consume_contiguous_rows(
22384    contiguous_row_selections: &mut Vec<Selection<Point>>,
22385    selection: &Selection<Point>,
22386    display_map: &DisplaySnapshot,
22387    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22388) -> (MultiBufferRow, MultiBufferRow) {
22389    contiguous_row_selections.push(selection.clone());
22390    let start_row = starting_row(selection, display_map);
22391    let mut end_row = ending_row(selection, display_map);
22392
22393    while let Some(next_selection) = selections.peek() {
22394        if next_selection.start.row <= end_row.0 {
22395            end_row = ending_row(next_selection, display_map);
22396            contiguous_row_selections.push(selections.next().unwrap().clone());
22397        } else {
22398            break;
22399        }
22400    }
22401    (start_row, end_row)
22402}
22403
22404fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22405    if selection.start.column > 0 {
22406        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22407    } else {
22408        MultiBufferRow(selection.start.row)
22409    }
22410}
22411
22412fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22413    if next_selection.end.column > 0 || next_selection.is_empty() {
22414        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22415    } else {
22416        MultiBufferRow(next_selection.end.row)
22417    }
22418}
22419
22420impl EditorSnapshot {
22421    pub fn remote_selections_in_range<'a>(
22422        &'a self,
22423        range: &'a Range<Anchor>,
22424        collaboration_hub: &dyn CollaborationHub,
22425        cx: &'a App,
22426    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22427        let participant_names = collaboration_hub.user_names(cx);
22428        let participant_indices = collaboration_hub.user_participant_indices(cx);
22429        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22430        let collaborators_by_replica_id = collaborators_by_peer_id
22431            .values()
22432            .map(|collaborator| (collaborator.replica_id, collaborator))
22433            .collect::<HashMap<_, _>>();
22434        self.buffer_snapshot
22435            .selections_in_range(range, false)
22436            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22437                if replica_id == AGENT_REPLICA_ID {
22438                    Some(RemoteSelection {
22439                        replica_id,
22440                        selection,
22441                        cursor_shape,
22442                        line_mode,
22443                        collaborator_id: CollaboratorId::Agent,
22444                        user_name: Some("Agent".into()),
22445                        color: cx.theme().players().agent(),
22446                    })
22447                } else {
22448                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22449                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22450                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22451                    Some(RemoteSelection {
22452                        replica_id,
22453                        selection,
22454                        cursor_shape,
22455                        line_mode,
22456                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22457                        user_name,
22458                        color: if let Some(index) = participant_index {
22459                            cx.theme().players().color_for_participant(index.0)
22460                        } else {
22461                            cx.theme().players().absent()
22462                        },
22463                    })
22464                }
22465            })
22466    }
22467
22468    pub fn hunks_for_ranges(
22469        &self,
22470        ranges: impl IntoIterator<Item = Range<Point>>,
22471    ) -> Vec<MultiBufferDiffHunk> {
22472        let mut hunks = Vec::new();
22473        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22474            HashMap::default();
22475        for query_range in ranges {
22476            let query_rows =
22477                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22478            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22479                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22480            ) {
22481                // Include deleted hunks that are adjacent to the query range, because
22482                // otherwise they would be missed.
22483                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22484                if hunk.status().is_deleted() {
22485                    intersects_range |= hunk.row_range.start == query_rows.end;
22486                    intersects_range |= hunk.row_range.end == query_rows.start;
22487                }
22488                if intersects_range {
22489                    if !processed_buffer_rows
22490                        .entry(hunk.buffer_id)
22491                        .or_default()
22492                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22493                    {
22494                        continue;
22495                    }
22496                    hunks.push(hunk);
22497                }
22498            }
22499        }
22500
22501        hunks
22502    }
22503
22504    fn display_diff_hunks_for_rows<'a>(
22505        &'a self,
22506        display_rows: Range<DisplayRow>,
22507        folded_buffers: &'a HashSet<BufferId>,
22508    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22509        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22510        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22511
22512        self.buffer_snapshot
22513            .diff_hunks_in_range(buffer_start..buffer_end)
22514            .filter_map(|hunk| {
22515                if folded_buffers.contains(&hunk.buffer_id) {
22516                    return None;
22517                }
22518
22519                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22520                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22521
22522                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22523                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22524
22525                let display_hunk = if hunk_display_start.column() != 0 {
22526                    DisplayDiffHunk::Folded {
22527                        display_row: hunk_display_start.row(),
22528                    }
22529                } else {
22530                    let mut end_row = hunk_display_end.row();
22531                    if hunk_display_end.column() > 0 {
22532                        end_row.0 += 1;
22533                    }
22534                    let is_created_file = hunk.is_created_file();
22535                    DisplayDiffHunk::Unfolded {
22536                        status: hunk.status(),
22537                        diff_base_byte_range: hunk.diff_base_byte_range,
22538                        display_row_range: hunk_display_start.row()..end_row,
22539                        multi_buffer_range: Anchor::range_in_buffer(
22540                            hunk.excerpt_id,
22541                            hunk.buffer_id,
22542                            hunk.buffer_range,
22543                        ),
22544                        is_created_file,
22545                    }
22546                };
22547
22548                Some(display_hunk)
22549            })
22550    }
22551
22552    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22553        self.display_snapshot.buffer_snapshot.language_at(position)
22554    }
22555
22556    pub fn is_focused(&self) -> bool {
22557        self.is_focused
22558    }
22559
22560    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22561        self.placeholder_text.as_ref()
22562    }
22563
22564    pub fn scroll_position(&self) -> gpui::Point<f32> {
22565        self.scroll_anchor.scroll_position(&self.display_snapshot)
22566    }
22567
22568    fn gutter_dimensions(
22569        &self,
22570        font_id: FontId,
22571        font_size: Pixels,
22572        max_line_number_width: Pixels,
22573        cx: &App,
22574    ) -> Option<GutterDimensions> {
22575        if !self.show_gutter {
22576            return None;
22577        }
22578
22579        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22580        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22581
22582        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22583            matches!(
22584                ProjectSettings::get_global(cx).git.git_gutter,
22585                Some(GitGutterSetting::TrackedFiles)
22586            )
22587        });
22588        let gutter_settings = EditorSettings::get_global(cx).gutter;
22589        let show_line_numbers = self
22590            .show_line_numbers
22591            .unwrap_or(gutter_settings.line_numbers);
22592        let line_gutter_width = if show_line_numbers {
22593            // Avoid flicker-like gutter resizes when the line number gains another digit by
22594            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22595            let min_width_for_number_on_gutter =
22596                ch_advance * gutter_settings.min_line_number_digits as f32;
22597            max_line_number_width.max(min_width_for_number_on_gutter)
22598        } else {
22599            0.0.into()
22600        };
22601
22602        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22603        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22604
22605        let git_blame_entries_width =
22606            self.git_blame_gutter_max_author_length
22607                .map(|max_author_length| {
22608                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22609                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22610
22611                    /// The number of characters to dedicate to gaps and margins.
22612                    const SPACING_WIDTH: usize = 4;
22613
22614                    let max_char_count = max_author_length.min(renderer.max_author_length())
22615                        + ::git::SHORT_SHA_LENGTH
22616                        + MAX_RELATIVE_TIMESTAMP.len()
22617                        + SPACING_WIDTH;
22618
22619                    ch_advance * max_char_count
22620                });
22621
22622        let is_singleton = self.buffer_snapshot.is_singleton();
22623
22624        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22625        left_padding += if !is_singleton {
22626            ch_width * 4.0
22627        } else if show_runnables || show_breakpoints {
22628            ch_width * 3.0
22629        } else if show_git_gutter && show_line_numbers {
22630            ch_width * 2.0
22631        } else if show_git_gutter || show_line_numbers {
22632            ch_width
22633        } else {
22634            px(0.)
22635        };
22636
22637        let shows_folds = is_singleton && gutter_settings.folds;
22638
22639        let right_padding = if shows_folds && show_line_numbers {
22640            ch_width * 4.0
22641        } else if shows_folds || (!is_singleton && show_line_numbers) {
22642            ch_width * 3.0
22643        } else if show_line_numbers {
22644            ch_width
22645        } else {
22646            px(0.)
22647        };
22648
22649        Some(GutterDimensions {
22650            left_padding,
22651            right_padding,
22652            width: line_gutter_width + left_padding + right_padding,
22653            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22654            git_blame_entries_width,
22655        })
22656    }
22657
22658    pub fn render_crease_toggle(
22659        &self,
22660        buffer_row: MultiBufferRow,
22661        row_contains_cursor: bool,
22662        editor: Entity<Editor>,
22663        window: &mut Window,
22664        cx: &mut App,
22665    ) -> Option<AnyElement> {
22666        let folded = self.is_line_folded(buffer_row);
22667        let mut is_foldable = false;
22668
22669        if let Some(crease) = self
22670            .crease_snapshot
22671            .query_row(buffer_row, &self.buffer_snapshot)
22672        {
22673            is_foldable = true;
22674            match crease {
22675                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22676                    if let Some(render_toggle) = render_toggle {
22677                        let toggle_callback =
22678                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22679                                if folded {
22680                                    editor.update(cx, |editor, cx| {
22681                                        editor.fold_at(buffer_row, window, cx)
22682                                    });
22683                                } else {
22684                                    editor.update(cx, |editor, cx| {
22685                                        editor.unfold_at(buffer_row, window, cx)
22686                                    });
22687                                }
22688                            });
22689                        return Some((render_toggle)(
22690                            buffer_row,
22691                            folded,
22692                            toggle_callback,
22693                            window,
22694                            cx,
22695                        ));
22696                    }
22697                }
22698            }
22699        }
22700
22701        is_foldable |= self.starts_indent(buffer_row);
22702
22703        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22704            Some(
22705                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22706                    .toggle_state(folded)
22707                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22708                        if folded {
22709                            this.unfold_at(buffer_row, window, cx);
22710                        } else {
22711                            this.fold_at(buffer_row, window, cx);
22712                        }
22713                    }))
22714                    .into_any_element(),
22715            )
22716        } else {
22717            None
22718        }
22719    }
22720
22721    pub fn render_crease_trailer(
22722        &self,
22723        buffer_row: MultiBufferRow,
22724        window: &mut Window,
22725        cx: &mut App,
22726    ) -> Option<AnyElement> {
22727        let folded = self.is_line_folded(buffer_row);
22728        if let Crease::Inline { render_trailer, .. } = self
22729            .crease_snapshot
22730            .query_row(buffer_row, &self.buffer_snapshot)?
22731        {
22732            let render_trailer = render_trailer.as_ref()?;
22733            Some(render_trailer(buffer_row, folded, window, cx))
22734        } else {
22735            None
22736        }
22737    }
22738}
22739
22740impl Deref for EditorSnapshot {
22741    type Target = DisplaySnapshot;
22742
22743    fn deref(&self) -> &Self::Target {
22744        &self.display_snapshot
22745    }
22746}
22747
22748#[derive(Clone, Debug, PartialEq, Eq)]
22749pub enum EditorEvent {
22750    InputIgnored {
22751        text: Arc<str>,
22752    },
22753    InputHandled {
22754        utf16_range_to_replace: Option<Range<isize>>,
22755        text: Arc<str>,
22756    },
22757    ExcerptsAdded {
22758        buffer: Entity<Buffer>,
22759        predecessor: ExcerptId,
22760        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22761    },
22762    ExcerptsRemoved {
22763        ids: Vec<ExcerptId>,
22764        removed_buffer_ids: Vec<BufferId>,
22765    },
22766    BufferFoldToggled {
22767        ids: Vec<ExcerptId>,
22768        folded: bool,
22769    },
22770    ExcerptsEdited {
22771        ids: Vec<ExcerptId>,
22772    },
22773    ExcerptsExpanded {
22774        ids: Vec<ExcerptId>,
22775    },
22776    BufferEdited,
22777    Edited {
22778        transaction_id: clock::Lamport,
22779    },
22780    Reparsed(BufferId),
22781    Focused,
22782    FocusedIn,
22783    Blurred,
22784    DirtyChanged,
22785    Saved,
22786    TitleChanged,
22787    DiffBaseChanged,
22788    SelectionsChanged {
22789        local: bool,
22790    },
22791    ScrollPositionChanged {
22792        local: bool,
22793        autoscroll: bool,
22794    },
22795    Closed,
22796    TransactionUndone {
22797        transaction_id: clock::Lamport,
22798    },
22799    TransactionBegun {
22800        transaction_id: clock::Lamport,
22801    },
22802    Reloaded,
22803    CursorShapeChanged,
22804    PushedToNavHistory {
22805        anchor: Anchor,
22806        is_deactivate: bool,
22807    },
22808}
22809
22810impl EventEmitter<EditorEvent> for Editor {}
22811
22812impl Focusable for Editor {
22813    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22814        self.focus_handle.clone()
22815    }
22816}
22817
22818impl Render for Editor {
22819    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22820        let settings = ThemeSettings::get_global(cx);
22821
22822        let mut text_style = match self.mode {
22823            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22824                color: cx.theme().colors().editor_foreground,
22825                font_family: settings.ui_font.family.clone(),
22826                font_features: settings.ui_font.features.clone(),
22827                font_fallbacks: settings.ui_font.fallbacks.clone(),
22828                font_size: rems(0.875).into(),
22829                font_weight: settings.ui_font.weight,
22830                line_height: relative(settings.buffer_line_height.value()),
22831                ..Default::default()
22832            },
22833            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22834                color: cx.theme().colors().editor_foreground,
22835                font_family: settings.buffer_font.family.clone(),
22836                font_features: settings.buffer_font.features.clone(),
22837                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22838                font_size: settings.buffer_font_size(cx).into(),
22839                font_weight: settings.buffer_font.weight,
22840                line_height: relative(settings.buffer_line_height.value()),
22841                ..Default::default()
22842            },
22843        };
22844        if let Some(text_style_refinement) = &self.text_style_refinement {
22845            text_style.refine(text_style_refinement)
22846        }
22847
22848        let background = match self.mode {
22849            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22850            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22851            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22852            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22853        };
22854
22855        EditorElement::new(
22856            &cx.entity(),
22857            EditorStyle {
22858                background,
22859                border: cx.theme().colors().border,
22860                local_player: cx.theme().players().local(),
22861                text: text_style,
22862                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22863                syntax: cx.theme().syntax().clone(),
22864                status: cx.theme().status().clone(),
22865                inlay_hints_style: make_inlay_hints_style(cx),
22866                edit_prediction_styles: make_suggestion_styles(cx),
22867                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22868                show_underlines: self.diagnostics_enabled(),
22869            },
22870        )
22871    }
22872}
22873
22874impl EntityInputHandler for Editor {
22875    fn text_for_range(
22876        &mut self,
22877        range_utf16: Range<usize>,
22878        adjusted_range: &mut Option<Range<usize>>,
22879        _: &mut Window,
22880        cx: &mut Context<Self>,
22881    ) -> Option<String> {
22882        let snapshot = self.buffer.read(cx).read(cx);
22883        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22884        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22885        if (start.0..end.0) != range_utf16 {
22886            adjusted_range.replace(start.0..end.0);
22887        }
22888        Some(snapshot.text_for_range(start..end).collect())
22889    }
22890
22891    fn selected_text_range(
22892        &mut self,
22893        ignore_disabled_input: bool,
22894        _: &mut Window,
22895        cx: &mut Context<Self>,
22896    ) -> Option<UTF16Selection> {
22897        // Prevent the IME menu from appearing when holding down an alphabetic key
22898        // while input is disabled.
22899        if !ignore_disabled_input && !self.input_enabled {
22900            return None;
22901        }
22902
22903        let selection = self.selections.newest::<OffsetUtf16>(cx);
22904        let range = selection.range();
22905
22906        Some(UTF16Selection {
22907            range: range.start.0..range.end.0,
22908            reversed: selection.reversed,
22909        })
22910    }
22911
22912    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22913        let snapshot = self.buffer.read(cx).read(cx);
22914        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22915        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22916    }
22917
22918    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22919        self.clear_highlights::<InputComposition>(cx);
22920        self.ime_transaction.take();
22921    }
22922
22923    fn replace_text_in_range(
22924        &mut self,
22925        range_utf16: Option<Range<usize>>,
22926        text: &str,
22927        window: &mut Window,
22928        cx: &mut Context<Self>,
22929    ) {
22930        if !self.input_enabled {
22931            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22932            return;
22933        }
22934
22935        self.transact(window, cx, |this, window, cx| {
22936            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22937                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22938                Some(this.selection_replacement_ranges(range_utf16, cx))
22939            } else {
22940                this.marked_text_ranges(cx)
22941            };
22942
22943            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22944                let newest_selection_id = this.selections.newest_anchor().id;
22945                this.selections
22946                    .all::<OffsetUtf16>(cx)
22947                    .iter()
22948                    .zip(ranges_to_replace.iter())
22949                    .find_map(|(selection, range)| {
22950                        if selection.id == newest_selection_id {
22951                            Some(
22952                                (range.start.0 as isize - selection.head().0 as isize)
22953                                    ..(range.end.0 as isize - selection.head().0 as isize),
22954                            )
22955                        } else {
22956                            None
22957                        }
22958                    })
22959            });
22960
22961            cx.emit(EditorEvent::InputHandled {
22962                utf16_range_to_replace: range_to_replace,
22963                text: text.into(),
22964            });
22965
22966            if let Some(new_selected_ranges) = new_selected_ranges {
22967                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22968                    selections.select_ranges(new_selected_ranges)
22969                });
22970                this.backspace(&Default::default(), window, cx);
22971            }
22972
22973            this.handle_input(text, window, cx);
22974        });
22975
22976        if let Some(transaction) = self.ime_transaction {
22977            self.buffer.update(cx, |buffer, cx| {
22978                buffer.group_until_transaction(transaction, cx);
22979            });
22980        }
22981
22982        self.unmark_text(window, cx);
22983    }
22984
22985    fn replace_and_mark_text_in_range(
22986        &mut self,
22987        range_utf16: Option<Range<usize>>,
22988        text: &str,
22989        new_selected_range_utf16: Option<Range<usize>>,
22990        window: &mut Window,
22991        cx: &mut Context<Self>,
22992    ) {
22993        if !self.input_enabled {
22994            return;
22995        }
22996
22997        let transaction = self.transact(window, cx, |this, window, cx| {
22998            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22999                let snapshot = this.buffer.read(cx).read(cx);
23000                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23001                    for marked_range in &mut marked_ranges {
23002                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23003                        marked_range.start.0 += relative_range_utf16.start;
23004                        marked_range.start =
23005                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23006                        marked_range.end =
23007                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23008                    }
23009                }
23010                Some(marked_ranges)
23011            } else if let Some(range_utf16) = range_utf16 {
23012                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23013                Some(this.selection_replacement_ranges(range_utf16, cx))
23014            } else {
23015                None
23016            };
23017
23018            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23019                let newest_selection_id = this.selections.newest_anchor().id;
23020                this.selections
23021                    .all::<OffsetUtf16>(cx)
23022                    .iter()
23023                    .zip(ranges_to_replace.iter())
23024                    .find_map(|(selection, range)| {
23025                        if selection.id == newest_selection_id {
23026                            Some(
23027                                (range.start.0 as isize - selection.head().0 as isize)
23028                                    ..(range.end.0 as isize - selection.head().0 as isize),
23029                            )
23030                        } else {
23031                            None
23032                        }
23033                    })
23034            });
23035
23036            cx.emit(EditorEvent::InputHandled {
23037                utf16_range_to_replace: range_to_replace,
23038                text: text.into(),
23039            });
23040
23041            if let Some(ranges) = ranges_to_replace {
23042                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23043                    s.select_ranges(ranges)
23044                });
23045            }
23046
23047            let marked_ranges = {
23048                let snapshot = this.buffer.read(cx).read(cx);
23049                this.selections
23050                    .disjoint_anchors()
23051                    .iter()
23052                    .map(|selection| {
23053                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23054                    })
23055                    .collect::<Vec<_>>()
23056            };
23057
23058            if text.is_empty() {
23059                this.unmark_text(window, cx);
23060            } else {
23061                this.highlight_text::<InputComposition>(
23062                    marked_ranges.clone(),
23063                    HighlightStyle {
23064                        underline: Some(UnderlineStyle {
23065                            thickness: px(1.),
23066                            color: None,
23067                            wavy: false,
23068                        }),
23069                        ..Default::default()
23070                    },
23071                    cx,
23072                );
23073            }
23074
23075            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23076            let use_autoclose = this.use_autoclose;
23077            let use_auto_surround = this.use_auto_surround;
23078            this.set_use_autoclose(false);
23079            this.set_use_auto_surround(false);
23080            this.handle_input(text, window, cx);
23081            this.set_use_autoclose(use_autoclose);
23082            this.set_use_auto_surround(use_auto_surround);
23083
23084            if let Some(new_selected_range) = new_selected_range_utf16 {
23085                let snapshot = this.buffer.read(cx).read(cx);
23086                let new_selected_ranges = marked_ranges
23087                    .into_iter()
23088                    .map(|marked_range| {
23089                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23090                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23091                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23092                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23093                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23094                    })
23095                    .collect::<Vec<_>>();
23096
23097                drop(snapshot);
23098                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23099                    selections.select_ranges(new_selected_ranges)
23100                });
23101            }
23102        });
23103
23104        self.ime_transaction = self.ime_transaction.or(transaction);
23105        if let Some(transaction) = self.ime_transaction {
23106            self.buffer.update(cx, |buffer, cx| {
23107                buffer.group_until_transaction(transaction, cx);
23108            });
23109        }
23110
23111        if self.text_highlights::<InputComposition>(cx).is_none() {
23112            self.ime_transaction.take();
23113        }
23114    }
23115
23116    fn bounds_for_range(
23117        &mut self,
23118        range_utf16: Range<usize>,
23119        element_bounds: gpui::Bounds<Pixels>,
23120        window: &mut Window,
23121        cx: &mut Context<Self>,
23122    ) -> Option<gpui::Bounds<Pixels>> {
23123        let text_layout_details = self.text_layout_details(window);
23124        let CharacterDimensions {
23125            em_width,
23126            em_advance,
23127            line_height,
23128        } = self.character_dimensions(window);
23129
23130        let snapshot = self.snapshot(window, cx);
23131        let scroll_position = snapshot.scroll_position();
23132        let scroll_left = scroll_position.x * em_advance;
23133
23134        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23135        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23136            + self.gutter_dimensions.full_width();
23137        let y = line_height * (start.row().as_f32() - scroll_position.y);
23138
23139        Some(Bounds {
23140            origin: element_bounds.origin + point(x, y),
23141            size: size(em_width, line_height),
23142        })
23143    }
23144
23145    fn character_index_for_point(
23146        &mut self,
23147        point: gpui::Point<Pixels>,
23148        _window: &mut Window,
23149        _cx: &mut Context<Self>,
23150    ) -> Option<usize> {
23151        let position_map = self.last_position_map.as_ref()?;
23152        if !position_map.text_hitbox.contains(&point) {
23153            return None;
23154        }
23155        let display_point = position_map.point_for_position(point).previous_valid;
23156        let anchor = position_map
23157            .snapshot
23158            .display_point_to_anchor(display_point, Bias::Left);
23159        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23160        Some(utf16_offset.0)
23161    }
23162}
23163
23164trait SelectionExt {
23165    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23166    fn spanned_rows(
23167        &self,
23168        include_end_if_at_line_start: bool,
23169        map: &DisplaySnapshot,
23170    ) -> Range<MultiBufferRow>;
23171}
23172
23173impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23174    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23175        let start = self
23176            .start
23177            .to_point(&map.buffer_snapshot)
23178            .to_display_point(map);
23179        let end = self
23180            .end
23181            .to_point(&map.buffer_snapshot)
23182            .to_display_point(map);
23183        if self.reversed {
23184            end..start
23185        } else {
23186            start..end
23187        }
23188    }
23189
23190    fn spanned_rows(
23191        &self,
23192        include_end_if_at_line_start: bool,
23193        map: &DisplaySnapshot,
23194    ) -> Range<MultiBufferRow> {
23195        let start = self.start.to_point(&map.buffer_snapshot);
23196        let mut end = self.end.to_point(&map.buffer_snapshot);
23197        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23198            end.row -= 1;
23199        }
23200
23201        let buffer_start = map.prev_line_boundary(start).0;
23202        let buffer_end = map.next_line_boundary(end).0;
23203        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23204    }
23205}
23206
23207impl<T: InvalidationRegion> InvalidationStack<T> {
23208    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23209    where
23210        S: Clone + ToOffset,
23211    {
23212        while let Some(region) = self.last() {
23213            let all_selections_inside_invalidation_ranges =
23214                if selections.len() == region.ranges().len() {
23215                    selections
23216                        .iter()
23217                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23218                        .all(|(selection, invalidation_range)| {
23219                            let head = selection.head().to_offset(buffer);
23220                            invalidation_range.start <= head && invalidation_range.end >= head
23221                        })
23222                } else {
23223                    false
23224                };
23225
23226            if all_selections_inside_invalidation_ranges {
23227                break;
23228            } else {
23229                self.pop();
23230            }
23231        }
23232    }
23233}
23234
23235impl<T> Default for InvalidationStack<T> {
23236    fn default() -> Self {
23237        Self(Default::default())
23238    }
23239}
23240
23241impl<T> Deref for InvalidationStack<T> {
23242    type Target = Vec<T>;
23243
23244    fn deref(&self) -> &Self::Target {
23245        &self.0
23246    }
23247}
23248
23249impl<T> DerefMut for InvalidationStack<T> {
23250    fn deref_mut(&mut self) -> &mut Self::Target {
23251        &mut self.0
23252    }
23253}
23254
23255impl InvalidationRegion for SnippetState {
23256    fn ranges(&self) -> &[Range<Anchor>] {
23257        &self.ranges[self.active_index]
23258    }
23259}
23260
23261fn edit_prediction_edit_text(
23262    current_snapshot: &BufferSnapshot,
23263    edits: &[(Range<Anchor>, String)],
23264    edit_preview: &EditPreview,
23265    include_deletions: bool,
23266    cx: &App,
23267) -> HighlightedText {
23268    let edits = edits
23269        .iter()
23270        .map(|(anchor, text)| {
23271            (
23272                anchor.start.text_anchor..anchor.end.text_anchor,
23273                text.clone(),
23274            )
23275        })
23276        .collect::<Vec<_>>();
23277
23278    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23279}
23280
23281fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23282    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23283    // Just show the raw edit text with basic styling
23284    let mut text = String::new();
23285    let mut highlights = Vec::new();
23286
23287    let insertion_highlight_style = HighlightStyle {
23288        color: Some(cx.theme().colors().text),
23289        ..Default::default()
23290    };
23291
23292    for (_, edit_text) in edits {
23293        let start_offset = text.len();
23294        text.push_str(edit_text);
23295        let end_offset = text.len();
23296
23297        if start_offset < end_offset {
23298            highlights.push((start_offset..end_offset, insertion_highlight_style));
23299        }
23300    }
23301
23302    HighlightedText {
23303        text: text.into(),
23304        highlights,
23305    }
23306}
23307
23308pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23309    match severity {
23310        lsp::DiagnosticSeverity::ERROR => colors.error,
23311        lsp::DiagnosticSeverity::WARNING => colors.warning,
23312        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23313        lsp::DiagnosticSeverity::HINT => colors.info,
23314        _ => colors.ignored,
23315    }
23316}
23317
23318pub fn styled_runs_for_code_label<'a>(
23319    label: &'a CodeLabel,
23320    syntax_theme: &'a theme::SyntaxTheme,
23321) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23322    let fade_out = HighlightStyle {
23323        fade_out: Some(0.35),
23324        ..Default::default()
23325    };
23326
23327    let mut prev_end = label.filter_range.end;
23328    label
23329        .runs
23330        .iter()
23331        .enumerate()
23332        .flat_map(move |(ix, (range, highlight_id))| {
23333            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23334                style
23335            } else {
23336                return Default::default();
23337            };
23338            let mut muted_style = style;
23339            muted_style.highlight(fade_out);
23340
23341            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23342            if range.start >= label.filter_range.end {
23343                if range.start > prev_end {
23344                    runs.push((prev_end..range.start, fade_out));
23345                }
23346                runs.push((range.clone(), muted_style));
23347            } else if range.end <= label.filter_range.end {
23348                runs.push((range.clone(), style));
23349            } else {
23350                runs.push((range.start..label.filter_range.end, style));
23351                runs.push((label.filter_range.end..range.end, muted_style));
23352            }
23353            prev_end = cmp::max(prev_end, range.end);
23354
23355            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23356                runs.push((prev_end..label.text.len(), fade_out));
23357            }
23358
23359            runs
23360        })
23361}
23362
23363pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23364    let mut prev_index = 0;
23365    let mut prev_codepoint: Option<char> = None;
23366    text.char_indices()
23367        .chain([(text.len(), '\0')])
23368        .filter_map(move |(index, codepoint)| {
23369            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23370            let is_boundary = index == text.len()
23371                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23372                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23373            if is_boundary {
23374                let chunk = &text[prev_index..index];
23375                prev_index = index;
23376                Some(chunk)
23377            } else {
23378                None
23379            }
23380        })
23381}
23382
23383pub trait RangeToAnchorExt: Sized {
23384    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23385
23386    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23387        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23388        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23389    }
23390}
23391
23392impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23393    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23394        let start_offset = self.start.to_offset(snapshot);
23395        let end_offset = self.end.to_offset(snapshot);
23396        if start_offset == end_offset {
23397            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23398        } else {
23399            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23400        }
23401    }
23402}
23403
23404pub trait RowExt {
23405    fn as_f32(&self) -> f32;
23406
23407    fn next_row(&self) -> Self;
23408
23409    fn previous_row(&self) -> Self;
23410
23411    fn minus(&self, other: Self) -> u32;
23412}
23413
23414impl RowExt for DisplayRow {
23415    fn as_f32(&self) -> f32 {
23416        self.0 as f32
23417    }
23418
23419    fn next_row(&self) -> Self {
23420        Self(self.0 + 1)
23421    }
23422
23423    fn previous_row(&self) -> Self {
23424        Self(self.0.saturating_sub(1))
23425    }
23426
23427    fn minus(&self, other: Self) -> u32 {
23428        self.0 - other.0
23429    }
23430}
23431
23432impl RowExt for MultiBufferRow {
23433    fn as_f32(&self) -> f32 {
23434        self.0 as f32
23435    }
23436
23437    fn next_row(&self) -> Self {
23438        Self(self.0 + 1)
23439    }
23440
23441    fn previous_row(&self) -> Self {
23442        Self(self.0.saturating_sub(1))
23443    }
23444
23445    fn minus(&self, other: Self) -> u32 {
23446        self.0 - other.0
23447    }
23448}
23449
23450trait RowRangeExt {
23451    type Row;
23452
23453    fn len(&self) -> usize;
23454
23455    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23456}
23457
23458impl RowRangeExt for Range<MultiBufferRow> {
23459    type Row = MultiBufferRow;
23460
23461    fn len(&self) -> usize {
23462        (self.end.0 - self.start.0) as usize
23463    }
23464
23465    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23466        (self.start.0..self.end.0).map(MultiBufferRow)
23467    }
23468}
23469
23470impl RowRangeExt for Range<DisplayRow> {
23471    type Row = DisplayRow;
23472
23473    fn len(&self) -> usize {
23474        (self.end.0 - self.start.0) as usize
23475    }
23476
23477    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23478        (self.start.0..self.end.0).map(DisplayRow)
23479    }
23480}
23481
23482/// If select range has more than one line, we
23483/// just point the cursor to range.start.
23484fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23485    if range.start.row == range.end.row {
23486        range
23487    } else {
23488        range.start..range.start
23489    }
23490}
23491pub struct KillRing(ClipboardItem);
23492impl Global for KillRing {}
23493
23494const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23495
23496enum BreakpointPromptEditAction {
23497    Log,
23498    Condition,
23499    HitCondition,
23500}
23501
23502struct BreakpointPromptEditor {
23503    pub(crate) prompt: Entity<Editor>,
23504    editor: WeakEntity<Editor>,
23505    breakpoint_anchor: Anchor,
23506    breakpoint: Breakpoint,
23507    edit_action: BreakpointPromptEditAction,
23508    block_ids: HashSet<CustomBlockId>,
23509    editor_margins: Arc<Mutex<EditorMargins>>,
23510    _subscriptions: Vec<Subscription>,
23511}
23512
23513impl BreakpointPromptEditor {
23514    const MAX_LINES: u8 = 4;
23515
23516    fn new(
23517        editor: WeakEntity<Editor>,
23518        breakpoint_anchor: Anchor,
23519        breakpoint: Breakpoint,
23520        edit_action: BreakpointPromptEditAction,
23521        window: &mut Window,
23522        cx: &mut Context<Self>,
23523    ) -> Self {
23524        let base_text = match edit_action {
23525            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23526            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23527            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23528        }
23529        .map(|msg| msg.to_string())
23530        .unwrap_or_default();
23531
23532        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23533        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23534
23535        let prompt = cx.new(|cx| {
23536            let mut prompt = Editor::new(
23537                EditorMode::AutoHeight {
23538                    min_lines: 1,
23539                    max_lines: Some(Self::MAX_LINES as usize),
23540                },
23541                buffer,
23542                None,
23543                window,
23544                cx,
23545            );
23546            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23547            prompt.set_show_cursor_when_unfocused(false, cx);
23548            prompt.set_placeholder_text(
23549                match edit_action {
23550                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23551                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23552                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23553                },
23554                cx,
23555            );
23556
23557            prompt
23558        });
23559
23560        Self {
23561            prompt,
23562            editor,
23563            breakpoint_anchor,
23564            breakpoint,
23565            edit_action,
23566            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23567            block_ids: Default::default(),
23568            _subscriptions: vec![],
23569        }
23570    }
23571
23572    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23573        self.block_ids.extend(block_ids)
23574    }
23575
23576    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23577        if let Some(editor) = self.editor.upgrade() {
23578            let message = self
23579                .prompt
23580                .read(cx)
23581                .buffer
23582                .read(cx)
23583                .as_singleton()
23584                .expect("A multi buffer in breakpoint prompt isn't possible")
23585                .read(cx)
23586                .as_rope()
23587                .to_string();
23588
23589            editor.update(cx, |editor, cx| {
23590                editor.edit_breakpoint_at_anchor(
23591                    self.breakpoint_anchor,
23592                    self.breakpoint.clone(),
23593                    match self.edit_action {
23594                        BreakpointPromptEditAction::Log => {
23595                            BreakpointEditAction::EditLogMessage(message.into())
23596                        }
23597                        BreakpointPromptEditAction::Condition => {
23598                            BreakpointEditAction::EditCondition(message.into())
23599                        }
23600                        BreakpointPromptEditAction::HitCondition => {
23601                            BreakpointEditAction::EditHitCondition(message.into())
23602                        }
23603                    },
23604                    cx,
23605                );
23606
23607                editor.remove_blocks(self.block_ids.clone(), None, cx);
23608                cx.focus_self(window);
23609            });
23610        }
23611    }
23612
23613    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23614        self.editor
23615            .update(cx, |editor, cx| {
23616                editor.remove_blocks(self.block_ids.clone(), None, cx);
23617                window.focus(&editor.focus_handle);
23618            })
23619            .log_err();
23620    }
23621
23622    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23623        let settings = ThemeSettings::get_global(cx);
23624        let text_style = TextStyle {
23625            color: if self.prompt.read(cx).read_only(cx) {
23626                cx.theme().colors().text_disabled
23627            } else {
23628                cx.theme().colors().text
23629            },
23630            font_family: settings.buffer_font.family.clone(),
23631            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23632            font_size: settings.buffer_font_size(cx).into(),
23633            font_weight: settings.buffer_font.weight,
23634            line_height: relative(settings.buffer_line_height.value()),
23635            ..Default::default()
23636        };
23637        EditorElement::new(
23638            &self.prompt,
23639            EditorStyle {
23640                background: cx.theme().colors().editor_background,
23641                local_player: cx.theme().players().local(),
23642                text: text_style,
23643                ..Default::default()
23644            },
23645        )
23646    }
23647}
23648
23649impl Render for BreakpointPromptEditor {
23650    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23651        let editor_margins = *self.editor_margins.lock();
23652        let gutter_dimensions = editor_margins.gutter;
23653        h_flex()
23654            .key_context("Editor")
23655            .bg(cx.theme().colors().editor_background)
23656            .border_y_1()
23657            .border_color(cx.theme().status().info_border)
23658            .size_full()
23659            .py(window.line_height() / 2.5)
23660            .on_action(cx.listener(Self::confirm))
23661            .on_action(cx.listener(Self::cancel))
23662            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23663            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23664    }
23665}
23666
23667impl Focusable for BreakpointPromptEditor {
23668    fn focus_handle(&self, cx: &App) -> FocusHandle {
23669        self.prompt.focus_handle(cx)
23670    }
23671}
23672
23673fn all_edits_insertions_or_deletions(
23674    edits: &Vec<(Range<Anchor>, String)>,
23675    snapshot: &MultiBufferSnapshot,
23676) -> bool {
23677    let mut all_insertions = true;
23678    let mut all_deletions = true;
23679
23680    for (range, new_text) in edits.iter() {
23681        let range_is_empty = range.to_offset(&snapshot).is_empty();
23682        let text_is_empty = new_text.is_empty();
23683
23684        if range_is_empty != text_is_empty {
23685            if range_is_empty {
23686                all_deletions = false;
23687            } else {
23688                all_insertions = false;
23689            }
23690        } else {
23691            return false;
23692        }
23693
23694        if !all_insertions && !all_deletions {
23695            return false;
23696        }
23697    }
23698    all_insertions || all_deletions
23699}
23700
23701struct MissingEditPredictionKeybindingTooltip;
23702
23703impl Render for MissingEditPredictionKeybindingTooltip {
23704    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23705        ui::tooltip_container(window, cx, |container, _, cx| {
23706            container
23707                .flex_shrink_0()
23708                .max_w_80()
23709                .min_h(rems_from_px(124.))
23710                .justify_between()
23711                .child(
23712                    v_flex()
23713                        .flex_1()
23714                        .text_ui_sm(cx)
23715                        .child(Label::new("Conflict with Accept Keybinding"))
23716                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23717                )
23718                .child(
23719                    h_flex()
23720                        .pb_1()
23721                        .gap_1()
23722                        .items_end()
23723                        .w_full()
23724                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23725                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23726                        }))
23727                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23728                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23729                        })),
23730                )
23731        })
23732    }
23733}
23734
23735#[derive(Debug, Clone, Copy, PartialEq)]
23736pub struct LineHighlight {
23737    pub background: Background,
23738    pub border: Option<gpui::Hsla>,
23739    pub include_gutter: bool,
23740    pub type_id: Option<TypeId>,
23741}
23742
23743struct LineManipulationResult {
23744    pub new_text: String,
23745    pub line_count_before: usize,
23746    pub line_count_after: usize,
23747}
23748
23749fn render_diff_hunk_controls(
23750    row: u32,
23751    status: &DiffHunkStatus,
23752    hunk_range: Range<Anchor>,
23753    is_created_file: bool,
23754    line_height: Pixels,
23755    editor: &Entity<Editor>,
23756    _window: &mut Window,
23757    cx: &mut App,
23758) -> AnyElement {
23759    h_flex()
23760        .h(line_height)
23761        .mr_1()
23762        .gap_1()
23763        .px_0p5()
23764        .pb_1()
23765        .border_x_1()
23766        .border_b_1()
23767        .border_color(cx.theme().colors().border_variant)
23768        .rounded_b_lg()
23769        .bg(cx.theme().colors().editor_background)
23770        .gap_1()
23771        .block_mouse_except_scroll()
23772        .shadow_md()
23773        .child(if status.has_secondary_hunk() {
23774            Button::new(("stage", row as u64), "Stage")
23775                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23776                .tooltip({
23777                    let focus_handle = editor.focus_handle(cx);
23778                    move |window, cx| {
23779                        Tooltip::for_action_in(
23780                            "Stage Hunk",
23781                            &::git::ToggleStaged,
23782                            &focus_handle,
23783                            window,
23784                            cx,
23785                        )
23786                    }
23787                })
23788                .on_click({
23789                    let editor = editor.clone();
23790                    move |_event, _window, cx| {
23791                        editor.update(cx, |editor, cx| {
23792                            editor.stage_or_unstage_diff_hunks(
23793                                true,
23794                                vec![hunk_range.start..hunk_range.start],
23795                                cx,
23796                            );
23797                        });
23798                    }
23799                })
23800        } else {
23801            Button::new(("unstage", row as u64), "Unstage")
23802                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23803                .tooltip({
23804                    let focus_handle = editor.focus_handle(cx);
23805                    move |window, cx| {
23806                        Tooltip::for_action_in(
23807                            "Unstage Hunk",
23808                            &::git::ToggleStaged,
23809                            &focus_handle,
23810                            window,
23811                            cx,
23812                        )
23813                    }
23814                })
23815                .on_click({
23816                    let editor = editor.clone();
23817                    move |_event, _window, cx| {
23818                        editor.update(cx, |editor, cx| {
23819                            editor.stage_or_unstage_diff_hunks(
23820                                false,
23821                                vec![hunk_range.start..hunk_range.start],
23822                                cx,
23823                            );
23824                        });
23825                    }
23826                })
23827        })
23828        .child(
23829            Button::new(("restore", row as u64), "Restore")
23830                .tooltip({
23831                    let focus_handle = editor.focus_handle(cx);
23832                    move |window, cx| {
23833                        Tooltip::for_action_in(
23834                            "Restore Hunk",
23835                            &::git::Restore,
23836                            &focus_handle,
23837                            window,
23838                            cx,
23839                        )
23840                    }
23841                })
23842                .on_click({
23843                    let editor = editor.clone();
23844                    move |_event, window, cx| {
23845                        editor.update(cx, |editor, cx| {
23846                            let snapshot = editor.snapshot(window, cx);
23847                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23848                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23849                        });
23850                    }
23851                })
23852                .disabled(is_created_file),
23853        )
23854        .when(
23855            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23856            |el| {
23857                el.child(
23858                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23859                        .shape(IconButtonShape::Square)
23860                        .icon_size(IconSize::Small)
23861                        // .disabled(!has_multiple_hunks)
23862                        .tooltip({
23863                            let focus_handle = editor.focus_handle(cx);
23864                            move |window, cx| {
23865                                Tooltip::for_action_in(
23866                                    "Next Hunk",
23867                                    &GoToHunk,
23868                                    &focus_handle,
23869                                    window,
23870                                    cx,
23871                                )
23872                            }
23873                        })
23874                        .on_click({
23875                            let editor = editor.clone();
23876                            move |_event, window, cx| {
23877                                editor.update(cx, |editor, cx| {
23878                                    let snapshot = editor.snapshot(window, cx);
23879                                    let position =
23880                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23881                                    editor.go_to_hunk_before_or_after_position(
23882                                        &snapshot,
23883                                        position,
23884                                        Direction::Next,
23885                                        window,
23886                                        cx,
23887                                    );
23888                                    editor.expand_selected_diff_hunks(cx);
23889                                });
23890                            }
23891                        }),
23892                )
23893                .child(
23894                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23895                        .shape(IconButtonShape::Square)
23896                        .icon_size(IconSize::Small)
23897                        // .disabled(!has_multiple_hunks)
23898                        .tooltip({
23899                            let focus_handle = editor.focus_handle(cx);
23900                            move |window, cx| {
23901                                Tooltip::for_action_in(
23902                                    "Previous Hunk",
23903                                    &GoToPreviousHunk,
23904                                    &focus_handle,
23905                                    window,
23906                                    cx,
23907                                )
23908                            }
23909                        })
23910                        .on_click({
23911                            let editor = editor.clone();
23912                            move |_event, window, cx| {
23913                                editor.update(cx, |editor, cx| {
23914                                    let snapshot = editor.snapshot(window, cx);
23915                                    let point =
23916                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23917                                    editor.go_to_hunk_before_or_after_position(
23918                                        &snapshot,
23919                                        point,
23920                                        Direction::Prev,
23921                                        window,
23922                                        cx,
23923                                    );
23924                                    editor.expand_selected_diff_hunks(cx);
23925                                });
23926                            }
23927                        }),
23928                )
23929            },
23930        )
23931        .into_any_element()
23932}