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