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;
   18mod 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_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use display_map::*;
   63pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   64pub use editor_settings::{
   65    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, SearchSettings,
   66    ShowScrollbar,
   67};
   68use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   69pub use editor_settings_controls::*;
   70use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   71pub use element::{
   72    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   73};
   74use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   75use futures::{
   76    FutureExt,
   77    future::{self, Shared, join},
   78};
   79use fuzzy::StringMatchCandidate;
   80
   81use ::git::blame::BlameEntry;
   82use ::git::{Restore, blame::ParsedCommitMessage};
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use git::blame::{GitBlame, GlobalBlameRenderer};
   88use gpui::{
   89    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   90    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   91    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   92    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   93    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   94    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   95    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   96    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   97};
   98use highlight_matching_bracket::refresh_matching_bracket_highlights;
   99use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  100pub use hover_popover::hover_markdown_style;
  101use hover_popover::{HoverState, hide_hover};
  102use indent_guides::ActiveIndentGuidesState;
  103use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  104pub use inline_completion::Direction;
  105use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  106pub use items::MAX_TAB_TITLE_LEN;
  107use itertools::Itertools;
  108use language::{
  109    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  110    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  111    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  112    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  113    language_settings::{
  114        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  115        all_language_settings, language_settings,
  116    },
  117    point_from_lsp, text_diff_with_options,
  118};
  119use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  120use linked_editing_ranges::refresh_linked_ranges;
  121use markdown::Markdown;
  122use mouse_context_menu::MouseContextMenu;
  123use persistence::DB;
  124use project::{
  125    ProjectPath,
  126    debugger::{
  127        breakpoint_store::{
  128            BreakpointEditAction, BreakpointState, BreakpointStore, BreakpointStoreEvent,
  129        },
  130        session::{Session, SessionEvent},
  131    },
  132    project_settings::DiagnosticSeverity,
  133};
  134
  135pub use git::blame::BlameRenderer;
  136pub use proposed_changes_editor::{
  137    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  138};
  139use smallvec::smallvec;
  140use std::{cell::OnceCell, iter::Peekable, ops::Not};
  141use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  142
  143pub use lsp::CompletionContext;
  144use lsp::{
  145    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  146    LanguageServerId, LanguageServerName,
  147};
  148
  149use language::BufferSnapshot;
  150pub use lsp_ext::lsp_tasks;
  151use movement::TextLayoutDetails;
  152pub use multi_buffer::{
  153    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  154    RowInfo, ToOffset, ToPoint,
  155};
  156use multi_buffer::{
  157    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  158    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  159};
  160use parking_lot::Mutex;
  161use project::{
  162    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  163    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  164    TaskSourceKind,
  165    debugger::breakpoint_store::Breakpoint,
  166    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  167    project_settings::{GitGutterSetting, ProjectSettings},
  168};
  169use rand::prelude::*;
  170use rpc::{ErrorExt, proto::*};
  171use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  172use selections_collection::{
  173    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  174};
  175use serde::{Deserialize, Serialize};
  176use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  177use smallvec::SmallVec;
  178use snippet::Snippet;
  179use std::sync::Arc;
  180use std::{
  181    any::TypeId,
  182    borrow::Cow,
  183    cell::RefCell,
  184    cmp::{self, Ordering, Reverse},
  185    mem,
  186    num::NonZeroU32,
  187    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  188    path::{Path, PathBuf},
  189    rc::Rc,
  190    time::{Duration, Instant},
  191};
  192pub use sum_tree::Bias;
  193use sum_tree::TreeMap;
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, 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},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::hover_links::{find_url, find_url_from_range};
  214use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  219const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  220const MAX_LINE_LEN: usize = 1024;
  221const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  222const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  223pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  224#[doc(hidden)]
  225pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  226const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  227
  228pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  231
  232pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  233pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  234pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  235pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  236
  237pub type RenderDiffHunkControlsFn = Arc<
  238    dyn Fn(
  239        u32,
  240        &DiffHunkStatus,
  241        Range<Anchor>,
  242        bool,
  243        Pixels,
  244        &Entity<Editor>,
  245        &mut Window,
  246        &mut App,
  247    ) -> AnyElement,
  248>;
  249
  250const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  251    alt: true,
  252    shift: true,
  253    control: false,
  254    platform: false,
  255    function: false,
  256};
  257
  258struct InlineValueCache {
  259    enabled: bool,
  260    inlays: Vec<InlayId>,
  261    refresh_task: Task<Option<()>>,
  262}
  263
  264impl InlineValueCache {
  265    fn new(enabled: bool) -> Self {
  266        Self {
  267            enabled,
  268            inlays: Vec::new(),
  269            refresh_task: Task::ready(None),
  270        }
  271    }
  272}
  273
  274#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  275pub enum InlayId {
  276    InlineCompletion(usize),
  277    Hint(usize),
  278    DebuggerValue(usize),
  279}
  280
  281impl InlayId {
  282    fn id(&self) -> usize {
  283        match self {
  284            Self::InlineCompletion(id) => *id,
  285            Self::Hint(id) => *id,
  286            Self::DebuggerValue(id) => *id,
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293enum DocumentHighlightRead {}
  294enum DocumentHighlightWrite {}
  295enum InputComposition {}
  296enum SelectedTextHighlight {}
  297
  298pub enum ConflictsOuter {}
  299pub enum ConflictsOurs {}
  300pub enum ConflictsTheirs {}
  301pub enum ConflictsOursMarker {}
  302pub enum ConflictsTheirsMarker {}
  303
  304#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  305pub enum Navigated {
  306    Yes,
  307    No,
  308}
  309
  310impl Navigated {
  311    pub fn from_bool(yes: bool) -> Navigated {
  312        if yes { Navigated::Yes } else { Navigated::No }
  313    }
  314}
  315
  316#[derive(Debug, Clone, PartialEq, Eq)]
  317enum DisplayDiffHunk {
  318    Folded {
  319        display_row: DisplayRow,
  320    },
  321    Unfolded {
  322        is_created_file: bool,
  323        diff_base_byte_range: Range<usize>,
  324        display_row_range: Range<DisplayRow>,
  325        multi_buffer_range: Range<Anchor>,
  326        status: DiffHunkStatus,
  327    },
  328}
  329
  330pub enum HideMouseCursorOrigin {
  331    TypingAction,
  332    MovementAction,
  333}
  334
  335pub fn init_settings(cx: &mut App) {
  336    EditorSettings::register(cx);
  337}
  338
  339pub fn init(cx: &mut App) {
  340    init_settings(cx);
  341
  342    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  343
  344    workspace::register_project_item::<Editor>(cx);
  345    workspace::FollowableViewRegistry::register::<Editor>(cx);
  346    workspace::register_serializable_item::<Editor>(cx);
  347
  348    cx.observe_new(
  349        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  350            workspace.register_action(Editor::new_file);
  351            workspace.register_action(Editor::new_file_vertical);
  352            workspace.register_action(Editor::new_file_horizontal);
  353            workspace.register_action(Editor::cancel_language_server_work);
  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        goal_column: u32,
  450    },
  451    Extend {
  452        position: DisplayPoint,
  453        click_count: usize,
  454    },
  455    Update {
  456        position: DisplayPoint,
  457        goal_column: u32,
  458        scroll_delta: gpui::Point<f32>,
  459    },
  460    End,
  461}
  462
  463#[derive(Clone, Debug)]
  464pub enum SelectMode {
  465    Character,
  466    Word(Range<Anchor>),
  467    Line(Range<Anchor>),
  468    All,
  469}
  470
  471#[derive(Clone, PartialEq, Eq, Debug)]
  472pub enum EditorMode {
  473    SingleLine {
  474        auto_width: bool,
  475    },
  476    AutoHeight {
  477        max_lines: usize,
  478    },
  479    Full {
  480        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  481        scale_ui_elements_with_buffer_font_size: bool,
  482        /// When set to `true`, the editor will render a background for the active line.
  483        show_active_line_background: bool,
  484        /// When set to `true`, the editor's height will be determined by its content.
  485        sized_by_content: bool,
  486    },
  487    Minimap {
  488        parent: WeakEntity<Editor>,
  489    },
  490}
  491
  492impl EditorMode {
  493    pub fn full() -> Self {
  494        Self::Full {
  495            scale_ui_elements_with_buffer_font_size: true,
  496            show_active_line_background: true,
  497            sized_by_content: false,
  498        }
  499    }
  500
  501    pub fn is_full(&self) -> bool {
  502        matches!(self, Self::Full { .. })
  503    }
  504
  505    fn is_minimap(&self) -> bool {
  506        matches!(self, Self::Minimap { .. })
  507    }
  508}
  509
  510#[derive(Copy, Clone, Debug)]
  511pub enum SoftWrap {
  512    /// Prefer not to wrap at all.
  513    ///
  514    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  515    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  516    GitDiff,
  517    /// Prefer a single line generally, unless an overly long line is encountered.
  518    None,
  519    /// Soft wrap lines that exceed the editor width.
  520    EditorWidth,
  521    /// Soft wrap lines at the preferred line length.
  522    Column(u32),
  523    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  524    Bounded(u32),
  525}
  526
  527#[derive(Clone)]
  528pub struct EditorStyle {
  529    pub background: Hsla,
  530    pub local_player: PlayerColor,
  531    pub text: TextStyle,
  532    pub scrollbar_width: Pixels,
  533    pub syntax: Arc<SyntaxTheme>,
  534    pub status: StatusColors,
  535    pub inlay_hints_style: HighlightStyle,
  536    pub inline_completion_styles: InlineCompletionStyles,
  537    pub unnecessary_code_fade: f32,
  538    pub show_underlines: bool,
  539}
  540
  541impl Default for EditorStyle {
  542    fn default() -> Self {
  543        Self {
  544            background: Hsla::default(),
  545            local_player: PlayerColor::default(),
  546            text: TextStyle::default(),
  547            scrollbar_width: Pixels::default(),
  548            syntax: Default::default(),
  549            // HACK: Status colors don't have a real default.
  550            // We should look into removing the status colors from the editor
  551            // style and retrieve them directly from the theme.
  552            status: StatusColors::dark(),
  553            inlay_hints_style: HighlightStyle::default(),
  554            inline_completion_styles: InlineCompletionStyles {
  555                insertion: HighlightStyle::default(),
  556                whitespace: HighlightStyle::default(),
  557            },
  558            unnecessary_code_fade: Default::default(),
  559            show_underlines: true,
  560        }
  561    }
  562}
  563
  564pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  565    let show_background = language_settings::language_settings(None, None, cx)
  566        .inlay_hints
  567        .show_background;
  568
  569    HighlightStyle {
  570        color: Some(cx.theme().status().hint),
  571        background_color: show_background.then(|| cx.theme().status().hint_background),
  572        ..HighlightStyle::default()
  573    }
  574}
  575
  576pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  577    InlineCompletionStyles {
  578        insertion: HighlightStyle {
  579            color: Some(cx.theme().status().predictive),
  580            ..HighlightStyle::default()
  581        },
  582        whitespace: HighlightStyle {
  583            background_color: Some(cx.theme().status().created_background),
  584            ..HighlightStyle::default()
  585        },
  586    }
  587}
  588
  589type CompletionId = usize;
  590
  591pub(crate) enum EditDisplayMode {
  592    TabAccept,
  593    DiffPopover,
  594    Inline,
  595}
  596
  597enum InlineCompletion {
  598    Edit {
  599        edits: Vec<(Range<Anchor>, String)>,
  600        edit_preview: Option<EditPreview>,
  601        display_mode: EditDisplayMode,
  602        snapshot: BufferSnapshot,
  603    },
  604    Move {
  605        target: Anchor,
  606        snapshot: BufferSnapshot,
  607    },
  608}
  609
  610struct InlineCompletionState {
  611    inlay_ids: Vec<InlayId>,
  612    completion: InlineCompletion,
  613    completion_id: Option<SharedString>,
  614    invalidation_range: Range<Anchor>,
  615}
  616
  617enum EditPredictionSettings {
  618    Disabled,
  619    Enabled {
  620        show_in_menu: bool,
  621        preview_requires_modifier: bool,
  622    },
  623}
  624
  625enum InlineCompletionHighlight {}
  626
  627#[derive(Debug, Clone)]
  628struct InlineDiagnostic {
  629    message: SharedString,
  630    group_id: usize,
  631    is_primary: bool,
  632    start: Point,
  633    severity: lsp::DiagnosticSeverity,
  634}
  635
  636pub enum MenuInlineCompletionsPolicy {
  637    Never,
  638    ByProvider,
  639}
  640
  641pub enum EditPredictionPreview {
  642    /// Modifier is not pressed
  643    Inactive { released_too_fast: bool },
  644    /// Modifier pressed
  645    Active {
  646        since: Instant,
  647        previous_scroll_position: Option<ScrollAnchor>,
  648    },
  649}
  650
  651impl EditPredictionPreview {
  652    pub fn released_too_fast(&self) -> bool {
  653        match self {
  654            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  655            EditPredictionPreview::Active { .. } => false,
  656        }
  657    }
  658
  659    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  660        if let EditPredictionPreview::Active {
  661            previous_scroll_position,
  662            ..
  663        } = self
  664        {
  665            *previous_scroll_position = scroll_position;
  666        }
  667    }
  668}
  669
  670pub struct ContextMenuOptions {
  671    pub min_entries_visible: usize,
  672    pub max_entries_visible: usize,
  673    pub placement: Option<ContextMenuPlacement>,
  674}
  675
  676#[derive(Debug, Clone, PartialEq, Eq)]
  677pub enum ContextMenuPlacement {
  678    Above,
  679    Below,
  680}
  681
  682#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  683struct EditorActionId(usize);
  684
  685impl EditorActionId {
  686    pub fn post_inc(&mut self) -> Self {
  687        let answer = self.0;
  688
  689        *self = Self(answer + 1);
  690
  691        Self(answer)
  692    }
  693}
  694
  695// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  696// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  697
  698type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  699type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  700
  701#[derive(Default)]
  702struct ScrollbarMarkerState {
  703    scrollbar_size: Size<Pixels>,
  704    dirty: bool,
  705    markers: Arc<[PaintQuad]>,
  706    pending_refresh: Option<Task<Result<()>>>,
  707}
  708
  709impl ScrollbarMarkerState {
  710    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  711        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  712    }
  713}
  714
  715#[derive(Clone, Copy, PartialEq, Eq)]
  716pub enum MinimapVisibility {
  717    Disabled,
  718    Enabled(bool),
  719}
  720
  721impl MinimapVisibility {
  722    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  723        if mode.is_full() {
  724            Self::Enabled(EditorSettings::get_global(cx).minimap.minimap_enabled())
  725        } else {
  726            Self::Disabled
  727        }
  728    }
  729
  730    fn disabled(&self) -> bool {
  731        match *self {
  732            Self::Disabled => true,
  733            _ => false,
  734        }
  735    }
  736
  737    fn visible(&self) -> bool {
  738        match *self {
  739            Self::Enabled(visible) => visible,
  740            _ => false,
  741        }
  742    }
  743
  744    fn toggle_visibility(&self) -> Self {
  745        match *self {
  746            Self::Enabled(visible) => Self::Enabled(!visible),
  747            Self::Disabled => Self::Disabled,
  748        }
  749    }
  750}
  751
  752#[derive(Clone, Debug)]
  753struct RunnableTasks {
  754    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  755    offset: multi_buffer::Anchor,
  756    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  757    column: u32,
  758    // Values of all named captures, including those starting with '_'
  759    extra_variables: HashMap<String, String>,
  760    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  761    context_range: Range<BufferOffset>,
  762}
  763
  764impl RunnableTasks {
  765    fn resolve<'a>(
  766        &'a self,
  767        cx: &'a task::TaskContext,
  768    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  769        self.templates.iter().filter_map(|(kind, template)| {
  770            template
  771                .resolve_task(&kind.to_id_base(), cx)
  772                .map(|task| (kind.clone(), task))
  773        })
  774    }
  775}
  776
  777#[derive(Clone)]
  778struct ResolvedTasks {
  779    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  780    position: Anchor,
  781}
  782
  783#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  784struct BufferOffset(usize);
  785
  786// Addons allow storing per-editor state in other crates (e.g. Vim)
  787pub trait Addon: 'static {
  788    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  789
  790    fn render_buffer_header_controls(
  791        &self,
  792        _: &ExcerptInfo,
  793        _: &Window,
  794        _: &App,
  795    ) -> Option<AnyElement> {
  796        None
  797    }
  798
  799    fn to_any(&self) -> &dyn std::any::Any;
  800
  801    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  802        None
  803    }
  804}
  805
  806/// A set of caret positions, registered when the editor was edited.
  807pub struct ChangeList {
  808    changes: Vec<Vec<Anchor>>,
  809    /// Currently "selected" change.
  810    position: Option<usize>,
  811}
  812
  813impl ChangeList {
  814    pub fn new() -> Self {
  815        Self {
  816            changes: Vec::new(),
  817            position: None,
  818        }
  819    }
  820
  821    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  822    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  823    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  824        if self.changes.is_empty() {
  825            return None;
  826        }
  827
  828        let prev = self.position.unwrap_or(self.changes.len());
  829        let next = if direction == Direction::Prev {
  830            prev.saturating_sub(count)
  831        } else {
  832            (prev + count).min(self.changes.len() - 1)
  833        };
  834        self.position = Some(next);
  835        self.changes.get(next).map(|anchors| anchors.as_slice())
  836    }
  837
  838    /// Adds a new change to the list, resetting the change list position.
  839    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  840        self.position.take();
  841        if pop_state {
  842            self.changes.pop();
  843        }
  844        self.changes.push(new_positions.clone());
  845    }
  846
  847    pub fn last(&self) -> Option<&[Anchor]> {
  848        self.changes.last().map(|anchors| anchors.as_slice())
  849    }
  850}
  851
  852#[derive(Clone)]
  853struct InlineBlamePopoverState {
  854    scroll_handle: ScrollHandle,
  855    commit_message: Option<ParsedCommitMessage>,
  856    markdown: Entity<Markdown>,
  857}
  858
  859struct InlineBlamePopover {
  860    position: gpui::Point<Pixels>,
  861    show_task: Option<Task<()>>,
  862    hide_task: Option<Task<()>>,
  863    popover_bounds: Option<Bounds<Pixels>>,
  864    popover_state: InlineBlamePopoverState,
  865}
  866
  867/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  868/// a breakpoint on them.
  869#[derive(Clone, Copy, Debug)]
  870struct PhantomBreakpointIndicator {
  871    display_row: DisplayRow,
  872    /// There's a small debounce between hovering over the line and showing the indicator.
  873    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  874    is_active: bool,
  875    collides_with_existing_breakpoint: bool,
  876}
  877/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  878///
  879/// See the [module level documentation](self) for more information.
  880pub struct Editor {
  881    focus_handle: FocusHandle,
  882    last_focused_descendant: Option<WeakFocusHandle>,
  883    /// The text buffer being edited
  884    buffer: Entity<MultiBuffer>,
  885    /// Map of how text in the buffer should be displayed.
  886    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  887    pub display_map: Entity<DisplayMap>,
  888    pub selections: SelectionsCollection,
  889    pub scroll_manager: ScrollManager,
  890    /// When inline assist editors are linked, they all render cursors because
  891    /// typing enters text into each of them, even the ones that aren't focused.
  892    pub(crate) show_cursor_when_unfocused: bool,
  893    columnar_selection_tail: Option<Anchor>,
  894    add_selections_state: Option<AddSelectionsState>,
  895    select_next_state: Option<SelectNextState>,
  896    select_prev_state: Option<SelectNextState>,
  897    selection_history: SelectionHistory,
  898    autoclose_regions: Vec<AutocloseRegion>,
  899    snippet_stack: InvalidationStack<SnippetState>,
  900    select_syntax_node_history: SelectSyntaxNodeHistory,
  901    ime_transaction: Option<TransactionId>,
  902    pub diagnostics_max_severity: DiagnosticSeverity,
  903    active_diagnostics: ActiveDiagnostic,
  904    show_inline_diagnostics: bool,
  905    inline_diagnostics_update: Task<()>,
  906    inline_diagnostics_enabled: bool,
  907    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  908    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  909    hard_wrap: Option<usize>,
  910
  911    // TODO: make this a access method
  912    pub project: Option<Entity<Project>>,
  913    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  914    completion_provider: Option<Box<dyn CompletionProvider>>,
  915    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  916    blink_manager: Entity<BlinkManager>,
  917    show_cursor_names: bool,
  918    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  919    pub show_local_selections: bool,
  920    mode: EditorMode,
  921    show_breadcrumbs: bool,
  922    show_gutter: bool,
  923    show_scrollbars: bool,
  924    minimap_visibility: MinimapVisibility,
  925    disable_expand_excerpt_buttons: bool,
  926    show_line_numbers: Option<bool>,
  927    use_relative_line_numbers: Option<bool>,
  928    show_git_diff_gutter: Option<bool>,
  929    show_code_actions: Option<bool>,
  930    show_runnables: Option<bool>,
  931    show_breakpoints: Option<bool>,
  932    show_wrap_guides: Option<bool>,
  933    show_indent_guides: Option<bool>,
  934    placeholder_text: Option<Arc<str>>,
  935    highlight_order: usize,
  936    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  937    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  938    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  939    scrollbar_marker_state: ScrollbarMarkerState,
  940    active_indent_guides_state: ActiveIndentGuidesState,
  941    nav_history: Option<ItemNavHistory>,
  942    context_menu: RefCell<Option<CodeContextMenu>>,
  943    context_menu_options: Option<ContextMenuOptions>,
  944    mouse_context_menu: Option<MouseContextMenu>,
  945    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  946    inline_blame_popover: Option<InlineBlamePopover>,
  947    signature_help_state: SignatureHelpState,
  948    auto_signature_help: Option<bool>,
  949    find_all_references_task_sources: Vec<Anchor>,
  950    next_completion_id: CompletionId,
  951    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  952    code_actions_task: Option<Task<Result<()>>>,
  953    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  954    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  955    document_highlights_task: Option<Task<()>>,
  956    linked_editing_range_task: Option<Task<Option<()>>>,
  957    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  958    pending_rename: Option<RenameState>,
  959    searchable: bool,
  960    cursor_shape: CursorShape,
  961    current_line_highlight: Option<CurrentLineHighlight>,
  962    collapse_matches: bool,
  963    autoindent_mode: Option<AutoindentMode>,
  964    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  965    input_enabled: bool,
  966    use_modal_editing: bool,
  967    read_only: bool,
  968    leader_id: Option<CollaboratorId>,
  969    remote_id: Option<ViewId>,
  970    pub hover_state: HoverState,
  971    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  972    gutter_hovered: bool,
  973    hovered_link_state: Option<HoveredLinkState>,
  974    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  975    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  976    active_inline_completion: Option<InlineCompletionState>,
  977    /// Used to prevent flickering as the user types while the menu is open
  978    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  979    edit_prediction_settings: EditPredictionSettings,
  980    inline_completions_hidden_for_vim_mode: bool,
  981    show_inline_completions_override: Option<bool>,
  982    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  983    edit_prediction_preview: EditPredictionPreview,
  984    edit_prediction_indent_conflict: bool,
  985    edit_prediction_requires_modifier_in_indent_conflict: bool,
  986    inlay_hint_cache: InlayHintCache,
  987    next_inlay_id: usize,
  988    _subscriptions: Vec<Subscription>,
  989    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  990    gutter_dimensions: GutterDimensions,
  991    style: Option<EditorStyle>,
  992    text_style_refinement: Option<TextStyleRefinement>,
  993    next_editor_action_id: EditorActionId,
  994    editor_actions:
  995        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  996    use_autoclose: bool,
  997    use_auto_surround: bool,
  998    auto_replace_emoji_shortcode: bool,
  999    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1000    show_git_blame_gutter: bool,
 1001    show_git_blame_inline: bool,
 1002    show_git_blame_inline_delay_task: Option<Task<()>>,
 1003    git_blame_inline_enabled: bool,
 1004    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1005    serialize_dirty_buffers: bool,
 1006    show_selection_menu: Option<bool>,
 1007    blame: Option<Entity<GitBlame>>,
 1008    blame_subscription: Option<Subscription>,
 1009    custom_context_menu: Option<
 1010        Box<
 1011            dyn 'static
 1012                + Fn(
 1013                    &mut Self,
 1014                    DisplayPoint,
 1015                    &mut Window,
 1016                    &mut Context<Self>,
 1017                ) -> Option<Entity<ui::ContextMenu>>,
 1018        >,
 1019    >,
 1020    last_bounds: Option<Bounds<Pixels>>,
 1021    last_position_map: Option<Rc<PositionMap>>,
 1022    expect_bounds_change: Option<Bounds<Pixels>>,
 1023    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1024    tasks_update_task: Option<Task<()>>,
 1025    breakpoint_store: Option<Entity<BreakpointStore>>,
 1026    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1027    in_project_search: bool,
 1028    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1029    breadcrumb_header: Option<String>,
 1030    focused_block: Option<FocusedBlock>,
 1031    next_scroll_position: NextScrollCursorCenterTopBottom,
 1032    addons: HashMap<TypeId, Box<dyn Addon>>,
 1033    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1034    load_diff_task: Option<Shared<Task<()>>>,
 1035    /// Whether we are temporarily displaying a diff other than git's
 1036    temporary_diff_override: bool,
 1037    selection_mark_mode: bool,
 1038    toggle_fold_multiple_buffers: Task<()>,
 1039    _scroll_cursor_center_top_bottom_task: Task<()>,
 1040    serialize_selections: Task<()>,
 1041    serialize_folds: Task<()>,
 1042    mouse_cursor_hidden: bool,
 1043    minimap: Option<Entity<Self>>,
 1044    hide_mouse_mode: HideMouseMode,
 1045    pub change_list: ChangeList,
 1046    inline_value_cache: InlineValueCache,
 1047}
 1048
 1049#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1050enum NextScrollCursorCenterTopBottom {
 1051    #[default]
 1052    Center,
 1053    Top,
 1054    Bottom,
 1055}
 1056
 1057impl NextScrollCursorCenterTopBottom {
 1058    fn next(&self) -> Self {
 1059        match self {
 1060            Self::Center => Self::Top,
 1061            Self::Top => Self::Bottom,
 1062            Self::Bottom => Self::Center,
 1063        }
 1064    }
 1065}
 1066
 1067#[derive(Clone)]
 1068pub struct EditorSnapshot {
 1069    pub mode: EditorMode,
 1070    show_gutter: bool,
 1071    show_line_numbers: Option<bool>,
 1072    show_git_diff_gutter: Option<bool>,
 1073    show_runnables: Option<bool>,
 1074    show_breakpoints: Option<bool>,
 1075    git_blame_gutter_max_author_length: Option<usize>,
 1076    pub display_snapshot: DisplaySnapshot,
 1077    pub placeholder_text: Option<Arc<str>>,
 1078    is_focused: bool,
 1079    scroll_anchor: ScrollAnchor,
 1080    ongoing_scroll: OngoingScroll,
 1081    current_line_highlight: CurrentLineHighlight,
 1082    gutter_hovered: bool,
 1083}
 1084
 1085#[derive(Default, Debug, Clone, Copy)]
 1086pub struct GutterDimensions {
 1087    pub left_padding: Pixels,
 1088    pub right_padding: Pixels,
 1089    pub width: Pixels,
 1090    pub margin: Pixels,
 1091    pub git_blame_entries_width: Option<Pixels>,
 1092}
 1093
 1094impl GutterDimensions {
 1095    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1096        Self {
 1097            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1098            ..Default::default()
 1099        }
 1100    }
 1101
 1102    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1103        -cx.text_system().descent(font_id, font_size)
 1104    }
 1105    /// The full width of the space taken up by the gutter.
 1106    pub fn full_width(&self) -> Pixels {
 1107        self.margin + self.width
 1108    }
 1109
 1110    /// The width of the space reserved for the fold indicators,
 1111    /// use alongside 'justify_end' and `gutter_width` to
 1112    /// right align content with the line numbers
 1113    pub fn fold_area_width(&self) -> Pixels {
 1114        self.margin + self.right_padding
 1115    }
 1116}
 1117
 1118#[derive(Debug)]
 1119pub struct RemoteSelection {
 1120    pub replica_id: ReplicaId,
 1121    pub selection: Selection<Anchor>,
 1122    pub cursor_shape: CursorShape,
 1123    pub collaborator_id: CollaboratorId,
 1124    pub line_mode: bool,
 1125    pub user_name: Option<SharedString>,
 1126    pub color: PlayerColor,
 1127}
 1128
 1129#[derive(Clone, Debug)]
 1130struct SelectionHistoryEntry {
 1131    selections: Arc<[Selection<Anchor>]>,
 1132    select_next_state: Option<SelectNextState>,
 1133    select_prev_state: Option<SelectNextState>,
 1134    add_selections_state: Option<AddSelectionsState>,
 1135}
 1136
 1137enum SelectionHistoryMode {
 1138    Normal,
 1139    Undoing,
 1140    Redoing,
 1141}
 1142
 1143#[derive(Clone, PartialEq, Eq, Hash)]
 1144struct HoveredCursor {
 1145    replica_id: u16,
 1146    selection_id: usize,
 1147}
 1148
 1149impl Default for SelectionHistoryMode {
 1150    fn default() -> Self {
 1151        Self::Normal
 1152    }
 1153}
 1154
 1155#[derive(Default)]
 1156struct SelectionHistory {
 1157    #[allow(clippy::type_complexity)]
 1158    selections_by_transaction:
 1159        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1160    mode: SelectionHistoryMode,
 1161    undo_stack: VecDeque<SelectionHistoryEntry>,
 1162    redo_stack: VecDeque<SelectionHistoryEntry>,
 1163}
 1164
 1165impl SelectionHistory {
 1166    fn insert_transaction(
 1167        &mut self,
 1168        transaction_id: TransactionId,
 1169        selections: Arc<[Selection<Anchor>]>,
 1170    ) {
 1171        self.selections_by_transaction
 1172            .insert(transaction_id, (selections, None));
 1173    }
 1174
 1175    #[allow(clippy::type_complexity)]
 1176    fn transaction(
 1177        &self,
 1178        transaction_id: TransactionId,
 1179    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1180        self.selections_by_transaction.get(&transaction_id)
 1181    }
 1182
 1183    #[allow(clippy::type_complexity)]
 1184    fn transaction_mut(
 1185        &mut self,
 1186        transaction_id: TransactionId,
 1187    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1188        self.selections_by_transaction.get_mut(&transaction_id)
 1189    }
 1190
 1191    fn push(&mut self, entry: SelectionHistoryEntry) {
 1192        if !entry.selections.is_empty() {
 1193            match self.mode {
 1194                SelectionHistoryMode::Normal => {
 1195                    self.push_undo(entry);
 1196                    self.redo_stack.clear();
 1197                }
 1198                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1199                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1200            }
 1201        }
 1202    }
 1203
 1204    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1205        if self
 1206            .undo_stack
 1207            .back()
 1208            .map_or(true, |e| e.selections != entry.selections)
 1209        {
 1210            self.undo_stack.push_back(entry);
 1211            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1212                self.undo_stack.pop_front();
 1213            }
 1214        }
 1215    }
 1216
 1217    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1218        if self
 1219            .redo_stack
 1220            .back()
 1221            .map_or(true, |e| e.selections != entry.selections)
 1222        {
 1223            self.redo_stack.push_back(entry);
 1224            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1225                self.redo_stack.pop_front();
 1226            }
 1227        }
 1228    }
 1229}
 1230
 1231#[derive(Clone, Copy)]
 1232pub struct RowHighlightOptions {
 1233    pub autoscroll: bool,
 1234    pub include_gutter: bool,
 1235}
 1236
 1237impl Default for RowHighlightOptions {
 1238    fn default() -> Self {
 1239        Self {
 1240            autoscroll: Default::default(),
 1241            include_gutter: true,
 1242        }
 1243    }
 1244}
 1245
 1246struct RowHighlight {
 1247    index: usize,
 1248    range: Range<Anchor>,
 1249    color: Hsla,
 1250    options: RowHighlightOptions,
 1251    type_id: TypeId,
 1252}
 1253
 1254#[derive(Clone, Debug)]
 1255struct AddSelectionsState {
 1256    above: bool,
 1257    stack: Vec<usize>,
 1258}
 1259
 1260#[derive(Clone)]
 1261struct SelectNextState {
 1262    query: AhoCorasick,
 1263    wordwise: bool,
 1264    done: bool,
 1265}
 1266
 1267impl std::fmt::Debug for SelectNextState {
 1268    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1269        f.debug_struct(std::any::type_name::<Self>())
 1270            .field("wordwise", &self.wordwise)
 1271            .field("done", &self.done)
 1272            .finish()
 1273    }
 1274}
 1275
 1276#[derive(Debug)]
 1277struct AutocloseRegion {
 1278    selection_id: usize,
 1279    range: Range<Anchor>,
 1280    pair: BracketPair,
 1281}
 1282
 1283#[derive(Debug)]
 1284struct SnippetState {
 1285    ranges: Vec<Vec<Range<Anchor>>>,
 1286    active_index: usize,
 1287    choices: Vec<Option<Vec<String>>>,
 1288}
 1289
 1290#[doc(hidden)]
 1291pub struct RenameState {
 1292    pub range: Range<Anchor>,
 1293    pub old_name: Arc<str>,
 1294    pub editor: Entity<Editor>,
 1295    block_id: CustomBlockId,
 1296}
 1297
 1298struct InvalidationStack<T>(Vec<T>);
 1299
 1300struct RegisteredInlineCompletionProvider {
 1301    provider: Arc<dyn InlineCompletionProviderHandle>,
 1302    _subscription: Subscription,
 1303}
 1304
 1305#[derive(Debug, PartialEq, Eq)]
 1306pub struct ActiveDiagnosticGroup {
 1307    pub active_range: Range<Anchor>,
 1308    pub active_message: String,
 1309    pub group_id: usize,
 1310    pub blocks: HashSet<CustomBlockId>,
 1311}
 1312
 1313#[derive(Debug, PartialEq, Eq)]
 1314
 1315pub(crate) enum ActiveDiagnostic {
 1316    None,
 1317    All,
 1318    Group(ActiveDiagnosticGroup),
 1319}
 1320
 1321#[derive(Serialize, Deserialize, Clone, Debug)]
 1322pub struct ClipboardSelection {
 1323    /// The number of bytes in this selection.
 1324    pub len: usize,
 1325    /// Whether this was a full-line selection.
 1326    pub is_entire_line: bool,
 1327    /// The indentation of the first line when this content was originally copied.
 1328    pub first_line_indent: u32,
 1329}
 1330
 1331// selections, scroll behavior, was newest selection reversed
 1332type SelectSyntaxNodeHistoryState = (
 1333    Box<[Selection<usize>]>,
 1334    SelectSyntaxNodeScrollBehavior,
 1335    bool,
 1336);
 1337
 1338#[derive(Default)]
 1339struct SelectSyntaxNodeHistory {
 1340    stack: Vec<SelectSyntaxNodeHistoryState>,
 1341    // disable temporarily to allow changing selections without losing the stack
 1342    pub disable_clearing: bool,
 1343}
 1344
 1345impl SelectSyntaxNodeHistory {
 1346    pub fn try_clear(&mut self) {
 1347        if !self.disable_clearing {
 1348            self.stack.clear();
 1349        }
 1350    }
 1351
 1352    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1353        self.stack.push(selection);
 1354    }
 1355
 1356    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1357        self.stack.pop()
 1358    }
 1359}
 1360
 1361enum SelectSyntaxNodeScrollBehavior {
 1362    CursorTop,
 1363    FitSelection,
 1364    CursorBottom,
 1365}
 1366
 1367#[derive(Debug)]
 1368pub(crate) struct NavigationData {
 1369    cursor_anchor: Anchor,
 1370    cursor_position: Point,
 1371    scroll_anchor: ScrollAnchor,
 1372    scroll_top_row: u32,
 1373}
 1374
 1375#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1376pub enum GotoDefinitionKind {
 1377    Symbol,
 1378    Declaration,
 1379    Type,
 1380    Implementation,
 1381}
 1382
 1383#[derive(Debug, Clone)]
 1384enum InlayHintRefreshReason {
 1385    ModifiersChanged(bool),
 1386    Toggle(bool),
 1387    SettingsChange(InlayHintSettings),
 1388    NewLinesShown,
 1389    BufferEdited(HashSet<Arc<Language>>),
 1390    RefreshRequested,
 1391    ExcerptsRemoved(Vec<ExcerptId>),
 1392}
 1393
 1394impl InlayHintRefreshReason {
 1395    fn description(&self) -> &'static str {
 1396        match self {
 1397            Self::ModifiersChanged(_) => "modifiers changed",
 1398            Self::Toggle(_) => "toggle",
 1399            Self::SettingsChange(_) => "settings change",
 1400            Self::NewLinesShown => "new lines shown",
 1401            Self::BufferEdited(_) => "buffer edited",
 1402            Self::RefreshRequested => "refresh requested",
 1403            Self::ExcerptsRemoved(_) => "excerpts removed",
 1404        }
 1405    }
 1406}
 1407
 1408pub enum FormatTarget {
 1409    Buffers,
 1410    Ranges(Vec<Range<MultiBufferPoint>>),
 1411}
 1412
 1413pub(crate) struct FocusedBlock {
 1414    id: BlockId,
 1415    focus_handle: WeakFocusHandle,
 1416}
 1417
 1418#[derive(Clone)]
 1419enum JumpData {
 1420    MultiBufferRow {
 1421        row: MultiBufferRow,
 1422        line_offset_from_top: u32,
 1423    },
 1424    MultiBufferPoint {
 1425        excerpt_id: ExcerptId,
 1426        position: Point,
 1427        anchor: text::Anchor,
 1428        line_offset_from_top: u32,
 1429    },
 1430}
 1431
 1432pub enum MultibufferSelectionMode {
 1433    First,
 1434    All,
 1435}
 1436
 1437#[derive(Clone, Copy, Debug, Default)]
 1438pub struct RewrapOptions {
 1439    pub override_language_settings: bool,
 1440    pub preserve_existing_whitespace: bool,
 1441}
 1442
 1443impl Editor {
 1444    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1445        let buffer = cx.new(|cx| Buffer::local("", cx));
 1446        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1447        Self::new(
 1448            EditorMode::SingleLine { auto_width: false },
 1449            buffer,
 1450            None,
 1451            window,
 1452            cx,
 1453        )
 1454    }
 1455
 1456    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1457        let buffer = cx.new(|cx| Buffer::local("", cx));
 1458        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1459        Self::new(EditorMode::full(), buffer, None, window, cx)
 1460    }
 1461
 1462    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1463        let buffer = cx.new(|cx| Buffer::local("", cx));
 1464        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1465        Self::new(
 1466            EditorMode::SingleLine { auto_width: true },
 1467            buffer,
 1468            None,
 1469            window,
 1470            cx,
 1471        )
 1472    }
 1473
 1474    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1475        let buffer = cx.new(|cx| Buffer::local("", cx));
 1476        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1477        Self::new(
 1478            EditorMode::AutoHeight { max_lines },
 1479            buffer,
 1480            None,
 1481            window,
 1482            cx,
 1483        )
 1484    }
 1485
 1486    pub fn for_buffer(
 1487        buffer: Entity<Buffer>,
 1488        project: Option<Entity<Project>>,
 1489        window: &mut Window,
 1490        cx: &mut Context<Self>,
 1491    ) -> Self {
 1492        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1493        Self::new(EditorMode::full(), buffer, project, window, cx)
 1494    }
 1495
 1496    pub fn for_multibuffer(
 1497        buffer: Entity<MultiBuffer>,
 1498        project: Option<Entity<Project>>,
 1499        window: &mut Window,
 1500        cx: &mut Context<Self>,
 1501    ) -> Self {
 1502        Self::new(EditorMode::full(), buffer, project, window, cx)
 1503    }
 1504
 1505    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1506        let mut clone = Self::new(
 1507            self.mode.clone(),
 1508            self.buffer.clone(),
 1509            self.project.clone(),
 1510            window,
 1511            cx,
 1512        );
 1513        self.display_map.update(cx, |display_map, cx| {
 1514            let snapshot = display_map.snapshot(cx);
 1515            clone.display_map.update(cx, |display_map, cx| {
 1516                display_map.set_state(&snapshot, cx);
 1517            });
 1518        });
 1519        clone.folds_did_change(cx);
 1520        clone.selections.clone_state(&self.selections);
 1521        clone.scroll_manager.clone_state(&self.scroll_manager);
 1522        clone.searchable = self.searchable;
 1523        clone.read_only = self.read_only;
 1524        clone
 1525    }
 1526
 1527    pub fn new(
 1528        mode: EditorMode,
 1529        buffer: Entity<MultiBuffer>,
 1530        project: Option<Entity<Project>>,
 1531        window: &mut Window,
 1532        cx: &mut Context<Self>,
 1533    ) -> Self {
 1534        Editor::new_internal(mode, buffer, project, None, window, cx)
 1535    }
 1536
 1537    fn new_internal(
 1538        mode: EditorMode,
 1539        buffer: Entity<MultiBuffer>,
 1540        project: Option<Entity<Project>>,
 1541        display_map: Option<Entity<DisplayMap>>,
 1542        window: &mut Window,
 1543        cx: &mut Context<Self>,
 1544    ) -> Self {
 1545        debug_assert!(
 1546            display_map.is_none() || mode.is_minimap(),
 1547            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1548        );
 1549
 1550        let full_mode = mode.is_full();
 1551        let diagnostics_max_severity = if full_mode {
 1552            EditorSettings::get_global(cx)
 1553                .diagnostics_max_severity
 1554                .unwrap_or(DiagnosticSeverity::Hint)
 1555        } else {
 1556            DiagnosticSeverity::Off
 1557        };
 1558        let style = window.text_style();
 1559        let font_size = style.font_size.to_pixels(window.rem_size());
 1560        let editor = cx.entity().downgrade();
 1561        let fold_placeholder = FoldPlaceholder {
 1562            constrain_width: true,
 1563            render: Arc::new(move |fold_id, fold_range, cx| {
 1564                let editor = editor.clone();
 1565                div()
 1566                    .id(fold_id)
 1567                    .bg(cx.theme().colors().ghost_element_background)
 1568                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1569                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1570                    .rounded_xs()
 1571                    .size_full()
 1572                    .cursor_pointer()
 1573                    .child("")
 1574                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1575                    .on_click(move |_, _window, cx| {
 1576                        editor
 1577                            .update(cx, |editor, cx| {
 1578                                editor.unfold_ranges(
 1579                                    &[fold_range.start..fold_range.end],
 1580                                    true,
 1581                                    false,
 1582                                    cx,
 1583                                );
 1584                                cx.stop_propagation();
 1585                            })
 1586                            .ok();
 1587                    })
 1588                    .into_any()
 1589            }),
 1590            merge_adjacent: true,
 1591            ..FoldPlaceholder::default()
 1592        };
 1593        let display_map = display_map.unwrap_or_else(|| {
 1594            cx.new(|cx| {
 1595                DisplayMap::new(
 1596                    buffer.clone(),
 1597                    style.font(),
 1598                    font_size,
 1599                    None,
 1600                    FILE_HEADER_HEIGHT,
 1601                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1602                    fold_placeholder,
 1603                    diagnostics_max_severity,
 1604                    cx,
 1605                )
 1606            })
 1607        });
 1608
 1609        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1610
 1611        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1612
 1613        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1614            .then(|| language_settings::SoftWrap::None);
 1615
 1616        let mut project_subscriptions = Vec::new();
 1617        if mode.is_full() {
 1618            if let Some(project) = project.as_ref() {
 1619                project_subscriptions.push(cx.subscribe_in(
 1620                    project,
 1621                    window,
 1622                    |editor, _, event, window, cx| match event {
 1623                        project::Event::RefreshCodeLens => {
 1624                            // we always query lens with actions, without storing them, always refreshing them
 1625                        }
 1626                        project::Event::RefreshInlayHints => {
 1627                            editor
 1628                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1629                        }
 1630                        project::Event::SnippetEdit(id, snippet_edits) => {
 1631                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1632                                let focus_handle = editor.focus_handle(cx);
 1633                                if focus_handle.is_focused(window) {
 1634                                    let snapshot = buffer.read(cx).snapshot();
 1635                                    for (range, snippet) in snippet_edits {
 1636                                        let editor_range =
 1637                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1638                                        editor
 1639                                            .insert_snippet(
 1640                                                &[editor_range],
 1641                                                snippet.clone(),
 1642                                                window,
 1643                                                cx,
 1644                                            )
 1645                                            .ok();
 1646                                    }
 1647                                }
 1648                            }
 1649                        }
 1650                        _ => {}
 1651                    },
 1652                ));
 1653                if let Some(task_inventory) = project
 1654                    .read(cx)
 1655                    .task_store()
 1656                    .read(cx)
 1657                    .task_inventory()
 1658                    .cloned()
 1659                {
 1660                    project_subscriptions.push(cx.observe_in(
 1661                        &task_inventory,
 1662                        window,
 1663                        |editor, _, window, cx| {
 1664                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1665                        },
 1666                    ));
 1667                };
 1668
 1669                project_subscriptions.push(cx.subscribe_in(
 1670                    &project.read(cx).breakpoint_store(),
 1671                    window,
 1672                    |editor, _, event, window, cx| match event {
 1673                        BreakpointStoreEvent::ClearDebugLines => {
 1674                            editor.clear_row_highlights::<ActiveDebugLine>();
 1675                            editor.refresh_inline_values(cx);
 1676                        }
 1677                        BreakpointStoreEvent::SetDebugLine => {
 1678                            if editor.go_to_active_debug_line(window, cx) {
 1679                                cx.stop_propagation();
 1680                            }
 1681
 1682                            editor.refresh_inline_values(cx);
 1683                        }
 1684                        _ => {}
 1685                    },
 1686                ));
 1687            }
 1688        }
 1689
 1690        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1691
 1692        let inlay_hint_settings =
 1693            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1694        let focus_handle = cx.focus_handle();
 1695        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1696            .detach();
 1697        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1698            .detach();
 1699        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1700            .detach();
 1701        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1702            .detach();
 1703
 1704        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1705            Some(false)
 1706        } else {
 1707            None
 1708        };
 1709
 1710        let breakpoint_store = match (&mode, project.as_ref()) {
 1711            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1712            _ => None,
 1713        };
 1714
 1715        let mut code_action_providers = Vec::new();
 1716        let mut load_uncommitted_diff = None;
 1717        if let Some(project) = project.clone() {
 1718            load_uncommitted_diff = Some(
 1719                update_uncommitted_diff_for_buffer(
 1720                    cx.entity(),
 1721                    &project,
 1722                    buffer.read(cx).all_buffers(),
 1723                    buffer.clone(),
 1724                    cx,
 1725                )
 1726                .shared(),
 1727            );
 1728            code_action_providers.push(Rc::new(project) as Rc<_>);
 1729        }
 1730
 1731        let mut this = Self {
 1732            focus_handle,
 1733            show_cursor_when_unfocused: false,
 1734            last_focused_descendant: None,
 1735            buffer: buffer.clone(),
 1736            display_map: display_map.clone(),
 1737            selections,
 1738            scroll_manager: ScrollManager::new(cx),
 1739            columnar_selection_tail: None,
 1740            add_selections_state: None,
 1741            select_next_state: None,
 1742            select_prev_state: None,
 1743            selection_history: SelectionHistory::default(),
 1744            autoclose_regions: Vec::new(),
 1745            snippet_stack: InvalidationStack::default(),
 1746            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1747            ime_transaction: None,
 1748            active_diagnostics: ActiveDiagnostic::None,
 1749            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1750            inline_diagnostics_update: Task::ready(()),
 1751            inline_diagnostics: Vec::new(),
 1752            soft_wrap_mode_override,
 1753            diagnostics_max_severity,
 1754            hard_wrap: None,
 1755            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1756            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1757            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1758            project,
 1759            blink_manager: blink_manager.clone(),
 1760            show_local_selections: true,
 1761            show_scrollbars: full_mode,
 1762            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1763            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1764            show_gutter: mode.is_full(),
 1765            show_line_numbers: None,
 1766            use_relative_line_numbers: None,
 1767            disable_expand_excerpt_buttons: false,
 1768            show_git_diff_gutter: None,
 1769            show_code_actions: None,
 1770            show_runnables: None,
 1771            show_breakpoints: None,
 1772            show_wrap_guides: None,
 1773            show_indent_guides,
 1774            placeholder_text: None,
 1775            highlight_order: 0,
 1776            highlighted_rows: HashMap::default(),
 1777            background_highlights: TreeMap::default(),
 1778            gutter_highlights: TreeMap::default(),
 1779            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1780            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1781            nav_history: None,
 1782            context_menu: RefCell::new(None),
 1783            context_menu_options: None,
 1784            mouse_context_menu: None,
 1785            completion_tasks: Vec::new(),
 1786            inline_blame_popover: None,
 1787            signature_help_state: SignatureHelpState::default(),
 1788            auto_signature_help: None,
 1789            find_all_references_task_sources: Vec::new(),
 1790            next_completion_id: 0,
 1791            next_inlay_id: 0,
 1792            code_action_providers,
 1793            available_code_actions: None,
 1794            code_actions_task: None,
 1795            quick_selection_highlight_task: None,
 1796            debounced_selection_highlight_task: None,
 1797            document_highlights_task: None,
 1798            linked_editing_range_task: None,
 1799            pending_rename: None,
 1800            searchable: true,
 1801            cursor_shape: EditorSettings::get_global(cx)
 1802                .cursor_shape
 1803                .unwrap_or_default(),
 1804            current_line_highlight: None,
 1805            autoindent_mode: Some(AutoindentMode::EachLine),
 1806            collapse_matches: false,
 1807            workspace: None,
 1808            input_enabled: true,
 1809            use_modal_editing: mode.is_full(),
 1810            read_only: mode.is_minimap(),
 1811            use_autoclose: true,
 1812            use_auto_surround: true,
 1813            auto_replace_emoji_shortcode: false,
 1814            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1815            leader_id: None,
 1816            remote_id: None,
 1817            hover_state: HoverState::default(),
 1818            pending_mouse_down: None,
 1819            hovered_link_state: None,
 1820            edit_prediction_provider: None,
 1821            active_inline_completion: None,
 1822            stale_inline_completion_in_menu: None,
 1823            edit_prediction_preview: EditPredictionPreview::Inactive {
 1824                released_too_fast: false,
 1825            },
 1826            inline_diagnostics_enabled: mode.is_full(),
 1827            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1828            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1829
 1830            gutter_hovered: false,
 1831            pixel_position_of_newest_cursor: None,
 1832            last_bounds: None,
 1833            last_position_map: None,
 1834            expect_bounds_change: None,
 1835            gutter_dimensions: GutterDimensions::default(),
 1836            style: None,
 1837            show_cursor_names: false,
 1838            hovered_cursors: HashMap::default(),
 1839            next_editor_action_id: EditorActionId::default(),
 1840            editor_actions: Rc::default(),
 1841            inline_completions_hidden_for_vim_mode: false,
 1842            show_inline_completions_override: None,
 1843            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1844            edit_prediction_settings: EditPredictionSettings::Disabled,
 1845            edit_prediction_indent_conflict: false,
 1846            edit_prediction_requires_modifier_in_indent_conflict: true,
 1847            custom_context_menu: None,
 1848            show_git_blame_gutter: false,
 1849            show_git_blame_inline: false,
 1850            show_selection_menu: None,
 1851            show_git_blame_inline_delay_task: None,
 1852            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1853            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1854            serialize_dirty_buffers: !mode.is_minimap()
 1855                && ProjectSettings::get_global(cx)
 1856                    .session
 1857                    .restore_unsaved_buffers,
 1858            blame: None,
 1859            blame_subscription: None,
 1860            tasks: BTreeMap::default(),
 1861
 1862            breakpoint_store,
 1863            gutter_breakpoint_indicator: (None, None),
 1864            _subscriptions: vec![
 1865                cx.observe(&buffer, Self::on_buffer_changed),
 1866                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1867                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1868                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1869                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1870                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1871                cx.observe_window_activation(window, |editor, window, cx| {
 1872                    let active = window.is_window_active();
 1873                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1874                        if active {
 1875                            blink_manager.enable(cx);
 1876                        } else {
 1877                            blink_manager.disable(cx);
 1878                        }
 1879                    });
 1880                }),
 1881            ],
 1882            tasks_update_task: None,
 1883            linked_edit_ranges: Default::default(),
 1884            in_project_search: false,
 1885            previous_search_ranges: None,
 1886            breadcrumb_header: None,
 1887            focused_block: None,
 1888            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1889            addons: HashMap::default(),
 1890            registered_buffers: HashMap::default(),
 1891            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1892            selection_mark_mode: false,
 1893            toggle_fold_multiple_buffers: Task::ready(()),
 1894            serialize_selections: Task::ready(()),
 1895            serialize_folds: Task::ready(()),
 1896            text_style_refinement: None,
 1897            load_diff_task: load_uncommitted_diff,
 1898            temporary_diff_override: false,
 1899            mouse_cursor_hidden: false,
 1900            minimap: None,
 1901            hide_mouse_mode: EditorSettings::get_global(cx)
 1902                .hide_mouse
 1903                .unwrap_or_default(),
 1904            change_list: ChangeList::new(),
 1905            mode,
 1906        };
 1907        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1908            this._subscriptions
 1909                .push(cx.observe(breakpoints, |_, _, cx| {
 1910                    cx.notify();
 1911                }));
 1912        }
 1913        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1914        this._subscriptions.extend(project_subscriptions);
 1915
 1916        this._subscriptions.push(cx.subscribe_in(
 1917            &cx.entity(),
 1918            window,
 1919            |editor, _, e: &EditorEvent, window, cx| match e {
 1920                EditorEvent::ScrollPositionChanged { local, .. } => {
 1921                    if *local {
 1922                        let new_anchor = editor.scroll_manager.anchor();
 1923                        let snapshot = editor.snapshot(window, cx);
 1924                        editor.update_restoration_data(cx, move |data| {
 1925                            data.scroll_position = (
 1926                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1927                                new_anchor.offset,
 1928                            );
 1929                        });
 1930                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1931                        editor.inline_blame_popover.take();
 1932                    }
 1933                }
 1934                EditorEvent::Edited { .. } => {
 1935                    if !vim_enabled(cx) {
 1936                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1937                        let pop_state = editor
 1938                            .change_list
 1939                            .last()
 1940                            .map(|previous| {
 1941                                previous.len() == selections.len()
 1942                                    && previous.iter().enumerate().all(|(ix, p)| {
 1943                                        p.to_display_point(&map).row()
 1944                                            == selections[ix].head().row()
 1945                                    })
 1946                            })
 1947                            .unwrap_or(false);
 1948                        let new_positions = selections
 1949                            .into_iter()
 1950                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1951                            .collect();
 1952                        editor
 1953                            .change_list
 1954                            .push_to_change_list(pop_state, new_positions);
 1955                    }
 1956                }
 1957                _ => (),
 1958            },
 1959        ));
 1960
 1961        if let Some(dap_store) = this
 1962            .project
 1963            .as_ref()
 1964            .map(|project| project.read(cx).dap_store())
 1965        {
 1966            let weak_editor = cx.weak_entity();
 1967
 1968            this._subscriptions
 1969                .push(
 1970                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1971                        let session_entity = cx.entity();
 1972                        weak_editor
 1973                            .update(cx, |editor, cx| {
 1974                                editor._subscriptions.push(
 1975                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1976                                );
 1977                            })
 1978                            .ok();
 1979                    }),
 1980                );
 1981
 1982            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1983                this._subscriptions
 1984                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1985            }
 1986        }
 1987
 1988        this.end_selection(window, cx);
 1989        this.scroll_manager.show_scrollbars(window, cx);
 1990        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1991
 1992        if full_mode {
 1993            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1994            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1995
 1996            if this.git_blame_inline_enabled {
 1997                this.start_git_blame_inline(false, window, cx);
 1998            }
 1999
 2000            this.go_to_active_debug_line(window, cx);
 2001
 2002            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2003                if let Some(project) = this.project.as_ref() {
 2004                    let handle = project.update(cx, |project, cx| {
 2005                        project.register_buffer_with_language_servers(&buffer, cx)
 2006                    });
 2007                    this.registered_buffers
 2008                        .insert(buffer.read(cx).remote_id(), handle);
 2009                }
 2010            }
 2011
 2012            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2013        }
 2014
 2015        this.report_editor_event("Editor Opened", None, cx);
 2016        this
 2017    }
 2018
 2019    pub fn deploy_mouse_context_menu(
 2020        &mut self,
 2021        position: gpui::Point<Pixels>,
 2022        context_menu: Entity<ContextMenu>,
 2023        window: &mut Window,
 2024        cx: &mut Context<Self>,
 2025    ) {
 2026        self.mouse_context_menu = Some(MouseContextMenu::new(
 2027            self,
 2028            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2029            context_menu,
 2030            window,
 2031            cx,
 2032        ));
 2033    }
 2034
 2035    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2036        self.mouse_context_menu
 2037            .as_ref()
 2038            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2039    }
 2040
 2041    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2042        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2043    }
 2044
 2045    fn key_context_internal(
 2046        &self,
 2047        has_active_edit_prediction: bool,
 2048        window: &Window,
 2049        cx: &App,
 2050    ) -> KeyContext {
 2051        let mut key_context = KeyContext::new_with_defaults();
 2052        key_context.add("Editor");
 2053        let mode = match self.mode {
 2054            EditorMode::SingleLine { .. } => "single_line",
 2055            EditorMode::AutoHeight { .. } => "auto_height",
 2056            EditorMode::Minimap { .. } => "minimap",
 2057            EditorMode::Full { .. } => "full",
 2058        };
 2059
 2060        if EditorSettings::jupyter_enabled(cx) {
 2061            key_context.add("jupyter");
 2062        }
 2063
 2064        key_context.set("mode", mode);
 2065        if self.pending_rename.is_some() {
 2066            key_context.add("renaming");
 2067        }
 2068
 2069        match self.context_menu.borrow().as_ref() {
 2070            Some(CodeContextMenu::Completions(_)) => {
 2071                key_context.add("menu");
 2072                key_context.add("showing_completions");
 2073            }
 2074            Some(CodeContextMenu::CodeActions(_)) => {
 2075                key_context.add("menu");
 2076                key_context.add("showing_code_actions")
 2077            }
 2078            None => {}
 2079        }
 2080
 2081        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2082        if !self.focus_handle(cx).contains_focused(window, cx)
 2083            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2084        {
 2085            for addon in self.addons.values() {
 2086                addon.extend_key_context(&mut key_context, cx)
 2087            }
 2088        }
 2089
 2090        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2091            if let Some(extension) = singleton_buffer
 2092                .read(cx)
 2093                .file()
 2094                .and_then(|file| file.path().extension()?.to_str())
 2095            {
 2096                key_context.set("extension", extension.to_string());
 2097            }
 2098        } else {
 2099            key_context.add("multibuffer");
 2100        }
 2101
 2102        if has_active_edit_prediction {
 2103            if self.edit_prediction_in_conflict() {
 2104                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2105            } else {
 2106                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2107                key_context.add("copilot_suggestion");
 2108            }
 2109        }
 2110
 2111        if self.selection_mark_mode {
 2112            key_context.add("selection_mode");
 2113        }
 2114
 2115        key_context
 2116    }
 2117
 2118    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2119        self.mouse_cursor_hidden = match origin {
 2120            HideMouseCursorOrigin::TypingAction => {
 2121                matches!(
 2122                    self.hide_mouse_mode,
 2123                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2124                )
 2125            }
 2126            HideMouseCursorOrigin::MovementAction => {
 2127                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2128            }
 2129        };
 2130    }
 2131
 2132    pub fn edit_prediction_in_conflict(&self) -> bool {
 2133        if !self.show_edit_predictions_in_menu() {
 2134            return false;
 2135        }
 2136
 2137        let showing_completions = self
 2138            .context_menu
 2139            .borrow()
 2140            .as_ref()
 2141            .map_or(false, |context| {
 2142                matches!(context, CodeContextMenu::Completions(_))
 2143            });
 2144
 2145        showing_completions
 2146            || self.edit_prediction_requires_modifier()
 2147            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2148            // bindings to insert tab characters.
 2149            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2150    }
 2151
 2152    pub fn accept_edit_prediction_keybind(
 2153        &self,
 2154        window: &Window,
 2155        cx: &App,
 2156    ) -> AcceptEditPredictionBinding {
 2157        let key_context = self.key_context_internal(true, window, cx);
 2158        let in_conflict = self.edit_prediction_in_conflict();
 2159
 2160        AcceptEditPredictionBinding(
 2161            window
 2162                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2163                .into_iter()
 2164                .filter(|binding| {
 2165                    !in_conflict
 2166                        || binding
 2167                            .keystrokes()
 2168                            .first()
 2169                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2170                })
 2171                .rev()
 2172                .min_by_key(|binding| {
 2173                    binding
 2174                        .keystrokes()
 2175                        .first()
 2176                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2177                }),
 2178        )
 2179    }
 2180
 2181    pub fn new_file(
 2182        workspace: &mut Workspace,
 2183        _: &workspace::NewFile,
 2184        window: &mut Window,
 2185        cx: &mut Context<Workspace>,
 2186    ) {
 2187        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2188            "Failed to create buffer",
 2189            window,
 2190            cx,
 2191            |e, _, _| match e.error_code() {
 2192                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2193                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2194                e.error_tag("required").unwrap_or("the latest version")
 2195            )),
 2196                _ => None,
 2197            },
 2198        );
 2199    }
 2200
 2201    pub fn new_in_workspace(
 2202        workspace: &mut Workspace,
 2203        window: &mut Window,
 2204        cx: &mut Context<Workspace>,
 2205    ) -> Task<Result<Entity<Editor>>> {
 2206        let project = workspace.project().clone();
 2207        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2208
 2209        cx.spawn_in(window, async move |workspace, cx| {
 2210            let buffer = create.await?;
 2211            workspace.update_in(cx, |workspace, window, cx| {
 2212                let editor =
 2213                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2214                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2215                editor
 2216            })
 2217        })
 2218    }
 2219
 2220    fn new_file_vertical(
 2221        workspace: &mut Workspace,
 2222        _: &workspace::NewFileSplitVertical,
 2223        window: &mut Window,
 2224        cx: &mut Context<Workspace>,
 2225    ) {
 2226        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2227    }
 2228
 2229    fn new_file_horizontal(
 2230        workspace: &mut Workspace,
 2231        _: &workspace::NewFileSplitHorizontal,
 2232        window: &mut Window,
 2233        cx: &mut Context<Workspace>,
 2234    ) {
 2235        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2236    }
 2237
 2238    fn new_file_in_direction(
 2239        workspace: &mut Workspace,
 2240        direction: SplitDirection,
 2241        window: &mut Window,
 2242        cx: &mut Context<Workspace>,
 2243    ) {
 2244        let project = workspace.project().clone();
 2245        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2246
 2247        cx.spawn_in(window, async move |workspace, cx| {
 2248            let buffer = create.await?;
 2249            workspace.update_in(cx, move |workspace, window, cx| {
 2250                workspace.split_item(
 2251                    direction,
 2252                    Box::new(
 2253                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2254                    ),
 2255                    window,
 2256                    cx,
 2257                )
 2258            })?;
 2259            anyhow::Ok(())
 2260        })
 2261        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2262            match e.error_code() {
 2263                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2264                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2265                e.error_tag("required").unwrap_or("the latest version")
 2266            )),
 2267                _ => None,
 2268            }
 2269        });
 2270    }
 2271
 2272    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2273        self.leader_id
 2274    }
 2275
 2276    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2277        &self.buffer
 2278    }
 2279
 2280    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2281        self.workspace.as_ref()?.0.upgrade()
 2282    }
 2283
 2284    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2285        self.buffer().read(cx).title(cx)
 2286    }
 2287
 2288    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2289        let git_blame_gutter_max_author_length = self
 2290            .render_git_blame_gutter(cx)
 2291            .then(|| {
 2292                if let Some(blame) = self.blame.as_ref() {
 2293                    let max_author_length =
 2294                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2295                    Some(max_author_length)
 2296                } else {
 2297                    None
 2298                }
 2299            })
 2300            .flatten();
 2301
 2302        EditorSnapshot {
 2303            mode: self.mode.clone(),
 2304            show_gutter: self.show_gutter,
 2305            show_line_numbers: self.show_line_numbers,
 2306            show_git_diff_gutter: self.show_git_diff_gutter,
 2307            show_runnables: self.show_runnables,
 2308            show_breakpoints: self.show_breakpoints,
 2309            git_blame_gutter_max_author_length,
 2310            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2311            scroll_anchor: self.scroll_manager.anchor(),
 2312            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2313            placeholder_text: self.placeholder_text.clone(),
 2314            is_focused: self.focus_handle.is_focused(window),
 2315            current_line_highlight: self
 2316                .current_line_highlight
 2317                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2318            gutter_hovered: self.gutter_hovered,
 2319        }
 2320    }
 2321
 2322    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2323        self.buffer.read(cx).language_at(point, cx)
 2324    }
 2325
 2326    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2327        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2328    }
 2329
 2330    pub fn active_excerpt(
 2331        &self,
 2332        cx: &App,
 2333    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2334        self.buffer
 2335            .read(cx)
 2336            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2337    }
 2338
 2339    pub fn mode(&self) -> &EditorMode {
 2340        &self.mode
 2341    }
 2342
 2343    pub fn set_mode(&mut self, mode: EditorMode) {
 2344        self.mode = mode;
 2345    }
 2346
 2347    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2348        self.collaboration_hub.as_deref()
 2349    }
 2350
 2351    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2352        self.collaboration_hub = Some(hub);
 2353    }
 2354
 2355    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2356        self.in_project_search = in_project_search;
 2357    }
 2358
 2359    pub fn set_custom_context_menu(
 2360        &mut self,
 2361        f: impl 'static
 2362        + Fn(
 2363            &mut Self,
 2364            DisplayPoint,
 2365            &mut Window,
 2366            &mut Context<Self>,
 2367        ) -> Option<Entity<ui::ContextMenu>>,
 2368    ) {
 2369        self.custom_context_menu = Some(Box::new(f))
 2370    }
 2371
 2372    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2373        self.completion_provider = provider;
 2374    }
 2375
 2376    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2377        self.semantics_provider.clone()
 2378    }
 2379
 2380    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2381        self.semantics_provider = provider;
 2382    }
 2383
 2384    pub fn set_edit_prediction_provider<T>(
 2385        &mut self,
 2386        provider: Option<Entity<T>>,
 2387        window: &mut Window,
 2388        cx: &mut Context<Self>,
 2389    ) where
 2390        T: EditPredictionProvider,
 2391    {
 2392        self.edit_prediction_provider =
 2393            provider.map(|provider| RegisteredInlineCompletionProvider {
 2394                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2395                    if this.focus_handle.is_focused(window) {
 2396                        this.update_visible_inline_completion(window, cx);
 2397                    }
 2398                }),
 2399                provider: Arc::new(provider),
 2400            });
 2401        self.update_edit_prediction_settings(cx);
 2402        self.refresh_inline_completion(false, false, window, cx);
 2403    }
 2404
 2405    pub fn placeholder_text(&self) -> Option<&str> {
 2406        self.placeholder_text.as_deref()
 2407    }
 2408
 2409    pub fn set_placeholder_text(
 2410        &mut self,
 2411        placeholder_text: impl Into<Arc<str>>,
 2412        cx: &mut Context<Self>,
 2413    ) {
 2414        let placeholder_text = Some(placeholder_text.into());
 2415        if self.placeholder_text != placeholder_text {
 2416            self.placeholder_text = placeholder_text;
 2417            cx.notify();
 2418        }
 2419    }
 2420
 2421    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2422        self.cursor_shape = cursor_shape;
 2423
 2424        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2425        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2426
 2427        cx.notify();
 2428    }
 2429
 2430    pub fn set_current_line_highlight(
 2431        &mut self,
 2432        current_line_highlight: Option<CurrentLineHighlight>,
 2433    ) {
 2434        self.current_line_highlight = current_line_highlight;
 2435    }
 2436
 2437    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2438        self.collapse_matches = collapse_matches;
 2439    }
 2440
 2441    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2442        let buffers = self.buffer.read(cx).all_buffers();
 2443        let Some(project) = self.project.as_ref() else {
 2444            return;
 2445        };
 2446        project.update(cx, |project, cx| {
 2447            for buffer in buffers {
 2448                self.registered_buffers
 2449                    .entry(buffer.read(cx).remote_id())
 2450                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2451            }
 2452        })
 2453    }
 2454
 2455    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2456        if self.collapse_matches {
 2457            return range.start..range.start;
 2458        }
 2459        range.clone()
 2460    }
 2461
 2462    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2463        if self.display_map.read(cx).clip_at_line_ends != clip {
 2464            self.display_map
 2465                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2466        }
 2467    }
 2468
 2469    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2470        self.input_enabled = input_enabled;
 2471    }
 2472
 2473    pub fn set_inline_completions_hidden_for_vim_mode(
 2474        &mut self,
 2475        hidden: bool,
 2476        window: &mut Window,
 2477        cx: &mut Context<Self>,
 2478    ) {
 2479        if hidden != self.inline_completions_hidden_for_vim_mode {
 2480            self.inline_completions_hidden_for_vim_mode = hidden;
 2481            if hidden {
 2482                self.update_visible_inline_completion(window, cx);
 2483            } else {
 2484                self.refresh_inline_completion(true, false, window, cx);
 2485            }
 2486        }
 2487    }
 2488
 2489    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2490        self.menu_inline_completions_policy = value;
 2491    }
 2492
 2493    pub fn set_autoindent(&mut self, autoindent: bool) {
 2494        if autoindent {
 2495            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2496        } else {
 2497            self.autoindent_mode = None;
 2498        }
 2499    }
 2500
 2501    pub fn read_only(&self, cx: &App) -> bool {
 2502        self.read_only || self.buffer.read(cx).read_only()
 2503    }
 2504
 2505    pub fn set_read_only(&mut self, read_only: bool) {
 2506        self.read_only = read_only;
 2507    }
 2508
 2509    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2510        self.use_autoclose = autoclose;
 2511    }
 2512
 2513    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2514        self.use_auto_surround = auto_surround;
 2515    }
 2516
 2517    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2518        self.auto_replace_emoji_shortcode = auto_replace;
 2519    }
 2520
 2521    pub fn toggle_edit_predictions(
 2522        &mut self,
 2523        _: &ToggleEditPrediction,
 2524        window: &mut Window,
 2525        cx: &mut Context<Self>,
 2526    ) {
 2527        if self.show_inline_completions_override.is_some() {
 2528            self.set_show_edit_predictions(None, window, cx);
 2529        } else {
 2530            let show_edit_predictions = !self.edit_predictions_enabled();
 2531            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2532        }
 2533    }
 2534
 2535    pub fn set_show_edit_predictions(
 2536        &mut self,
 2537        show_edit_predictions: Option<bool>,
 2538        window: &mut Window,
 2539        cx: &mut Context<Self>,
 2540    ) {
 2541        self.show_inline_completions_override = show_edit_predictions;
 2542        self.update_edit_prediction_settings(cx);
 2543
 2544        if let Some(false) = show_edit_predictions {
 2545            self.discard_inline_completion(false, cx);
 2546        } else {
 2547            self.refresh_inline_completion(false, true, window, cx);
 2548        }
 2549    }
 2550
 2551    fn inline_completions_disabled_in_scope(
 2552        &self,
 2553        buffer: &Entity<Buffer>,
 2554        buffer_position: language::Anchor,
 2555        cx: &App,
 2556    ) -> bool {
 2557        let snapshot = buffer.read(cx).snapshot();
 2558        let settings = snapshot.settings_at(buffer_position, cx);
 2559
 2560        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2561            return false;
 2562        };
 2563
 2564        scope.override_name().map_or(false, |scope_name| {
 2565            settings
 2566                .edit_predictions_disabled_in
 2567                .iter()
 2568                .any(|s| s == scope_name)
 2569        })
 2570    }
 2571
 2572    pub fn set_use_modal_editing(&mut self, to: bool) {
 2573        self.use_modal_editing = to;
 2574    }
 2575
 2576    pub fn use_modal_editing(&self) -> bool {
 2577        self.use_modal_editing
 2578    }
 2579
 2580    fn selections_did_change(
 2581        &mut self,
 2582        local: bool,
 2583        old_cursor_position: &Anchor,
 2584        show_completions: bool,
 2585        window: &mut Window,
 2586        cx: &mut Context<Self>,
 2587    ) {
 2588        window.invalidate_character_coordinates();
 2589
 2590        // Copy selections to primary selection buffer
 2591        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2592        if local {
 2593            let selections = self.selections.all::<usize>(cx);
 2594            let buffer_handle = self.buffer.read(cx).read(cx);
 2595
 2596            let mut text = String::new();
 2597            for (index, selection) in selections.iter().enumerate() {
 2598                let text_for_selection = buffer_handle
 2599                    .text_for_range(selection.start..selection.end)
 2600                    .collect::<String>();
 2601
 2602                text.push_str(&text_for_selection);
 2603                if index != selections.len() - 1 {
 2604                    text.push('\n');
 2605                }
 2606            }
 2607
 2608            if !text.is_empty() {
 2609                cx.write_to_primary(ClipboardItem::new_string(text));
 2610            }
 2611        }
 2612
 2613        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2614            self.buffer.update(cx, |buffer, cx| {
 2615                buffer.set_active_selections(
 2616                    &self.selections.disjoint_anchors(),
 2617                    self.selections.line_mode,
 2618                    self.cursor_shape,
 2619                    cx,
 2620                )
 2621            });
 2622        }
 2623        let display_map = self
 2624            .display_map
 2625            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2626        let buffer = &display_map.buffer_snapshot;
 2627        self.add_selections_state = None;
 2628        self.select_next_state = None;
 2629        self.select_prev_state = None;
 2630        self.select_syntax_node_history.try_clear();
 2631        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2632        self.snippet_stack
 2633            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2634        self.take_rename(false, window, cx);
 2635
 2636        let new_cursor_position = self.selections.newest_anchor().head();
 2637
 2638        self.push_to_nav_history(
 2639            *old_cursor_position,
 2640            Some(new_cursor_position.to_point(buffer)),
 2641            false,
 2642            cx,
 2643        );
 2644
 2645        if local {
 2646            let new_cursor_position = self.selections.newest_anchor().head();
 2647            let mut context_menu = self.context_menu.borrow_mut();
 2648            let completion_menu = match context_menu.as_ref() {
 2649                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2650                _ => {
 2651                    *context_menu = None;
 2652                    None
 2653                }
 2654            };
 2655            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2656                if !self.registered_buffers.contains_key(&buffer_id) {
 2657                    if let Some(project) = self.project.as_ref() {
 2658                        project.update(cx, |project, cx| {
 2659                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2660                                return;
 2661                            };
 2662                            self.registered_buffers.insert(
 2663                                buffer_id,
 2664                                project.register_buffer_with_language_servers(&buffer, cx),
 2665                            );
 2666                        })
 2667                    }
 2668                }
 2669            }
 2670
 2671            if let Some(completion_menu) = completion_menu {
 2672                let cursor_position = new_cursor_position.to_offset(buffer);
 2673                let (word_range, kind) =
 2674                    buffer.surrounding_word(completion_menu.initial_position, true);
 2675                if kind == Some(CharKind::Word)
 2676                    && word_range.to_inclusive().contains(&cursor_position)
 2677                {
 2678                    let mut completion_menu = completion_menu.clone();
 2679                    drop(context_menu);
 2680
 2681                    let query = Self::completion_query(buffer, cursor_position);
 2682                    cx.spawn(async move |this, cx| {
 2683                        completion_menu
 2684                            .filter(query.as_deref(), cx.background_executor().clone())
 2685                            .await;
 2686
 2687                        this.update(cx, |this, cx| {
 2688                            let mut context_menu = this.context_menu.borrow_mut();
 2689                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2690                            else {
 2691                                return;
 2692                            };
 2693
 2694                            if menu.id > completion_menu.id {
 2695                                return;
 2696                            }
 2697
 2698                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2699                            drop(context_menu);
 2700                            cx.notify();
 2701                        })
 2702                    })
 2703                    .detach();
 2704
 2705                    if show_completions {
 2706                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2707                    }
 2708                } else {
 2709                    drop(context_menu);
 2710                    self.hide_context_menu(window, cx);
 2711                }
 2712            } else {
 2713                drop(context_menu);
 2714            }
 2715
 2716            hide_hover(self, cx);
 2717
 2718            if old_cursor_position.to_display_point(&display_map).row()
 2719                != new_cursor_position.to_display_point(&display_map).row()
 2720            {
 2721                self.available_code_actions.take();
 2722            }
 2723            self.refresh_code_actions(window, cx);
 2724            self.refresh_document_highlights(cx);
 2725            self.refresh_selected_text_highlights(false, window, cx);
 2726            refresh_matching_bracket_highlights(self, window, cx);
 2727            self.update_visible_inline_completion(window, cx);
 2728            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2729            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2730            self.inline_blame_popover.take();
 2731            if self.git_blame_inline_enabled {
 2732                self.start_inline_blame_timer(window, cx);
 2733            }
 2734        }
 2735
 2736        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2737        cx.emit(EditorEvent::SelectionsChanged { local });
 2738
 2739        let selections = &self.selections.disjoint;
 2740        if selections.len() == 1 {
 2741            cx.emit(SearchEvent::ActiveMatchChanged)
 2742        }
 2743        if local {
 2744            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2745                let inmemory_selections = selections
 2746                    .iter()
 2747                    .map(|s| {
 2748                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2749                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2750                    })
 2751                    .collect();
 2752                self.update_restoration_data(cx, |data| {
 2753                    data.selections = inmemory_selections;
 2754                });
 2755
 2756                if WorkspaceSettings::get(None, cx).restore_on_startup
 2757                    != RestoreOnStartupBehavior::None
 2758                {
 2759                    if let Some(workspace_id) =
 2760                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2761                    {
 2762                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2763                        let selections = selections.clone();
 2764                        let background_executor = cx.background_executor().clone();
 2765                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2766                        self.serialize_selections = cx.background_spawn(async move {
 2767                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2768                    let db_selections = selections
 2769                        .iter()
 2770                        .map(|selection| {
 2771                            (
 2772                                selection.start.to_offset(&snapshot),
 2773                                selection.end.to_offset(&snapshot),
 2774                            )
 2775                        })
 2776                        .collect();
 2777
 2778                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2779                        .await
 2780                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2781                        .log_err();
 2782                });
 2783                    }
 2784                }
 2785            }
 2786        }
 2787
 2788        cx.notify();
 2789    }
 2790
 2791    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2792        use text::ToOffset as _;
 2793        use text::ToPoint as _;
 2794
 2795        if self.mode.is_minimap()
 2796            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2797        {
 2798            return;
 2799        }
 2800
 2801        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2802            return;
 2803        };
 2804
 2805        let snapshot = singleton.read(cx).snapshot();
 2806        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2807            let display_snapshot = display_map.snapshot(cx);
 2808
 2809            display_snapshot
 2810                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2811                .map(|fold| {
 2812                    fold.range.start.text_anchor.to_point(&snapshot)
 2813                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2814                })
 2815                .collect()
 2816        });
 2817        self.update_restoration_data(cx, |data| {
 2818            data.folds = inmemory_folds;
 2819        });
 2820
 2821        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2822            return;
 2823        };
 2824        let background_executor = cx.background_executor().clone();
 2825        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2826        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2827            display_map
 2828                .snapshot(cx)
 2829                .folds_in_range(0..snapshot.len())
 2830                .map(|fold| {
 2831                    (
 2832                        fold.range.start.text_anchor.to_offset(&snapshot),
 2833                        fold.range.end.text_anchor.to_offset(&snapshot),
 2834                    )
 2835                })
 2836                .collect()
 2837        });
 2838        self.serialize_folds = cx.background_spawn(async move {
 2839            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2840            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2841                .await
 2842                .with_context(|| {
 2843                    format!(
 2844                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2845                    )
 2846                })
 2847                .log_err();
 2848        });
 2849    }
 2850
 2851    pub fn sync_selections(
 2852        &mut self,
 2853        other: Entity<Editor>,
 2854        cx: &mut Context<Self>,
 2855    ) -> gpui::Subscription {
 2856        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2857        self.selections.change_with(cx, |selections| {
 2858            selections.select_anchors(other_selections);
 2859        });
 2860
 2861        let other_subscription =
 2862            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2863                EditorEvent::SelectionsChanged { local: true } => {
 2864                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2865                    if other_selections.is_empty() {
 2866                        return;
 2867                    }
 2868                    this.selections.change_with(cx, |selections| {
 2869                        selections.select_anchors(other_selections);
 2870                    });
 2871                }
 2872                _ => {}
 2873            });
 2874
 2875        let this_subscription =
 2876            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2877                EditorEvent::SelectionsChanged { local: true } => {
 2878                    let these_selections = this.selections.disjoint.to_vec();
 2879                    if these_selections.is_empty() {
 2880                        return;
 2881                    }
 2882                    other.update(cx, |other_editor, cx| {
 2883                        other_editor.selections.change_with(cx, |selections| {
 2884                            selections.select_anchors(these_selections);
 2885                        })
 2886                    });
 2887                }
 2888                _ => {}
 2889            });
 2890
 2891        Subscription::join(other_subscription, this_subscription)
 2892    }
 2893
 2894    pub fn change_selections<R>(
 2895        &mut self,
 2896        autoscroll: Option<Autoscroll>,
 2897        window: &mut Window,
 2898        cx: &mut Context<Self>,
 2899        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2900    ) -> R {
 2901        self.change_selections_inner(autoscroll, true, window, cx, change)
 2902    }
 2903
 2904    fn change_selections_inner<R>(
 2905        &mut self,
 2906        autoscroll: Option<Autoscroll>,
 2907        request_completions: bool,
 2908        window: &mut Window,
 2909        cx: &mut Context<Self>,
 2910        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2911    ) -> R {
 2912        let old_cursor_position = self.selections.newest_anchor().head();
 2913        self.push_to_selection_history();
 2914
 2915        let (changed, result) = self.selections.change_with(cx, change);
 2916
 2917        if changed {
 2918            if let Some(autoscroll) = autoscroll {
 2919                self.request_autoscroll(autoscroll, cx);
 2920            }
 2921            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2922
 2923            if self.should_open_signature_help_automatically(
 2924                &old_cursor_position,
 2925                self.signature_help_state.backspace_pressed(),
 2926                cx,
 2927            ) {
 2928                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2929            }
 2930            self.signature_help_state.set_backspace_pressed(false);
 2931        }
 2932
 2933        result
 2934    }
 2935
 2936    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2937    where
 2938        I: IntoIterator<Item = (Range<S>, T)>,
 2939        S: ToOffset,
 2940        T: Into<Arc<str>>,
 2941    {
 2942        if self.read_only(cx) {
 2943            return;
 2944        }
 2945
 2946        self.buffer
 2947            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2948    }
 2949
 2950    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2951    where
 2952        I: IntoIterator<Item = (Range<S>, T)>,
 2953        S: ToOffset,
 2954        T: Into<Arc<str>>,
 2955    {
 2956        if self.read_only(cx) {
 2957            return;
 2958        }
 2959
 2960        self.buffer.update(cx, |buffer, cx| {
 2961            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2962        });
 2963    }
 2964
 2965    pub fn edit_with_block_indent<I, S, T>(
 2966        &mut self,
 2967        edits: I,
 2968        original_indent_columns: Vec<Option<u32>>,
 2969        cx: &mut Context<Self>,
 2970    ) where
 2971        I: IntoIterator<Item = (Range<S>, T)>,
 2972        S: ToOffset,
 2973        T: Into<Arc<str>>,
 2974    {
 2975        if self.read_only(cx) {
 2976            return;
 2977        }
 2978
 2979        self.buffer.update(cx, |buffer, cx| {
 2980            buffer.edit(
 2981                edits,
 2982                Some(AutoindentMode::Block {
 2983                    original_indent_columns,
 2984                }),
 2985                cx,
 2986            )
 2987        });
 2988    }
 2989
 2990    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2991        self.hide_context_menu(window, cx);
 2992
 2993        match phase {
 2994            SelectPhase::Begin {
 2995                position,
 2996                add,
 2997                click_count,
 2998            } => self.begin_selection(position, add, click_count, window, cx),
 2999            SelectPhase::BeginColumnar {
 3000                position,
 3001                goal_column,
 3002                reset,
 3003            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3004            SelectPhase::Extend {
 3005                position,
 3006                click_count,
 3007            } => self.extend_selection(position, click_count, window, cx),
 3008            SelectPhase::Update {
 3009                position,
 3010                goal_column,
 3011                scroll_delta,
 3012            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3013            SelectPhase::End => self.end_selection(window, cx),
 3014        }
 3015    }
 3016
 3017    fn extend_selection(
 3018        &mut self,
 3019        position: DisplayPoint,
 3020        click_count: usize,
 3021        window: &mut Window,
 3022        cx: &mut Context<Self>,
 3023    ) {
 3024        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3025        let tail = self.selections.newest::<usize>(cx).tail();
 3026        self.begin_selection(position, false, click_count, window, cx);
 3027
 3028        let position = position.to_offset(&display_map, Bias::Left);
 3029        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3030
 3031        let mut pending_selection = self
 3032            .selections
 3033            .pending_anchor()
 3034            .expect("extend_selection not called with pending selection");
 3035        if position >= tail {
 3036            pending_selection.start = tail_anchor;
 3037        } else {
 3038            pending_selection.end = tail_anchor;
 3039            pending_selection.reversed = true;
 3040        }
 3041
 3042        let mut pending_mode = self.selections.pending_mode().unwrap();
 3043        match &mut pending_mode {
 3044            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3045            _ => {}
 3046        }
 3047
 3048        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3049
 3050        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3051            s.set_pending(pending_selection, pending_mode)
 3052        });
 3053    }
 3054
 3055    fn begin_selection(
 3056        &mut self,
 3057        position: DisplayPoint,
 3058        add: bool,
 3059        click_count: usize,
 3060        window: &mut Window,
 3061        cx: &mut Context<Self>,
 3062    ) {
 3063        if !self.focus_handle.is_focused(window) {
 3064            self.last_focused_descendant = None;
 3065            window.focus(&self.focus_handle);
 3066        }
 3067
 3068        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3069        let buffer = &display_map.buffer_snapshot;
 3070        let position = display_map.clip_point(position, Bias::Left);
 3071
 3072        let start;
 3073        let end;
 3074        let mode;
 3075        let mut auto_scroll;
 3076        match click_count {
 3077            1 => {
 3078                start = buffer.anchor_before(position.to_point(&display_map));
 3079                end = start;
 3080                mode = SelectMode::Character;
 3081                auto_scroll = true;
 3082            }
 3083            2 => {
 3084                let range = movement::surrounding_word(&display_map, position);
 3085                start = buffer.anchor_before(range.start.to_point(&display_map));
 3086                end = buffer.anchor_before(range.end.to_point(&display_map));
 3087                mode = SelectMode::Word(start..end);
 3088                auto_scroll = true;
 3089            }
 3090            3 => {
 3091                let position = display_map
 3092                    .clip_point(position, Bias::Left)
 3093                    .to_point(&display_map);
 3094                let line_start = display_map.prev_line_boundary(position).0;
 3095                let next_line_start = buffer.clip_point(
 3096                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3097                    Bias::Left,
 3098                );
 3099                start = buffer.anchor_before(line_start);
 3100                end = buffer.anchor_before(next_line_start);
 3101                mode = SelectMode::Line(start..end);
 3102                auto_scroll = true;
 3103            }
 3104            _ => {
 3105                start = buffer.anchor_before(0);
 3106                end = buffer.anchor_before(buffer.len());
 3107                mode = SelectMode::All;
 3108                auto_scroll = false;
 3109            }
 3110        }
 3111        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3112
 3113        let point_to_delete: Option<usize> = {
 3114            let selected_points: Vec<Selection<Point>> =
 3115                self.selections.disjoint_in_range(start..end, cx);
 3116
 3117            if !add || click_count > 1 {
 3118                None
 3119            } else if !selected_points.is_empty() {
 3120                Some(selected_points[0].id)
 3121            } else {
 3122                let clicked_point_already_selected =
 3123                    self.selections.disjoint.iter().find(|selection| {
 3124                        selection.start.to_point(buffer) == start.to_point(buffer)
 3125                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3126                    });
 3127
 3128                clicked_point_already_selected.map(|selection| selection.id)
 3129            }
 3130        };
 3131
 3132        let selections_count = self.selections.count();
 3133
 3134        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3135            if let Some(point_to_delete) = point_to_delete {
 3136                s.delete(point_to_delete);
 3137
 3138                if selections_count == 1 {
 3139                    s.set_pending_anchor_range(start..end, mode);
 3140                }
 3141            } else {
 3142                if !add {
 3143                    s.clear_disjoint();
 3144                }
 3145
 3146                s.set_pending_anchor_range(start..end, mode);
 3147            }
 3148        });
 3149    }
 3150
 3151    fn begin_columnar_selection(
 3152        &mut self,
 3153        position: DisplayPoint,
 3154        goal_column: u32,
 3155        reset: bool,
 3156        window: &mut Window,
 3157        cx: &mut Context<Self>,
 3158    ) {
 3159        if !self.focus_handle.is_focused(window) {
 3160            self.last_focused_descendant = None;
 3161            window.focus(&self.focus_handle);
 3162        }
 3163
 3164        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3165
 3166        if reset {
 3167            let pointer_position = display_map
 3168                .buffer_snapshot
 3169                .anchor_before(position.to_point(&display_map));
 3170
 3171            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3172                s.clear_disjoint();
 3173                s.set_pending_anchor_range(
 3174                    pointer_position..pointer_position,
 3175                    SelectMode::Character,
 3176                );
 3177            });
 3178        }
 3179
 3180        let tail = self.selections.newest::<Point>(cx).tail();
 3181        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3182
 3183        if !reset {
 3184            self.select_columns(
 3185                tail.to_display_point(&display_map),
 3186                position,
 3187                goal_column,
 3188                &display_map,
 3189                window,
 3190                cx,
 3191            );
 3192        }
 3193    }
 3194
 3195    fn update_selection(
 3196        &mut self,
 3197        position: DisplayPoint,
 3198        goal_column: u32,
 3199        scroll_delta: gpui::Point<f32>,
 3200        window: &mut Window,
 3201        cx: &mut Context<Self>,
 3202    ) {
 3203        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3204
 3205        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3206            let tail = tail.to_display_point(&display_map);
 3207            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3208        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3209            let buffer = self.buffer.read(cx).snapshot(cx);
 3210            let head;
 3211            let tail;
 3212            let mode = self.selections.pending_mode().unwrap();
 3213            match &mode {
 3214                SelectMode::Character => {
 3215                    head = position.to_point(&display_map);
 3216                    tail = pending.tail().to_point(&buffer);
 3217                }
 3218                SelectMode::Word(original_range) => {
 3219                    let original_display_range = original_range.start.to_display_point(&display_map)
 3220                        ..original_range.end.to_display_point(&display_map);
 3221                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3222                        ..original_display_range.end.to_point(&display_map);
 3223                    if movement::is_inside_word(&display_map, position)
 3224                        || original_display_range.contains(&position)
 3225                    {
 3226                        let word_range = movement::surrounding_word(&display_map, position);
 3227                        if word_range.start < original_display_range.start {
 3228                            head = word_range.start.to_point(&display_map);
 3229                        } else {
 3230                            head = word_range.end.to_point(&display_map);
 3231                        }
 3232                    } else {
 3233                        head = position.to_point(&display_map);
 3234                    }
 3235
 3236                    if head <= original_buffer_range.start {
 3237                        tail = original_buffer_range.end;
 3238                    } else {
 3239                        tail = original_buffer_range.start;
 3240                    }
 3241                }
 3242                SelectMode::Line(original_range) => {
 3243                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3244
 3245                    let position = display_map
 3246                        .clip_point(position, Bias::Left)
 3247                        .to_point(&display_map);
 3248                    let line_start = display_map.prev_line_boundary(position).0;
 3249                    let next_line_start = buffer.clip_point(
 3250                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3251                        Bias::Left,
 3252                    );
 3253
 3254                    if line_start < original_range.start {
 3255                        head = line_start
 3256                    } else {
 3257                        head = next_line_start
 3258                    }
 3259
 3260                    if head <= original_range.start {
 3261                        tail = original_range.end;
 3262                    } else {
 3263                        tail = original_range.start;
 3264                    }
 3265                }
 3266                SelectMode::All => {
 3267                    return;
 3268                }
 3269            };
 3270
 3271            if head < tail {
 3272                pending.start = buffer.anchor_before(head);
 3273                pending.end = buffer.anchor_before(tail);
 3274                pending.reversed = true;
 3275            } else {
 3276                pending.start = buffer.anchor_before(tail);
 3277                pending.end = buffer.anchor_before(head);
 3278                pending.reversed = false;
 3279            }
 3280
 3281            self.change_selections(None, window, cx, |s| {
 3282                s.set_pending(pending, mode);
 3283            });
 3284        } else {
 3285            log::error!("update_selection dispatched with no pending selection");
 3286            return;
 3287        }
 3288
 3289        self.apply_scroll_delta(scroll_delta, window, cx);
 3290        cx.notify();
 3291    }
 3292
 3293    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3294        self.columnar_selection_tail.take();
 3295        if self.selections.pending_anchor().is_some() {
 3296            let selections = self.selections.all::<usize>(cx);
 3297            self.change_selections(None, window, cx, |s| {
 3298                s.select(selections);
 3299                s.clear_pending();
 3300            });
 3301        }
 3302    }
 3303
 3304    fn select_columns(
 3305        &mut self,
 3306        tail: DisplayPoint,
 3307        head: DisplayPoint,
 3308        goal_column: u32,
 3309        display_map: &DisplaySnapshot,
 3310        window: &mut Window,
 3311        cx: &mut Context<Self>,
 3312    ) {
 3313        let start_row = cmp::min(tail.row(), head.row());
 3314        let end_row = cmp::max(tail.row(), head.row());
 3315        let start_column = cmp::min(tail.column(), goal_column);
 3316        let end_column = cmp::max(tail.column(), goal_column);
 3317        let reversed = start_column < tail.column();
 3318
 3319        let selection_ranges = (start_row.0..=end_row.0)
 3320            .map(DisplayRow)
 3321            .filter_map(|row| {
 3322                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3323                    let start = display_map
 3324                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3325                        .to_point(display_map);
 3326                    let end = display_map
 3327                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3328                        .to_point(display_map);
 3329                    if reversed {
 3330                        Some(end..start)
 3331                    } else {
 3332                        Some(start..end)
 3333                    }
 3334                } else {
 3335                    None
 3336                }
 3337            })
 3338            .collect::<Vec<_>>();
 3339
 3340        self.change_selections(None, window, cx, |s| {
 3341            s.select_ranges(selection_ranges);
 3342        });
 3343        cx.notify();
 3344    }
 3345
 3346    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3347        self.selections
 3348            .all_adjusted(cx)
 3349            .iter()
 3350            .any(|selection| !selection.is_empty())
 3351    }
 3352
 3353    pub fn has_pending_nonempty_selection(&self) -> bool {
 3354        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3355            Some(Selection { start, end, .. }) => start != end,
 3356            None => false,
 3357        };
 3358
 3359        pending_nonempty_selection
 3360            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3361    }
 3362
 3363    pub fn has_pending_selection(&self) -> bool {
 3364        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3365    }
 3366
 3367    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3368        self.selection_mark_mode = false;
 3369
 3370        if self.clear_expanded_diff_hunks(cx) {
 3371            cx.notify();
 3372            return;
 3373        }
 3374        if self.dismiss_menus_and_popups(true, window, cx) {
 3375            return;
 3376        }
 3377
 3378        if self.mode.is_full()
 3379            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3380        {
 3381            return;
 3382        }
 3383
 3384        cx.propagate();
 3385    }
 3386
 3387    pub fn dismiss_menus_and_popups(
 3388        &mut self,
 3389        is_user_requested: bool,
 3390        window: &mut Window,
 3391        cx: &mut Context<Self>,
 3392    ) -> bool {
 3393        if self.take_rename(false, window, cx).is_some() {
 3394            return true;
 3395        }
 3396
 3397        if hide_hover(self, cx) {
 3398            return true;
 3399        }
 3400
 3401        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3402            return true;
 3403        }
 3404
 3405        if self.hide_context_menu(window, cx).is_some() {
 3406            return true;
 3407        }
 3408
 3409        if self.mouse_context_menu.take().is_some() {
 3410            return true;
 3411        }
 3412
 3413        if is_user_requested && self.discard_inline_completion(true, cx) {
 3414            return true;
 3415        }
 3416
 3417        if self.snippet_stack.pop().is_some() {
 3418            return true;
 3419        }
 3420
 3421        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3422            self.dismiss_diagnostics(cx);
 3423            return true;
 3424        }
 3425
 3426        false
 3427    }
 3428
 3429    fn linked_editing_ranges_for(
 3430        &self,
 3431        selection: Range<text::Anchor>,
 3432        cx: &App,
 3433    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3434        if self.linked_edit_ranges.is_empty() {
 3435            return None;
 3436        }
 3437        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3438            selection.end.buffer_id.and_then(|end_buffer_id| {
 3439                if selection.start.buffer_id != Some(end_buffer_id) {
 3440                    return None;
 3441                }
 3442                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3443                let snapshot = buffer.read(cx).snapshot();
 3444                self.linked_edit_ranges
 3445                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3446                    .map(|ranges| (ranges, snapshot, buffer))
 3447            })?;
 3448        use text::ToOffset as TO;
 3449        // find offset from the start of current range to current cursor position
 3450        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3451
 3452        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3453        let start_difference = start_offset - start_byte_offset;
 3454        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3455        let end_difference = end_offset - start_byte_offset;
 3456        // Current range has associated linked ranges.
 3457        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3458        for range in linked_ranges.iter() {
 3459            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3460            let end_offset = start_offset + end_difference;
 3461            let start_offset = start_offset + start_difference;
 3462            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3463                continue;
 3464            }
 3465            if self.selections.disjoint_anchor_ranges().any(|s| {
 3466                if s.start.buffer_id != selection.start.buffer_id
 3467                    || s.end.buffer_id != selection.end.buffer_id
 3468                {
 3469                    return false;
 3470                }
 3471                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3472                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3473            }) {
 3474                continue;
 3475            }
 3476            let start = buffer_snapshot.anchor_after(start_offset);
 3477            let end = buffer_snapshot.anchor_after(end_offset);
 3478            linked_edits
 3479                .entry(buffer.clone())
 3480                .or_default()
 3481                .push(start..end);
 3482        }
 3483        Some(linked_edits)
 3484    }
 3485
 3486    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3487        let text: Arc<str> = text.into();
 3488
 3489        if self.read_only(cx) {
 3490            return;
 3491        }
 3492
 3493        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3494
 3495        let selections = self.selections.all_adjusted(cx);
 3496        let mut bracket_inserted = false;
 3497        let mut edits = Vec::new();
 3498        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3499        let mut new_selections = Vec::with_capacity(selections.len());
 3500        let mut new_autoclose_regions = Vec::new();
 3501        let snapshot = self.buffer.read(cx).read(cx);
 3502        let mut clear_linked_edit_ranges = false;
 3503
 3504        for (selection, autoclose_region) in
 3505            self.selections_with_autoclose_regions(selections, &snapshot)
 3506        {
 3507            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3508                // Determine if the inserted text matches the opening or closing
 3509                // bracket of any of this language's bracket pairs.
 3510                let mut bracket_pair = None;
 3511                let mut is_bracket_pair_start = false;
 3512                let mut is_bracket_pair_end = false;
 3513                if !text.is_empty() {
 3514                    let mut bracket_pair_matching_end = None;
 3515                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3516                    //  and they are removing the character that triggered IME popup.
 3517                    for (pair, enabled) in scope.brackets() {
 3518                        if !pair.close && !pair.surround {
 3519                            continue;
 3520                        }
 3521
 3522                        if enabled && pair.start.ends_with(text.as_ref()) {
 3523                            let prefix_len = pair.start.len() - text.len();
 3524                            let preceding_text_matches_prefix = prefix_len == 0
 3525                                || (selection.start.column >= (prefix_len as u32)
 3526                                    && snapshot.contains_str_at(
 3527                                        Point::new(
 3528                                            selection.start.row,
 3529                                            selection.start.column - (prefix_len as u32),
 3530                                        ),
 3531                                        &pair.start[..prefix_len],
 3532                                    ));
 3533                            if preceding_text_matches_prefix {
 3534                                bracket_pair = Some(pair.clone());
 3535                                is_bracket_pair_start = true;
 3536                                break;
 3537                            }
 3538                        }
 3539                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3540                        {
 3541                            // take first bracket pair matching end, but don't break in case a later bracket
 3542                            // pair matches start
 3543                            bracket_pair_matching_end = Some(pair.clone());
 3544                        }
 3545                    }
 3546                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3547                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3548                        is_bracket_pair_end = true;
 3549                    }
 3550                }
 3551
 3552                if let Some(bracket_pair) = bracket_pair {
 3553                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3554                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3555                    let auto_surround =
 3556                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3557                    if selection.is_empty() {
 3558                        if is_bracket_pair_start {
 3559                            // If the inserted text is a suffix of an opening bracket and the
 3560                            // selection is preceded by the rest of the opening bracket, then
 3561                            // insert the closing bracket.
 3562                            let following_text_allows_autoclose = snapshot
 3563                                .chars_at(selection.start)
 3564                                .next()
 3565                                .map_or(true, |c| scope.should_autoclose_before(c));
 3566
 3567                            let preceding_text_allows_autoclose = selection.start.column == 0
 3568                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3569                                    true,
 3570                                    |c| {
 3571                                        bracket_pair.start != bracket_pair.end
 3572                                            || !snapshot
 3573                                                .char_classifier_at(selection.start)
 3574                                                .is_word(c)
 3575                                    },
 3576                                );
 3577
 3578                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3579                                && bracket_pair.start.len() == 1
 3580                            {
 3581                                let target = bracket_pair.start.chars().next().unwrap();
 3582                                let current_line_count = snapshot
 3583                                    .reversed_chars_at(selection.start)
 3584                                    .take_while(|&c| c != '\n')
 3585                                    .filter(|&c| c == target)
 3586                                    .count();
 3587                                current_line_count % 2 == 1
 3588                            } else {
 3589                                false
 3590                            };
 3591
 3592                            if autoclose
 3593                                && bracket_pair.close
 3594                                && following_text_allows_autoclose
 3595                                && preceding_text_allows_autoclose
 3596                                && !is_closing_quote
 3597                            {
 3598                                let anchor = snapshot.anchor_before(selection.end);
 3599                                new_selections.push((selection.map(|_| anchor), text.len()));
 3600                                new_autoclose_regions.push((
 3601                                    anchor,
 3602                                    text.len(),
 3603                                    selection.id,
 3604                                    bracket_pair.clone(),
 3605                                ));
 3606                                edits.push((
 3607                                    selection.range(),
 3608                                    format!("{}{}", text, bracket_pair.end).into(),
 3609                                ));
 3610                                bracket_inserted = true;
 3611                                continue;
 3612                            }
 3613                        }
 3614
 3615                        if let Some(region) = autoclose_region {
 3616                            // If the selection is followed by an auto-inserted closing bracket,
 3617                            // then don't insert that closing bracket again; just move the selection
 3618                            // past the closing bracket.
 3619                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3620                                && text.as_ref() == region.pair.end.as_str();
 3621                            if should_skip {
 3622                                let anchor = snapshot.anchor_after(selection.end);
 3623                                new_selections
 3624                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3625                                continue;
 3626                            }
 3627                        }
 3628
 3629                        let always_treat_brackets_as_autoclosed = snapshot
 3630                            .language_settings_at(selection.start, cx)
 3631                            .always_treat_brackets_as_autoclosed;
 3632                        if always_treat_brackets_as_autoclosed
 3633                            && is_bracket_pair_end
 3634                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3635                        {
 3636                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3637                            // and the inserted text is a closing bracket and the selection is followed
 3638                            // by the closing bracket then move the selection past the closing bracket.
 3639                            let anchor = snapshot.anchor_after(selection.end);
 3640                            new_selections.push((selection.map(|_| anchor), text.len()));
 3641                            continue;
 3642                        }
 3643                    }
 3644                    // If an opening bracket is 1 character long and is typed while
 3645                    // text is selected, then surround that text with the bracket pair.
 3646                    else if auto_surround
 3647                        && bracket_pair.surround
 3648                        && is_bracket_pair_start
 3649                        && bracket_pair.start.chars().count() == 1
 3650                    {
 3651                        edits.push((selection.start..selection.start, text.clone()));
 3652                        edits.push((
 3653                            selection.end..selection.end,
 3654                            bracket_pair.end.as_str().into(),
 3655                        ));
 3656                        bracket_inserted = true;
 3657                        new_selections.push((
 3658                            Selection {
 3659                                id: selection.id,
 3660                                start: snapshot.anchor_after(selection.start),
 3661                                end: snapshot.anchor_before(selection.end),
 3662                                reversed: selection.reversed,
 3663                                goal: selection.goal,
 3664                            },
 3665                            0,
 3666                        ));
 3667                        continue;
 3668                    }
 3669                }
 3670            }
 3671
 3672            if self.auto_replace_emoji_shortcode
 3673                && selection.is_empty()
 3674                && text.as_ref().ends_with(':')
 3675            {
 3676                if let Some(possible_emoji_short_code) =
 3677                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3678                {
 3679                    if !possible_emoji_short_code.is_empty() {
 3680                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3681                            let emoji_shortcode_start = Point::new(
 3682                                selection.start.row,
 3683                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3684                            );
 3685
 3686                            // Remove shortcode from buffer
 3687                            edits.push((
 3688                                emoji_shortcode_start..selection.start,
 3689                                "".to_string().into(),
 3690                            ));
 3691                            new_selections.push((
 3692                                Selection {
 3693                                    id: selection.id,
 3694                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3695                                    end: snapshot.anchor_before(selection.start),
 3696                                    reversed: selection.reversed,
 3697                                    goal: selection.goal,
 3698                                },
 3699                                0,
 3700                            ));
 3701
 3702                            // Insert emoji
 3703                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3704                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3705                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3706
 3707                            continue;
 3708                        }
 3709                    }
 3710                }
 3711            }
 3712
 3713            // If not handling any auto-close operation, then just replace the selected
 3714            // text with the given input and move the selection to the end of the
 3715            // newly inserted text.
 3716            let anchor = snapshot.anchor_after(selection.end);
 3717            if !self.linked_edit_ranges.is_empty() {
 3718                let start_anchor = snapshot.anchor_before(selection.start);
 3719
 3720                let is_word_char = text.chars().next().map_or(true, |char| {
 3721                    let classifier = snapshot
 3722                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3723                        .ignore_punctuation(true);
 3724                    classifier.is_word(char)
 3725                });
 3726
 3727                if is_word_char {
 3728                    if let Some(ranges) = self
 3729                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3730                    {
 3731                        for (buffer, edits) in ranges {
 3732                            linked_edits
 3733                                .entry(buffer.clone())
 3734                                .or_default()
 3735                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3736                        }
 3737                    }
 3738                } else {
 3739                    clear_linked_edit_ranges = true;
 3740                }
 3741            }
 3742
 3743            new_selections.push((selection.map(|_| anchor), 0));
 3744            edits.push((selection.start..selection.end, text.clone()));
 3745        }
 3746
 3747        drop(snapshot);
 3748
 3749        self.transact(window, cx, |this, window, cx| {
 3750            if clear_linked_edit_ranges {
 3751                this.linked_edit_ranges.clear();
 3752            }
 3753            let initial_buffer_versions =
 3754                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3755
 3756            this.buffer.update(cx, |buffer, cx| {
 3757                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3758            });
 3759            for (buffer, edits) in linked_edits {
 3760                buffer.update(cx, |buffer, cx| {
 3761                    let snapshot = buffer.snapshot();
 3762                    let edits = edits
 3763                        .into_iter()
 3764                        .map(|(range, text)| {
 3765                            use text::ToPoint as TP;
 3766                            let end_point = TP::to_point(&range.end, &snapshot);
 3767                            let start_point = TP::to_point(&range.start, &snapshot);
 3768                            (start_point..end_point, text)
 3769                        })
 3770                        .sorted_by_key(|(range, _)| range.start);
 3771                    buffer.edit(edits, None, cx);
 3772                })
 3773            }
 3774            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3775            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3776            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3777            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3778                .zip(new_selection_deltas)
 3779                .map(|(selection, delta)| Selection {
 3780                    id: selection.id,
 3781                    start: selection.start + delta,
 3782                    end: selection.end + delta,
 3783                    reversed: selection.reversed,
 3784                    goal: SelectionGoal::None,
 3785                })
 3786                .collect::<Vec<_>>();
 3787
 3788            let mut i = 0;
 3789            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3790                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3791                let start = map.buffer_snapshot.anchor_before(position);
 3792                let end = map.buffer_snapshot.anchor_after(position);
 3793                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3794                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3795                        Ordering::Less => i += 1,
 3796                        Ordering::Greater => break,
 3797                        Ordering::Equal => {
 3798                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3799                                Ordering::Less => i += 1,
 3800                                Ordering::Equal => break,
 3801                                Ordering::Greater => break,
 3802                            }
 3803                        }
 3804                    }
 3805                }
 3806                this.autoclose_regions.insert(
 3807                    i,
 3808                    AutocloseRegion {
 3809                        selection_id,
 3810                        range: start..end,
 3811                        pair,
 3812                    },
 3813                );
 3814            }
 3815
 3816            let had_active_inline_completion = this.has_active_inline_completion();
 3817            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3818                s.select(new_selections)
 3819            });
 3820
 3821            if !bracket_inserted {
 3822                if let Some(on_type_format_task) =
 3823                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3824                {
 3825                    on_type_format_task.detach_and_log_err(cx);
 3826                }
 3827            }
 3828
 3829            let editor_settings = EditorSettings::get_global(cx);
 3830            if bracket_inserted
 3831                && (editor_settings.auto_signature_help
 3832                    || editor_settings.show_signature_help_after_edits)
 3833            {
 3834                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3835            }
 3836
 3837            let trigger_in_words =
 3838                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3839            if this.hard_wrap.is_some() {
 3840                let latest: Range<Point> = this.selections.newest(cx).range();
 3841                if latest.is_empty()
 3842                    && this
 3843                        .buffer()
 3844                        .read(cx)
 3845                        .snapshot(cx)
 3846                        .line_len(MultiBufferRow(latest.start.row))
 3847                        == latest.start.column
 3848                {
 3849                    this.rewrap_impl(
 3850                        RewrapOptions {
 3851                            override_language_settings: true,
 3852                            preserve_existing_whitespace: true,
 3853                        },
 3854                        cx,
 3855                    )
 3856                }
 3857            }
 3858            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3859            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3860            this.refresh_inline_completion(true, false, window, cx);
 3861            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3862        });
 3863    }
 3864
 3865    fn find_possible_emoji_shortcode_at_position(
 3866        snapshot: &MultiBufferSnapshot,
 3867        position: Point,
 3868    ) -> Option<String> {
 3869        let mut chars = Vec::new();
 3870        let mut found_colon = false;
 3871        for char in snapshot.reversed_chars_at(position).take(100) {
 3872            // Found a possible emoji shortcode in the middle of the buffer
 3873            if found_colon {
 3874                if char.is_whitespace() {
 3875                    chars.reverse();
 3876                    return Some(chars.iter().collect());
 3877                }
 3878                // If the previous character is not a whitespace, we are in the middle of a word
 3879                // and we only want to complete the shortcode if the word is made up of other emojis
 3880                let mut containing_word = String::new();
 3881                for ch in snapshot
 3882                    .reversed_chars_at(position)
 3883                    .skip(chars.len() + 1)
 3884                    .take(100)
 3885                {
 3886                    if ch.is_whitespace() {
 3887                        break;
 3888                    }
 3889                    containing_word.push(ch);
 3890                }
 3891                let containing_word = containing_word.chars().rev().collect::<String>();
 3892                if util::word_consists_of_emojis(containing_word.as_str()) {
 3893                    chars.reverse();
 3894                    return Some(chars.iter().collect());
 3895                }
 3896            }
 3897
 3898            if char.is_whitespace() || !char.is_ascii() {
 3899                return None;
 3900            }
 3901            if char == ':' {
 3902                found_colon = true;
 3903            } else {
 3904                chars.push(char);
 3905            }
 3906        }
 3907        // Found a possible emoji shortcode at the beginning of the buffer
 3908        chars.reverse();
 3909        Some(chars.iter().collect())
 3910    }
 3911
 3912    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3913        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3914        self.transact(window, cx, |this, window, cx| {
 3915            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3916                let selections = this.selections.all::<usize>(cx);
 3917                let multi_buffer = this.buffer.read(cx);
 3918                let buffer = multi_buffer.snapshot(cx);
 3919                selections
 3920                    .iter()
 3921                    .map(|selection| {
 3922                        let start_point = selection.start.to_point(&buffer);
 3923                        let mut existing_indent =
 3924                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3925                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3926                        let start = selection.start;
 3927                        let end = selection.end;
 3928                        let selection_is_empty = start == end;
 3929                        let language_scope = buffer.language_scope_at(start);
 3930                        let (
 3931                            comment_delimiter,
 3932                            doc_delimiter,
 3933                            insert_extra_newline,
 3934                            indent_on_newline,
 3935                            indent_on_extra_newline,
 3936                        ) = if let Some(language) = &language_scope {
 3937                            let mut insert_extra_newline =
 3938                                insert_extra_newline_brackets(&buffer, start..end, language)
 3939                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3940
 3941                            // Comment extension on newline is allowed only for cursor selections
 3942                            let comment_delimiter = maybe!({
 3943                                if !selection_is_empty {
 3944                                    return None;
 3945                                }
 3946
 3947                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3948                                    return None;
 3949                                }
 3950
 3951                                let delimiters = language.line_comment_prefixes();
 3952                                let max_len_of_delimiter =
 3953                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3954                                let (snapshot, range) =
 3955                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3956
 3957                                let num_of_whitespaces = snapshot
 3958                                    .chars_for_range(range.clone())
 3959                                    .take_while(|c| c.is_whitespace())
 3960                                    .count();
 3961                                let comment_candidate = snapshot
 3962                                    .chars_for_range(range)
 3963                                    .skip(num_of_whitespaces)
 3964                                    .take(max_len_of_delimiter)
 3965                                    .collect::<String>();
 3966                                let (delimiter, trimmed_len) =
 3967                                    delimiters.iter().find_map(|delimiter| {
 3968                                        let trimmed = delimiter.trim_end();
 3969                                        if comment_candidate.starts_with(trimmed) {
 3970                                            Some((delimiter, trimmed.len()))
 3971                                        } else {
 3972                                            None
 3973                                        }
 3974                                    })?;
 3975                                let cursor_is_placed_after_comment_marker =
 3976                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3977                                if cursor_is_placed_after_comment_marker {
 3978                                    Some(delimiter.clone())
 3979                                } else {
 3980                                    None
 3981                                }
 3982                            });
 3983
 3984                            let mut indent_on_newline = IndentSize::spaces(0);
 3985                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3986
 3987                            let doc_delimiter = maybe!({
 3988                                if !selection_is_empty {
 3989                                    return None;
 3990                                }
 3991
 3992                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3993                                    return None;
 3994                                }
 3995
 3996                                let DocumentationConfig {
 3997                                    start: start_tag,
 3998                                    end: end_tag,
 3999                                    prefix: delimiter,
 4000                                    tab_size: len,
 4001                                } = language.documentation()?;
 4002
 4003                                let (snapshot, range) =
 4004                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4005
 4006                                let num_of_whitespaces = snapshot
 4007                                    .chars_for_range(range.clone())
 4008                                    .take_while(|c| c.is_whitespace())
 4009                                    .count();
 4010
 4011                                let cursor_is_after_start_tag = {
 4012                                    let start_tag_len = start_tag.len();
 4013                                    let start_tag_line = snapshot
 4014                                        .chars_for_range(range.clone())
 4015                                        .skip(num_of_whitespaces)
 4016                                        .take(start_tag_len)
 4017                                        .collect::<String>();
 4018                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4019                                        num_of_whitespaces + start_tag_len
 4020                                            <= start_point.column as usize
 4021                                    } else {
 4022                                        false
 4023                                    }
 4024                                };
 4025
 4026                                let cursor_is_after_delimiter = {
 4027                                    let delimiter_trim = delimiter.trim_end();
 4028                                    let delimiter_line = snapshot
 4029                                        .chars_for_range(range.clone())
 4030                                        .skip(num_of_whitespaces)
 4031                                        .take(delimiter_trim.len())
 4032                                        .collect::<String>();
 4033                                    if delimiter_line.starts_with(delimiter_trim) {
 4034                                        num_of_whitespaces + delimiter_trim.len()
 4035                                            <= start_point.column as usize
 4036                                    } else {
 4037                                        false
 4038                                    }
 4039                                };
 4040
 4041                                let cursor_is_before_end_tag_if_exists = {
 4042                                    let num_of_whitespaces_rev = snapshot
 4043                                        .reversed_chars_for_range(range.clone())
 4044                                        .take_while(|c| c.is_whitespace())
 4045                                        .count();
 4046                                    let mut line_iter = snapshot
 4047                                        .reversed_chars_for_range(range)
 4048                                        .skip(num_of_whitespaces_rev);
 4049                                    let end_tag_exists = end_tag
 4050                                        .chars()
 4051                                        .rev()
 4052                                        .all(|char| line_iter.next() == Some(char));
 4053                                    if end_tag_exists {
 4054                                        let max_point = snapshot.line_len(start_point.row) as usize;
 4055                                        let ordering = (num_of_whitespaces_rev
 4056                                            + end_tag.len()
 4057                                            + start_point.column as usize)
 4058                                            .cmp(&max_point);
 4059                                        let cursor_is_before_end_tag =
 4060                                            ordering != Ordering::Greater;
 4061                                        if cursor_is_after_start_tag {
 4062                                            if cursor_is_before_end_tag {
 4063                                                insert_extra_newline = true;
 4064                                            }
 4065                                            let cursor_is_at_start_of_end_tag =
 4066                                                ordering == Ordering::Equal;
 4067                                            if cursor_is_at_start_of_end_tag {
 4068                                                indent_on_extra_newline.len = (*len).into();
 4069                                            }
 4070                                        }
 4071                                        cursor_is_before_end_tag
 4072                                    } else {
 4073                                        true
 4074                                    }
 4075                                };
 4076
 4077                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4078                                    && cursor_is_before_end_tag_if_exists
 4079                                {
 4080                                    if cursor_is_after_start_tag {
 4081                                        indent_on_newline.len = (*len).into();
 4082                                    }
 4083                                    Some(delimiter.clone())
 4084                                } else {
 4085                                    None
 4086                                }
 4087                            });
 4088
 4089                            (
 4090                                comment_delimiter,
 4091                                doc_delimiter,
 4092                                insert_extra_newline,
 4093                                indent_on_newline,
 4094                                indent_on_extra_newline,
 4095                            )
 4096                        } else {
 4097                            (
 4098                                None,
 4099                                None,
 4100                                false,
 4101                                IndentSize::default(),
 4102                                IndentSize::default(),
 4103                            )
 4104                        };
 4105
 4106                        let prevent_auto_indent = doc_delimiter.is_some();
 4107                        let delimiter = comment_delimiter.or(doc_delimiter);
 4108
 4109                        let capacity_for_delimiter =
 4110                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4111                        let mut new_text = String::with_capacity(
 4112                            1 + capacity_for_delimiter
 4113                                + existing_indent.len as usize
 4114                                + indent_on_newline.len as usize
 4115                                + indent_on_extra_newline.len as usize,
 4116                        );
 4117                        new_text.push('\n');
 4118                        new_text.extend(existing_indent.chars());
 4119                        new_text.extend(indent_on_newline.chars());
 4120
 4121                        if let Some(delimiter) = &delimiter {
 4122                            new_text.push_str(delimiter);
 4123                        }
 4124
 4125                        if insert_extra_newline {
 4126                            new_text.push('\n');
 4127                            new_text.extend(existing_indent.chars());
 4128                            new_text.extend(indent_on_extra_newline.chars());
 4129                        }
 4130
 4131                        let anchor = buffer.anchor_after(end);
 4132                        let new_selection = selection.map(|_| anchor);
 4133                        (
 4134                            ((start..end, new_text), prevent_auto_indent),
 4135                            (insert_extra_newline, new_selection),
 4136                        )
 4137                    })
 4138                    .unzip()
 4139            };
 4140
 4141            let mut auto_indent_edits = Vec::new();
 4142            let mut edits = Vec::new();
 4143            for (edit, prevent_auto_indent) in edits_with_flags {
 4144                if prevent_auto_indent {
 4145                    edits.push(edit);
 4146                } else {
 4147                    auto_indent_edits.push(edit);
 4148                }
 4149            }
 4150            if !edits.is_empty() {
 4151                this.edit(edits, cx);
 4152            }
 4153            if !auto_indent_edits.is_empty() {
 4154                this.edit_with_autoindent(auto_indent_edits, cx);
 4155            }
 4156
 4157            let buffer = this.buffer.read(cx).snapshot(cx);
 4158            let new_selections = selection_info
 4159                .into_iter()
 4160                .map(|(extra_newline_inserted, new_selection)| {
 4161                    let mut cursor = new_selection.end.to_point(&buffer);
 4162                    if extra_newline_inserted {
 4163                        cursor.row -= 1;
 4164                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4165                    }
 4166                    new_selection.map(|_| cursor)
 4167                })
 4168                .collect();
 4169
 4170            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4171                s.select(new_selections)
 4172            });
 4173            this.refresh_inline_completion(true, false, window, cx);
 4174        });
 4175    }
 4176
 4177    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4178        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4179
 4180        let buffer = self.buffer.read(cx);
 4181        let snapshot = buffer.snapshot(cx);
 4182
 4183        let mut edits = Vec::new();
 4184        let mut rows = Vec::new();
 4185
 4186        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4187            let cursor = selection.head();
 4188            let row = cursor.row;
 4189
 4190            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4191
 4192            let newline = "\n".to_string();
 4193            edits.push((start_of_line..start_of_line, newline));
 4194
 4195            rows.push(row + rows_inserted as u32);
 4196        }
 4197
 4198        self.transact(window, cx, |editor, window, cx| {
 4199            editor.edit(edits, cx);
 4200
 4201            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4202                let mut index = 0;
 4203                s.move_cursors_with(|map, _, _| {
 4204                    let row = rows[index];
 4205                    index += 1;
 4206
 4207                    let point = Point::new(row, 0);
 4208                    let boundary = map.next_line_boundary(point).1;
 4209                    let clipped = map.clip_point(boundary, Bias::Left);
 4210
 4211                    (clipped, SelectionGoal::None)
 4212                });
 4213            });
 4214
 4215            let mut indent_edits = Vec::new();
 4216            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4217            for row in rows {
 4218                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4219                for (row, indent) in indents {
 4220                    if indent.len == 0 {
 4221                        continue;
 4222                    }
 4223
 4224                    let text = match indent.kind {
 4225                        IndentKind::Space => " ".repeat(indent.len as usize),
 4226                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4227                    };
 4228                    let point = Point::new(row.0, 0);
 4229                    indent_edits.push((point..point, text));
 4230                }
 4231            }
 4232            editor.edit(indent_edits, cx);
 4233        });
 4234    }
 4235
 4236    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4237        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4238
 4239        let buffer = self.buffer.read(cx);
 4240        let snapshot = buffer.snapshot(cx);
 4241
 4242        let mut edits = Vec::new();
 4243        let mut rows = Vec::new();
 4244        let mut rows_inserted = 0;
 4245
 4246        for selection in self.selections.all_adjusted(cx) {
 4247            let cursor = selection.head();
 4248            let row = cursor.row;
 4249
 4250            let point = Point::new(row + 1, 0);
 4251            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4252
 4253            let newline = "\n".to_string();
 4254            edits.push((start_of_line..start_of_line, newline));
 4255
 4256            rows_inserted += 1;
 4257            rows.push(row + rows_inserted);
 4258        }
 4259
 4260        self.transact(window, cx, |editor, window, cx| {
 4261            editor.edit(edits, cx);
 4262
 4263            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4264                let mut index = 0;
 4265                s.move_cursors_with(|map, _, _| {
 4266                    let row = rows[index];
 4267                    index += 1;
 4268
 4269                    let point = Point::new(row, 0);
 4270                    let boundary = map.next_line_boundary(point).1;
 4271                    let clipped = map.clip_point(boundary, Bias::Left);
 4272
 4273                    (clipped, SelectionGoal::None)
 4274                });
 4275            });
 4276
 4277            let mut indent_edits = Vec::new();
 4278            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4279            for row in rows {
 4280                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4281                for (row, indent) in indents {
 4282                    if indent.len == 0 {
 4283                        continue;
 4284                    }
 4285
 4286                    let text = match indent.kind {
 4287                        IndentKind::Space => " ".repeat(indent.len as usize),
 4288                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4289                    };
 4290                    let point = Point::new(row.0, 0);
 4291                    indent_edits.push((point..point, text));
 4292                }
 4293            }
 4294            editor.edit(indent_edits, cx);
 4295        });
 4296    }
 4297
 4298    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4299        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4300            original_indent_columns: Vec::new(),
 4301        });
 4302        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4303    }
 4304
 4305    fn insert_with_autoindent_mode(
 4306        &mut self,
 4307        text: &str,
 4308        autoindent_mode: Option<AutoindentMode>,
 4309        window: &mut Window,
 4310        cx: &mut Context<Self>,
 4311    ) {
 4312        if self.read_only(cx) {
 4313            return;
 4314        }
 4315
 4316        let text: Arc<str> = text.into();
 4317        self.transact(window, cx, |this, window, cx| {
 4318            let old_selections = this.selections.all_adjusted(cx);
 4319            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4320                let anchors = {
 4321                    let snapshot = buffer.read(cx);
 4322                    old_selections
 4323                        .iter()
 4324                        .map(|s| {
 4325                            let anchor = snapshot.anchor_after(s.head());
 4326                            s.map(|_| anchor)
 4327                        })
 4328                        .collect::<Vec<_>>()
 4329                };
 4330                buffer.edit(
 4331                    old_selections
 4332                        .iter()
 4333                        .map(|s| (s.start..s.end, text.clone())),
 4334                    autoindent_mode,
 4335                    cx,
 4336                );
 4337                anchors
 4338            });
 4339
 4340            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4341                s.select_anchors(selection_anchors);
 4342            });
 4343
 4344            cx.notify();
 4345        });
 4346    }
 4347
 4348    fn trigger_completion_on_input(
 4349        &mut self,
 4350        text: &str,
 4351        trigger_in_words: bool,
 4352        window: &mut Window,
 4353        cx: &mut Context<Self>,
 4354    ) {
 4355        let ignore_completion_provider = self
 4356            .context_menu
 4357            .borrow()
 4358            .as_ref()
 4359            .map(|menu| match menu {
 4360                CodeContextMenu::Completions(completions_menu) => {
 4361                    completions_menu.ignore_completion_provider
 4362                }
 4363                CodeContextMenu::CodeActions(_) => false,
 4364            })
 4365            .unwrap_or(false);
 4366
 4367        if ignore_completion_provider {
 4368            self.show_word_completions(&ShowWordCompletions, window, cx);
 4369        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4370            self.show_completions(
 4371                &ShowCompletions {
 4372                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4373                },
 4374                window,
 4375                cx,
 4376            );
 4377        } else {
 4378            self.hide_context_menu(window, cx);
 4379        }
 4380    }
 4381
 4382    fn is_completion_trigger(
 4383        &self,
 4384        text: &str,
 4385        trigger_in_words: bool,
 4386        cx: &mut Context<Self>,
 4387    ) -> bool {
 4388        let position = self.selections.newest_anchor().head();
 4389        let multibuffer = self.buffer.read(cx);
 4390        let Some(buffer) = position
 4391            .buffer_id
 4392            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4393        else {
 4394            return false;
 4395        };
 4396
 4397        if let Some(completion_provider) = &self.completion_provider {
 4398            completion_provider.is_completion_trigger(
 4399                &buffer,
 4400                position.text_anchor,
 4401                text,
 4402                trigger_in_words,
 4403                cx,
 4404            )
 4405        } else {
 4406            false
 4407        }
 4408    }
 4409
 4410    /// If any empty selections is touching the start of its innermost containing autoclose
 4411    /// region, expand it to select the brackets.
 4412    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4413        let selections = self.selections.all::<usize>(cx);
 4414        let buffer = self.buffer.read(cx).read(cx);
 4415        let new_selections = self
 4416            .selections_with_autoclose_regions(selections, &buffer)
 4417            .map(|(mut selection, region)| {
 4418                if !selection.is_empty() {
 4419                    return selection;
 4420                }
 4421
 4422                if let Some(region) = region {
 4423                    let mut range = region.range.to_offset(&buffer);
 4424                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4425                        range.start -= region.pair.start.len();
 4426                        if buffer.contains_str_at(range.start, &region.pair.start)
 4427                            && buffer.contains_str_at(range.end, &region.pair.end)
 4428                        {
 4429                            range.end += region.pair.end.len();
 4430                            selection.start = range.start;
 4431                            selection.end = range.end;
 4432
 4433                            return selection;
 4434                        }
 4435                    }
 4436                }
 4437
 4438                let always_treat_brackets_as_autoclosed = buffer
 4439                    .language_settings_at(selection.start, cx)
 4440                    .always_treat_brackets_as_autoclosed;
 4441
 4442                if !always_treat_brackets_as_autoclosed {
 4443                    return selection;
 4444                }
 4445
 4446                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4447                    for (pair, enabled) in scope.brackets() {
 4448                        if !enabled || !pair.close {
 4449                            continue;
 4450                        }
 4451
 4452                        if buffer.contains_str_at(selection.start, &pair.end) {
 4453                            let pair_start_len = pair.start.len();
 4454                            if buffer.contains_str_at(
 4455                                selection.start.saturating_sub(pair_start_len),
 4456                                &pair.start,
 4457                            ) {
 4458                                selection.start -= pair_start_len;
 4459                                selection.end += pair.end.len();
 4460
 4461                                return selection;
 4462                            }
 4463                        }
 4464                    }
 4465                }
 4466
 4467                selection
 4468            })
 4469            .collect();
 4470
 4471        drop(buffer);
 4472        self.change_selections(None, window, cx, |selections| {
 4473            selections.select(new_selections)
 4474        });
 4475    }
 4476
 4477    /// Iterate the given selections, and for each one, find the smallest surrounding
 4478    /// autoclose region. This uses the ordering of the selections and the autoclose
 4479    /// regions to avoid repeated comparisons.
 4480    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4481        &'a self,
 4482        selections: impl IntoIterator<Item = Selection<D>>,
 4483        buffer: &'a MultiBufferSnapshot,
 4484    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4485        let mut i = 0;
 4486        let mut regions = self.autoclose_regions.as_slice();
 4487        selections.into_iter().map(move |selection| {
 4488            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4489
 4490            let mut enclosing = None;
 4491            while let Some(pair_state) = regions.get(i) {
 4492                if pair_state.range.end.to_offset(buffer) < range.start {
 4493                    regions = &regions[i + 1..];
 4494                    i = 0;
 4495                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4496                    break;
 4497                } else {
 4498                    if pair_state.selection_id == selection.id {
 4499                        enclosing = Some(pair_state);
 4500                    }
 4501                    i += 1;
 4502                }
 4503            }
 4504
 4505            (selection, enclosing)
 4506        })
 4507    }
 4508
 4509    /// Remove any autoclose regions that no longer contain their selection.
 4510    fn invalidate_autoclose_regions(
 4511        &mut self,
 4512        mut selections: &[Selection<Anchor>],
 4513        buffer: &MultiBufferSnapshot,
 4514    ) {
 4515        self.autoclose_regions.retain(|state| {
 4516            let mut i = 0;
 4517            while let Some(selection) = selections.get(i) {
 4518                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4519                    selections = &selections[1..];
 4520                    continue;
 4521                }
 4522                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4523                    break;
 4524                }
 4525                if selection.id == state.selection_id {
 4526                    return true;
 4527                } else {
 4528                    i += 1;
 4529                }
 4530            }
 4531            false
 4532        });
 4533    }
 4534
 4535    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4536        let offset = position.to_offset(buffer);
 4537        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4538        if offset > word_range.start && kind == Some(CharKind::Word) {
 4539            Some(
 4540                buffer
 4541                    .text_for_range(word_range.start..offset)
 4542                    .collect::<String>(),
 4543            )
 4544        } else {
 4545            None
 4546        }
 4547    }
 4548
 4549    pub fn toggle_inline_values(
 4550        &mut self,
 4551        _: &ToggleInlineValues,
 4552        _: &mut Window,
 4553        cx: &mut Context<Self>,
 4554    ) {
 4555        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4556
 4557        self.refresh_inline_values(cx);
 4558    }
 4559
 4560    pub fn toggle_inlay_hints(
 4561        &mut self,
 4562        _: &ToggleInlayHints,
 4563        _: &mut Window,
 4564        cx: &mut Context<Self>,
 4565    ) {
 4566        self.refresh_inlay_hints(
 4567            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4568            cx,
 4569        );
 4570    }
 4571
 4572    pub fn inlay_hints_enabled(&self) -> bool {
 4573        self.inlay_hint_cache.enabled
 4574    }
 4575
 4576    pub fn inline_values_enabled(&self) -> bool {
 4577        self.inline_value_cache.enabled
 4578    }
 4579
 4580    #[cfg(any(test, feature = "test-support"))]
 4581    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4582        self.display_map
 4583            .read(cx)
 4584            .current_inlays()
 4585            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4586            .cloned()
 4587            .collect()
 4588    }
 4589
 4590    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4591        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4592            return;
 4593        }
 4594
 4595        let reason_description = reason.description();
 4596        let ignore_debounce = matches!(
 4597            reason,
 4598            InlayHintRefreshReason::SettingsChange(_)
 4599                | InlayHintRefreshReason::Toggle(_)
 4600                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4601                | InlayHintRefreshReason::ModifiersChanged(_)
 4602        );
 4603        let (invalidate_cache, required_languages) = match reason {
 4604            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4605                match self.inlay_hint_cache.modifiers_override(enabled) {
 4606                    Some(enabled) => {
 4607                        if enabled {
 4608                            (InvalidationStrategy::RefreshRequested, None)
 4609                        } else {
 4610                            self.splice_inlays(
 4611                                &self
 4612                                    .visible_inlay_hints(cx)
 4613                                    .iter()
 4614                                    .map(|inlay| inlay.id)
 4615                                    .collect::<Vec<InlayId>>(),
 4616                                Vec::new(),
 4617                                cx,
 4618                            );
 4619                            return;
 4620                        }
 4621                    }
 4622                    None => return,
 4623                }
 4624            }
 4625            InlayHintRefreshReason::Toggle(enabled) => {
 4626                if self.inlay_hint_cache.toggle(enabled) {
 4627                    if enabled {
 4628                        (InvalidationStrategy::RefreshRequested, None)
 4629                    } else {
 4630                        self.splice_inlays(
 4631                            &self
 4632                                .visible_inlay_hints(cx)
 4633                                .iter()
 4634                                .map(|inlay| inlay.id)
 4635                                .collect::<Vec<InlayId>>(),
 4636                            Vec::new(),
 4637                            cx,
 4638                        );
 4639                        return;
 4640                    }
 4641                } else {
 4642                    return;
 4643                }
 4644            }
 4645            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4646                match self.inlay_hint_cache.update_settings(
 4647                    &self.buffer,
 4648                    new_settings,
 4649                    self.visible_inlay_hints(cx),
 4650                    cx,
 4651                ) {
 4652                    ControlFlow::Break(Some(InlaySplice {
 4653                        to_remove,
 4654                        to_insert,
 4655                    })) => {
 4656                        self.splice_inlays(&to_remove, to_insert, cx);
 4657                        return;
 4658                    }
 4659                    ControlFlow::Break(None) => return,
 4660                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4661                }
 4662            }
 4663            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4664                if let Some(InlaySplice {
 4665                    to_remove,
 4666                    to_insert,
 4667                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4668                {
 4669                    self.splice_inlays(&to_remove, to_insert, cx);
 4670                }
 4671                self.display_map.update(cx, |display_map, _| {
 4672                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4673                });
 4674                return;
 4675            }
 4676            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4677            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4678                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4679            }
 4680            InlayHintRefreshReason::RefreshRequested => {
 4681                (InvalidationStrategy::RefreshRequested, None)
 4682            }
 4683        };
 4684
 4685        if let Some(InlaySplice {
 4686            to_remove,
 4687            to_insert,
 4688        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4689            reason_description,
 4690            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4691            invalidate_cache,
 4692            ignore_debounce,
 4693            cx,
 4694        ) {
 4695            self.splice_inlays(&to_remove, to_insert, cx);
 4696        }
 4697    }
 4698
 4699    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4700        self.display_map
 4701            .read(cx)
 4702            .current_inlays()
 4703            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4704            .cloned()
 4705            .collect()
 4706    }
 4707
 4708    pub fn excerpts_for_inlay_hints_query(
 4709        &self,
 4710        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4711        cx: &mut Context<Editor>,
 4712    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4713        let Some(project) = self.project.as_ref() else {
 4714            return HashMap::default();
 4715        };
 4716        let project = project.read(cx);
 4717        let multi_buffer = self.buffer().read(cx);
 4718        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4719        let multi_buffer_visible_start = self
 4720            .scroll_manager
 4721            .anchor()
 4722            .anchor
 4723            .to_point(&multi_buffer_snapshot);
 4724        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4725            multi_buffer_visible_start
 4726                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4727            Bias::Left,
 4728        );
 4729        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4730        multi_buffer_snapshot
 4731            .range_to_buffer_ranges(multi_buffer_visible_range)
 4732            .into_iter()
 4733            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4734            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4735                let buffer_file = project::File::from_dyn(buffer.file())?;
 4736                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4737                let worktree_entry = buffer_worktree
 4738                    .read(cx)
 4739                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4740                if worktree_entry.is_ignored {
 4741                    return None;
 4742                }
 4743
 4744                let language = buffer.language()?;
 4745                if let Some(restrict_to_languages) = restrict_to_languages {
 4746                    if !restrict_to_languages.contains(language) {
 4747                        return None;
 4748                    }
 4749                }
 4750                Some((
 4751                    excerpt_id,
 4752                    (
 4753                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4754                        buffer.version().clone(),
 4755                        excerpt_visible_range,
 4756                    ),
 4757                ))
 4758            })
 4759            .collect()
 4760    }
 4761
 4762    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4763        TextLayoutDetails {
 4764            text_system: window.text_system().clone(),
 4765            editor_style: self.style.clone().unwrap(),
 4766            rem_size: window.rem_size(),
 4767            scroll_anchor: self.scroll_manager.anchor(),
 4768            visible_rows: self.visible_line_count(),
 4769            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4770        }
 4771    }
 4772
 4773    pub fn splice_inlays(
 4774        &self,
 4775        to_remove: &[InlayId],
 4776        to_insert: Vec<Inlay>,
 4777        cx: &mut Context<Self>,
 4778    ) {
 4779        self.display_map.update(cx, |display_map, cx| {
 4780            display_map.splice_inlays(to_remove, to_insert, cx)
 4781        });
 4782        cx.notify();
 4783    }
 4784
 4785    fn trigger_on_type_formatting(
 4786        &self,
 4787        input: String,
 4788        window: &mut Window,
 4789        cx: &mut Context<Self>,
 4790    ) -> Option<Task<Result<()>>> {
 4791        if input.len() != 1 {
 4792            return None;
 4793        }
 4794
 4795        let project = self.project.as_ref()?;
 4796        let position = self.selections.newest_anchor().head();
 4797        let (buffer, buffer_position) = self
 4798            .buffer
 4799            .read(cx)
 4800            .text_anchor_for_position(position, cx)?;
 4801
 4802        let settings = language_settings::language_settings(
 4803            buffer
 4804                .read(cx)
 4805                .language_at(buffer_position)
 4806                .map(|l| l.name()),
 4807            buffer.read(cx).file(),
 4808            cx,
 4809        );
 4810        if !settings.use_on_type_format {
 4811            return None;
 4812        }
 4813
 4814        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4815        // hence we do LSP request & edit on host side only — add formats to host's history.
 4816        let push_to_lsp_host_history = true;
 4817        // If this is not the host, append its history with new edits.
 4818        let push_to_client_history = project.read(cx).is_via_collab();
 4819
 4820        let on_type_formatting = project.update(cx, |project, cx| {
 4821            project.on_type_format(
 4822                buffer.clone(),
 4823                buffer_position,
 4824                input,
 4825                push_to_lsp_host_history,
 4826                cx,
 4827            )
 4828        });
 4829        Some(cx.spawn_in(window, async move |editor, cx| {
 4830            if let Some(transaction) = on_type_formatting.await? {
 4831                if push_to_client_history {
 4832                    buffer
 4833                        .update(cx, |buffer, _| {
 4834                            buffer.push_transaction(transaction, Instant::now());
 4835                            buffer.finalize_last_transaction();
 4836                        })
 4837                        .ok();
 4838                }
 4839                editor.update(cx, |editor, cx| {
 4840                    editor.refresh_document_highlights(cx);
 4841                })?;
 4842            }
 4843            Ok(())
 4844        }))
 4845    }
 4846
 4847    pub fn show_word_completions(
 4848        &mut self,
 4849        _: &ShowWordCompletions,
 4850        window: &mut Window,
 4851        cx: &mut Context<Self>,
 4852    ) {
 4853        self.open_completions_menu(true, None, window, cx);
 4854    }
 4855
 4856    pub fn show_completions(
 4857        &mut self,
 4858        options: &ShowCompletions,
 4859        window: &mut Window,
 4860        cx: &mut Context<Self>,
 4861    ) {
 4862        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4863    }
 4864
 4865    fn open_completions_menu(
 4866        &mut self,
 4867        ignore_completion_provider: bool,
 4868        trigger: Option<&str>,
 4869        window: &mut Window,
 4870        cx: &mut Context<Self>,
 4871    ) {
 4872        if self.pending_rename.is_some() {
 4873            return;
 4874        }
 4875        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4876            return;
 4877        }
 4878
 4879        let position = self.selections.newest_anchor().head();
 4880        if position.diff_base_anchor.is_some() {
 4881            return;
 4882        }
 4883        let (buffer, buffer_position) =
 4884            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4885                output
 4886            } else {
 4887                return;
 4888            };
 4889        let buffer_snapshot = buffer.read(cx).snapshot();
 4890        let show_completion_documentation = buffer_snapshot
 4891            .settings_at(buffer_position, cx)
 4892            .show_completion_documentation;
 4893
 4894        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4895
 4896        let trigger_kind = match trigger {
 4897            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4898                CompletionTriggerKind::TRIGGER_CHARACTER
 4899            }
 4900            _ => CompletionTriggerKind::INVOKED,
 4901        };
 4902        let completion_context = CompletionContext {
 4903            trigger_character: trigger.and_then(|trigger| {
 4904                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4905                    Some(String::from(trigger))
 4906                } else {
 4907                    None
 4908                }
 4909            }),
 4910            trigger_kind,
 4911        };
 4912
 4913        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4914        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4915            let word_to_exclude = buffer_snapshot
 4916                .text_for_range(old_range.clone())
 4917                .collect::<String>();
 4918            (
 4919                buffer_snapshot.anchor_before(old_range.start)
 4920                    ..buffer_snapshot.anchor_after(old_range.end),
 4921                Some(word_to_exclude),
 4922            )
 4923        } else {
 4924            (buffer_position..buffer_position, None)
 4925        };
 4926
 4927        let completion_settings = language_settings(
 4928            buffer_snapshot
 4929                .language_at(buffer_position)
 4930                .map(|language| language.name()),
 4931            buffer_snapshot.file(),
 4932            cx,
 4933        )
 4934        .completions;
 4935
 4936        // The document can be large, so stay in reasonable bounds when searching for words,
 4937        // otherwise completion pop-up might be slow to appear.
 4938        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4939        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4940        let min_word_search = buffer_snapshot.clip_point(
 4941            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4942            Bias::Left,
 4943        );
 4944        let max_word_search = buffer_snapshot.clip_point(
 4945            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4946            Bias::Right,
 4947        );
 4948        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4949            ..buffer_snapshot.point_to_offset(max_word_search);
 4950
 4951        let provider = self
 4952            .completion_provider
 4953            .as_ref()
 4954            .filter(|_| !ignore_completion_provider);
 4955        let skip_digits = query
 4956            .as_ref()
 4957            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4958
 4959        let (mut words, provided_completions) = match provider {
 4960            Some(provider) => {
 4961                let completions = provider.completions(
 4962                    position.excerpt_id,
 4963                    &buffer,
 4964                    buffer_position,
 4965                    completion_context,
 4966                    window,
 4967                    cx,
 4968                );
 4969
 4970                let words = match completion_settings.words {
 4971                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4972                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4973                        .background_spawn(async move {
 4974                            buffer_snapshot.words_in_range(WordsQuery {
 4975                                fuzzy_contents: None,
 4976                                range: word_search_range,
 4977                                skip_digits,
 4978                            })
 4979                        }),
 4980                };
 4981
 4982                (words, completions)
 4983            }
 4984            None => (
 4985                cx.background_spawn(async move {
 4986                    buffer_snapshot.words_in_range(WordsQuery {
 4987                        fuzzy_contents: None,
 4988                        range: word_search_range,
 4989                        skip_digits,
 4990                    })
 4991                }),
 4992                Task::ready(Ok(None)),
 4993            ),
 4994        };
 4995
 4996        let sort_completions = provider
 4997            .as_ref()
 4998            .map_or(false, |provider| provider.sort_completions());
 4999
 5000        let filter_completions = provider
 5001            .as_ref()
 5002            .map_or(true, |provider| provider.filter_completions());
 5003
 5004        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5005
 5006        let id = post_inc(&mut self.next_completion_id);
 5007        let task = cx.spawn_in(window, async move |editor, cx| {
 5008            async move {
 5009                editor.update(cx, |this, _| {
 5010                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5011                })?;
 5012
 5013                let mut completions = Vec::new();
 5014                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5015                    completions.extend(provided_completions);
 5016                    if completion_settings.words == WordsCompletionMode::Fallback {
 5017                        words = Task::ready(BTreeMap::default());
 5018                    }
 5019                }
 5020
 5021                let mut words = words.await;
 5022                if let Some(word_to_exclude) = &word_to_exclude {
 5023                    words.remove(word_to_exclude);
 5024                }
 5025                for lsp_completion in &completions {
 5026                    words.remove(&lsp_completion.new_text);
 5027                }
 5028                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5029                    replace_range: old_range.clone(),
 5030                    new_text: word.clone(),
 5031                    label: CodeLabel::plain(word, None),
 5032                    icon_path: None,
 5033                    documentation: None,
 5034                    source: CompletionSource::BufferWord {
 5035                        word_range,
 5036                        resolved: false,
 5037                    },
 5038                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5039                    confirm: None,
 5040                }));
 5041
 5042                let menu = if completions.is_empty() {
 5043                    None
 5044                } else {
 5045                    let mut menu = CompletionsMenu::new(
 5046                        id,
 5047                        sort_completions,
 5048                        show_completion_documentation,
 5049                        ignore_completion_provider,
 5050                        position,
 5051                        buffer.clone(),
 5052                        completions.into(),
 5053                        snippet_sort_order,
 5054                    );
 5055
 5056                    menu.filter(
 5057                        if filter_completions {
 5058                            query.as_deref()
 5059                        } else {
 5060                            None
 5061                        },
 5062                        cx.background_executor().clone(),
 5063                    )
 5064                    .await;
 5065
 5066                    menu.visible().then_some(menu)
 5067                };
 5068
 5069                editor.update_in(cx, |editor, window, cx| {
 5070                    match editor.context_menu.borrow().as_ref() {
 5071                        None => {}
 5072                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5073                            if prev_menu.id > id {
 5074                                return;
 5075                            }
 5076                        }
 5077                        _ => return,
 5078                    }
 5079
 5080                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5081                        let mut menu = menu.unwrap();
 5082                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5083
 5084                        *editor.context_menu.borrow_mut() =
 5085                            Some(CodeContextMenu::Completions(menu));
 5086
 5087                        if editor.show_edit_predictions_in_menu() {
 5088                            editor.update_visible_inline_completion(window, cx);
 5089                        } else {
 5090                            editor.discard_inline_completion(false, cx);
 5091                        }
 5092
 5093                        cx.notify();
 5094                    } else if editor.completion_tasks.len() <= 1 {
 5095                        // If there are no more completion tasks and the last menu was
 5096                        // empty, we should hide it.
 5097                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5098                        // If it was already hidden and we don't show inline
 5099                        // completions in the menu, we should also show the
 5100                        // inline-completion when available.
 5101                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5102                            editor.update_visible_inline_completion(window, cx);
 5103                        }
 5104                    }
 5105                })?;
 5106
 5107                anyhow::Ok(())
 5108            }
 5109            .log_err()
 5110            .await
 5111        });
 5112
 5113        self.completion_tasks.push((id, task));
 5114    }
 5115
 5116    #[cfg(feature = "test-support")]
 5117    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5118        let menu = self.context_menu.borrow();
 5119        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5120            let completions = menu.completions.borrow();
 5121            Some(completions.to_vec())
 5122        } else {
 5123            None
 5124        }
 5125    }
 5126
 5127    pub fn confirm_completion(
 5128        &mut self,
 5129        action: &ConfirmCompletion,
 5130        window: &mut Window,
 5131        cx: &mut Context<Self>,
 5132    ) -> Option<Task<Result<()>>> {
 5133        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5134        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5135    }
 5136
 5137    pub fn confirm_completion_insert(
 5138        &mut self,
 5139        _: &ConfirmCompletionInsert,
 5140        window: &mut Window,
 5141        cx: &mut Context<Self>,
 5142    ) -> Option<Task<Result<()>>> {
 5143        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5144        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5145    }
 5146
 5147    pub fn confirm_completion_replace(
 5148        &mut self,
 5149        _: &ConfirmCompletionReplace,
 5150        window: &mut Window,
 5151        cx: &mut Context<Self>,
 5152    ) -> Option<Task<Result<()>>> {
 5153        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5154        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5155    }
 5156
 5157    pub fn compose_completion(
 5158        &mut self,
 5159        action: &ComposeCompletion,
 5160        window: &mut Window,
 5161        cx: &mut Context<Self>,
 5162    ) -> Option<Task<Result<()>>> {
 5163        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5164        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5165    }
 5166
 5167    fn do_completion(
 5168        &mut self,
 5169        item_ix: Option<usize>,
 5170        intent: CompletionIntent,
 5171        window: &mut Window,
 5172        cx: &mut Context<Editor>,
 5173    ) -> Option<Task<Result<()>>> {
 5174        use language::ToOffset as _;
 5175
 5176        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5177        else {
 5178            return None;
 5179        };
 5180
 5181        let candidate_id = {
 5182            let entries = completions_menu.entries.borrow();
 5183            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5184            if self.show_edit_predictions_in_menu() {
 5185                self.discard_inline_completion(true, cx);
 5186            }
 5187            mat.candidate_id
 5188        };
 5189
 5190        let buffer_handle = completions_menu.buffer;
 5191        let completion = completions_menu
 5192            .completions
 5193            .borrow()
 5194            .get(candidate_id)?
 5195            .clone();
 5196        cx.stop_propagation();
 5197
 5198        let snapshot = self.buffer.read(cx).snapshot(cx);
 5199        let newest_anchor = self.selections.newest_anchor();
 5200
 5201        let snippet;
 5202        let new_text;
 5203        if completion.is_snippet() {
 5204            let mut snippet_source = completion.new_text.clone();
 5205            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5206                if scope.prefers_label_for_snippet_in_completion() {
 5207                    if let Some(label) = completion.label() {
 5208                        if matches!(
 5209                            completion.kind(),
 5210                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5211                        ) {
 5212                            snippet_source = label;
 5213                        }
 5214                    }
 5215                }
 5216            }
 5217            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5218            new_text = snippet.as_ref().unwrap().text.clone();
 5219        } else {
 5220            snippet = None;
 5221            new_text = completion.new_text.clone();
 5222        };
 5223
 5224        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5225        let buffer = buffer_handle.read(cx);
 5226        let replace_range_multibuffer = {
 5227            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5228            let multibuffer_anchor = snapshot
 5229                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5230                .unwrap()
 5231                ..snapshot
 5232                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5233                    .unwrap();
 5234            multibuffer_anchor.start.to_offset(&snapshot)
 5235                ..multibuffer_anchor.end.to_offset(&snapshot)
 5236        };
 5237        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5238            return None;
 5239        }
 5240
 5241        let old_text = buffer
 5242            .text_for_range(replace_range.clone())
 5243            .collect::<String>();
 5244        let lookbehind = newest_anchor
 5245            .start
 5246            .text_anchor
 5247            .to_offset(buffer)
 5248            .saturating_sub(replace_range.start);
 5249        let lookahead = replace_range
 5250            .end
 5251            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5252        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5253        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5254
 5255        let selections = self.selections.all::<usize>(cx);
 5256        let mut ranges = Vec::new();
 5257        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5258
 5259        for selection in &selections {
 5260            let range = if selection.id == newest_anchor.id {
 5261                replace_range_multibuffer.clone()
 5262            } else {
 5263                let mut range = selection.range();
 5264
 5265                // if prefix is present, don't duplicate it
 5266                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5267                    range.start = range.start.saturating_sub(lookbehind);
 5268
 5269                    // if suffix is also present, mimic the newest cursor and replace it
 5270                    if selection.id != newest_anchor.id
 5271                        && snapshot.contains_str_at(range.end, suffix)
 5272                    {
 5273                        range.end += lookahead;
 5274                    }
 5275                }
 5276                range
 5277            };
 5278
 5279            ranges.push(range.clone());
 5280
 5281            if !self.linked_edit_ranges.is_empty() {
 5282                let start_anchor = snapshot.anchor_before(range.start);
 5283                let end_anchor = snapshot.anchor_after(range.end);
 5284                if let Some(ranges) = self
 5285                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5286                {
 5287                    for (buffer, edits) in ranges {
 5288                        linked_edits
 5289                            .entry(buffer.clone())
 5290                            .or_default()
 5291                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5292                    }
 5293                }
 5294            }
 5295        }
 5296
 5297        cx.emit(EditorEvent::InputHandled {
 5298            utf16_range_to_replace: None,
 5299            text: new_text.clone().into(),
 5300        });
 5301
 5302        self.transact(window, cx, |this, window, cx| {
 5303            if let Some(mut snippet) = snippet {
 5304                snippet.text = new_text.to_string();
 5305                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5306            } else {
 5307                this.buffer.update(cx, |buffer, cx| {
 5308                    let auto_indent = match completion.insert_text_mode {
 5309                        Some(InsertTextMode::AS_IS) => None,
 5310                        _ => this.autoindent_mode.clone(),
 5311                    };
 5312                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5313                    buffer.edit(edits, auto_indent, cx);
 5314                });
 5315            }
 5316            for (buffer, edits) in linked_edits {
 5317                buffer.update(cx, |buffer, cx| {
 5318                    let snapshot = buffer.snapshot();
 5319                    let edits = edits
 5320                        .into_iter()
 5321                        .map(|(range, text)| {
 5322                            use text::ToPoint as TP;
 5323                            let end_point = TP::to_point(&range.end, &snapshot);
 5324                            let start_point = TP::to_point(&range.start, &snapshot);
 5325                            (start_point..end_point, text)
 5326                        })
 5327                        .sorted_by_key(|(range, _)| range.start);
 5328                    buffer.edit(edits, None, cx);
 5329                })
 5330            }
 5331
 5332            this.refresh_inline_completion(true, false, window, cx);
 5333        });
 5334
 5335        let show_new_completions_on_confirm = completion
 5336            .confirm
 5337            .as_ref()
 5338            .map_or(false, |confirm| confirm(intent, window, cx));
 5339        if show_new_completions_on_confirm {
 5340            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5341        }
 5342
 5343        let provider = self.completion_provider.as_ref()?;
 5344        drop(completion);
 5345        let apply_edits = provider.apply_additional_edits_for_completion(
 5346            buffer_handle,
 5347            completions_menu.completions.clone(),
 5348            candidate_id,
 5349            true,
 5350            cx,
 5351        );
 5352
 5353        let editor_settings = EditorSettings::get_global(cx);
 5354        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5355            // After the code completion is finished, users often want to know what signatures are needed.
 5356            // so we should automatically call signature_help
 5357            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5358        }
 5359
 5360        Some(cx.foreground_executor().spawn(async move {
 5361            apply_edits.await?;
 5362            Ok(())
 5363        }))
 5364    }
 5365
 5366    pub fn toggle_code_actions(
 5367        &mut self,
 5368        action: &ToggleCodeActions,
 5369        window: &mut Window,
 5370        cx: &mut Context<Self>,
 5371    ) {
 5372        let quick_launch = action.quick_launch;
 5373        let mut context_menu = self.context_menu.borrow_mut();
 5374        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5375            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5376                // Toggle if we're selecting the same one
 5377                *context_menu = None;
 5378                cx.notify();
 5379                return;
 5380            } else {
 5381                // Otherwise, clear it and start a new one
 5382                *context_menu = None;
 5383                cx.notify();
 5384            }
 5385        }
 5386        drop(context_menu);
 5387        let snapshot = self.snapshot(window, cx);
 5388        let deployed_from_indicator = action.deployed_from_indicator;
 5389        let mut task = self.code_actions_task.take();
 5390        let action = action.clone();
 5391        cx.spawn_in(window, async move |editor, cx| {
 5392            while let Some(prev_task) = task {
 5393                prev_task.await.log_err();
 5394                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5395            }
 5396
 5397            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5398                if editor.focus_handle.is_focused(window) {
 5399                    let multibuffer_point = action
 5400                        .deployed_from_indicator
 5401                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5402                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5403                    let (buffer, buffer_row) = snapshot
 5404                        .buffer_snapshot
 5405                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5406                        .and_then(|(buffer_snapshot, range)| {
 5407                            editor
 5408                                .buffer
 5409                                .read(cx)
 5410                                .buffer(buffer_snapshot.remote_id())
 5411                                .map(|buffer| (buffer, range.start.row))
 5412                        })?;
 5413                    let (_, code_actions) = editor
 5414                        .available_code_actions
 5415                        .clone()
 5416                        .and_then(|(location, code_actions)| {
 5417                            let snapshot = location.buffer.read(cx).snapshot();
 5418                            let point_range = location.range.to_point(&snapshot);
 5419                            let point_range = point_range.start.row..=point_range.end.row;
 5420                            if point_range.contains(&buffer_row) {
 5421                                Some((location, code_actions))
 5422                            } else {
 5423                                None
 5424                            }
 5425                        })
 5426                        .unzip();
 5427                    let buffer_id = buffer.read(cx).remote_id();
 5428                    let tasks = editor
 5429                        .tasks
 5430                        .get(&(buffer_id, buffer_row))
 5431                        .map(|t| Arc::new(t.to_owned()));
 5432                    if tasks.is_none() && code_actions.is_none() {
 5433                        return None;
 5434                    }
 5435
 5436                    editor.completion_tasks.clear();
 5437                    editor.discard_inline_completion(false, cx);
 5438                    let task_context =
 5439                        tasks
 5440                            .as_ref()
 5441                            .zip(editor.project.clone())
 5442                            .map(|(tasks, project)| {
 5443                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5444                            });
 5445
 5446                    Some(cx.spawn_in(window, async move |editor, cx| {
 5447                        let task_context = match task_context {
 5448                            Some(task_context) => task_context.await,
 5449                            None => None,
 5450                        };
 5451                        let resolved_tasks =
 5452                            tasks
 5453                                .zip(task_context.clone())
 5454                                .map(|(tasks, task_context)| ResolvedTasks {
 5455                                    templates: tasks.resolve(&task_context).collect(),
 5456                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5457                                        multibuffer_point.row,
 5458                                        tasks.column,
 5459                                    )),
 5460                                });
 5461                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5462                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5463                                maybe!({
 5464                                    let project = editor.project.as_ref()?;
 5465                                    let dap_store = project.read(cx).dap_store();
 5466                                    let mut scenarios = vec![];
 5467                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5468                                    let buffer = buffer.read(cx);
 5469                                    let language = buffer.language()?;
 5470                                    let file = buffer.file();
 5471                                    let debug_adapter =
 5472                                        language_settings(language.name().into(), file, cx)
 5473                                            .debuggers
 5474                                            .first()
 5475                                            .map(SharedString::from)
 5476                                            .or_else(|| {
 5477                                                language
 5478                                                    .config()
 5479                                                    .debuggers
 5480                                                    .first()
 5481                                                    .map(SharedString::from)
 5482                                            })?;
 5483
 5484                                    dap_store.update(cx, |dap_store, cx| {
 5485                                        for (_, task) in &resolved_tasks.templates {
 5486                                            if let Some(scenario) = dap_store
 5487                                                .debug_scenario_for_build_task(
 5488                                                    task.original_task().clone(),
 5489                                                    debug_adapter.clone().into(),
 5490                                                    task.display_label().to_owned().into(),
 5491                                                    cx,
 5492                                                )
 5493                                            {
 5494                                                scenarios.push(scenario);
 5495                                            }
 5496                                        }
 5497                                    });
 5498                                    Some(scenarios)
 5499                                })
 5500                                .unwrap_or_default()
 5501                            } else {
 5502                                vec![]
 5503                            }
 5504                        })?;
 5505                        let spawn_straight_away = quick_launch
 5506                            && resolved_tasks
 5507                                .as_ref()
 5508                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5509                            && code_actions
 5510                                .as_ref()
 5511                                .map_or(true, |actions| actions.is_empty())
 5512                            && debug_scenarios.is_empty();
 5513                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5514                            *editor.context_menu.borrow_mut() =
 5515                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5516                                    buffer,
 5517                                    actions: CodeActionContents::new(
 5518                                        resolved_tasks,
 5519                                        code_actions,
 5520                                        debug_scenarios,
 5521                                        task_context.unwrap_or_default(),
 5522                                    ),
 5523                                    selected_item: Default::default(),
 5524                                    scroll_handle: UniformListScrollHandle::default(),
 5525                                    deployed_from_indicator,
 5526                                }));
 5527                            if spawn_straight_away {
 5528                                if let Some(task) = editor.confirm_code_action(
 5529                                    &ConfirmCodeAction { item_ix: Some(0) },
 5530                                    window,
 5531                                    cx,
 5532                                ) {
 5533                                    cx.notify();
 5534                                    return task;
 5535                                }
 5536                            }
 5537                            cx.notify();
 5538                            Task::ready(Ok(()))
 5539                        }) {
 5540                            task.await
 5541                        } else {
 5542                            Ok(())
 5543                        }
 5544                    }))
 5545                } else {
 5546                    Some(Task::ready(Ok(())))
 5547                }
 5548            })?;
 5549            if let Some(task) = spawned_test_task {
 5550                task.await?;
 5551            }
 5552
 5553            Ok::<_, anyhow::Error>(())
 5554        })
 5555        .detach_and_log_err(cx);
 5556    }
 5557
 5558    pub fn confirm_code_action(
 5559        &mut self,
 5560        action: &ConfirmCodeAction,
 5561        window: &mut Window,
 5562        cx: &mut Context<Self>,
 5563    ) -> Option<Task<Result<()>>> {
 5564        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5565
 5566        let actions_menu =
 5567            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5568                menu
 5569            } else {
 5570                return None;
 5571            };
 5572
 5573        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5574        let action = actions_menu.actions.get(action_ix)?;
 5575        let title = action.label();
 5576        let buffer = actions_menu.buffer;
 5577        let workspace = self.workspace()?;
 5578
 5579        match action {
 5580            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5581                workspace.update(cx, |workspace, cx| {
 5582                    workspace.schedule_resolved_task(
 5583                        task_source_kind,
 5584                        resolved_task,
 5585                        false,
 5586                        window,
 5587                        cx,
 5588                    );
 5589
 5590                    Some(Task::ready(Ok(())))
 5591                })
 5592            }
 5593            CodeActionsItem::CodeAction {
 5594                excerpt_id,
 5595                action,
 5596                provider,
 5597            } => {
 5598                let apply_code_action =
 5599                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5600                let workspace = workspace.downgrade();
 5601                Some(cx.spawn_in(window, async move |editor, cx| {
 5602                    let project_transaction = apply_code_action.await?;
 5603                    Self::open_project_transaction(
 5604                        &editor,
 5605                        workspace,
 5606                        project_transaction,
 5607                        title,
 5608                        cx,
 5609                    )
 5610                    .await
 5611                }))
 5612            }
 5613            CodeActionsItem::DebugScenario(scenario) => {
 5614                let context = actions_menu.actions.context.clone();
 5615
 5616                workspace.update(cx, |workspace, cx| {
 5617                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5618                });
 5619                Some(Task::ready(Ok(())))
 5620            }
 5621        }
 5622    }
 5623
 5624    pub async fn open_project_transaction(
 5625        this: &WeakEntity<Editor>,
 5626        workspace: WeakEntity<Workspace>,
 5627        transaction: ProjectTransaction,
 5628        title: String,
 5629        cx: &mut AsyncWindowContext,
 5630    ) -> Result<()> {
 5631        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5632        cx.update(|_, cx| {
 5633            entries.sort_unstable_by_key(|(buffer, _)| {
 5634                buffer.read(cx).file().map(|f| f.path().clone())
 5635            });
 5636        })?;
 5637
 5638        // If the project transaction's edits are all contained within this editor, then
 5639        // avoid opening a new editor to display them.
 5640
 5641        if let Some((buffer, transaction)) = entries.first() {
 5642            if entries.len() == 1 {
 5643                let excerpt = this.update(cx, |editor, cx| {
 5644                    editor
 5645                        .buffer()
 5646                        .read(cx)
 5647                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5648                })?;
 5649                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5650                    if excerpted_buffer == *buffer {
 5651                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5652                            let excerpt_range = excerpt_range.to_offset(buffer);
 5653                            buffer
 5654                                .edited_ranges_for_transaction::<usize>(transaction)
 5655                                .all(|range| {
 5656                                    excerpt_range.start <= range.start
 5657                                        && excerpt_range.end >= range.end
 5658                                })
 5659                        })?;
 5660
 5661                        if all_edits_within_excerpt {
 5662                            return Ok(());
 5663                        }
 5664                    }
 5665                }
 5666            }
 5667        } else {
 5668            return Ok(());
 5669        }
 5670
 5671        let mut ranges_to_highlight = Vec::new();
 5672        let excerpt_buffer = cx.new(|cx| {
 5673            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5674            for (buffer_handle, transaction) in &entries {
 5675                let edited_ranges = buffer_handle
 5676                    .read(cx)
 5677                    .edited_ranges_for_transaction::<Point>(transaction)
 5678                    .collect::<Vec<_>>();
 5679                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5680                    PathKey::for_buffer(buffer_handle, cx),
 5681                    buffer_handle.clone(),
 5682                    edited_ranges,
 5683                    DEFAULT_MULTIBUFFER_CONTEXT,
 5684                    cx,
 5685                );
 5686
 5687                ranges_to_highlight.extend(ranges);
 5688            }
 5689            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5690            multibuffer
 5691        })?;
 5692
 5693        workspace.update_in(cx, |workspace, window, cx| {
 5694            let project = workspace.project().clone();
 5695            let editor =
 5696                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5697            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5698            editor.update(cx, |editor, cx| {
 5699                editor.highlight_background::<Self>(
 5700                    &ranges_to_highlight,
 5701                    |theme| theme.editor_highlighted_line_background,
 5702                    cx,
 5703                );
 5704            });
 5705        })?;
 5706
 5707        Ok(())
 5708    }
 5709
 5710    pub fn clear_code_action_providers(&mut self) {
 5711        self.code_action_providers.clear();
 5712        self.available_code_actions.take();
 5713    }
 5714
 5715    pub fn add_code_action_provider(
 5716        &mut self,
 5717        provider: Rc<dyn CodeActionProvider>,
 5718        window: &mut Window,
 5719        cx: &mut Context<Self>,
 5720    ) {
 5721        if self
 5722            .code_action_providers
 5723            .iter()
 5724            .any(|existing_provider| existing_provider.id() == provider.id())
 5725        {
 5726            return;
 5727        }
 5728
 5729        self.code_action_providers.push(provider);
 5730        self.refresh_code_actions(window, cx);
 5731    }
 5732
 5733    pub fn remove_code_action_provider(
 5734        &mut self,
 5735        id: Arc<str>,
 5736        window: &mut Window,
 5737        cx: &mut Context<Self>,
 5738    ) {
 5739        self.code_action_providers
 5740            .retain(|provider| provider.id() != id);
 5741        self.refresh_code_actions(window, cx);
 5742    }
 5743
 5744    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5745        let newest_selection = self.selections.newest_anchor().clone();
 5746        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5747        let buffer = self.buffer.read(cx);
 5748        if newest_selection.head().diff_base_anchor.is_some() {
 5749            return None;
 5750        }
 5751        let (start_buffer, start) =
 5752            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5753        let (end_buffer, end) =
 5754            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5755        if start_buffer != end_buffer {
 5756            return None;
 5757        }
 5758
 5759        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5760            cx.background_executor()
 5761                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5762                .await;
 5763
 5764            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5765                let providers = this.code_action_providers.clone();
 5766                let tasks = this
 5767                    .code_action_providers
 5768                    .iter()
 5769                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5770                    .collect::<Vec<_>>();
 5771                (providers, tasks)
 5772            })?;
 5773
 5774            let mut actions = Vec::new();
 5775            for (provider, provider_actions) in
 5776                providers.into_iter().zip(future::join_all(tasks).await)
 5777            {
 5778                if let Some(provider_actions) = provider_actions.log_err() {
 5779                    actions.extend(provider_actions.into_iter().map(|action| {
 5780                        AvailableCodeAction {
 5781                            excerpt_id: newest_selection.start.excerpt_id,
 5782                            action,
 5783                            provider: provider.clone(),
 5784                        }
 5785                    }));
 5786                }
 5787            }
 5788
 5789            this.update(cx, |this, cx| {
 5790                this.available_code_actions = if actions.is_empty() {
 5791                    None
 5792                } else {
 5793                    Some((
 5794                        Location {
 5795                            buffer: start_buffer,
 5796                            range: start..end,
 5797                        },
 5798                        actions.into(),
 5799                    ))
 5800                };
 5801                cx.notify();
 5802            })
 5803        }));
 5804        None
 5805    }
 5806
 5807    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5808        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5809            self.show_git_blame_inline = false;
 5810
 5811            self.show_git_blame_inline_delay_task =
 5812                Some(cx.spawn_in(window, async move |this, cx| {
 5813                    cx.background_executor().timer(delay).await;
 5814
 5815                    this.update(cx, |this, cx| {
 5816                        this.show_git_blame_inline = true;
 5817                        cx.notify();
 5818                    })
 5819                    .log_err();
 5820                }));
 5821        }
 5822    }
 5823
 5824    fn show_blame_popover(
 5825        &mut self,
 5826        blame_entry: &BlameEntry,
 5827        position: gpui::Point<Pixels>,
 5828        cx: &mut Context<Self>,
 5829    ) {
 5830        if let Some(state) = &mut self.inline_blame_popover {
 5831            state.hide_task.take();
 5832            cx.notify();
 5833        } else {
 5834            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5835            let show_task = cx.spawn(async move |editor, cx| {
 5836                cx.background_executor()
 5837                    .timer(std::time::Duration::from_millis(delay))
 5838                    .await;
 5839                editor
 5840                    .update(cx, |editor, cx| {
 5841                        if let Some(state) = &mut editor.inline_blame_popover {
 5842                            state.show_task = None;
 5843                            cx.notify();
 5844                        }
 5845                    })
 5846                    .ok();
 5847            });
 5848            let Some(blame) = self.blame.as_ref() else {
 5849                return;
 5850            };
 5851            let blame = blame.read(cx);
 5852            let details = blame.details_for_entry(&blame_entry);
 5853            let markdown = cx.new(|cx| {
 5854                Markdown::new(
 5855                    details
 5856                        .as_ref()
 5857                        .map(|message| message.message.clone())
 5858                        .unwrap_or_default(),
 5859                    None,
 5860                    None,
 5861                    cx,
 5862                )
 5863            });
 5864            self.inline_blame_popover = Some(InlineBlamePopover {
 5865                position,
 5866                show_task: Some(show_task),
 5867                hide_task: None,
 5868                popover_bounds: None,
 5869                popover_state: InlineBlamePopoverState {
 5870                    scroll_handle: ScrollHandle::new(),
 5871                    commit_message: details,
 5872                    markdown,
 5873                },
 5874            });
 5875        }
 5876    }
 5877
 5878    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5879        if let Some(state) = &mut self.inline_blame_popover {
 5880            if state.show_task.is_some() {
 5881                self.inline_blame_popover.take();
 5882                cx.notify();
 5883            } else {
 5884                let hide_task = cx.spawn(async move |editor, cx| {
 5885                    cx.background_executor()
 5886                        .timer(std::time::Duration::from_millis(100))
 5887                        .await;
 5888                    editor
 5889                        .update(cx, |editor, cx| {
 5890                            editor.inline_blame_popover.take();
 5891                            cx.notify();
 5892                        })
 5893                        .ok();
 5894                });
 5895                state.hide_task = Some(hide_task);
 5896            }
 5897        }
 5898    }
 5899
 5900    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5901        if self.pending_rename.is_some() {
 5902            return None;
 5903        }
 5904
 5905        let provider = self.semantics_provider.clone()?;
 5906        let buffer = self.buffer.read(cx);
 5907        let newest_selection = self.selections.newest_anchor().clone();
 5908        let cursor_position = newest_selection.head();
 5909        let (cursor_buffer, cursor_buffer_position) =
 5910            buffer.text_anchor_for_position(cursor_position, cx)?;
 5911        let (tail_buffer, tail_buffer_position) =
 5912            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5913        if cursor_buffer != tail_buffer {
 5914            return None;
 5915        }
 5916
 5917        let snapshot = cursor_buffer.read(cx).snapshot();
 5918        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5919        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5920        if start_word_range != end_word_range {
 5921            self.document_highlights_task.take();
 5922            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5923            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5924            return None;
 5925        }
 5926
 5927        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5928        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5929            cx.background_executor()
 5930                .timer(Duration::from_millis(debounce))
 5931                .await;
 5932
 5933            let highlights = if let Some(highlights) = cx
 5934                .update(|cx| {
 5935                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5936                })
 5937                .ok()
 5938                .flatten()
 5939            {
 5940                highlights.await.log_err()
 5941            } else {
 5942                None
 5943            };
 5944
 5945            if let Some(highlights) = highlights {
 5946                this.update(cx, |this, cx| {
 5947                    if this.pending_rename.is_some() {
 5948                        return;
 5949                    }
 5950
 5951                    let buffer_id = cursor_position.buffer_id;
 5952                    let buffer = this.buffer.read(cx);
 5953                    if !buffer
 5954                        .text_anchor_for_position(cursor_position, cx)
 5955                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5956                    {
 5957                        return;
 5958                    }
 5959
 5960                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5961                    let mut write_ranges = Vec::new();
 5962                    let mut read_ranges = Vec::new();
 5963                    for highlight in highlights {
 5964                        for (excerpt_id, excerpt_range) in
 5965                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5966                        {
 5967                            let start = highlight
 5968                                .range
 5969                                .start
 5970                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5971                            let end = highlight
 5972                                .range
 5973                                .end
 5974                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5975                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5976                                continue;
 5977                            }
 5978
 5979                            let range = Anchor {
 5980                                buffer_id,
 5981                                excerpt_id,
 5982                                text_anchor: start,
 5983                                diff_base_anchor: None,
 5984                            }..Anchor {
 5985                                buffer_id,
 5986                                excerpt_id,
 5987                                text_anchor: end,
 5988                                diff_base_anchor: None,
 5989                            };
 5990                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5991                                write_ranges.push(range);
 5992                            } else {
 5993                                read_ranges.push(range);
 5994                            }
 5995                        }
 5996                    }
 5997
 5998                    this.highlight_background::<DocumentHighlightRead>(
 5999                        &read_ranges,
 6000                        |theme| theme.editor_document_highlight_read_background,
 6001                        cx,
 6002                    );
 6003                    this.highlight_background::<DocumentHighlightWrite>(
 6004                        &write_ranges,
 6005                        |theme| theme.editor_document_highlight_write_background,
 6006                        cx,
 6007                    );
 6008                    cx.notify();
 6009                })
 6010                .log_err();
 6011            }
 6012        }));
 6013        None
 6014    }
 6015
 6016    fn prepare_highlight_query_from_selection(
 6017        &mut self,
 6018        cx: &mut Context<Editor>,
 6019    ) -> Option<(String, Range<Anchor>)> {
 6020        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6021            return None;
 6022        }
 6023        if !EditorSettings::get_global(cx).selection_highlight {
 6024            return None;
 6025        }
 6026        if self.selections.count() != 1 || self.selections.line_mode {
 6027            return None;
 6028        }
 6029        let selection = self.selections.newest::<Point>(cx);
 6030        if selection.is_empty() || selection.start.row != selection.end.row {
 6031            return None;
 6032        }
 6033        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6034        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6035        let query = multi_buffer_snapshot
 6036            .text_for_range(selection_anchor_range.clone())
 6037            .collect::<String>();
 6038        if query.trim().is_empty() {
 6039            return None;
 6040        }
 6041        Some((query, selection_anchor_range))
 6042    }
 6043
 6044    fn update_selection_occurrence_highlights(
 6045        &mut self,
 6046        query_text: String,
 6047        query_range: Range<Anchor>,
 6048        multi_buffer_range_to_query: Range<Point>,
 6049        use_debounce: bool,
 6050        window: &mut Window,
 6051        cx: &mut Context<Editor>,
 6052    ) -> Task<()> {
 6053        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6054        cx.spawn_in(window, async move |editor, cx| {
 6055            if use_debounce {
 6056                cx.background_executor()
 6057                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6058                    .await;
 6059            }
 6060            let match_task = cx.background_spawn(async move {
 6061                let buffer_ranges = multi_buffer_snapshot
 6062                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6063                    .into_iter()
 6064                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6065                let mut match_ranges = Vec::new();
 6066                let Ok(regex) = project::search::SearchQuery::text(
 6067                    query_text.clone(),
 6068                    false,
 6069                    false,
 6070                    false,
 6071                    Default::default(),
 6072                    Default::default(),
 6073                    false,
 6074                    None,
 6075                ) else {
 6076                    return Vec::default();
 6077                };
 6078                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6079                    match_ranges.extend(
 6080                        regex
 6081                            .search(&buffer_snapshot, Some(search_range.clone()))
 6082                            .await
 6083                            .into_iter()
 6084                            .filter_map(|match_range| {
 6085                                let match_start = buffer_snapshot
 6086                                    .anchor_after(search_range.start + match_range.start);
 6087                                let match_end = buffer_snapshot
 6088                                    .anchor_before(search_range.start + match_range.end);
 6089                                let match_anchor_range = Anchor::range_in_buffer(
 6090                                    excerpt_id,
 6091                                    buffer_snapshot.remote_id(),
 6092                                    match_start..match_end,
 6093                                );
 6094                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6095                            }),
 6096                    );
 6097                }
 6098                match_ranges
 6099            });
 6100            let match_ranges = match_task.await;
 6101            editor
 6102                .update_in(cx, |editor, _, cx| {
 6103                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6104                    if !match_ranges.is_empty() {
 6105                        editor.highlight_background::<SelectedTextHighlight>(
 6106                            &match_ranges,
 6107                            |theme| theme.editor_document_highlight_bracket_background,
 6108                            cx,
 6109                        )
 6110                    }
 6111                })
 6112                .log_err();
 6113        })
 6114    }
 6115
 6116    fn refresh_selected_text_highlights(
 6117        &mut self,
 6118        on_buffer_edit: bool,
 6119        window: &mut Window,
 6120        cx: &mut Context<Editor>,
 6121    ) {
 6122        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6123        else {
 6124            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6125            self.quick_selection_highlight_task.take();
 6126            self.debounced_selection_highlight_task.take();
 6127            return;
 6128        };
 6129        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6130        if on_buffer_edit
 6131            || self
 6132                .quick_selection_highlight_task
 6133                .as_ref()
 6134                .map_or(true, |(prev_anchor_range, _)| {
 6135                    prev_anchor_range != &query_range
 6136                })
 6137        {
 6138            let multi_buffer_visible_start = self
 6139                .scroll_manager
 6140                .anchor()
 6141                .anchor
 6142                .to_point(&multi_buffer_snapshot);
 6143            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6144                multi_buffer_visible_start
 6145                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6146                Bias::Left,
 6147            );
 6148            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6149            self.quick_selection_highlight_task = Some((
 6150                query_range.clone(),
 6151                self.update_selection_occurrence_highlights(
 6152                    query_text.clone(),
 6153                    query_range.clone(),
 6154                    multi_buffer_visible_range,
 6155                    false,
 6156                    window,
 6157                    cx,
 6158                ),
 6159            ));
 6160        }
 6161        if on_buffer_edit
 6162            || self
 6163                .debounced_selection_highlight_task
 6164                .as_ref()
 6165                .map_or(true, |(prev_anchor_range, _)| {
 6166                    prev_anchor_range != &query_range
 6167                })
 6168        {
 6169            let multi_buffer_start = multi_buffer_snapshot
 6170                .anchor_before(0)
 6171                .to_point(&multi_buffer_snapshot);
 6172            let multi_buffer_end = multi_buffer_snapshot
 6173                .anchor_after(multi_buffer_snapshot.len())
 6174                .to_point(&multi_buffer_snapshot);
 6175            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6176            self.debounced_selection_highlight_task = Some((
 6177                query_range.clone(),
 6178                self.update_selection_occurrence_highlights(
 6179                    query_text,
 6180                    query_range,
 6181                    multi_buffer_full_range,
 6182                    true,
 6183                    window,
 6184                    cx,
 6185                ),
 6186            ));
 6187        }
 6188    }
 6189
 6190    pub fn refresh_inline_completion(
 6191        &mut self,
 6192        debounce: bool,
 6193        user_requested: bool,
 6194        window: &mut Window,
 6195        cx: &mut Context<Self>,
 6196    ) -> Option<()> {
 6197        let provider = self.edit_prediction_provider()?;
 6198        let cursor = self.selections.newest_anchor().head();
 6199        let (buffer, cursor_buffer_position) =
 6200            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6201
 6202        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6203            self.discard_inline_completion(false, cx);
 6204            return None;
 6205        }
 6206
 6207        if !user_requested
 6208            && (!self.should_show_edit_predictions()
 6209                || !self.is_focused(window)
 6210                || buffer.read(cx).is_empty())
 6211        {
 6212            self.discard_inline_completion(false, cx);
 6213            return None;
 6214        }
 6215
 6216        self.update_visible_inline_completion(window, cx);
 6217        provider.refresh(
 6218            self.project.clone(),
 6219            buffer,
 6220            cursor_buffer_position,
 6221            debounce,
 6222            cx,
 6223        );
 6224        Some(())
 6225    }
 6226
 6227    fn show_edit_predictions_in_menu(&self) -> bool {
 6228        match self.edit_prediction_settings {
 6229            EditPredictionSettings::Disabled => false,
 6230            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6231        }
 6232    }
 6233
 6234    pub fn edit_predictions_enabled(&self) -> bool {
 6235        match self.edit_prediction_settings {
 6236            EditPredictionSettings::Disabled => false,
 6237            EditPredictionSettings::Enabled { .. } => true,
 6238        }
 6239    }
 6240
 6241    fn edit_prediction_requires_modifier(&self) -> bool {
 6242        match self.edit_prediction_settings {
 6243            EditPredictionSettings::Disabled => false,
 6244            EditPredictionSettings::Enabled {
 6245                preview_requires_modifier,
 6246                ..
 6247            } => preview_requires_modifier,
 6248        }
 6249    }
 6250
 6251    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6252        if self.edit_prediction_provider.is_none() {
 6253            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6254        } else {
 6255            let selection = self.selections.newest_anchor();
 6256            let cursor = selection.head();
 6257
 6258            if let Some((buffer, cursor_buffer_position)) =
 6259                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6260            {
 6261                self.edit_prediction_settings =
 6262                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6263            }
 6264        }
 6265    }
 6266
 6267    fn edit_prediction_settings_at_position(
 6268        &self,
 6269        buffer: &Entity<Buffer>,
 6270        buffer_position: language::Anchor,
 6271        cx: &App,
 6272    ) -> EditPredictionSettings {
 6273        if !self.mode.is_full()
 6274            || !self.show_inline_completions_override.unwrap_or(true)
 6275            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6276        {
 6277            return EditPredictionSettings::Disabled;
 6278        }
 6279
 6280        let buffer = buffer.read(cx);
 6281
 6282        let file = buffer.file();
 6283
 6284        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6285            return EditPredictionSettings::Disabled;
 6286        };
 6287
 6288        let by_provider = matches!(
 6289            self.menu_inline_completions_policy,
 6290            MenuInlineCompletionsPolicy::ByProvider
 6291        );
 6292
 6293        let show_in_menu = by_provider
 6294            && self
 6295                .edit_prediction_provider
 6296                .as_ref()
 6297                .map_or(false, |provider| {
 6298                    provider.provider.show_completions_in_menu()
 6299                });
 6300
 6301        let preview_requires_modifier =
 6302            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6303
 6304        EditPredictionSettings::Enabled {
 6305            show_in_menu,
 6306            preview_requires_modifier,
 6307        }
 6308    }
 6309
 6310    fn should_show_edit_predictions(&self) -> bool {
 6311        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6312    }
 6313
 6314    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6315        matches!(
 6316            self.edit_prediction_preview,
 6317            EditPredictionPreview::Active { .. }
 6318        )
 6319    }
 6320
 6321    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6322        let cursor = self.selections.newest_anchor().head();
 6323        if let Some((buffer, cursor_position)) =
 6324            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6325        {
 6326            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6327        } else {
 6328            false
 6329        }
 6330    }
 6331
 6332    pub fn supports_minimap(&self, cx: &App) -> bool {
 6333        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6334    }
 6335
 6336    fn edit_predictions_enabled_in_buffer(
 6337        &self,
 6338        buffer: &Entity<Buffer>,
 6339        buffer_position: language::Anchor,
 6340        cx: &App,
 6341    ) -> bool {
 6342        maybe!({
 6343            if self.read_only(cx) {
 6344                return Some(false);
 6345            }
 6346            let provider = self.edit_prediction_provider()?;
 6347            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6348                return Some(false);
 6349            }
 6350            let buffer = buffer.read(cx);
 6351            let Some(file) = buffer.file() else {
 6352                return Some(true);
 6353            };
 6354            let settings = all_language_settings(Some(file), cx);
 6355            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6356        })
 6357        .unwrap_or(false)
 6358    }
 6359
 6360    fn cycle_inline_completion(
 6361        &mut self,
 6362        direction: Direction,
 6363        window: &mut Window,
 6364        cx: &mut Context<Self>,
 6365    ) -> Option<()> {
 6366        let provider = self.edit_prediction_provider()?;
 6367        let cursor = self.selections.newest_anchor().head();
 6368        let (buffer, cursor_buffer_position) =
 6369            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6370        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6371            return None;
 6372        }
 6373
 6374        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6375        self.update_visible_inline_completion(window, cx);
 6376
 6377        Some(())
 6378    }
 6379
 6380    pub fn show_inline_completion(
 6381        &mut self,
 6382        _: &ShowEditPrediction,
 6383        window: &mut Window,
 6384        cx: &mut Context<Self>,
 6385    ) {
 6386        if !self.has_active_inline_completion() {
 6387            self.refresh_inline_completion(false, true, window, cx);
 6388            return;
 6389        }
 6390
 6391        self.update_visible_inline_completion(window, cx);
 6392    }
 6393
 6394    pub fn display_cursor_names(
 6395        &mut self,
 6396        _: &DisplayCursorNames,
 6397        window: &mut Window,
 6398        cx: &mut Context<Self>,
 6399    ) {
 6400        self.show_cursor_names(window, cx);
 6401    }
 6402
 6403    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6404        self.show_cursor_names = true;
 6405        cx.notify();
 6406        cx.spawn_in(window, async move |this, cx| {
 6407            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6408            this.update(cx, |this, cx| {
 6409                this.show_cursor_names = false;
 6410                cx.notify()
 6411            })
 6412            .ok()
 6413        })
 6414        .detach();
 6415    }
 6416
 6417    pub fn next_edit_prediction(
 6418        &mut self,
 6419        _: &NextEditPrediction,
 6420        window: &mut Window,
 6421        cx: &mut Context<Self>,
 6422    ) {
 6423        if self.has_active_inline_completion() {
 6424            self.cycle_inline_completion(Direction::Next, window, cx);
 6425        } else {
 6426            let is_copilot_disabled = self
 6427                .refresh_inline_completion(false, true, window, cx)
 6428                .is_none();
 6429            if is_copilot_disabled {
 6430                cx.propagate();
 6431            }
 6432        }
 6433    }
 6434
 6435    pub fn previous_edit_prediction(
 6436        &mut self,
 6437        _: &PreviousEditPrediction,
 6438        window: &mut Window,
 6439        cx: &mut Context<Self>,
 6440    ) {
 6441        if self.has_active_inline_completion() {
 6442            self.cycle_inline_completion(Direction::Prev, window, cx);
 6443        } else {
 6444            let is_copilot_disabled = self
 6445                .refresh_inline_completion(false, true, window, cx)
 6446                .is_none();
 6447            if is_copilot_disabled {
 6448                cx.propagate();
 6449            }
 6450        }
 6451    }
 6452
 6453    pub fn accept_edit_prediction(
 6454        &mut self,
 6455        _: &AcceptEditPrediction,
 6456        window: &mut Window,
 6457        cx: &mut Context<Self>,
 6458    ) {
 6459        if self.show_edit_predictions_in_menu() {
 6460            self.hide_context_menu(window, cx);
 6461        }
 6462
 6463        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6464            return;
 6465        };
 6466
 6467        self.report_inline_completion_event(
 6468            active_inline_completion.completion_id.clone(),
 6469            true,
 6470            cx,
 6471        );
 6472
 6473        match &active_inline_completion.completion {
 6474            InlineCompletion::Move { target, .. } => {
 6475                let target = *target;
 6476
 6477                if let Some(position_map) = &self.last_position_map {
 6478                    if position_map
 6479                        .visible_row_range
 6480                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6481                        || !self.edit_prediction_requires_modifier()
 6482                    {
 6483                        self.unfold_ranges(&[target..target], true, false, cx);
 6484                        // Note that this is also done in vim's handler of the Tab action.
 6485                        self.change_selections(
 6486                            Some(Autoscroll::newest()),
 6487                            window,
 6488                            cx,
 6489                            |selections| {
 6490                                selections.select_anchor_ranges([target..target]);
 6491                            },
 6492                        );
 6493                        self.clear_row_highlights::<EditPredictionPreview>();
 6494
 6495                        self.edit_prediction_preview
 6496                            .set_previous_scroll_position(None);
 6497                    } else {
 6498                        self.edit_prediction_preview
 6499                            .set_previous_scroll_position(Some(
 6500                                position_map.snapshot.scroll_anchor,
 6501                            ));
 6502
 6503                        self.highlight_rows::<EditPredictionPreview>(
 6504                            target..target,
 6505                            cx.theme().colors().editor_highlighted_line_background,
 6506                            RowHighlightOptions {
 6507                                autoscroll: true,
 6508                                ..Default::default()
 6509                            },
 6510                            cx,
 6511                        );
 6512                        self.request_autoscroll(Autoscroll::fit(), cx);
 6513                    }
 6514                }
 6515            }
 6516            InlineCompletion::Edit { edits, .. } => {
 6517                if let Some(provider) = self.edit_prediction_provider() {
 6518                    provider.accept(cx);
 6519                }
 6520
 6521                let snapshot = self.buffer.read(cx).snapshot(cx);
 6522                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6523
 6524                self.buffer.update(cx, |buffer, cx| {
 6525                    buffer.edit(edits.iter().cloned(), None, cx)
 6526                });
 6527
 6528                self.change_selections(None, window, cx, |s| {
 6529                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 6530                });
 6531
 6532                self.update_visible_inline_completion(window, cx);
 6533                if self.active_inline_completion.is_none() {
 6534                    self.refresh_inline_completion(true, true, window, cx);
 6535                }
 6536
 6537                cx.notify();
 6538            }
 6539        }
 6540
 6541        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6542    }
 6543
 6544    pub fn accept_partial_inline_completion(
 6545        &mut self,
 6546        _: &AcceptPartialEditPrediction,
 6547        window: &mut Window,
 6548        cx: &mut Context<Self>,
 6549    ) {
 6550        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6551            return;
 6552        };
 6553        if self.selections.count() != 1 {
 6554            return;
 6555        }
 6556
 6557        self.report_inline_completion_event(
 6558            active_inline_completion.completion_id.clone(),
 6559            true,
 6560            cx,
 6561        );
 6562
 6563        match &active_inline_completion.completion {
 6564            InlineCompletion::Move { target, .. } => {
 6565                let target = *target;
 6566                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6567                    selections.select_anchor_ranges([target..target]);
 6568                });
 6569            }
 6570            InlineCompletion::Edit { edits, .. } => {
 6571                // Find an insertion that starts at the cursor position.
 6572                let snapshot = self.buffer.read(cx).snapshot(cx);
 6573                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6574                let insertion = edits.iter().find_map(|(range, text)| {
 6575                    let range = range.to_offset(&snapshot);
 6576                    if range.is_empty() && range.start == cursor_offset {
 6577                        Some(text)
 6578                    } else {
 6579                        None
 6580                    }
 6581                });
 6582
 6583                if let Some(text) = insertion {
 6584                    let mut partial_completion = text
 6585                        .chars()
 6586                        .by_ref()
 6587                        .take_while(|c| c.is_alphabetic())
 6588                        .collect::<String>();
 6589                    if partial_completion.is_empty() {
 6590                        partial_completion = text
 6591                            .chars()
 6592                            .by_ref()
 6593                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6594                            .collect::<String>();
 6595                    }
 6596
 6597                    cx.emit(EditorEvent::InputHandled {
 6598                        utf16_range_to_replace: None,
 6599                        text: partial_completion.clone().into(),
 6600                    });
 6601
 6602                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6603
 6604                    self.refresh_inline_completion(true, true, window, cx);
 6605                    cx.notify();
 6606                } else {
 6607                    self.accept_edit_prediction(&Default::default(), window, cx);
 6608                }
 6609            }
 6610        }
 6611    }
 6612
 6613    fn discard_inline_completion(
 6614        &mut self,
 6615        should_report_inline_completion_event: bool,
 6616        cx: &mut Context<Self>,
 6617    ) -> bool {
 6618        if should_report_inline_completion_event {
 6619            let completion_id = self
 6620                .active_inline_completion
 6621                .as_ref()
 6622                .and_then(|active_completion| active_completion.completion_id.clone());
 6623
 6624            self.report_inline_completion_event(completion_id, false, cx);
 6625        }
 6626
 6627        if let Some(provider) = self.edit_prediction_provider() {
 6628            provider.discard(cx);
 6629        }
 6630
 6631        self.take_active_inline_completion(cx)
 6632    }
 6633
 6634    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6635        let Some(provider) = self.edit_prediction_provider() else {
 6636            return;
 6637        };
 6638
 6639        let Some((_, buffer, _)) = self
 6640            .buffer
 6641            .read(cx)
 6642            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6643        else {
 6644            return;
 6645        };
 6646
 6647        let extension = buffer
 6648            .read(cx)
 6649            .file()
 6650            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6651
 6652        let event_type = match accepted {
 6653            true => "Edit Prediction Accepted",
 6654            false => "Edit Prediction Discarded",
 6655        };
 6656        telemetry::event!(
 6657            event_type,
 6658            provider = provider.name(),
 6659            prediction_id = id,
 6660            suggestion_accepted = accepted,
 6661            file_extension = extension,
 6662        );
 6663    }
 6664
 6665    pub fn has_active_inline_completion(&self) -> bool {
 6666        self.active_inline_completion.is_some()
 6667    }
 6668
 6669    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6670        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6671            return false;
 6672        };
 6673
 6674        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6675        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6676        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6677        true
 6678    }
 6679
 6680    /// Returns true when we're displaying the edit prediction popover below the cursor
 6681    /// like we are not previewing and the LSP autocomplete menu is visible
 6682    /// or we are in `when_holding_modifier` mode.
 6683    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6684        if self.edit_prediction_preview_is_active()
 6685            || !self.show_edit_predictions_in_menu()
 6686            || !self.edit_predictions_enabled()
 6687        {
 6688            return false;
 6689        }
 6690
 6691        if self.has_visible_completions_menu() {
 6692            return true;
 6693        }
 6694
 6695        has_completion && self.edit_prediction_requires_modifier()
 6696    }
 6697
 6698    fn handle_modifiers_changed(
 6699        &mut self,
 6700        modifiers: Modifiers,
 6701        position_map: &PositionMap,
 6702        window: &mut Window,
 6703        cx: &mut Context<Self>,
 6704    ) {
 6705        if self.show_edit_predictions_in_menu() {
 6706            self.update_edit_prediction_preview(&modifiers, window, cx);
 6707        }
 6708
 6709        self.update_selection_mode(&modifiers, position_map, window, cx);
 6710
 6711        let mouse_position = window.mouse_position();
 6712        if !position_map.text_hitbox.is_hovered(window) {
 6713            return;
 6714        }
 6715
 6716        self.update_hovered_link(
 6717            position_map.point_for_position(mouse_position),
 6718            &position_map.snapshot,
 6719            modifiers,
 6720            window,
 6721            cx,
 6722        )
 6723    }
 6724
 6725    fn update_selection_mode(
 6726        &mut self,
 6727        modifiers: &Modifiers,
 6728        position_map: &PositionMap,
 6729        window: &mut Window,
 6730        cx: &mut Context<Self>,
 6731    ) {
 6732        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6733            return;
 6734        }
 6735
 6736        let mouse_position = window.mouse_position();
 6737        let point_for_position = position_map.point_for_position(mouse_position);
 6738        let position = point_for_position.previous_valid;
 6739
 6740        self.select(
 6741            SelectPhase::BeginColumnar {
 6742                position,
 6743                reset: false,
 6744                goal_column: point_for_position.exact_unclipped.column(),
 6745            },
 6746            window,
 6747            cx,
 6748        );
 6749    }
 6750
 6751    fn update_edit_prediction_preview(
 6752        &mut self,
 6753        modifiers: &Modifiers,
 6754        window: &mut Window,
 6755        cx: &mut Context<Self>,
 6756    ) {
 6757        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6758        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6759            return;
 6760        };
 6761
 6762        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6763            if matches!(
 6764                self.edit_prediction_preview,
 6765                EditPredictionPreview::Inactive { .. }
 6766            ) {
 6767                self.edit_prediction_preview = EditPredictionPreview::Active {
 6768                    previous_scroll_position: None,
 6769                    since: Instant::now(),
 6770                };
 6771
 6772                self.update_visible_inline_completion(window, cx);
 6773                cx.notify();
 6774            }
 6775        } else if let EditPredictionPreview::Active {
 6776            previous_scroll_position,
 6777            since,
 6778        } = self.edit_prediction_preview
 6779        {
 6780            if let (Some(previous_scroll_position), Some(position_map)) =
 6781                (previous_scroll_position, self.last_position_map.as_ref())
 6782            {
 6783                self.set_scroll_position(
 6784                    previous_scroll_position
 6785                        .scroll_position(&position_map.snapshot.display_snapshot),
 6786                    window,
 6787                    cx,
 6788                );
 6789            }
 6790
 6791            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6792                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6793            };
 6794            self.clear_row_highlights::<EditPredictionPreview>();
 6795            self.update_visible_inline_completion(window, cx);
 6796            cx.notify();
 6797        }
 6798    }
 6799
 6800    fn update_visible_inline_completion(
 6801        &mut self,
 6802        _window: &mut Window,
 6803        cx: &mut Context<Self>,
 6804    ) -> Option<()> {
 6805        let selection = self.selections.newest_anchor();
 6806        let cursor = selection.head();
 6807        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6808        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6809        let excerpt_id = cursor.excerpt_id;
 6810
 6811        let show_in_menu = self.show_edit_predictions_in_menu();
 6812        let completions_menu_has_precedence = !show_in_menu
 6813            && (self.context_menu.borrow().is_some()
 6814                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6815
 6816        if completions_menu_has_precedence
 6817            || !offset_selection.is_empty()
 6818            || self
 6819                .active_inline_completion
 6820                .as_ref()
 6821                .map_or(false, |completion| {
 6822                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6823                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6824                    !invalidation_range.contains(&offset_selection.head())
 6825                })
 6826        {
 6827            self.discard_inline_completion(false, cx);
 6828            return None;
 6829        }
 6830
 6831        self.take_active_inline_completion(cx);
 6832        let Some(provider) = self.edit_prediction_provider() else {
 6833            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6834            return None;
 6835        };
 6836
 6837        let (buffer, cursor_buffer_position) =
 6838            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6839
 6840        self.edit_prediction_settings =
 6841            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6842
 6843        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6844
 6845        if self.edit_prediction_indent_conflict {
 6846            let cursor_point = cursor.to_point(&multibuffer);
 6847
 6848            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6849
 6850            if let Some((_, indent)) = indents.iter().next() {
 6851                if indent.len == cursor_point.column {
 6852                    self.edit_prediction_indent_conflict = false;
 6853                }
 6854            }
 6855        }
 6856
 6857        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6858        let edits = inline_completion
 6859            .edits
 6860            .into_iter()
 6861            .flat_map(|(range, new_text)| {
 6862                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6863                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6864                Some((start..end, new_text))
 6865            })
 6866            .collect::<Vec<_>>();
 6867        if edits.is_empty() {
 6868            return None;
 6869        }
 6870
 6871        let first_edit_start = edits.first().unwrap().0.start;
 6872        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6873        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6874
 6875        let last_edit_end = edits.last().unwrap().0.end;
 6876        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6877        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6878
 6879        let cursor_row = cursor.to_point(&multibuffer).row;
 6880
 6881        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6882
 6883        let mut inlay_ids = Vec::new();
 6884        let invalidation_row_range;
 6885        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6886            Some(cursor_row..edit_end_row)
 6887        } else if cursor_row > edit_end_row {
 6888            Some(edit_start_row..cursor_row)
 6889        } else {
 6890            None
 6891        };
 6892        let is_move =
 6893            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6894        let completion = if is_move {
 6895            invalidation_row_range =
 6896                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6897            let target = first_edit_start;
 6898            InlineCompletion::Move { target, snapshot }
 6899        } else {
 6900            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6901                && !self.inline_completions_hidden_for_vim_mode;
 6902
 6903            if show_completions_in_buffer {
 6904                if edits
 6905                    .iter()
 6906                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6907                {
 6908                    let mut inlays = Vec::new();
 6909                    for (range, new_text) in &edits {
 6910                        let inlay = Inlay::inline_completion(
 6911                            post_inc(&mut self.next_inlay_id),
 6912                            range.start,
 6913                            new_text.as_str(),
 6914                        );
 6915                        inlay_ids.push(inlay.id);
 6916                        inlays.push(inlay);
 6917                    }
 6918
 6919                    self.splice_inlays(&[], inlays, cx);
 6920                } else {
 6921                    let background_color = cx.theme().status().deleted_background;
 6922                    self.highlight_text::<InlineCompletionHighlight>(
 6923                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6924                        HighlightStyle {
 6925                            background_color: Some(background_color),
 6926                            ..Default::default()
 6927                        },
 6928                        cx,
 6929                    );
 6930                }
 6931            }
 6932
 6933            invalidation_row_range = edit_start_row..edit_end_row;
 6934
 6935            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6936                if provider.show_tab_accept_marker() {
 6937                    EditDisplayMode::TabAccept
 6938                } else {
 6939                    EditDisplayMode::Inline
 6940                }
 6941            } else {
 6942                EditDisplayMode::DiffPopover
 6943            };
 6944
 6945            InlineCompletion::Edit {
 6946                edits,
 6947                edit_preview: inline_completion.edit_preview,
 6948                display_mode,
 6949                snapshot,
 6950            }
 6951        };
 6952
 6953        let invalidation_range = multibuffer
 6954            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6955            ..multibuffer.anchor_after(Point::new(
 6956                invalidation_row_range.end,
 6957                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6958            ));
 6959
 6960        self.stale_inline_completion_in_menu = None;
 6961        self.active_inline_completion = Some(InlineCompletionState {
 6962            inlay_ids,
 6963            completion,
 6964            completion_id: inline_completion.id,
 6965            invalidation_range,
 6966        });
 6967
 6968        cx.notify();
 6969
 6970        Some(())
 6971    }
 6972
 6973    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6974        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6975    }
 6976
 6977    fn clear_tasks(&mut self) {
 6978        self.tasks.clear()
 6979    }
 6980
 6981    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 6982        if self.tasks.insert(key, value).is_some() {
 6983            // This case should hopefully be rare, but just in case...
 6984            log::error!(
 6985                "multiple different run targets found on a single line, only the last target will be rendered"
 6986            )
 6987        }
 6988    }
 6989
 6990    /// Get all display points of breakpoints that will be rendered within editor
 6991    ///
 6992    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 6993    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 6994    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 6995    fn active_breakpoints(
 6996        &self,
 6997        range: Range<DisplayRow>,
 6998        window: &mut Window,
 6999        cx: &mut Context<Self>,
 7000    ) -> HashMap<DisplayRow, (Anchor, Breakpoint)> {
 7001        let mut breakpoint_display_points = HashMap::default();
 7002
 7003        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7004            return breakpoint_display_points;
 7005        };
 7006
 7007        let snapshot = self.snapshot(window, cx);
 7008
 7009        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7010        let Some(project) = self.project.as_ref() else {
 7011            return breakpoint_display_points;
 7012        };
 7013
 7014        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7015            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7016
 7017        for (buffer_snapshot, range, excerpt_id) in
 7018            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7019        {
 7020            let Some(buffer) = project.read_with(cx, |this, cx| {
 7021                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7022            }) else {
 7023                continue;
 7024            };
 7025            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7026                &buffer,
 7027                Some(
 7028                    buffer_snapshot.anchor_before(range.start)
 7029                        ..buffer_snapshot.anchor_after(range.end),
 7030                ),
 7031                buffer_snapshot,
 7032                cx,
 7033            );
 7034            for (anchor, breakpoint) in breakpoints {
 7035                let multi_buffer_anchor =
 7036                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), *anchor);
 7037                let position = multi_buffer_anchor
 7038                    .to_point(&multi_buffer_snapshot)
 7039                    .to_display_point(&snapshot);
 7040
 7041                breakpoint_display_points
 7042                    .insert(position.row(), (multi_buffer_anchor, breakpoint.clone()));
 7043            }
 7044        }
 7045
 7046        breakpoint_display_points
 7047    }
 7048
 7049    fn breakpoint_context_menu(
 7050        &self,
 7051        anchor: Anchor,
 7052        window: &mut Window,
 7053        cx: &mut Context<Self>,
 7054    ) -> Entity<ui::ContextMenu> {
 7055        let weak_editor = cx.weak_entity();
 7056        let focus_handle = self.focus_handle(cx);
 7057
 7058        let row = self
 7059            .buffer
 7060            .read(cx)
 7061            .snapshot(cx)
 7062            .summary_for_anchor::<Point>(&anchor)
 7063            .row;
 7064
 7065        let breakpoint = self
 7066            .breakpoint_at_row(row, window, cx)
 7067            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7068
 7069        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7070            "Edit Log Breakpoint"
 7071        } else {
 7072            "Set Log Breakpoint"
 7073        };
 7074
 7075        let condition_breakpoint_msg = if breakpoint
 7076            .as_ref()
 7077            .is_some_and(|bp| bp.1.condition.is_some())
 7078        {
 7079            "Edit Condition Breakpoint"
 7080        } else {
 7081            "Set Condition Breakpoint"
 7082        };
 7083
 7084        let hit_condition_breakpoint_msg = if breakpoint
 7085            .as_ref()
 7086            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7087        {
 7088            "Edit Hit Condition Breakpoint"
 7089        } else {
 7090            "Set Hit Condition Breakpoint"
 7091        };
 7092
 7093        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7094            "Unset Breakpoint"
 7095        } else {
 7096            "Set Breakpoint"
 7097        };
 7098
 7099        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7100            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7101
 7102        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7103            BreakpointState::Enabled => Some("Disable"),
 7104            BreakpointState::Disabled => Some("Enable"),
 7105        });
 7106
 7107        let (anchor, breakpoint) =
 7108            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7109
 7110        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7111            menu.on_blur_subscription(Subscription::new(|| {}))
 7112                .context(focus_handle)
 7113                .when(run_to_cursor, |this| {
 7114                    let weak_editor = weak_editor.clone();
 7115                    this.entry("Run to cursor", None, move |window, cx| {
 7116                        weak_editor
 7117                            .update(cx, |editor, cx| {
 7118                                editor.change_selections(None, window, cx, |s| {
 7119                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7120                                });
 7121                            })
 7122                            .ok();
 7123
 7124                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7125                    })
 7126                    .separator()
 7127                })
 7128                .when_some(toggle_state_msg, |this, msg| {
 7129                    this.entry(msg, None, {
 7130                        let weak_editor = weak_editor.clone();
 7131                        let breakpoint = breakpoint.clone();
 7132                        move |_window, cx| {
 7133                            weak_editor
 7134                                .update(cx, |this, cx| {
 7135                                    this.edit_breakpoint_at_anchor(
 7136                                        anchor,
 7137                                        breakpoint.as_ref().clone(),
 7138                                        BreakpointEditAction::InvertState,
 7139                                        cx,
 7140                                    );
 7141                                })
 7142                                .log_err();
 7143                        }
 7144                    })
 7145                })
 7146                .entry(set_breakpoint_msg, None, {
 7147                    let weak_editor = weak_editor.clone();
 7148                    let breakpoint = breakpoint.clone();
 7149                    move |_window, cx| {
 7150                        weak_editor
 7151                            .update(cx, |this, cx| {
 7152                                this.edit_breakpoint_at_anchor(
 7153                                    anchor,
 7154                                    breakpoint.as_ref().clone(),
 7155                                    BreakpointEditAction::Toggle,
 7156                                    cx,
 7157                                );
 7158                            })
 7159                            .log_err();
 7160                    }
 7161                })
 7162                .entry(log_breakpoint_msg, None, {
 7163                    let breakpoint = breakpoint.clone();
 7164                    let weak_editor = weak_editor.clone();
 7165                    move |window, cx| {
 7166                        weak_editor
 7167                            .update(cx, |this, cx| {
 7168                                this.add_edit_breakpoint_block(
 7169                                    anchor,
 7170                                    breakpoint.as_ref(),
 7171                                    BreakpointPromptEditAction::Log,
 7172                                    window,
 7173                                    cx,
 7174                                );
 7175                            })
 7176                            .log_err();
 7177                    }
 7178                })
 7179                .entry(condition_breakpoint_msg, None, {
 7180                    let breakpoint = breakpoint.clone();
 7181                    let weak_editor = weak_editor.clone();
 7182                    move |window, cx| {
 7183                        weak_editor
 7184                            .update(cx, |this, cx| {
 7185                                this.add_edit_breakpoint_block(
 7186                                    anchor,
 7187                                    breakpoint.as_ref(),
 7188                                    BreakpointPromptEditAction::Condition,
 7189                                    window,
 7190                                    cx,
 7191                                );
 7192                            })
 7193                            .log_err();
 7194                    }
 7195                })
 7196                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7197                    weak_editor
 7198                        .update(cx, |this, cx| {
 7199                            this.add_edit_breakpoint_block(
 7200                                anchor,
 7201                                breakpoint.as_ref(),
 7202                                BreakpointPromptEditAction::HitCondition,
 7203                                window,
 7204                                cx,
 7205                            );
 7206                        })
 7207                        .log_err();
 7208                })
 7209        })
 7210    }
 7211
 7212    fn render_breakpoint(
 7213        &self,
 7214        position: Anchor,
 7215        row: DisplayRow,
 7216        breakpoint: &Breakpoint,
 7217        cx: &mut Context<Self>,
 7218    ) -> IconButton {
 7219        // Is it a breakpoint that shows up when hovering over gutter?
 7220        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7221            (false, false),
 7222            |PhantomBreakpointIndicator {
 7223                 is_active,
 7224                 display_row,
 7225                 collides_with_existing_breakpoint,
 7226             }| {
 7227                (
 7228                    is_active && display_row == row,
 7229                    collides_with_existing_breakpoint,
 7230                )
 7231            },
 7232        );
 7233
 7234        let (color, icon) = {
 7235            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7236                (false, false) => ui::IconName::DebugBreakpoint,
 7237                (true, false) => ui::IconName::DebugLogBreakpoint,
 7238                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7239                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7240            };
 7241
 7242            let color = if is_phantom {
 7243                Color::Hint
 7244            } else {
 7245                Color::Debugger
 7246            };
 7247
 7248            (color, icon)
 7249        };
 7250
 7251        let breakpoint = Arc::from(breakpoint.clone());
 7252
 7253        let alt_as_text = gpui::Keystroke {
 7254            modifiers: Modifiers::secondary_key(),
 7255            ..Default::default()
 7256        };
 7257        let primary_action_text = if breakpoint.is_disabled() {
 7258            "enable"
 7259        } else if is_phantom && !collides_with_existing {
 7260            "set"
 7261        } else {
 7262            "unset"
 7263        };
 7264        let mut primary_text = format!("Click to {primary_action_text}");
 7265        if collides_with_existing && !breakpoint.is_disabled() {
 7266            use std::fmt::Write;
 7267            write!(primary_text, ", {alt_as_text}-click to disable").ok();
 7268        }
 7269        let primary_text = SharedString::from(primary_text);
 7270        let focus_handle = self.focus_handle.clone();
 7271        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7272            .icon_size(IconSize::XSmall)
 7273            .size(ui::ButtonSize::None)
 7274            .icon_color(color)
 7275            .style(ButtonStyle::Transparent)
 7276            .on_click(cx.listener({
 7277                let breakpoint = breakpoint.clone();
 7278
 7279                move |editor, event: &ClickEvent, window, cx| {
 7280                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7281                        BreakpointEditAction::InvertState
 7282                    } else {
 7283                        BreakpointEditAction::Toggle
 7284                    };
 7285
 7286                    window.focus(&editor.focus_handle(cx));
 7287                    editor.edit_breakpoint_at_anchor(
 7288                        position,
 7289                        breakpoint.as_ref().clone(),
 7290                        edit_action,
 7291                        cx,
 7292                    );
 7293                }
 7294            }))
 7295            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7296                editor.set_breakpoint_context_menu(
 7297                    row,
 7298                    Some(position),
 7299                    event.down.position,
 7300                    window,
 7301                    cx,
 7302                );
 7303            }))
 7304            .tooltip(move |window, cx| {
 7305                Tooltip::with_meta_in(
 7306                    primary_text.clone(),
 7307                    None,
 7308                    "Right-click for more options",
 7309                    &focus_handle,
 7310                    window,
 7311                    cx,
 7312                )
 7313            })
 7314    }
 7315
 7316    fn build_tasks_context(
 7317        project: &Entity<Project>,
 7318        buffer: &Entity<Buffer>,
 7319        buffer_row: u32,
 7320        tasks: &Arc<RunnableTasks>,
 7321        cx: &mut Context<Self>,
 7322    ) -> Task<Option<task::TaskContext>> {
 7323        let position = Point::new(buffer_row, tasks.column);
 7324        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7325        let location = Location {
 7326            buffer: buffer.clone(),
 7327            range: range_start..range_start,
 7328        };
 7329        // Fill in the environmental variables from the tree-sitter captures
 7330        let mut captured_task_variables = TaskVariables::default();
 7331        for (capture_name, value) in tasks.extra_variables.clone() {
 7332            captured_task_variables.insert(
 7333                task::VariableName::Custom(capture_name.into()),
 7334                value.clone(),
 7335            );
 7336        }
 7337        project.update(cx, |project, cx| {
 7338            project.task_store().update(cx, |task_store, cx| {
 7339                task_store.task_context_for_location(captured_task_variables, location, cx)
 7340            })
 7341        })
 7342    }
 7343
 7344    pub fn spawn_nearest_task(
 7345        &mut self,
 7346        action: &SpawnNearestTask,
 7347        window: &mut Window,
 7348        cx: &mut Context<Self>,
 7349    ) {
 7350        let Some((workspace, _)) = self.workspace.clone() else {
 7351            return;
 7352        };
 7353        let Some(project) = self.project.clone() else {
 7354            return;
 7355        };
 7356
 7357        // Try to find a closest, enclosing node using tree-sitter that has a
 7358        // task
 7359        let Some((buffer, buffer_row, tasks)) = self
 7360            .find_enclosing_node_task(cx)
 7361            // Or find the task that's closest in row-distance.
 7362            .or_else(|| self.find_closest_task(cx))
 7363        else {
 7364            return;
 7365        };
 7366
 7367        let reveal_strategy = action.reveal;
 7368        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7369        cx.spawn_in(window, async move |_, cx| {
 7370            let context = task_context.await?;
 7371            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7372
 7373            let resolved = &mut resolved_task.resolved;
 7374            resolved.reveal = reveal_strategy;
 7375
 7376            workspace
 7377                .update_in(cx, |workspace, window, cx| {
 7378                    workspace.schedule_resolved_task(
 7379                        task_source_kind,
 7380                        resolved_task,
 7381                        false,
 7382                        window,
 7383                        cx,
 7384                    );
 7385                })
 7386                .ok()
 7387        })
 7388        .detach();
 7389    }
 7390
 7391    fn find_closest_task(
 7392        &mut self,
 7393        cx: &mut Context<Self>,
 7394    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7395        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7396
 7397        let ((buffer_id, row), tasks) = self
 7398            .tasks
 7399            .iter()
 7400            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7401
 7402        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7403        let tasks = Arc::new(tasks.to_owned());
 7404        Some((buffer, *row, tasks))
 7405    }
 7406
 7407    fn find_enclosing_node_task(
 7408        &mut self,
 7409        cx: &mut Context<Self>,
 7410    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7411        let snapshot = self.buffer.read(cx).snapshot(cx);
 7412        let offset = self.selections.newest::<usize>(cx).head();
 7413        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7414        let buffer_id = excerpt.buffer().remote_id();
 7415
 7416        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7417        let mut cursor = layer.node().walk();
 7418
 7419        while cursor.goto_first_child_for_byte(offset).is_some() {
 7420            if cursor.node().end_byte() == offset {
 7421                cursor.goto_next_sibling();
 7422            }
 7423        }
 7424
 7425        // Ascend to the smallest ancestor that contains the range and has a task.
 7426        loop {
 7427            let node = cursor.node();
 7428            let node_range = node.byte_range();
 7429            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7430
 7431            // Check if this node contains our offset
 7432            if node_range.start <= offset && node_range.end >= offset {
 7433                // If it contains offset, check for task
 7434                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7435                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7436                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7437                }
 7438            }
 7439
 7440            if !cursor.goto_parent() {
 7441                break;
 7442            }
 7443        }
 7444        None
 7445    }
 7446
 7447    fn render_run_indicator(
 7448        &self,
 7449        _style: &EditorStyle,
 7450        is_active: bool,
 7451        row: DisplayRow,
 7452        breakpoint: Option<(Anchor, Breakpoint)>,
 7453        cx: &mut Context<Self>,
 7454    ) -> IconButton {
 7455        let color = Color::Muted;
 7456        let position = breakpoint.as_ref().map(|(anchor, _)| *anchor);
 7457
 7458        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7459            .shape(ui::IconButtonShape::Square)
 7460            .icon_size(IconSize::XSmall)
 7461            .icon_color(color)
 7462            .toggle_state(is_active)
 7463            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7464                let quick_launch = e.down.button == MouseButton::Left;
 7465                window.focus(&editor.focus_handle(cx));
 7466                editor.toggle_code_actions(
 7467                    &ToggleCodeActions {
 7468                        deployed_from_indicator: Some(row),
 7469                        quick_launch,
 7470                    },
 7471                    window,
 7472                    cx,
 7473                );
 7474            }))
 7475            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7476                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7477            }))
 7478    }
 7479
 7480    pub fn context_menu_visible(&self) -> bool {
 7481        !self.edit_prediction_preview_is_active()
 7482            && self
 7483                .context_menu
 7484                .borrow()
 7485                .as_ref()
 7486                .map_or(false, |menu| menu.visible())
 7487    }
 7488
 7489    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7490        self.context_menu
 7491            .borrow()
 7492            .as_ref()
 7493            .map(|menu| menu.origin())
 7494    }
 7495
 7496    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7497        self.context_menu_options = Some(options);
 7498    }
 7499
 7500    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7501    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7502
 7503    fn render_edit_prediction_popover(
 7504        &mut self,
 7505        text_bounds: &Bounds<Pixels>,
 7506        content_origin: gpui::Point<Pixels>,
 7507        right_margin: Pixels,
 7508        editor_snapshot: &EditorSnapshot,
 7509        visible_row_range: Range<DisplayRow>,
 7510        scroll_top: f32,
 7511        scroll_bottom: f32,
 7512        line_layouts: &[LineWithInvisibles],
 7513        line_height: Pixels,
 7514        scroll_pixel_position: gpui::Point<Pixels>,
 7515        newest_selection_head: Option<DisplayPoint>,
 7516        editor_width: Pixels,
 7517        style: &EditorStyle,
 7518        window: &mut Window,
 7519        cx: &mut App,
 7520    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7521        if self.mode().is_minimap() {
 7522            return None;
 7523        }
 7524        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7525
 7526        if self.edit_prediction_visible_in_cursor_popover(true) {
 7527            return None;
 7528        }
 7529
 7530        match &active_inline_completion.completion {
 7531            InlineCompletion::Move { target, .. } => {
 7532                let target_display_point = target.to_display_point(editor_snapshot);
 7533
 7534                if self.edit_prediction_requires_modifier() {
 7535                    if !self.edit_prediction_preview_is_active() {
 7536                        return None;
 7537                    }
 7538
 7539                    self.render_edit_prediction_modifier_jump_popover(
 7540                        text_bounds,
 7541                        content_origin,
 7542                        visible_row_range,
 7543                        line_layouts,
 7544                        line_height,
 7545                        scroll_pixel_position,
 7546                        newest_selection_head,
 7547                        target_display_point,
 7548                        window,
 7549                        cx,
 7550                    )
 7551                } else {
 7552                    self.render_edit_prediction_eager_jump_popover(
 7553                        text_bounds,
 7554                        content_origin,
 7555                        editor_snapshot,
 7556                        visible_row_range,
 7557                        scroll_top,
 7558                        scroll_bottom,
 7559                        line_height,
 7560                        scroll_pixel_position,
 7561                        target_display_point,
 7562                        editor_width,
 7563                        window,
 7564                        cx,
 7565                    )
 7566                }
 7567            }
 7568            InlineCompletion::Edit {
 7569                display_mode: EditDisplayMode::Inline,
 7570                ..
 7571            } => None,
 7572            InlineCompletion::Edit {
 7573                display_mode: EditDisplayMode::TabAccept,
 7574                edits,
 7575                ..
 7576            } => {
 7577                let range = &edits.first()?.0;
 7578                let target_display_point = range.end.to_display_point(editor_snapshot);
 7579
 7580                self.render_edit_prediction_end_of_line_popover(
 7581                    "Accept",
 7582                    editor_snapshot,
 7583                    visible_row_range,
 7584                    target_display_point,
 7585                    line_height,
 7586                    scroll_pixel_position,
 7587                    content_origin,
 7588                    editor_width,
 7589                    window,
 7590                    cx,
 7591                )
 7592            }
 7593            InlineCompletion::Edit {
 7594                edits,
 7595                edit_preview,
 7596                display_mode: EditDisplayMode::DiffPopover,
 7597                snapshot,
 7598            } => self.render_edit_prediction_diff_popover(
 7599                text_bounds,
 7600                content_origin,
 7601                right_margin,
 7602                editor_snapshot,
 7603                visible_row_range,
 7604                line_layouts,
 7605                line_height,
 7606                scroll_pixel_position,
 7607                newest_selection_head,
 7608                editor_width,
 7609                style,
 7610                edits,
 7611                edit_preview,
 7612                snapshot,
 7613                window,
 7614                cx,
 7615            ),
 7616        }
 7617    }
 7618
 7619    fn render_edit_prediction_modifier_jump_popover(
 7620        &mut self,
 7621        text_bounds: &Bounds<Pixels>,
 7622        content_origin: gpui::Point<Pixels>,
 7623        visible_row_range: Range<DisplayRow>,
 7624        line_layouts: &[LineWithInvisibles],
 7625        line_height: Pixels,
 7626        scroll_pixel_position: gpui::Point<Pixels>,
 7627        newest_selection_head: Option<DisplayPoint>,
 7628        target_display_point: DisplayPoint,
 7629        window: &mut Window,
 7630        cx: &mut App,
 7631    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7632        let scrolled_content_origin =
 7633            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7634
 7635        const SCROLL_PADDING_Y: Pixels = px(12.);
 7636
 7637        if target_display_point.row() < visible_row_range.start {
 7638            return self.render_edit_prediction_scroll_popover(
 7639                |_| SCROLL_PADDING_Y,
 7640                IconName::ArrowUp,
 7641                visible_row_range,
 7642                line_layouts,
 7643                newest_selection_head,
 7644                scrolled_content_origin,
 7645                window,
 7646                cx,
 7647            );
 7648        } else if target_display_point.row() >= visible_row_range.end {
 7649            return self.render_edit_prediction_scroll_popover(
 7650                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7651                IconName::ArrowDown,
 7652                visible_row_range,
 7653                line_layouts,
 7654                newest_selection_head,
 7655                scrolled_content_origin,
 7656                window,
 7657                cx,
 7658            );
 7659        }
 7660
 7661        const POLE_WIDTH: Pixels = px(2.);
 7662
 7663        let line_layout =
 7664            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7665        let target_column = target_display_point.column() as usize;
 7666
 7667        let target_x = line_layout.x_for_index(target_column);
 7668        let target_y =
 7669            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7670
 7671        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7672
 7673        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7674        border_color.l += 0.001;
 7675
 7676        let mut element = v_flex()
 7677            .items_end()
 7678            .when(flag_on_right, |el| el.items_start())
 7679            .child(if flag_on_right {
 7680                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7681                    .rounded_bl(px(0.))
 7682                    .rounded_tl(px(0.))
 7683                    .border_l_2()
 7684                    .border_color(border_color)
 7685            } else {
 7686                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7687                    .rounded_br(px(0.))
 7688                    .rounded_tr(px(0.))
 7689                    .border_r_2()
 7690                    .border_color(border_color)
 7691            })
 7692            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7693            .into_any();
 7694
 7695        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7696
 7697        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7698            - point(
 7699                if flag_on_right {
 7700                    POLE_WIDTH
 7701                } else {
 7702                    size.width - POLE_WIDTH
 7703                },
 7704                size.height - line_height,
 7705            );
 7706
 7707        origin.x = origin.x.max(content_origin.x);
 7708
 7709        element.prepaint_at(origin, window, cx);
 7710
 7711        Some((element, origin))
 7712    }
 7713
 7714    fn render_edit_prediction_scroll_popover(
 7715        &mut self,
 7716        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7717        scroll_icon: IconName,
 7718        visible_row_range: Range<DisplayRow>,
 7719        line_layouts: &[LineWithInvisibles],
 7720        newest_selection_head: Option<DisplayPoint>,
 7721        scrolled_content_origin: gpui::Point<Pixels>,
 7722        window: &mut Window,
 7723        cx: &mut App,
 7724    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7725        let mut element = self
 7726            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7727            .into_any();
 7728
 7729        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7730
 7731        let cursor = newest_selection_head?;
 7732        let cursor_row_layout =
 7733            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7734        let cursor_column = cursor.column() as usize;
 7735
 7736        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7737
 7738        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7739
 7740        element.prepaint_at(origin, window, cx);
 7741        Some((element, origin))
 7742    }
 7743
 7744    fn render_edit_prediction_eager_jump_popover(
 7745        &mut self,
 7746        text_bounds: &Bounds<Pixels>,
 7747        content_origin: gpui::Point<Pixels>,
 7748        editor_snapshot: &EditorSnapshot,
 7749        visible_row_range: Range<DisplayRow>,
 7750        scroll_top: f32,
 7751        scroll_bottom: f32,
 7752        line_height: Pixels,
 7753        scroll_pixel_position: gpui::Point<Pixels>,
 7754        target_display_point: DisplayPoint,
 7755        editor_width: Pixels,
 7756        window: &mut Window,
 7757        cx: &mut App,
 7758    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7759        if target_display_point.row().as_f32() < scroll_top {
 7760            let mut element = self
 7761                .render_edit_prediction_line_popover(
 7762                    "Jump to Edit",
 7763                    Some(IconName::ArrowUp),
 7764                    window,
 7765                    cx,
 7766                )?
 7767                .into_any();
 7768
 7769            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7770            let offset = point(
 7771                (text_bounds.size.width - size.width) / 2.,
 7772                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7773            );
 7774
 7775            let origin = text_bounds.origin + offset;
 7776            element.prepaint_at(origin, window, cx);
 7777            Some((element, origin))
 7778        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7779            let mut element = self
 7780                .render_edit_prediction_line_popover(
 7781                    "Jump to Edit",
 7782                    Some(IconName::ArrowDown),
 7783                    window,
 7784                    cx,
 7785                )?
 7786                .into_any();
 7787
 7788            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7789            let offset = point(
 7790                (text_bounds.size.width - size.width) / 2.,
 7791                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7792            );
 7793
 7794            let origin = text_bounds.origin + offset;
 7795            element.prepaint_at(origin, window, cx);
 7796            Some((element, origin))
 7797        } else {
 7798            self.render_edit_prediction_end_of_line_popover(
 7799                "Jump to Edit",
 7800                editor_snapshot,
 7801                visible_row_range,
 7802                target_display_point,
 7803                line_height,
 7804                scroll_pixel_position,
 7805                content_origin,
 7806                editor_width,
 7807                window,
 7808                cx,
 7809            )
 7810        }
 7811    }
 7812
 7813    fn render_edit_prediction_end_of_line_popover(
 7814        self: &mut Editor,
 7815        label: &'static str,
 7816        editor_snapshot: &EditorSnapshot,
 7817        visible_row_range: Range<DisplayRow>,
 7818        target_display_point: DisplayPoint,
 7819        line_height: Pixels,
 7820        scroll_pixel_position: gpui::Point<Pixels>,
 7821        content_origin: gpui::Point<Pixels>,
 7822        editor_width: Pixels,
 7823        window: &mut Window,
 7824        cx: &mut App,
 7825    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7826        let target_line_end = DisplayPoint::new(
 7827            target_display_point.row(),
 7828            editor_snapshot.line_len(target_display_point.row()),
 7829        );
 7830
 7831        let mut element = self
 7832            .render_edit_prediction_line_popover(label, None, window, cx)?
 7833            .into_any();
 7834
 7835        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7836
 7837        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7838
 7839        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7840        let mut origin = start_point
 7841            + line_origin
 7842            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7843        origin.x = origin.x.max(content_origin.x);
 7844
 7845        let max_x = content_origin.x + editor_width - size.width;
 7846
 7847        if origin.x > max_x {
 7848            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7849
 7850            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7851                origin.y += offset;
 7852                IconName::ArrowUp
 7853            } else {
 7854                origin.y -= offset;
 7855                IconName::ArrowDown
 7856            };
 7857
 7858            element = self
 7859                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7860                .into_any();
 7861
 7862            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7863
 7864            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7865        }
 7866
 7867        element.prepaint_at(origin, window, cx);
 7868        Some((element, origin))
 7869    }
 7870
 7871    fn render_edit_prediction_diff_popover(
 7872        self: &Editor,
 7873        text_bounds: &Bounds<Pixels>,
 7874        content_origin: gpui::Point<Pixels>,
 7875        right_margin: Pixels,
 7876        editor_snapshot: &EditorSnapshot,
 7877        visible_row_range: Range<DisplayRow>,
 7878        line_layouts: &[LineWithInvisibles],
 7879        line_height: Pixels,
 7880        scroll_pixel_position: gpui::Point<Pixels>,
 7881        newest_selection_head: Option<DisplayPoint>,
 7882        editor_width: Pixels,
 7883        style: &EditorStyle,
 7884        edits: &Vec<(Range<Anchor>, String)>,
 7885        edit_preview: &Option<language::EditPreview>,
 7886        snapshot: &language::BufferSnapshot,
 7887        window: &mut Window,
 7888        cx: &mut App,
 7889    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7890        let edit_start = edits
 7891            .first()
 7892            .unwrap()
 7893            .0
 7894            .start
 7895            .to_display_point(editor_snapshot);
 7896        let edit_end = edits
 7897            .last()
 7898            .unwrap()
 7899            .0
 7900            .end
 7901            .to_display_point(editor_snapshot);
 7902
 7903        let is_visible = visible_row_range.contains(&edit_start.row())
 7904            || visible_row_range.contains(&edit_end.row());
 7905        if !is_visible {
 7906            return None;
 7907        }
 7908
 7909        let highlighted_edits =
 7910            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7911
 7912        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7913        let line_count = highlighted_edits.text.lines().count();
 7914
 7915        const BORDER_WIDTH: Pixels = px(1.);
 7916
 7917        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7918        let has_keybind = keybind.is_some();
 7919
 7920        let mut element = h_flex()
 7921            .items_start()
 7922            .child(
 7923                h_flex()
 7924                    .bg(cx.theme().colors().editor_background)
 7925                    .border(BORDER_WIDTH)
 7926                    .shadow_sm()
 7927                    .border_color(cx.theme().colors().border)
 7928                    .rounded_l_lg()
 7929                    .when(line_count > 1, |el| el.rounded_br_lg())
 7930                    .pr_1()
 7931                    .child(styled_text),
 7932            )
 7933            .child(
 7934                h_flex()
 7935                    .h(line_height + BORDER_WIDTH * 2.)
 7936                    .px_1p5()
 7937                    .gap_1()
 7938                    // Workaround: For some reason, there's a gap if we don't do this
 7939                    .ml(-BORDER_WIDTH)
 7940                    .shadow(smallvec![gpui::BoxShadow {
 7941                        color: gpui::black().opacity(0.05),
 7942                        offset: point(px(1.), px(1.)),
 7943                        blur_radius: px(2.),
 7944                        spread_radius: px(0.),
 7945                    }])
 7946                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7947                    .border(BORDER_WIDTH)
 7948                    .border_color(cx.theme().colors().border)
 7949                    .rounded_r_lg()
 7950                    .id("edit_prediction_diff_popover_keybind")
 7951                    .when(!has_keybind, |el| {
 7952                        let status_colors = cx.theme().status();
 7953
 7954                        el.bg(status_colors.error_background)
 7955                            .border_color(status_colors.error.opacity(0.6))
 7956                            .child(Icon::new(IconName::Info).color(Color::Error))
 7957                            .cursor_default()
 7958                            .hoverable_tooltip(move |_window, cx| {
 7959                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7960                            })
 7961                    })
 7962                    .children(keybind),
 7963            )
 7964            .into_any();
 7965
 7966        let longest_row =
 7967            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 7968        let longest_line_width = if visible_row_range.contains(&longest_row) {
 7969            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 7970        } else {
 7971            layout_line(
 7972                longest_row,
 7973                editor_snapshot,
 7974                style,
 7975                editor_width,
 7976                |_| false,
 7977                window,
 7978                cx,
 7979            )
 7980            .width
 7981        };
 7982
 7983        let viewport_bounds =
 7984            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 7985                right: -right_margin,
 7986                ..Default::default()
 7987            });
 7988
 7989        let x_after_longest =
 7990            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 7991                - scroll_pixel_position.x;
 7992
 7993        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7994
 7995        // Fully visible if it can be displayed within the window (allow overlapping other
 7996        // panes). However, this is only allowed if the popover starts within text_bounds.
 7997        let can_position_to_the_right = x_after_longest < text_bounds.right()
 7998            && x_after_longest + element_bounds.width < viewport_bounds.right();
 7999
 8000        let mut origin = if can_position_to_the_right {
 8001            point(
 8002                x_after_longest,
 8003                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8004                    - scroll_pixel_position.y,
 8005            )
 8006        } else {
 8007            let cursor_row = newest_selection_head.map(|head| head.row());
 8008            let above_edit = edit_start
 8009                .row()
 8010                .0
 8011                .checked_sub(line_count as u32)
 8012                .map(DisplayRow);
 8013            let below_edit = Some(edit_end.row() + 1);
 8014            let above_cursor =
 8015                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8016            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8017
 8018            // Place the edit popover adjacent to the edit if there is a location
 8019            // available that is onscreen and does not obscure the cursor. Otherwise,
 8020            // place it adjacent to the cursor.
 8021            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8022                .into_iter()
 8023                .flatten()
 8024                .find(|&start_row| {
 8025                    let end_row = start_row + line_count as u32;
 8026                    visible_row_range.contains(&start_row)
 8027                        && visible_row_range.contains(&end_row)
 8028                        && cursor_row.map_or(true, |cursor_row| {
 8029                            !((start_row..end_row).contains(&cursor_row))
 8030                        })
 8031                })?;
 8032
 8033            content_origin
 8034                + point(
 8035                    -scroll_pixel_position.x,
 8036                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8037                )
 8038        };
 8039
 8040        origin.x -= BORDER_WIDTH;
 8041
 8042        window.defer_draw(element, origin, 1);
 8043
 8044        // Do not return an element, since it will already be drawn due to defer_draw.
 8045        None
 8046    }
 8047
 8048    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8049        px(30.)
 8050    }
 8051
 8052    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8053        if self.read_only(cx) {
 8054            cx.theme().players().read_only()
 8055        } else {
 8056            self.style.as_ref().unwrap().local_player
 8057        }
 8058    }
 8059
 8060    fn render_edit_prediction_accept_keybind(
 8061        &self,
 8062        window: &mut Window,
 8063        cx: &App,
 8064    ) -> Option<AnyElement> {
 8065        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8066        let accept_keystroke = accept_binding.keystroke()?;
 8067
 8068        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8069
 8070        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8071            Color::Accent
 8072        } else {
 8073            Color::Muted
 8074        };
 8075
 8076        h_flex()
 8077            .px_0p5()
 8078            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8079            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8080            .text_size(TextSize::XSmall.rems(cx))
 8081            .child(h_flex().children(ui::render_modifiers(
 8082                &accept_keystroke.modifiers,
 8083                PlatformStyle::platform(),
 8084                Some(modifiers_color),
 8085                Some(IconSize::XSmall.rems().into()),
 8086                true,
 8087            )))
 8088            .when(is_platform_style_mac, |parent| {
 8089                parent.child(accept_keystroke.key.clone())
 8090            })
 8091            .when(!is_platform_style_mac, |parent| {
 8092                parent.child(
 8093                    Key::new(
 8094                        util::capitalize(&accept_keystroke.key),
 8095                        Some(Color::Default),
 8096                    )
 8097                    .size(Some(IconSize::XSmall.rems().into())),
 8098                )
 8099            })
 8100            .into_any()
 8101            .into()
 8102    }
 8103
 8104    fn render_edit_prediction_line_popover(
 8105        &self,
 8106        label: impl Into<SharedString>,
 8107        icon: Option<IconName>,
 8108        window: &mut Window,
 8109        cx: &App,
 8110    ) -> Option<Stateful<Div>> {
 8111        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8112
 8113        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8114        let has_keybind = keybind.is_some();
 8115
 8116        let result = h_flex()
 8117            .id("ep-line-popover")
 8118            .py_0p5()
 8119            .pl_1()
 8120            .pr(padding_right)
 8121            .gap_1()
 8122            .rounded_md()
 8123            .border_1()
 8124            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8125            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8126            .shadow_sm()
 8127            .when(!has_keybind, |el| {
 8128                let status_colors = cx.theme().status();
 8129
 8130                el.bg(status_colors.error_background)
 8131                    .border_color(status_colors.error.opacity(0.6))
 8132                    .pl_2()
 8133                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8134                    .cursor_default()
 8135                    .hoverable_tooltip(move |_window, cx| {
 8136                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8137                    })
 8138            })
 8139            .children(keybind)
 8140            .child(
 8141                Label::new(label)
 8142                    .size(LabelSize::Small)
 8143                    .when(!has_keybind, |el| {
 8144                        el.color(cx.theme().status().error.into()).strikethrough()
 8145                    }),
 8146            )
 8147            .when(!has_keybind, |el| {
 8148                el.child(
 8149                    h_flex().ml_1().child(
 8150                        Icon::new(IconName::Info)
 8151                            .size(IconSize::Small)
 8152                            .color(cx.theme().status().error.into()),
 8153                    ),
 8154                )
 8155            })
 8156            .when_some(icon, |element, icon| {
 8157                element.child(
 8158                    div()
 8159                        .mt(px(1.5))
 8160                        .child(Icon::new(icon).size(IconSize::Small)),
 8161                )
 8162            });
 8163
 8164        Some(result)
 8165    }
 8166
 8167    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8168        let accent_color = cx.theme().colors().text_accent;
 8169        let editor_bg_color = cx.theme().colors().editor_background;
 8170        editor_bg_color.blend(accent_color.opacity(0.1))
 8171    }
 8172
 8173    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8174        let accent_color = cx.theme().colors().text_accent;
 8175        let editor_bg_color = cx.theme().colors().editor_background;
 8176        editor_bg_color.blend(accent_color.opacity(0.6))
 8177    }
 8178
 8179    fn render_edit_prediction_cursor_popover(
 8180        &self,
 8181        min_width: Pixels,
 8182        max_width: Pixels,
 8183        cursor_point: Point,
 8184        style: &EditorStyle,
 8185        accept_keystroke: Option<&gpui::Keystroke>,
 8186        _window: &Window,
 8187        cx: &mut Context<Editor>,
 8188    ) -> Option<AnyElement> {
 8189        let provider = self.edit_prediction_provider.as_ref()?;
 8190
 8191        if provider.provider.needs_terms_acceptance(cx) {
 8192            return Some(
 8193                h_flex()
 8194                    .min_w(min_width)
 8195                    .flex_1()
 8196                    .px_2()
 8197                    .py_1()
 8198                    .gap_3()
 8199                    .elevation_2(cx)
 8200                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8201                    .id("accept-terms")
 8202                    .cursor_pointer()
 8203                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8204                    .on_click(cx.listener(|this, _event, window, cx| {
 8205                        cx.stop_propagation();
 8206                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8207                        window.dispatch_action(
 8208                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8209                            cx,
 8210                        );
 8211                    }))
 8212                    .child(
 8213                        h_flex()
 8214                            .flex_1()
 8215                            .gap_2()
 8216                            .child(Icon::new(IconName::ZedPredict))
 8217                            .child(Label::new("Accept Terms of Service"))
 8218                            .child(div().w_full())
 8219                            .child(
 8220                                Icon::new(IconName::ArrowUpRight)
 8221                                    .color(Color::Muted)
 8222                                    .size(IconSize::Small),
 8223                            )
 8224                            .into_any_element(),
 8225                    )
 8226                    .into_any(),
 8227            );
 8228        }
 8229
 8230        let is_refreshing = provider.provider.is_refreshing(cx);
 8231
 8232        fn pending_completion_container() -> Div {
 8233            h_flex()
 8234                .h_full()
 8235                .flex_1()
 8236                .gap_2()
 8237                .child(Icon::new(IconName::ZedPredict))
 8238        }
 8239
 8240        let completion = match &self.active_inline_completion {
 8241            Some(prediction) => {
 8242                if !self.has_visible_completions_menu() {
 8243                    const RADIUS: Pixels = px(6.);
 8244                    const BORDER_WIDTH: Pixels = px(1.);
 8245
 8246                    return Some(
 8247                        h_flex()
 8248                            .elevation_2(cx)
 8249                            .border(BORDER_WIDTH)
 8250                            .border_color(cx.theme().colors().border)
 8251                            .when(accept_keystroke.is_none(), |el| {
 8252                                el.border_color(cx.theme().status().error)
 8253                            })
 8254                            .rounded(RADIUS)
 8255                            .rounded_tl(px(0.))
 8256                            .overflow_hidden()
 8257                            .child(div().px_1p5().child(match &prediction.completion {
 8258                                InlineCompletion::Move { target, snapshot } => {
 8259                                    use text::ToPoint as _;
 8260                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8261                                    {
 8262                                        Icon::new(IconName::ZedPredictDown)
 8263                                    } else {
 8264                                        Icon::new(IconName::ZedPredictUp)
 8265                                    }
 8266                                }
 8267                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8268                            }))
 8269                            .child(
 8270                                h_flex()
 8271                                    .gap_1()
 8272                                    .py_1()
 8273                                    .px_2()
 8274                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8275                                    .border_l_1()
 8276                                    .border_color(cx.theme().colors().border)
 8277                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8278                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8279                                        el.child(
 8280                                            Label::new("Hold")
 8281                                                .size(LabelSize::Small)
 8282                                                .when(accept_keystroke.is_none(), |el| {
 8283                                                    el.strikethrough()
 8284                                                })
 8285                                                .line_height_style(LineHeightStyle::UiLabel),
 8286                                        )
 8287                                    })
 8288                                    .id("edit_prediction_cursor_popover_keybind")
 8289                                    .when(accept_keystroke.is_none(), |el| {
 8290                                        let status_colors = cx.theme().status();
 8291
 8292                                        el.bg(status_colors.error_background)
 8293                                            .border_color(status_colors.error.opacity(0.6))
 8294                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8295                                            .cursor_default()
 8296                                            .hoverable_tooltip(move |_window, cx| {
 8297                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8298                                                    .into()
 8299                                            })
 8300                                    })
 8301                                    .when_some(
 8302                                        accept_keystroke.as_ref(),
 8303                                        |el, accept_keystroke| {
 8304                                            el.child(h_flex().children(ui::render_modifiers(
 8305                                                &accept_keystroke.modifiers,
 8306                                                PlatformStyle::platform(),
 8307                                                Some(Color::Default),
 8308                                                Some(IconSize::XSmall.rems().into()),
 8309                                                false,
 8310                                            )))
 8311                                        },
 8312                                    ),
 8313                            )
 8314                            .into_any(),
 8315                    );
 8316                }
 8317
 8318                self.render_edit_prediction_cursor_popover_preview(
 8319                    prediction,
 8320                    cursor_point,
 8321                    style,
 8322                    cx,
 8323                )?
 8324            }
 8325
 8326            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8327                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8328                    stale_completion,
 8329                    cursor_point,
 8330                    style,
 8331                    cx,
 8332                )?,
 8333
 8334                None => {
 8335                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8336                }
 8337            },
 8338
 8339            None => pending_completion_container().child(Label::new("No Prediction")),
 8340        };
 8341
 8342        let completion = if is_refreshing {
 8343            completion
 8344                .with_animation(
 8345                    "loading-completion",
 8346                    Animation::new(Duration::from_secs(2))
 8347                        .repeat()
 8348                        .with_easing(pulsating_between(0.4, 0.8)),
 8349                    |label, delta| label.opacity(delta),
 8350                )
 8351                .into_any_element()
 8352        } else {
 8353            completion.into_any_element()
 8354        };
 8355
 8356        let has_completion = self.active_inline_completion.is_some();
 8357
 8358        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8359        Some(
 8360            h_flex()
 8361                .min_w(min_width)
 8362                .max_w(max_width)
 8363                .flex_1()
 8364                .elevation_2(cx)
 8365                .border_color(cx.theme().colors().border)
 8366                .child(
 8367                    div()
 8368                        .flex_1()
 8369                        .py_1()
 8370                        .px_2()
 8371                        .overflow_hidden()
 8372                        .child(completion),
 8373                )
 8374                .when_some(accept_keystroke, |el, accept_keystroke| {
 8375                    if !accept_keystroke.modifiers.modified() {
 8376                        return el;
 8377                    }
 8378
 8379                    el.child(
 8380                        h_flex()
 8381                            .h_full()
 8382                            .border_l_1()
 8383                            .rounded_r_lg()
 8384                            .border_color(cx.theme().colors().border)
 8385                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8386                            .gap_1()
 8387                            .py_1()
 8388                            .px_2()
 8389                            .child(
 8390                                h_flex()
 8391                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8392                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8393                                    .child(h_flex().children(ui::render_modifiers(
 8394                                        &accept_keystroke.modifiers,
 8395                                        PlatformStyle::platform(),
 8396                                        Some(if !has_completion {
 8397                                            Color::Muted
 8398                                        } else {
 8399                                            Color::Default
 8400                                        }),
 8401                                        None,
 8402                                        false,
 8403                                    ))),
 8404                            )
 8405                            .child(Label::new("Preview").into_any_element())
 8406                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8407                    )
 8408                })
 8409                .into_any(),
 8410        )
 8411    }
 8412
 8413    fn render_edit_prediction_cursor_popover_preview(
 8414        &self,
 8415        completion: &InlineCompletionState,
 8416        cursor_point: Point,
 8417        style: &EditorStyle,
 8418        cx: &mut Context<Editor>,
 8419    ) -> Option<Div> {
 8420        use text::ToPoint as _;
 8421
 8422        fn render_relative_row_jump(
 8423            prefix: impl Into<String>,
 8424            current_row: u32,
 8425            target_row: u32,
 8426        ) -> Div {
 8427            let (row_diff, arrow) = if target_row < current_row {
 8428                (current_row - target_row, IconName::ArrowUp)
 8429            } else {
 8430                (target_row - current_row, IconName::ArrowDown)
 8431            };
 8432
 8433            h_flex()
 8434                .child(
 8435                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8436                        .color(Color::Muted)
 8437                        .size(LabelSize::Small),
 8438                )
 8439                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8440        }
 8441
 8442        match &completion.completion {
 8443            InlineCompletion::Move {
 8444                target, snapshot, ..
 8445            } => Some(
 8446                h_flex()
 8447                    .px_2()
 8448                    .gap_2()
 8449                    .flex_1()
 8450                    .child(
 8451                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8452                            Icon::new(IconName::ZedPredictDown)
 8453                        } else {
 8454                            Icon::new(IconName::ZedPredictUp)
 8455                        },
 8456                    )
 8457                    .child(Label::new("Jump to Edit")),
 8458            ),
 8459
 8460            InlineCompletion::Edit {
 8461                edits,
 8462                edit_preview,
 8463                snapshot,
 8464                display_mode: _,
 8465            } => {
 8466                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8467
 8468                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8469                    &snapshot,
 8470                    &edits,
 8471                    edit_preview.as_ref()?,
 8472                    true,
 8473                    cx,
 8474                )
 8475                .first_line_preview();
 8476
 8477                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8478                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8479
 8480                let preview = h_flex()
 8481                    .gap_1()
 8482                    .min_w_16()
 8483                    .child(styled_text)
 8484                    .when(has_more_lines, |parent| parent.child(""));
 8485
 8486                let left = if first_edit_row != cursor_point.row {
 8487                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8488                        .into_any_element()
 8489                } else {
 8490                    Icon::new(IconName::ZedPredict).into_any_element()
 8491                };
 8492
 8493                Some(
 8494                    h_flex()
 8495                        .h_full()
 8496                        .flex_1()
 8497                        .gap_2()
 8498                        .pr_1()
 8499                        .overflow_x_hidden()
 8500                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8501                        .child(left)
 8502                        .child(preview),
 8503                )
 8504            }
 8505        }
 8506    }
 8507
 8508    fn render_context_menu(
 8509        &self,
 8510        style: &EditorStyle,
 8511        max_height_in_lines: u32,
 8512        window: &mut Window,
 8513        cx: &mut Context<Editor>,
 8514    ) -> Option<AnyElement> {
 8515        let menu = self.context_menu.borrow();
 8516        let menu = menu.as_ref()?;
 8517        if !menu.visible() {
 8518            return None;
 8519        };
 8520        Some(menu.render(style, max_height_in_lines, window, cx))
 8521    }
 8522
 8523    fn render_context_menu_aside(
 8524        &mut self,
 8525        max_size: Size<Pixels>,
 8526        window: &mut Window,
 8527        cx: &mut Context<Editor>,
 8528    ) -> Option<AnyElement> {
 8529        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8530            if menu.visible() {
 8531                menu.render_aside(self, max_size, window, cx)
 8532            } else {
 8533                None
 8534            }
 8535        })
 8536    }
 8537
 8538    fn hide_context_menu(
 8539        &mut self,
 8540        window: &mut Window,
 8541        cx: &mut Context<Self>,
 8542    ) -> Option<CodeContextMenu> {
 8543        cx.notify();
 8544        self.completion_tasks.clear();
 8545        let context_menu = self.context_menu.borrow_mut().take();
 8546        self.stale_inline_completion_in_menu.take();
 8547        self.update_visible_inline_completion(window, cx);
 8548        context_menu
 8549    }
 8550
 8551    fn show_snippet_choices(
 8552        &mut self,
 8553        choices: &Vec<String>,
 8554        selection: Range<Anchor>,
 8555        cx: &mut Context<Self>,
 8556    ) {
 8557        if selection.start.buffer_id.is_none() {
 8558            return;
 8559        }
 8560        let buffer_id = selection.start.buffer_id.unwrap();
 8561        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8562        let id = post_inc(&mut self.next_completion_id);
 8563        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8564
 8565        if let Some(buffer) = buffer {
 8566            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8567                CompletionsMenu::new_snippet_choices(
 8568                    id,
 8569                    true,
 8570                    choices,
 8571                    selection,
 8572                    buffer,
 8573                    snippet_sort_order,
 8574                ),
 8575            ));
 8576        }
 8577    }
 8578
 8579    pub fn insert_snippet(
 8580        &mut self,
 8581        insertion_ranges: &[Range<usize>],
 8582        snippet: Snippet,
 8583        window: &mut Window,
 8584        cx: &mut Context<Self>,
 8585    ) -> Result<()> {
 8586        struct Tabstop<T> {
 8587            is_end_tabstop: bool,
 8588            ranges: Vec<Range<T>>,
 8589            choices: Option<Vec<String>>,
 8590        }
 8591
 8592        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8593            let snippet_text: Arc<str> = snippet.text.clone().into();
 8594            let edits = insertion_ranges
 8595                .iter()
 8596                .cloned()
 8597                .map(|range| (range, snippet_text.clone()));
 8598            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8599
 8600            let snapshot = &*buffer.read(cx);
 8601            let snippet = &snippet;
 8602            snippet
 8603                .tabstops
 8604                .iter()
 8605                .map(|tabstop| {
 8606                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8607                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8608                    });
 8609                    let mut tabstop_ranges = tabstop
 8610                        .ranges
 8611                        .iter()
 8612                        .flat_map(|tabstop_range| {
 8613                            let mut delta = 0_isize;
 8614                            insertion_ranges.iter().map(move |insertion_range| {
 8615                                let insertion_start = insertion_range.start as isize + delta;
 8616                                delta +=
 8617                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8618
 8619                                let start = ((insertion_start + tabstop_range.start) as usize)
 8620                                    .min(snapshot.len());
 8621                                let end = ((insertion_start + tabstop_range.end) as usize)
 8622                                    .min(snapshot.len());
 8623                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8624                            })
 8625                        })
 8626                        .collect::<Vec<_>>();
 8627                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8628
 8629                    Tabstop {
 8630                        is_end_tabstop,
 8631                        ranges: tabstop_ranges,
 8632                        choices: tabstop.choices.clone(),
 8633                    }
 8634                })
 8635                .collect::<Vec<_>>()
 8636        });
 8637        if let Some(tabstop) = tabstops.first() {
 8638            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8639                s.select_ranges(tabstop.ranges.iter().cloned());
 8640            });
 8641
 8642            if let Some(choices) = &tabstop.choices {
 8643                if let Some(selection) = tabstop.ranges.first() {
 8644                    self.show_snippet_choices(choices, selection.clone(), cx)
 8645                }
 8646            }
 8647
 8648            // If we're already at the last tabstop and it's at the end of the snippet,
 8649            // we're done, we don't need to keep the state around.
 8650            if !tabstop.is_end_tabstop {
 8651                let choices = tabstops
 8652                    .iter()
 8653                    .map(|tabstop| tabstop.choices.clone())
 8654                    .collect();
 8655
 8656                let ranges = tabstops
 8657                    .into_iter()
 8658                    .map(|tabstop| tabstop.ranges)
 8659                    .collect::<Vec<_>>();
 8660
 8661                self.snippet_stack.push(SnippetState {
 8662                    active_index: 0,
 8663                    ranges,
 8664                    choices,
 8665                });
 8666            }
 8667
 8668            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8669            if self.autoclose_regions.is_empty() {
 8670                let snapshot = self.buffer.read(cx).snapshot(cx);
 8671                for selection in &mut self.selections.all::<Point>(cx) {
 8672                    let selection_head = selection.head();
 8673                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8674                        continue;
 8675                    };
 8676
 8677                    let mut bracket_pair = None;
 8678                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8679                    let prev_chars = snapshot
 8680                        .reversed_chars_at(selection_head)
 8681                        .collect::<String>();
 8682                    for (pair, enabled) in scope.brackets() {
 8683                        if enabled
 8684                            && pair.close
 8685                            && prev_chars.starts_with(pair.start.as_str())
 8686                            && next_chars.starts_with(pair.end.as_str())
 8687                        {
 8688                            bracket_pair = Some(pair.clone());
 8689                            break;
 8690                        }
 8691                    }
 8692                    if let Some(pair) = bracket_pair {
 8693                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8694                        let autoclose_enabled =
 8695                            self.use_autoclose && snapshot_settings.use_autoclose;
 8696                        if autoclose_enabled {
 8697                            let start = snapshot.anchor_after(selection_head);
 8698                            let end = snapshot.anchor_after(selection_head);
 8699                            self.autoclose_regions.push(AutocloseRegion {
 8700                                selection_id: selection.id,
 8701                                range: start..end,
 8702                                pair,
 8703                            });
 8704                        }
 8705                    }
 8706                }
 8707            }
 8708        }
 8709        Ok(())
 8710    }
 8711
 8712    pub fn move_to_next_snippet_tabstop(
 8713        &mut self,
 8714        window: &mut Window,
 8715        cx: &mut Context<Self>,
 8716    ) -> bool {
 8717        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8718    }
 8719
 8720    pub fn move_to_prev_snippet_tabstop(
 8721        &mut self,
 8722        window: &mut Window,
 8723        cx: &mut Context<Self>,
 8724    ) -> bool {
 8725        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8726    }
 8727
 8728    pub fn move_to_snippet_tabstop(
 8729        &mut self,
 8730        bias: Bias,
 8731        window: &mut Window,
 8732        cx: &mut Context<Self>,
 8733    ) -> bool {
 8734        if let Some(mut snippet) = self.snippet_stack.pop() {
 8735            match bias {
 8736                Bias::Left => {
 8737                    if snippet.active_index > 0 {
 8738                        snippet.active_index -= 1;
 8739                    } else {
 8740                        self.snippet_stack.push(snippet);
 8741                        return false;
 8742                    }
 8743                }
 8744                Bias::Right => {
 8745                    if snippet.active_index + 1 < snippet.ranges.len() {
 8746                        snippet.active_index += 1;
 8747                    } else {
 8748                        self.snippet_stack.push(snippet);
 8749                        return false;
 8750                    }
 8751                }
 8752            }
 8753            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8754                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8755                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8756                });
 8757
 8758                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8759                    if let Some(selection) = current_ranges.first() {
 8760                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8761                    }
 8762                }
 8763
 8764                // If snippet state is not at the last tabstop, push it back on the stack
 8765                if snippet.active_index + 1 < snippet.ranges.len() {
 8766                    self.snippet_stack.push(snippet);
 8767                }
 8768                return true;
 8769            }
 8770        }
 8771
 8772        false
 8773    }
 8774
 8775    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8776        self.transact(window, cx, |this, window, cx| {
 8777            this.select_all(&SelectAll, window, cx);
 8778            this.insert("", window, cx);
 8779        });
 8780    }
 8781
 8782    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8783        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8784        self.transact(window, cx, |this, window, cx| {
 8785            this.select_autoclose_pair(window, cx);
 8786            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8787            if !this.linked_edit_ranges.is_empty() {
 8788                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8789                let snapshot = this.buffer.read(cx).snapshot(cx);
 8790
 8791                for selection in selections.iter() {
 8792                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8793                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8794                    if selection_start.buffer_id != selection_end.buffer_id {
 8795                        continue;
 8796                    }
 8797                    if let Some(ranges) =
 8798                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8799                    {
 8800                        for (buffer, entries) in ranges {
 8801                            linked_ranges.entry(buffer).or_default().extend(entries);
 8802                        }
 8803                    }
 8804                }
 8805            }
 8806
 8807            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8808            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8809            for selection in &mut selections {
 8810                if selection.is_empty() {
 8811                    let old_head = selection.head();
 8812                    let mut new_head =
 8813                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8814                            .to_point(&display_map);
 8815                    if let Some((buffer, line_buffer_range)) = display_map
 8816                        .buffer_snapshot
 8817                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8818                    {
 8819                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8820                        let indent_len = match indent_size.kind {
 8821                            IndentKind::Space => {
 8822                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8823                            }
 8824                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8825                        };
 8826                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8827                            let indent_len = indent_len.get();
 8828                            new_head = cmp::min(
 8829                                new_head,
 8830                                MultiBufferPoint::new(
 8831                                    old_head.row,
 8832                                    ((old_head.column - 1) / indent_len) * indent_len,
 8833                                ),
 8834                            );
 8835                        }
 8836                    }
 8837
 8838                    selection.set_head(new_head, SelectionGoal::None);
 8839                }
 8840            }
 8841
 8842            this.signature_help_state.set_backspace_pressed(true);
 8843            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8844                s.select(selections)
 8845            });
 8846            this.insert("", window, cx);
 8847            let empty_str: Arc<str> = Arc::from("");
 8848            for (buffer, edits) in linked_ranges {
 8849                let snapshot = buffer.read(cx).snapshot();
 8850                use text::ToPoint as TP;
 8851
 8852                let edits = edits
 8853                    .into_iter()
 8854                    .map(|range| {
 8855                        let end_point = TP::to_point(&range.end, &snapshot);
 8856                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8857
 8858                        if end_point == start_point {
 8859                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8860                                .saturating_sub(1);
 8861                            start_point =
 8862                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8863                        };
 8864
 8865                        (start_point..end_point, empty_str.clone())
 8866                    })
 8867                    .sorted_by_key(|(range, _)| range.start)
 8868                    .collect::<Vec<_>>();
 8869                buffer.update(cx, |this, cx| {
 8870                    this.edit(edits, None, cx);
 8871                })
 8872            }
 8873            this.refresh_inline_completion(true, false, window, cx);
 8874            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8875        });
 8876    }
 8877
 8878    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8879        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8880        self.transact(window, cx, |this, window, cx| {
 8881            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8882                s.move_with(|map, selection| {
 8883                    if selection.is_empty() {
 8884                        let cursor = movement::right(map, selection.head());
 8885                        selection.end = cursor;
 8886                        selection.reversed = true;
 8887                        selection.goal = SelectionGoal::None;
 8888                    }
 8889                })
 8890            });
 8891            this.insert("", window, cx);
 8892            this.refresh_inline_completion(true, false, window, cx);
 8893        });
 8894    }
 8895
 8896    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8897        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8898        if self.move_to_prev_snippet_tabstop(window, cx) {
 8899            return;
 8900        }
 8901        self.outdent(&Outdent, window, cx);
 8902    }
 8903
 8904    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8905        if self.move_to_next_snippet_tabstop(window, cx) {
 8906            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8907            return;
 8908        }
 8909        if self.read_only(cx) {
 8910            return;
 8911        }
 8912        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8913        let mut selections = self.selections.all_adjusted(cx);
 8914        let buffer = self.buffer.read(cx);
 8915        let snapshot = buffer.snapshot(cx);
 8916        let rows_iter = selections.iter().map(|s| s.head().row);
 8917        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8918
 8919        let has_some_cursor_in_whitespace = selections
 8920            .iter()
 8921            .filter(|selection| selection.is_empty())
 8922            .any(|selection| {
 8923                let cursor = selection.head();
 8924                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8925                cursor.column < current_indent.len
 8926            });
 8927
 8928        let mut edits = Vec::new();
 8929        let mut prev_edited_row = 0;
 8930        let mut row_delta = 0;
 8931        for selection in &mut selections {
 8932            if selection.start.row != prev_edited_row {
 8933                row_delta = 0;
 8934            }
 8935            prev_edited_row = selection.end.row;
 8936
 8937            // If the selection is non-empty, then increase the indentation of the selected lines.
 8938            if !selection.is_empty() {
 8939                row_delta =
 8940                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8941                continue;
 8942            }
 8943
 8944            let cursor = selection.head();
 8945            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8946            if let Some(suggested_indent) =
 8947                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8948            {
 8949                // Don't do anything if already at suggested indent
 8950                // and there is any other cursor which is not
 8951                if has_some_cursor_in_whitespace
 8952                    && cursor.column == current_indent.len
 8953                    && current_indent.len == suggested_indent.len
 8954                {
 8955                    continue;
 8956                }
 8957
 8958                // Adjust line and move cursor to suggested indent
 8959                // if cursor is not at suggested indent
 8960                if cursor.column < suggested_indent.len
 8961                    && cursor.column <= current_indent.len
 8962                    && current_indent.len <= suggested_indent.len
 8963                {
 8964                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8965                    selection.end = selection.start;
 8966                    if row_delta == 0 {
 8967                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 8968                            cursor.row,
 8969                            current_indent,
 8970                            suggested_indent,
 8971                        ));
 8972                        row_delta = suggested_indent.len - current_indent.len;
 8973                    }
 8974                    continue;
 8975                }
 8976
 8977                // If current indent is more than suggested indent
 8978                // only move cursor to current indent and skip indent
 8979                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 8980                    selection.start = Point::new(cursor.row, current_indent.len);
 8981                    selection.end = selection.start;
 8982                    continue;
 8983                }
 8984            }
 8985
 8986            // Otherwise, insert a hard or soft tab.
 8987            let settings = buffer.language_settings_at(cursor, cx);
 8988            let tab_size = if settings.hard_tabs {
 8989                IndentSize::tab()
 8990            } else {
 8991                let tab_size = settings.tab_size.get();
 8992                let indent_remainder = snapshot
 8993                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 8994                    .flat_map(str::chars)
 8995                    .fold(row_delta % tab_size, |counter: u32, c| {
 8996                        if c == '\t' {
 8997                            0
 8998                        } else {
 8999                            (counter + 1) % tab_size
 9000                        }
 9001                    });
 9002
 9003                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9004                IndentSize::spaces(chars_to_next_tab_stop)
 9005            };
 9006            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9007            selection.end = selection.start;
 9008            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9009            row_delta += tab_size.len;
 9010        }
 9011
 9012        self.transact(window, cx, |this, window, cx| {
 9013            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9014            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9015                s.select(selections)
 9016            });
 9017            this.refresh_inline_completion(true, false, window, cx);
 9018        });
 9019    }
 9020
 9021    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9022        if self.read_only(cx) {
 9023            return;
 9024        }
 9025        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9026        let mut selections = self.selections.all::<Point>(cx);
 9027        let mut prev_edited_row = 0;
 9028        let mut row_delta = 0;
 9029        let mut edits = Vec::new();
 9030        let buffer = self.buffer.read(cx);
 9031        let snapshot = buffer.snapshot(cx);
 9032        for selection in &mut selections {
 9033            if selection.start.row != prev_edited_row {
 9034                row_delta = 0;
 9035            }
 9036            prev_edited_row = selection.end.row;
 9037
 9038            row_delta =
 9039                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9040        }
 9041
 9042        self.transact(window, cx, |this, window, cx| {
 9043            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9044            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9045                s.select(selections)
 9046            });
 9047        });
 9048    }
 9049
 9050    fn indent_selection(
 9051        buffer: &MultiBuffer,
 9052        snapshot: &MultiBufferSnapshot,
 9053        selection: &mut Selection<Point>,
 9054        edits: &mut Vec<(Range<Point>, String)>,
 9055        delta_for_start_row: u32,
 9056        cx: &App,
 9057    ) -> u32 {
 9058        let settings = buffer.language_settings_at(selection.start, cx);
 9059        let tab_size = settings.tab_size.get();
 9060        let indent_kind = if settings.hard_tabs {
 9061            IndentKind::Tab
 9062        } else {
 9063            IndentKind::Space
 9064        };
 9065        let mut start_row = selection.start.row;
 9066        let mut end_row = selection.end.row + 1;
 9067
 9068        // If a selection ends at the beginning of a line, don't indent
 9069        // that last line.
 9070        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9071            end_row -= 1;
 9072        }
 9073
 9074        // Avoid re-indenting a row that has already been indented by a
 9075        // previous selection, but still update this selection's column
 9076        // to reflect that indentation.
 9077        if delta_for_start_row > 0 {
 9078            start_row += 1;
 9079            selection.start.column += delta_for_start_row;
 9080            if selection.end.row == selection.start.row {
 9081                selection.end.column += delta_for_start_row;
 9082            }
 9083        }
 9084
 9085        let mut delta_for_end_row = 0;
 9086        let has_multiple_rows = start_row + 1 != end_row;
 9087        for row in start_row..end_row {
 9088            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9089            let indent_delta = match (current_indent.kind, indent_kind) {
 9090                (IndentKind::Space, IndentKind::Space) => {
 9091                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9092                    IndentSize::spaces(columns_to_next_tab_stop)
 9093                }
 9094                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9095                (_, IndentKind::Tab) => IndentSize::tab(),
 9096            };
 9097
 9098            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9099                0
 9100            } else {
 9101                selection.start.column
 9102            };
 9103            let row_start = Point::new(row, start);
 9104            edits.push((
 9105                row_start..row_start,
 9106                indent_delta.chars().collect::<String>(),
 9107            ));
 9108
 9109            // Update this selection's endpoints to reflect the indentation.
 9110            if row == selection.start.row {
 9111                selection.start.column += indent_delta.len;
 9112            }
 9113            if row == selection.end.row {
 9114                selection.end.column += indent_delta.len;
 9115                delta_for_end_row = indent_delta.len;
 9116            }
 9117        }
 9118
 9119        if selection.start.row == selection.end.row {
 9120            delta_for_start_row + delta_for_end_row
 9121        } else {
 9122            delta_for_end_row
 9123        }
 9124    }
 9125
 9126    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9127        if self.read_only(cx) {
 9128            return;
 9129        }
 9130        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9131        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9132        let selections = self.selections.all::<Point>(cx);
 9133        let mut deletion_ranges = Vec::new();
 9134        let mut last_outdent = None;
 9135        {
 9136            let buffer = self.buffer.read(cx);
 9137            let snapshot = buffer.snapshot(cx);
 9138            for selection in &selections {
 9139                let settings = buffer.language_settings_at(selection.start, cx);
 9140                let tab_size = settings.tab_size.get();
 9141                let mut rows = selection.spanned_rows(false, &display_map);
 9142
 9143                // Avoid re-outdenting a row that has already been outdented by a
 9144                // previous selection.
 9145                if let Some(last_row) = last_outdent {
 9146                    if last_row == rows.start {
 9147                        rows.start = rows.start.next_row();
 9148                    }
 9149                }
 9150                let has_multiple_rows = rows.len() > 1;
 9151                for row in rows.iter_rows() {
 9152                    let indent_size = snapshot.indent_size_for_line(row);
 9153                    if indent_size.len > 0 {
 9154                        let deletion_len = match indent_size.kind {
 9155                            IndentKind::Space => {
 9156                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9157                                if columns_to_prev_tab_stop == 0 {
 9158                                    tab_size
 9159                                } else {
 9160                                    columns_to_prev_tab_stop
 9161                                }
 9162                            }
 9163                            IndentKind::Tab => 1,
 9164                        };
 9165                        let start = if has_multiple_rows
 9166                            || deletion_len > selection.start.column
 9167                            || indent_size.len < selection.start.column
 9168                        {
 9169                            0
 9170                        } else {
 9171                            selection.start.column - deletion_len
 9172                        };
 9173                        deletion_ranges.push(
 9174                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9175                        );
 9176                        last_outdent = Some(row);
 9177                    }
 9178                }
 9179            }
 9180        }
 9181
 9182        self.transact(window, cx, |this, window, cx| {
 9183            this.buffer.update(cx, |buffer, cx| {
 9184                let empty_str: Arc<str> = Arc::default();
 9185                buffer.edit(
 9186                    deletion_ranges
 9187                        .into_iter()
 9188                        .map(|range| (range, empty_str.clone())),
 9189                    None,
 9190                    cx,
 9191                );
 9192            });
 9193            let selections = this.selections.all::<usize>(cx);
 9194            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9195                s.select(selections)
 9196            });
 9197        });
 9198    }
 9199
 9200    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9201        if self.read_only(cx) {
 9202            return;
 9203        }
 9204        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9205        let selections = self
 9206            .selections
 9207            .all::<usize>(cx)
 9208            .into_iter()
 9209            .map(|s| s.range());
 9210
 9211        self.transact(window, cx, |this, window, cx| {
 9212            this.buffer.update(cx, |buffer, cx| {
 9213                buffer.autoindent_ranges(selections, cx);
 9214            });
 9215            let selections = this.selections.all::<usize>(cx);
 9216            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9217                s.select(selections)
 9218            });
 9219        });
 9220    }
 9221
 9222    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9223        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9224        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9225        let selections = self.selections.all::<Point>(cx);
 9226
 9227        let mut new_cursors = Vec::new();
 9228        let mut edit_ranges = Vec::new();
 9229        let mut selections = selections.iter().peekable();
 9230        while let Some(selection) = selections.next() {
 9231            let mut rows = selection.spanned_rows(false, &display_map);
 9232            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9233
 9234            // Accumulate contiguous regions of rows that we want to delete.
 9235            while let Some(next_selection) = selections.peek() {
 9236                let next_rows = next_selection.spanned_rows(false, &display_map);
 9237                if next_rows.start <= rows.end {
 9238                    rows.end = next_rows.end;
 9239                    selections.next().unwrap();
 9240                } else {
 9241                    break;
 9242                }
 9243            }
 9244
 9245            let buffer = &display_map.buffer_snapshot;
 9246            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9247            let edit_end;
 9248            let cursor_buffer_row;
 9249            if buffer.max_point().row >= rows.end.0 {
 9250                // If there's a line after the range, delete the \n from the end of the row range
 9251                // and position the cursor on the next line.
 9252                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9253                cursor_buffer_row = rows.end;
 9254            } else {
 9255                // If there isn't a line after the range, delete the \n from the line before the
 9256                // start of the row range and position the cursor there.
 9257                edit_start = edit_start.saturating_sub(1);
 9258                edit_end = buffer.len();
 9259                cursor_buffer_row = rows.start.previous_row();
 9260            }
 9261
 9262            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9263            *cursor.column_mut() =
 9264                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9265
 9266            new_cursors.push((
 9267                selection.id,
 9268                buffer.anchor_after(cursor.to_point(&display_map)),
 9269            ));
 9270            edit_ranges.push(edit_start..edit_end);
 9271        }
 9272
 9273        self.transact(window, cx, |this, window, cx| {
 9274            let buffer = this.buffer.update(cx, |buffer, cx| {
 9275                let empty_str: Arc<str> = Arc::default();
 9276                buffer.edit(
 9277                    edit_ranges
 9278                        .into_iter()
 9279                        .map(|range| (range, empty_str.clone())),
 9280                    None,
 9281                    cx,
 9282                );
 9283                buffer.snapshot(cx)
 9284            });
 9285            let new_selections = new_cursors
 9286                .into_iter()
 9287                .map(|(id, cursor)| {
 9288                    let cursor = cursor.to_point(&buffer);
 9289                    Selection {
 9290                        id,
 9291                        start: cursor,
 9292                        end: cursor,
 9293                        reversed: false,
 9294                        goal: SelectionGoal::None,
 9295                    }
 9296                })
 9297                .collect();
 9298
 9299            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9300                s.select(new_selections);
 9301            });
 9302        });
 9303    }
 9304
 9305    pub fn join_lines_impl(
 9306        &mut self,
 9307        insert_whitespace: bool,
 9308        window: &mut Window,
 9309        cx: &mut Context<Self>,
 9310    ) {
 9311        if self.read_only(cx) {
 9312            return;
 9313        }
 9314        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9315        for selection in self.selections.all::<Point>(cx) {
 9316            let start = MultiBufferRow(selection.start.row);
 9317            // Treat single line selections as if they include the next line. Otherwise this action
 9318            // would do nothing for single line selections individual cursors.
 9319            let end = if selection.start.row == selection.end.row {
 9320                MultiBufferRow(selection.start.row + 1)
 9321            } else {
 9322                MultiBufferRow(selection.end.row)
 9323            };
 9324
 9325            if let Some(last_row_range) = row_ranges.last_mut() {
 9326                if start <= last_row_range.end {
 9327                    last_row_range.end = end;
 9328                    continue;
 9329                }
 9330            }
 9331            row_ranges.push(start..end);
 9332        }
 9333
 9334        let snapshot = self.buffer.read(cx).snapshot(cx);
 9335        let mut cursor_positions = Vec::new();
 9336        for row_range in &row_ranges {
 9337            let anchor = snapshot.anchor_before(Point::new(
 9338                row_range.end.previous_row().0,
 9339                snapshot.line_len(row_range.end.previous_row()),
 9340            ));
 9341            cursor_positions.push(anchor..anchor);
 9342        }
 9343
 9344        self.transact(window, cx, |this, window, cx| {
 9345            for row_range in row_ranges.into_iter().rev() {
 9346                for row in row_range.iter_rows().rev() {
 9347                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9348                    let next_line_row = row.next_row();
 9349                    let indent = snapshot.indent_size_for_line(next_line_row);
 9350                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9351
 9352                    let replace =
 9353                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9354                            " "
 9355                        } else {
 9356                            ""
 9357                        };
 9358
 9359                    this.buffer.update(cx, |buffer, cx| {
 9360                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9361                    });
 9362                }
 9363            }
 9364
 9365            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9366                s.select_anchor_ranges(cursor_positions)
 9367            });
 9368        });
 9369    }
 9370
 9371    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9372        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9373        self.join_lines_impl(true, window, cx);
 9374    }
 9375
 9376    pub fn sort_lines_case_sensitive(
 9377        &mut self,
 9378        _: &SortLinesCaseSensitive,
 9379        window: &mut Window,
 9380        cx: &mut Context<Self>,
 9381    ) {
 9382        self.manipulate_lines(window, cx, |lines| lines.sort())
 9383    }
 9384
 9385    pub fn sort_lines_case_insensitive(
 9386        &mut self,
 9387        _: &SortLinesCaseInsensitive,
 9388        window: &mut Window,
 9389        cx: &mut Context<Self>,
 9390    ) {
 9391        self.manipulate_lines(window, cx, |lines| {
 9392            lines.sort_by_key(|line| line.to_lowercase())
 9393        })
 9394    }
 9395
 9396    pub fn unique_lines_case_insensitive(
 9397        &mut self,
 9398        _: &UniqueLinesCaseInsensitive,
 9399        window: &mut Window,
 9400        cx: &mut Context<Self>,
 9401    ) {
 9402        self.manipulate_lines(window, cx, |lines| {
 9403            let mut seen = HashSet::default();
 9404            lines.retain(|line| seen.insert(line.to_lowercase()));
 9405        })
 9406    }
 9407
 9408    pub fn unique_lines_case_sensitive(
 9409        &mut self,
 9410        _: &UniqueLinesCaseSensitive,
 9411        window: &mut Window,
 9412        cx: &mut Context<Self>,
 9413    ) {
 9414        self.manipulate_lines(window, cx, |lines| {
 9415            let mut seen = HashSet::default();
 9416            lines.retain(|line| seen.insert(*line));
 9417        })
 9418    }
 9419
 9420    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9421        let Some(project) = self.project.clone() else {
 9422            return;
 9423        };
 9424        self.reload(project, window, cx)
 9425            .detach_and_notify_err(window, cx);
 9426    }
 9427
 9428    pub fn restore_file(
 9429        &mut self,
 9430        _: &::git::RestoreFile,
 9431        window: &mut Window,
 9432        cx: &mut Context<Self>,
 9433    ) {
 9434        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9435        let mut buffer_ids = HashSet::default();
 9436        let snapshot = self.buffer().read(cx).snapshot(cx);
 9437        for selection in self.selections.all::<usize>(cx) {
 9438            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9439        }
 9440
 9441        let buffer = self.buffer().read(cx);
 9442        let ranges = buffer_ids
 9443            .into_iter()
 9444            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9445            .collect::<Vec<_>>();
 9446
 9447        self.restore_hunks_in_ranges(ranges, window, cx);
 9448    }
 9449
 9450    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9451        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9452        let selections = self
 9453            .selections
 9454            .all(cx)
 9455            .into_iter()
 9456            .map(|s| s.range())
 9457            .collect();
 9458        self.restore_hunks_in_ranges(selections, window, cx);
 9459    }
 9460
 9461    pub fn restore_hunks_in_ranges(
 9462        &mut self,
 9463        ranges: Vec<Range<Point>>,
 9464        window: &mut Window,
 9465        cx: &mut Context<Editor>,
 9466    ) {
 9467        let mut revert_changes = HashMap::default();
 9468        let chunk_by = self
 9469            .snapshot(window, cx)
 9470            .hunks_for_ranges(ranges)
 9471            .into_iter()
 9472            .chunk_by(|hunk| hunk.buffer_id);
 9473        for (buffer_id, hunks) in &chunk_by {
 9474            let hunks = hunks.collect::<Vec<_>>();
 9475            for hunk in &hunks {
 9476                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9477            }
 9478            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9479        }
 9480        drop(chunk_by);
 9481        if !revert_changes.is_empty() {
 9482            self.transact(window, cx, |editor, window, cx| {
 9483                editor.restore(revert_changes, window, cx);
 9484            });
 9485        }
 9486    }
 9487
 9488    pub fn open_active_item_in_terminal(
 9489        &mut self,
 9490        _: &OpenInTerminal,
 9491        window: &mut Window,
 9492        cx: &mut Context<Self>,
 9493    ) {
 9494        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9495            let project_path = buffer.read(cx).project_path(cx)?;
 9496            let project = self.project.as_ref()?.read(cx);
 9497            let entry = project.entry_for_path(&project_path, cx)?;
 9498            let parent = match &entry.canonical_path {
 9499                Some(canonical_path) => canonical_path.to_path_buf(),
 9500                None => project.absolute_path(&project_path, cx)?,
 9501            }
 9502            .parent()?
 9503            .to_path_buf();
 9504            Some(parent)
 9505        }) {
 9506            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9507        }
 9508    }
 9509
 9510    fn set_breakpoint_context_menu(
 9511        &mut self,
 9512        display_row: DisplayRow,
 9513        position: Option<Anchor>,
 9514        clicked_point: gpui::Point<Pixels>,
 9515        window: &mut Window,
 9516        cx: &mut Context<Self>,
 9517    ) {
 9518        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9519            return;
 9520        }
 9521        let source = self
 9522            .buffer
 9523            .read(cx)
 9524            .snapshot(cx)
 9525            .anchor_before(Point::new(display_row.0, 0u32));
 9526
 9527        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9528
 9529        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9530            self,
 9531            source,
 9532            clicked_point,
 9533            context_menu,
 9534            window,
 9535            cx,
 9536        );
 9537    }
 9538
 9539    fn add_edit_breakpoint_block(
 9540        &mut self,
 9541        anchor: Anchor,
 9542        breakpoint: &Breakpoint,
 9543        edit_action: BreakpointPromptEditAction,
 9544        window: &mut Window,
 9545        cx: &mut Context<Self>,
 9546    ) {
 9547        let weak_editor = cx.weak_entity();
 9548        let bp_prompt = cx.new(|cx| {
 9549            BreakpointPromptEditor::new(
 9550                weak_editor,
 9551                anchor,
 9552                breakpoint.clone(),
 9553                edit_action,
 9554                window,
 9555                cx,
 9556            )
 9557        });
 9558
 9559        let height = bp_prompt.update(cx, |this, cx| {
 9560            this.prompt
 9561                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9562        });
 9563        let cloned_prompt = bp_prompt.clone();
 9564        let blocks = vec![BlockProperties {
 9565            style: BlockStyle::Sticky,
 9566            placement: BlockPlacement::Above(anchor),
 9567            height: Some(height),
 9568            render: Arc::new(move |cx| {
 9569                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9570                cloned_prompt.clone().into_any_element()
 9571            }),
 9572            priority: 0,
 9573            render_in_minimap: true,
 9574        }];
 9575
 9576        let focus_handle = bp_prompt.focus_handle(cx);
 9577        window.focus(&focus_handle);
 9578
 9579        let block_ids = self.insert_blocks(blocks, None, cx);
 9580        bp_prompt.update(cx, |prompt, _| {
 9581            prompt.add_block_ids(block_ids);
 9582        });
 9583    }
 9584
 9585    pub(crate) fn breakpoint_at_row(
 9586        &self,
 9587        row: u32,
 9588        window: &mut Window,
 9589        cx: &mut Context<Self>,
 9590    ) -> Option<(Anchor, Breakpoint)> {
 9591        let snapshot = self.snapshot(window, cx);
 9592        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9593
 9594        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9595    }
 9596
 9597    pub(crate) fn breakpoint_at_anchor(
 9598        &self,
 9599        breakpoint_position: Anchor,
 9600        snapshot: &EditorSnapshot,
 9601        cx: &mut Context<Self>,
 9602    ) -> Option<(Anchor, Breakpoint)> {
 9603        let project = self.project.clone()?;
 9604
 9605        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9606            snapshot
 9607                .buffer_snapshot
 9608                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9609        })?;
 9610
 9611        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9612        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9613        let buffer_snapshot = buffer.read(cx).snapshot();
 9614
 9615        let row = buffer_snapshot
 9616            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9617            .row;
 9618
 9619        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9620        let anchor_end = snapshot
 9621            .buffer_snapshot
 9622            .anchor_after(Point::new(row, line_len));
 9623
 9624        let bp = self
 9625            .breakpoint_store
 9626            .as_ref()?
 9627            .read_with(cx, |breakpoint_store, cx| {
 9628                breakpoint_store
 9629                    .breakpoints(
 9630                        &buffer,
 9631                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9632                        &buffer_snapshot,
 9633                        cx,
 9634                    )
 9635                    .next()
 9636                    .and_then(|(anchor, bp)| {
 9637                        let breakpoint_row = buffer_snapshot
 9638                            .summary_for_anchor::<text::PointUtf16>(anchor)
 9639                            .row;
 9640
 9641                        if breakpoint_row == row {
 9642                            snapshot
 9643                                .buffer_snapshot
 9644                                .anchor_in_excerpt(enclosing_excerpt, *anchor)
 9645                                .map(|anchor| (anchor, bp.clone()))
 9646                        } else {
 9647                            None
 9648                        }
 9649                    })
 9650            });
 9651        bp
 9652    }
 9653
 9654    pub fn edit_log_breakpoint(
 9655        &mut self,
 9656        _: &EditLogBreakpoint,
 9657        window: &mut Window,
 9658        cx: &mut Context<Self>,
 9659    ) {
 9660        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9661            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9662                message: None,
 9663                state: BreakpointState::Enabled,
 9664                condition: None,
 9665                hit_condition: None,
 9666            });
 9667
 9668            self.add_edit_breakpoint_block(
 9669                anchor,
 9670                &breakpoint,
 9671                BreakpointPromptEditAction::Log,
 9672                window,
 9673                cx,
 9674            );
 9675        }
 9676    }
 9677
 9678    fn breakpoints_at_cursors(
 9679        &self,
 9680        window: &mut Window,
 9681        cx: &mut Context<Self>,
 9682    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9683        let snapshot = self.snapshot(window, cx);
 9684        let cursors = self
 9685            .selections
 9686            .disjoint_anchors()
 9687            .into_iter()
 9688            .map(|selection| {
 9689                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9690
 9691                let breakpoint_position = self
 9692                    .breakpoint_at_row(cursor_position.row, window, cx)
 9693                    .map(|bp| bp.0)
 9694                    .unwrap_or_else(|| {
 9695                        snapshot
 9696                            .display_snapshot
 9697                            .buffer_snapshot
 9698                            .anchor_after(Point::new(cursor_position.row, 0))
 9699                    });
 9700
 9701                let breakpoint = self
 9702                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9703                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9704
 9705                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9706            })
 9707            // 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.
 9708            .collect::<HashMap<Anchor, _>>();
 9709
 9710        cursors.into_iter().collect()
 9711    }
 9712
 9713    pub fn enable_breakpoint(
 9714        &mut self,
 9715        _: &crate::actions::EnableBreakpoint,
 9716        window: &mut Window,
 9717        cx: &mut Context<Self>,
 9718    ) {
 9719        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9720            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9721                continue;
 9722            };
 9723            self.edit_breakpoint_at_anchor(
 9724                anchor,
 9725                breakpoint,
 9726                BreakpointEditAction::InvertState,
 9727                cx,
 9728            );
 9729        }
 9730    }
 9731
 9732    pub fn disable_breakpoint(
 9733        &mut self,
 9734        _: &crate::actions::DisableBreakpoint,
 9735        window: &mut Window,
 9736        cx: &mut Context<Self>,
 9737    ) {
 9738        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9739            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9740                continue;
 9741            };
 9742            self.edit_breakpoint_at_anchor(
 9743                anchor,
 9744                breakpoint,
 9745                BreakpointEditAction::InvertState,
 9746                cx,
 9747            );
 9748        }
 9749    }
 9750
 9751    pub fn toggle_breakpoint(
 9752        &mut self,
 9753        _: &crate::actions::ToggleBreakpoint,
 9754        window: &mut Window,
 9755        cx: &mut Context<Self>,
 9756    ) {
 9757        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9758            if let Some(breakpoint) = breakpoint {
 9759                self.edit_breakpoint_at_anchor(
 9760                    anchor,
 9761                    breakpoint,
 9762                    BreakpointEditAction::Toggle,
 9763                    cx,
 9764                );
 9765            } else {
 9766                self.edit_breakpoint_at_anchor(
 9767                    anchor,
 9768                    Breakpoint::new_standard(),
 9769                    BreakpointEditAction::Toggle,
 9770                    cx,
 9771                );
 9772            }
 9773        }
 9774    }
 9775
 9776    pub fn edit_breakpoint_at_anchor(
 9777        &mut self,
 9778        breakpoint_position: Anchor,
 9779        breakpoint: Breakpoint,
 9780        edit_action: BreakpointEditAction,
 9781        cx: &mut Context<Self>,
 9782    ) {
 9783        let Some(breakpoint_store) = &self.breakpoint_store else {
 9784            return;
 9785        };
 9786
 9787        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9788            if breakpoint_position == Anchor::min() {
 9789                self.buffer()
 9790                    .read(cx)
 9791                    .excerpt_buffer_ids()
 9792                    .into_iter()
 9793                    .next()
 9794            } else {
 9795                None
 9796            }
 9797        }) else {
 9798            return;
 9799        };
 9800
 9801        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9802            return;
 9803        };
 9804
 9805        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9806            breakpoint_store.toggle_breakpoint(
 9807                buffer,
 9808                (breakpoint_position.text_anchor, breakpoint),
 9809                edit_action,
 9810                cx,
 9811            );
 9812        });
 9813
 9814        cx.notify();
 9815    }
 9816
 9817    #[cfg(any(test, feature = "test-support"))]
 9818    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9819        self.breakpoint_store.clone()
 9820    }
 9821
 9822    pub fn prepare_restore_change(
 9823        &self,
 9824        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9825        hunk: &MultiBufferDiffHunk,
 9826        cx: &mut App,
 9827    ) -> Option<()> {
 9828        if hunk.is_created_file() {
 9829            return None;
 9830        }
 9831        let buffer = self.buffer.read(cx);
 9832        let diff = buffer.diff_for(hunk.buffer_id)?;
 9833        let buffer = buffer.buffer(hunk.buffer_id)?;
 9834        let buffer = buffer.read(cx);
 9835        let original_text = diff
 9836            .read(cx)
 9837            .base_text()
 9838            .as_rope()
 9839            .slice(hunk.diff_base_byte_range.clone());
 9840        let buffer_snapshot = buffer.snapshot();
 9841        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9842        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9843            probe
 9844                .0
 9845                .start
 9846                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9847                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9848        }) {
 9849            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9850            Some(())
 9851        } else {
 9852            None
 9853        }
 9854    }
 9855
 9856    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9857        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9858    }
 9859
 9860    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9861        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9862    }
 9863
 9864    fn manipulate_lines<Fn>(
 9865        &mut self,
 9866        window: &mut Window,
 9867        cx: &mut Context<Self>,
 9868        mut callback: Fn,
 9869    ) where
 9870        Fn: FnMut(&mut Vec<&str>),
 9871    {
 9872        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9873
 9874        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9875        let buffer = self.buffer.read(cx).snapshot(cx);
 9876
 9877        let mut edits = Vec::new();
 9878
 9879        let selections = self.selections.all::<Point>(cx);
 9880        let mut selections = selections.iter().peekable();
 9881        let mut contiguous_row_selections = Vec::new();
 9882        let mut new_selections = Vec::new();
 9883        let mut added_lines = 0;
 9884        let mut removed_lines = 0;
 9885
 9886        while let Some(selection) = selections.next() {
 9887            let (start_row, end_row) = consume_contiguous_rows(
 9888                &mut contiguous_row_selections,
 9889                selection,
 9890                &display_map,
 9891                &mut selections,
 9892            );
 9893
 9894            let start_point = Point::new(start_row.0, 0);
 9895            let end_point = Point::new(
 9896                end_row.previous_row().0,
 9897                buffer.line_len(end_row.previous_row()),
 9898            );
 9899            let text = buffer
 9900                .text_for_range(start_point..end_point)
 9901                .collect::<String>();
 9902
 9903            let mut lines = text.split('\n').collect_vec();
 9904
 9905            let lines_before = lines.len();
 9906            callback(&mut lines);
 9907            let lines_after = lines.len();
 9908
 9909            edits.push((start_point..end_point, lines.join("\n")));
 9910
 9911            // Selections must change based on added and removed line count
 9912            let start_row =
 9913                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9914            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9915            new_selections.push(Selection {
 9916                id: selection.id,
 9917                start: start_row,
 9918                end: end_row,
 9919                goal: SelectionGoal::None,
 9920                reversed: selection.reversed,
 9921            });
 9922
 9923            if lines_after > lines_before {
 9924                added_lines += lines_after - lines_before;
 9925            } else if lines_before > lines_after {
 9926                removed_lines += lines_before - lines_after;
 9927            }
 9928        }
 9929
 9930        self.transact(window, cx, |this, window, cx| {
 9931            let buffer = this.buffer.update(cx, |buffer, cx| {
 9932                buffer.edit(edits, None, cx);
 9933                buffer.snapshot(cx)
 9934            });
 9935
 9936            // Recalculate offsets on newly edited buffer
 9937            let new_selections = new_selections
 9938                .iter()
 9939                .map(|s| {
 9940                    let start_point = Point::new(s.start.0, 0);
 9941                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9942                    Selection {
 9943                        id: s.id,
 9944                        start: buffer.point_to_offset(start_point),
 9945                        end: buffer.point_to_offset(end_point),
 9946                        goal: s.goal,
 9947                        reversed: s.reversed,
 9948                    }
 9949                })
 9950                .collect();
 9951
 9952            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9953                s.select(new_selections);
 9954            });
 9955
 9956            this.request_autoscroll(Autoscroll::fit(), cx);
 9957        });
 9958    }
 9959
 9960    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9961        self.manipulate_text(window, cx, |text| {
 9962            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9963            if has_upper_case_characters {
 9964                text.to_lowercase()
 9965            } else {
 9966                text.to_uppercase()
 9967            }
 9968        })
 9969    }
 9970
 9971    pub fn convert_to_upper_case(
 9972        &mut self,
 9973        _: &ConvertToUpperCase,
 9974        window: &mut Window,
 9975        cx: &mut Context<Self>,
 9976    ) {
 9977        self.manipulate_text(window, cx, |text| text.to_uppercase())
 9978    }
 9979
 9980    pub fn convert_to_lower_case(
 9981        &mut self,
 9982        _: &ConvertToLowerCase,
 9983        window: &mut Window,
 9984        cx: &mut Context<Self>,
 9985    ) {
 9986        self.manipulate_text(window, cx, |text| text.to_lowercase())
 9987    }
 9988
 9989    pub fn convert_to_title_case(
 9990        &mut self,
 9991        _: &ConvertToTitleCase,
 9992        window: &mut Window,
 9993        cx: &mut Context<Self>,
 9994    ) {
 9995        self.manipulate_text(window, cx, |text| {
 9996            text.split('\n')
 9997                .map(|line| line.to_case(Case::Title))
 9998                .join("\n")
 9999        })
10000    }
10001
10002    pub fn convert_to_snake_case(
10003        &mut self,
10004        _: &ConvertToSnakeCase,
10005        window: &mut Window,
10006        cx: &mut Context<Self>,
10007    ) {
10008        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10009    }
10010
10011    pub fn convert_to_kebab_case(
10012        &mut self,
10013        _: &ConvertToKebabCase,
10014        window: &mut Window,
10015        cx: &mut Context<Self>,
10016    ) {
10017        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10018    }
10019
10020    pub fn convert_to_upper_camel_case(
10021        &mut self,
10022        _: &ConvertToUpperCamelCase,
10023        window: &mut Window,
10024        cx: &mut Context<Self>,
10025    ) {
10026        self.manipulate_text(window, cx, |text| {
10027            text.split('\n')
10028                .map(|line| line.to_case(Case::UpperCamel))
10029                .join("\n")
10030        })
10031    }
10032
10033    pub fn convert_to_lower_camel_case(
10034        &mut self,
10035        _: &ConvertToLowerCamelCase,
10036        window: &mut Window,
10037        cx: &mut Context<Self>,
10038    ) {
10039        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10040    }
10041
10042    pub fn convert_to_opposite_case(
10043        &mut self,
10044        _: &ConvertToOppositeCase,
10045        window: &mut Window,
10046        cx: &mut Context<Self>,
10047    ) {
10048        self.manipulate_text(window, cx, |text| {
10049            text.chars()
10050                .fold(String::with_capacity(text.len()), |mut t, c| {
10051                    if c.is_uppercase() {
10052                        t.extend(c.to_lowercase());
10053                    } else {
10054                        t.extend(c.to_uppercase());
10055                    }
10056                    t
10057                })
10058        })
10059    }
10060
10061    pub fn convert_to_rot13(
10062        &mut self,
10063        _: &ConvertToRot13,
10064        window: &mut Window,
10065        cx: &mut Context<Self>,
10066    ) {
10067        self.manipulate_text(window, cx, |text| {
10068            text.chars()
10069                .map(|c| match c {
10070                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10071                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10072                    _ => c,
10073                })
10074                .collect()
10075        })
10076    }
10077
10078    pub fn convert_to_rot47(
10079        &mut self,
10080        _: &ConvertToRot47,
10081        window: &mut Window,
10082        cx: &mut Context<Self>,
10083    ) {
10084        self.manipulate_text(window, cx, |text| {
10085            text.chars()
10086                .map(|c| {
10087                    let code_point = c as u32;
10088                    if code_point >= 33 && code_point <= 126 {
10089                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10090                    }
10091                    c
10092                })
10093                .collect()
10094        })
10095    }
10096
10097    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10098    where
10099        Fn: FnMut(&str) -> String,
10100    {
10101        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10102        let buffer = self.buffer.read(cx).snapshot(cx);
10103
10104        let mut new_selections = Vec::new();
10105        let mut edits = Vec::new();
10106        let mut selection_adjustment = 0i32;
10107
10108        for selection in self.selections.all::<usize>(cx) {
10109            let selection_is_empty = selection.is_empty();
10110
10111            let (start, end) = if selection_is_empty {
10112                let word_range = movement::surrounding_word(
10113                    &display_map,
10114                    selection.start.to_display_point(&display_map),
10115                );
10116                let start = word_range.start.to_offset(&display_map, Bias::Left);
10117                let end = word_range.end.to_offset(&display_map, Bias::Left);
10118                (start, end)
10119            } else {
10120                (selection.start, selection.end)
10121            };
10122
10123            let text = buffer.text_for_range(start..end).collect::<String>();
10124            let old_length = text.len() as i32;
10125            let text = callback(&text);
10126
10127            new_selections.push(Selection {
10128                start: (start as i32 - selection_adjustment) as usize,
10129                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10130                goal: SelectionGoal::None,
10131                ..selection
10132            });
10133
10134            selection_adjustment += old_length - text.len() as i32;
10135
10136            edits.push((start..end, text));
10137        }
10138
10139        self.transact(window, cx, |this, window, cx| {
10140            this.buffer.update(cx, |buffer, cx| {
10141                buffer.edit(edits, None, cx);
10142            });
10143
10144            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10145                s.select(new_selections);
10146            });
10147
10148            this.request_autoscroll(Autoscroll::fit(), cx);
10149        });
10150    }
10151
10152    pub fn duplicate(
10153        &mut self,
10154        upwards: bool,
10155        whole_lines: bool,
10156        window: &mut Window,
10157        cx: &mut Context<Self>,
10158    ) {
10159        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10160
10161        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10162        let buffer = &display_map.buffer_snapshot;
10163        let selections = self.selections.all::<Point>(cx);
10164
10165        let mut edits = Vec::new();
10166        let mut selections_iter = selections.iter().peekable();
10167        while let Some(selection) = selections_iter.next() {
10168            let mut rows = selection.spanned_rows(false, &display_map);
10169            // duplicate line-wise
10170            if whole_lines || selection.start == selection.end {
10171                // Avoid duplicating the same lines twice.
10172                while let Some(next_selection) = selections_iter.peek() {
10173                    let next_rows = next_selection.spanned_rows(false, &display_map);
10174                    if next_rows.start < rows.end {
10175                        rows.end = next_rows.end;
10176                        selections_iter.next().unwrap();
10177                    } else {
10178                        break;
10179                    }
10180                }
10181
10182                // Copy the text from the selected row region and splice it either at the start
10183                // or end of the region.
10184                let start = Point::new(rows.start.0, 0);
10185                let end = Point::new(
10186                    rows.end.previous_row().0,
10187                    buffer.line_len(rows.end.previous_row()),
10188                );
10189                let text = buffer
10190                    .text_for_range(start..end)
10191                    .chain(Some("\n"))
10192                    .collect::<String>();
10193                let insert_location = if upwards {
10194                    Point::new(rows.end.0, 0)
10195                } else {
10196                    start
10197                };
10198                edits.push((insert_location..insert_location, text));
10199            } else {
10200                // duplicate character-wise
10201                let start = selection.start;
10202                let end = selection.end;
10203                let text = buffer.text_for_range(start..end).collect::<String>();
10204                edits.push((selection.end..selection.end, text));
10205            }
10206        }
10207
10208        self.transact(window, cx, |this, _, cx| {
10209            this.buffer.update(cx, |buffer, cx| {
10210                buffer.edit(edits, None, cx);
10211            });
10212
10213            this.request_autoscroll(Autoscroll::fit(), cx);
10214        });
10215    }
10216
10217    pub fn duplicate_line_up(
10218        &mut self,
10219        _: &DuplicateLineUp,
10220        window: &mut Window,
10221        cx: &mut Context<Self>,
10222    ) {
10223        self.duplicate(true, true, window, cx);
10224    }
10225
10226    pub fn duplicate_line_down(
10227        &mut self,
10228        _: &DuplicateLineDown,
10229        window: &mut Window,
10230        cx: &mut Context<Self>,
10231    ) {
10232        self.duplicate(false, true, window, cx);
10233    }
10234
10235    pub fn duplicate_selection(
10236        &mut self,
10237        _: &DuplicateSelection,
10238        window: &mut Window,
10239        cx: &mut Context<Self>,
10240    ) {
10241        self.duplicate(false, false, window, cx);
10242    }
10243
10244    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10245        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10246
10247        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10248        let buffer = self.buffer.read(cx).snapshot(cx);
10249
10250        let mut edits = Vec::new();
10251        let mut unfold_ranges = Vec::new();
10252        let mut refold_creases = Vec::new();
10253
10254        let selections = self.selections.all::<Point>(cx);
10255        let mut selections = selections.iter().peekable();
10256        let mut contiguous_row_selections = Vec::new();
10257        let mut new_selections = Vec::new();
10258
10259        while let Some(selection) = selections.next() {
10260            // Find all the selections that span a contiguous row range
10261            let (start_row, end_row) = consume_contiguous_rows(
10262                &mut contiguous_row_selections,
10263                selection,
10264                &display_map,
10265                &mut selections,
10266            );
10267
10268            // Move the text spanned by the row range to be before the line preceding the row range
10269            if start_row.0 > 0 {
10270                let range_to_move = Point::new(
10271                    start_row.previous_row().0,
10272                    buffer.line_len(start_row.previous_row()),
10273                )
10274                    ..Point::new(
10275                        end_row.previous_row().0,
10276                        buffer.line_len(end_row.previous_row()),
10277                    );
10278                let insertion_point = display_map
10279                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10280                    .0;
10281
10282                // Don't move lines across excerpts
10283                if buffer
10284                    .excerpt_containing(insertion_point..range_to_move.end)
10285                    .is_some()
10286                {
10287                    let text = buffer
10288                        .text_for_range(range_to_move.clone())
10289                        .flat_map(|s| s.chars())
10290                        .skip(1)
10291                        .chain(['\n'])
10292                        .collect::<String>();
10293
10294                    edits.push((
10295                        buffer.anchor_after(range_to_move.start)
10296                            ..buffer.anchor_before(range_to_move.end),
10297                        String::new(),
10298                    ));
10299                    let insertion_anchor = buffer.anchor_after(insertion_point);
10300                    edits.push((insertion_anchor..insertion_anchor, text));
10301
10302                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10303
10304                    // Move selections up
10305                    new_selections.extend(contiguous_row_selections.drain(..).map(
10306                        |mut selection| {
10307                            selection.start.row -= row_delta;
10308                            selection.end.row -= row_delta;
10309                            selection
10310                        },
10311                    ));
10312
10313                    // Move folds up
10314                    unfold_ranges.push(range_to_move.clone());
10315                    for fold in display_map.folds_in_range(
10316                        buffer.anchor_before(range_to_move.start)
10317                            ..buffer.anchor_after(range_to_move.end),
10318                    ) {
10319                        let mut start = fold.range.start.to_point(&buffer);
10320                        let mut end = fold.range.end.to_point(&buffer);
10321                        start.row -= row_delta;
10322                        end.row -= row_delta;
10323                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10324                    }
10325                }
10326            }
10327
10328            // If we didn't move line(s), preserve the existing selections
10329            new_selections.append(&mut contiguous_row_selections);
10330        }
10331
10332        self.transact(window, cx, |this, window, cx| {
10333            this.unfold_ranges(&unfold_ranges, true, true, cx);
10334            this.buffer.update(cx, |buffer, cx| {
10335                for (range, text) in edits {
10336                    buffer.edit([(range, text)], None, cx);
10337                }
10338            });
10339            this.fold_creases(refold_creases, true, window, cx);
10340            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10341                s.select(new_selections);
10342            })
10343        });
10344    }
10345
10346    pub fn move_line_down(
10347        &mut self,
10348        _: &MoveLineDown,
10349        window: &mut Window,
10350        cx: &mut Context<Self>,
10351    ) {
10352        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10353
10354        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10355        let buffer = self.buffer.read(cx).snapshot(cx);
10356
10357        let mut edits = Vec::new();
10358        let mut unfold_ranges = Vec::new();
10359        let mut refold_creases = Vec::new();
10360
10361        let selections = self.selections.all::<Point>(cx);
10362        let mut selections = selections.iter().peekable();
10363        let mut contiguous_row_selections = Vec::new();
10364        let mut new_selections = Vec::new();
10365
10366        while let Some(selection) = selections.next() {
10367            // Find all the selections that span a contiguous row range
10368            let (start_row, end_row) = consume_contiguous_rows(
10369                &mut contiguous_row_selections,
10370                selection,
10371                &display_map,
10372                &mut selections,
10373            );
10374
10375            // Move the text spanned by the row range to be after the last line of the row range
10376            if end_row.0 <= buffer.max_point().row {
10377                let range_to_move =
10378                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10379                let insertion_point = display_map
10380                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10381                    .0;
10382
10383                // Don't move lines across excerpt boundaries
10384                if buffer
10385                    .excerpt_containing(range_to_move.start..insertion_point)
10386                    .is_some()
10387                {
10388                    let mut text = String::from("\n");
10389                    text.extend(buffer.text_for_range(range_to_move.clone()));
10390                    text.pop(); // Drop trailing newline
10391                    edits.push((
10392                        buffer.anchor_after(range_to_move.start)
10393                            ..buffer.anchor_before(range_to_move.end),
10394                        String::new(),
10395                    ));
10396                    let insertion_anchor = buffer.anchor_after(insertion_point);
10397                    edits.push((insertion_anchor..insertion_anchor, text));
10398
10399                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10400
10401                    // Move selections down
10402                    new_selections.extend(contiguous_row_selections.drain(..).map(
10403                        |mut selection| {
10404                            selection.start.row += row_delta;
10405                            selection.end.row += row_delta;
10406                            selection
10407                        },
10408                    ));
10409
10410                    // Move folds down
10411                    unfold_ranges.push(range_to_move.clone());
10412                    for fold in display_map.folds_in_range(
10413                        buffer.anchor_before(range_to_move.start)
10414                            ..buffer.anchor_after(range_to_move.end),
10415                    ) {
10416                        let mut start = fold.range.start.to_point(&buffer);
10417                        let mut end = fold.range.end.to_point(&buffer);
10418                        start.row += row_delta;
10419                        end.row += row_delta;
10420                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10421                    }
10422                }
10423            }
10424
10425            // If we didn't move line(s), preserve the existing selections
10426            new_selections.append(&mut contiguous_row_selections);
10427        }
10428
10429        self.transact(window, cx, |this, window, cx| {
10430            this.unfold_ranges(&unfold_ranges, true, true, cx);
10431            this.buffer.update(cx, |buffer, cx| {
10432                for (range, text) in edits {
10433                    buffer.edit([(range, text)], None, cx);
10434                }
10435            });
10436            this.fold_creases(refold_creases, true, window, cx);
10437            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10438                s.select(new_selections)
10439            });
10440        });
10441    }
10442
10443    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10444        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10445        let text_layout_details = &self.text_layout_details(window);
10446        self.transact(window, cx, |this, window, cx| {
10447            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10448                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10449                s.move_with(|display_map, selection| {
10450                    if !selection.is_empty() {
10451                        return;
10452                    }
10453
10454                    let mut head = selection.head();
10455                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10456                    if head.column() == display_map.line_len(head.row()) {
10457                        transpose_offset = display_map
10458                            .buffer_snapshot
10459                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10460                    }
10461
10462                    if transpose_offset == 0 {
10463                        return;
10464                    }
10465
10466                    *head.column_mut() += 1;
10467                    head = display_map.clip_point(head, Bias::Right);
10468                    let goal = SelectionGoal::HorizontalPosition(
10469                        display_map
10470                            .x_for_display_point(head, text_layout_details)
10471                            .into(),
10472                    );
10473                    selection.collapse_to(head, goal);
10474
10475                    let transpose_start = display_map
10476                        .buffer_snapshot
10477                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10478                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10479                        let transpose_end = display_map
10480                            .buffer_snapshot
10481                            .clip_offset(transpose_offset + 1, Bias::Right);
10482                        if let Some(ch) =
10483                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10484                        {
10485                            edits.push((transpose_start..transpose_offset, String::new()));
10486                            edits.push((transpose_end..transpose_end, ch.to_string()));
10487                        }
10488                    }
10489                });
10490                edits
10491            });
10492            this.buffer
10493                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10494            let selections = this.selections.all::<usize>(cx);
10495            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10496                s.select(selections);
10497            });
10498        });
10499    }
10500
10501    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10502        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10503        self.rewrap_impl(RewrapOptions::default(), cx)
10504    }
10505
10506    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10507        let buffer = self.buffer.read(cx).snapshot(cx);
10508        let selections = self.selections.all::<Point>(cx);
10509        let mut selections = selections.iter().peekable();
10510
10511        let mut edits = Vec::new();
10512        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10513
10514        while let Some(selection) = selections.next() {
10515            let mut start_row = selection.start.row;
10516            let mut end_row = selection.end.row;
10517
10518            // Skip selections that overlap with a range that has already been rewrapped.
10519            let selection_range = start_row..end_row;
10520            if rewrapped_row_ranges
10521                .iter()
10522                .any(|range| range.overlaps(&selection_range))
10523            {
10524                continue;
10525            }
10526
10527            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10528
10529            // Since not all lines in the selection may be at the same indent
10530            // level, choose the indent size that is the most common between all
10531            // of the lines.
10532            //
10533            // If there is a tie, we use the deepest indent.
10534            let (indent_size, indent_end) = {
10535                let mut indent_size_occurrences = HashMap::default();
10536                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10537
10538                for row in start_row..=end_row {
10539                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10540                    rows_by_indent_size.entry(indent).or_default().push(row);
10541                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10542                }
10543
10544                let indent_size = indent_size_occurrences
10545                    .into_iter()
10546                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10547                    .map(|(indent, _)| indent)
10548                    .unwrap_or_default();
10549                let row = rows_by_indent_size[&indent_size][0];
10550                let indent_end = Point::new(row, indent_size.len);
10551
10552                (indent_size, indent_end)
10553            };
10554
10555            let mut line_prefix = indent_size.chars().collect::<String>();
10556
10557            let mut inside_comment = false;
10558            if let Some(comment_prefix) =
10559                buffer
10560                    .language_scope_at(selection.head())
10561                    .and_then(|language| {
10562                        language
10563                            .line_comment_prefixes()
10564                            .iter()
10565                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10566                            .cloned()
10567                    })
10568            {
10569                line_prefix.push_str(&comment_prefix);
10570                inside_comment = true;
10571            }
10572
10573            let language_settings = buffer.language_settings_at(selection.head(), cx);
10574            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10575                RewrapBehavior::InComments => inside_comment,
10576                RewrapBehavior::InSelections => !selection.is_empty(),
10577                RewrapBehavior::Anywhere => true,
10578            };
10579
10580            let should_rewrap = options.override_language_settings
10581                || allow_rewrap_based_on_language
10582                || self.hard_wrap.is_some();
10583            if !should_rewrap {
10584                continue;
10585            }
10586
10587            if selection.is_empty() {
10588                'expand_upwards: while start_row > 0 {
10589                    let prev_row = start_row - 1;
10590                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10591                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10592                    {
10593                        start_row = prev_row;
10594                    } else {
10595                        break 'expand_upwards;
10596                    }
10597                }
10598
10599                'expand_downwards: while end_row < buffer.max_point().row {
10600                    let next_row = end_row + 1;
10601                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10602                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10603                    {
10604                        end_row = next_row;
10605                    } else {
10606                        break 'expand_downwards;
10607                    }
10608                }
10609            }
10610
10611            let start = Point::new(start_row, 0);
10612            let start_offset = start.to_offset(&buffer);
10613            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10614            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10615            let Some(lines_without_prefixes) = selection_text
10616                .lines()
10617                .map(|line| {
10618                    line.strip_prefix(&line_prefix)
10619                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10620                        .ok_or_else(|| {
10621                            anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
10622                        })
10623                })
10624                .collect::<Result<Vec<_>, _>>()
10625                .log_err()
10626            else {
10627                continue;
10628            };
10629
10630            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10631                buffer
10632                    .language_settings_at(Point::new(start_row, 0), cx)
10633                    .preferred_line_length as usize
10634            });
10635            let wrapped_text = wrap_with_prefix(
10636                line_prefix,
10637                lines_without_prefixes.join("\n"),
10638                wrap_column,
10639                tab_size,
10640                options.preserve_existing_whitespace,
10641            );
10642
10643            // TODO: should always use char-based diff while still supporting cursor behavior that
10644            // matches vim.
10645            let mut diff_options = DiffOptions::default();
10646            if options.override_language_settings {
10647                diff_options.max_word_diff_len = 0;
10648                diff_options.max_word_diff_line_count = 0;
10649            } else {
10650                diff_options.max_word_diff_len = usize::MAX;
10651                diff_options.max_word_diff_line_count = usize::MAX;
10652            }
10653
10654            for (old_range, new_text) in
10655                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10656            {
10657                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10658                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10659                edits.push((edit_start..edit_end, new_text));
10660            }
10661
10662            rewrapped_row_ranges.push(start_row..=end_row);
10663        }
10664
10665        self.buffer
10666            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10667    }
10668
10669    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10670        let mut text = String::new();
10671        let buffer = self.buffer.read(cx).snapshot(cx);
10672        let mut selections = self.selections.all::<Point>(cx);
10673        let mut clipboard_selections = Vec::with_capacity(selections.len());
10674        {
10675            let max_point = buffer.max_point();
10676            let mut is_first = true;
10677            for selection in &mut selections {
10678                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10679                if is_entire_line {
10680                    selection.start = Point::new(selection.start.row, 0);
10681                    if !selection.is_empty() && selection.end.column == 0 {
10682                        selection.end = cmp::min(max_point, selection.end);
10683                    } else {
10684                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10685                    }
10686                    selection.goal = SelectionGoal::None;
10687                }
10688                if is_first {
10689                    is_first = false;
10690                } else {
10691                    text += "\n";
10692                }
10693                let mut len = 0;
10694                for chunk in buffer.text_for_range(selection.start..selection.end) {
10695                    text.push_str(chunk);
10696                    len += chunk.len();
10697                }
10698                clipboard_selections.push(ClipboardSelection {
10699                    len,
10700                    is_entire_line,
10701                    first_line_indent: buffer
10702                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10703                        .len,
10704                });
10705            }
10706        }
10707
10708        self.transact(window, cx, |this, window, cx| {
10709            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10710                s.select(selections);
10711            });
10712            this.insert("", window, cx);
10713        });
10714        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10715    }
10716
10717    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10718        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10719        let item = self.cut_common(window, cx);
10720        cx.write_to_clipboard(item);
10721    }
10722
10723    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10724        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10725        self.change_selections(None, window, cx, |s| {
10726            s.move_with(|snapshot, sel| {
10727                if sel.is_empty() {
10728                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10729                }
10730            });
10731        });
10732        let item = self.cut_common(window, cx);
10733        cx.set_global(KillRing(item))
10734    }
10735
10736    pub fn kill_ring_yank(
10737        &mut self,
10738        _: &KillRingYank,
10739        window: &mut Window,
10740        cx: &mut Context<Self>,
10741    ) {
10742        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10743        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10744            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10745                (kill_ring.text().to_string(), kill_ring.metadata_json())
10746            } else {
10747                return;
10748            }
10749        } else {
10750            return;
10751        };
10752        self.do_paste(&text, metadata, false, window, cx);
10753    }
10754
10755    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10756        self.do_copy(true, cx);
10757    }
10758
10759    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10760        self.do_copy(false, cx);
10761    }
10762
10763    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10764        let selections = self.selections.all::<Point>(cx);
10765        let buffer = self.buffer.read(cx).read(cx);
10766        let mut text = String::new();
10767
10768        let mut clipboard_selections = Vec::with_capacity(selections.len());
10769        {
10770            let max_point = buffer.max_point();
10771            let mut is_first = true;
10772            for selection in &selections {
10773                let mut start = selection.start;
10774                let mut end = selection.end;
10775                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10776                if is_entire_line {
10777                    start = Point::new(start.row, 0);
10778                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10779                }
10780
10781                let mut trimmed_selections = Vec::new();
10782                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10783                    let row = MultiBufferRow(start.row);
10784                    let first_indent = buffer.indent_size_for_line(row);
10785                    if first_indent.len == 0 || start.column > first_indent.len {
10786                        trimmed_selections.push(start..end);
10787                    } else {
10788                        trimmed_selections.push(
10789                            Point::new(row.0, first_indent.len)
10790                                ..Point::new(row.0, buffer.line_len(row)),
10791                        );
10792                        for row in start.row + 1..=end.row {
10793                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10794                            if row == end.row {
10795                                line_len = end.column;
10796                            }
10797                            if line_len == 0 {
10798                                trimmed_selections
10799                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10800                                continue;
10801                            }
10802                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10803                            if row_indent_size.len >= first_indent.len {
10804                                trimmed_selections.push(
10805                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10806                                );
10807                            } else {
10808                                trimmed_selections.clear();
10809                                trimmed_selections.push(start..end);
10810                                break;
10811                            }
10812                        }
10813                    }
10814                } else {
10815                    trimmed_selections.push(start..end);
10816                }
10817
10818                for trimmed_range in trimmed_selections {
10819                    if is_first {
10820                        is_first = false;
10821                    } else {
10822                        text += "\n";
10823                    }
10824                    let mut len = 0;
10825                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10826                        text.push_str(chunk);
10827                        len += chunk.len();
10828                    }
10829                    clipboard_selections.push(ClipboardSelection {
10830                        len,
10831                        is_entire_line,
10832                        first_line_indent: buffer
10833                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10834                            .len,
10835                    });
10836                }
10837            }
10838        }
10839
10840        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10841            text,
10842            clipboard_selections,
10843        ));
10844    }
10845
10846    pub fn do_paste(
10847        &mut self,
10848        text: &String,
10849        clipboard_selections: Option<Vec<ClipboardSelection>>,
10850        handle_entire_lines: bool,
10851        window: &mut Window,
10852        cx: &mut Context<Self>,
10853    ) {
10854        if self.read_only(cx) {
10855            return;
10856        }
10857
10858        let clipboard_text = Cow::Borrowed(text);
10859
10860        self.transact(window, cx, |this, window, cx| {
10861            if let Some(mut clipboard_selections) = clipboard_selections {
10862                let old_selections = this.selections.all::<usize>(cx);
10863                let all_selections_were_entire_line =
10864                    clipboard_selections.iter().all(|s| s.is_entire_line);
10865                let first_selection_indent_column =
10866                    clipboard_selections.first().map(|s| s.first_line_indent);
10867                if clipboard_selections.len() != old_selections.len() {
10868                    clipboard_selections.drain(..);
10869                }
10870                let cursor_offset = this.selections.last::<usize>(cx).head();
10871                let mut auto_indent_on_paste = true;
10872
10873                this.buffer.update(cx, |buffer, cx| {
10874                    let snapshot = buffer.read(cx);
10875                    auto_indent_on_paste = snapshot
10876                        .language_settings_at(cursor_offset, cx)
10877                        .auto_indent_on_paste;
10878
10879                    let mut start_offset = 0;
10880                    let mut edits = Vec::new();
10881                    let mut original_indent_columns = Vec::new();
10882                    for (ix, selection) in old_selections.iter().enumerate() {
10883                        let to_insert;
10884                        let entire_line;
10885                        let original_indent_column;
10886                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10887                            let end_offset = start_offset + clipboard_selection.len;
10888                            to_insert = &clipboard_text[start_offset..end_offset];
10889                            entire_line = clipboard_selection.is_entire_line;
10890                            start_offset = end_offset + 1;
10891                            original_indent_column = Some(clipboard_selection.first_line_indent);
10892                        } else {
10893                            to_insert = clipboard_text.as_str();
10894                            entire_line = all_selections_were_entire_line;
10895                            original_indent_column = first_selection_indent_column
10896                        }
10897
10898                        // If the corresponding selection was empty when this slice of the
10899                        // clipboard text was written, then the entire line containing the
10900                        // selection was copied. If this selection is also currently empty,
10901                        // then paste the line before the current line of the buffer.
10902                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10903                            let column = selection.start.to_point(&snapshot).column as usize;
10904                            let line_start = selection.start - column;
10905                            line_start..line_start
10906                        } else {
10907                            selection.range()
10908                        };
10909
10910                        edits.push((range, to_insert));
10911                        original_indent_columns.push(original_indent_column);
10912                    }
10913                    drop(snapshot);
10914
10915                    buffer.edit(
10916                        edits,
10917                        if auto_indent_on_paste {
10918                            Some(AutoindentMode::Block {
10919                                original_indent_columns,
10920                            })
10921                        } else {
10922                            None
10923                        },
10924                        cx,
10925                    );
10926                });
10927
10928                let selections = this.selections.all::<usize>(cx);
10929                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10930                    s.select(selections)
10931                });
10932            } else {
10933                this.insert(&clipboard_text, window, cx);
10934            }
10935        });
10936    }
10937
10938    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10939        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10940        if let Some(item) = cx.read_from_clipboard() {
10941            let entries = item.entries();
10942
10943            match entries.first() {
10944                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10945                // of all the pasted entries.
10946                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10947                    .do_paste(
10948                        clipboard_string.text(),
10949                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10950                        true,
10951                        window,
10952                        cx,
10953                    ),
10954                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10955            }
10956        }
10957    }
10958
10959    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10960        if self.read_only(cx) {
10961            return;
10962        }
10963
10964        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10965
10966        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
10967            if let Some((selections, _)) =
10968                self.selection_history.transaction(transaction_id).cloned()
10969            {
10970                self.change_selections(None, window, cx, |s| {
10971                    s.select_anchors(selections.to_vec());
10972                });
10973            } else {
10974                log::error!(
10975                    "No entry in selection_history found for undo. \
10976                     This may correspond to a bug where undo does not update the selection. \
10977                     If this is occurring, please add details to \
10978                     https://github.com/zed-industries/zed/issues/22692"
10979                );
10980            }
10981            self.request_autoscroll(Autoscroll::fit(), cx);
10982            self.unmark_text(window, cx);
10983            self.refresh_inline_completion(true, false, window, cx);
10984            cx.emit(EditorEvent::Edited { transaction_id });
10985            cx.emit(EditorEvent::TransactionUndone { transaction_id });
10986        }
10987    }
10988
10989    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
10990        if self.read_only(cx) {
10991            return;
10992        }
10993
10994        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10995
10996        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
10997            if let Some((_, Some(selections))) =
10998                self.selection_history.transaction(transaction_id).cloned()
10999            {
11000                self.change_selections(None, window, cx, |s| {
11001                    s.select_anchors(selections.to_vec());
11002                });
11003            } else {
11004                log::error!(
11005                    "No entry in selection_history found for redo. \
11006                     This may correspond to a bug where undo does not update the selection. \
11007                     If this is occurring, please add details to \
11008                     https://github.com/zed-industries/zed/issues/22692"
11009                );
11010            }
11011            self.request_autoscroll(Autoscroll::fit(), cx);
11012            self.unmark_text(window, cx);
11013            self.refresh_inline_completion(true, false, window, cx);
11014            cx.emit(EditorEvent::Edited { transaction_id });
11015        }
11016    }
11017
11018    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11019        self.buffer
11020            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11021    }
11022
11023    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11024        self.buffer
11025            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11026    }
11027
11028    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11029        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11030        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11031            s.move_with(|map, selection| {
11032                let cursor = if selection.is_empty() {
11033                    movement::left(map, selection.start)
11034                } else {
11035                    selection.start
11036                };
11037                selection.collapse_to(cursor, SelectionGoal::None);
11038            });
11039        })
11040    }
11041
11042    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11043        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11044        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11045            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11046        })
11047    }
11048
11049    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11050        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11051        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11052            s.move_with(|map, selection| {
11053                let cursor = if selection.is_empty() {
11054                    movement::right(map, selection.end)
11055                } else {
11056                    selection.end
11057                };
11058                selection.collapse_to(cursor, SelectionGoal::None)
11059            });
11060        })
11061    }
11062
11063    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11064        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11065        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11066            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11067        })
11068    }
11069
11070    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11071        if self.take_rename(true, window, cx).is_some() {
11072            return;
11073        }
11074
11075        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11076            cx.propagate();
11077            return;
11078        }
11079
11080        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11081
11082        let text_layout_details = &self.text_layout_details(window);
11083        let selection_count = self.selections.count();
11084        let first_selection = self.selections.first_anchor();
11085
11086        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11087            s.move_with(|map, selection| {
11088                if !selection.is_empty() {
11089                    selection.goal = SelectionGoal::None;
11090                }
11091                let (cursor, goal) = movement::up(
11092                    map,
11093                    selection.start,
11094                    selection.goal,
11095                    false,
11096                    text_layout_details,
11097                );
11098                selection.collapse_to(cursor, goal);
11099            });
11100        });
11101
11102        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11103        {
11104            cx.propagate();
11105        }
11106    }
11107
11108    pub fn move_up_by_lines(
11109        &mut self,
11110        action: &MoveUpByLines,
11111        window: &mut Window,
11112        cx: &mut Context<Self>,
11113    ) {
11114        if self.take_rename(true, window, cx).is_some() {
11115            return;
11116        }
11117
11118        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11119            cx.propagate();
11120            return;
11121        }
11122
11123        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11124
11125        let text_layout_details = &self.text_layout_details(window);
11126
11127        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11128            s.move_with(|map, selection| {
11129                if !selection.is_empty() {
11130                    selection.goal = SelectionGoal::None;
11131                }
11132                let (cursor, goal) = movement::up_by_rows(
11133                    map,
11134                    selection.start,
11135                    action.lines,
11136                    selection.goal,
11137                    false,
11138                    text_layout_details,
11139                );
11140                selection.collapse_to(cursor, goal);
11141            });
11142        })
11143    }
11144
11145    pub fn move_down_by_lines(
11146        &mut self,
11147        action: &MoveDownByLines,
11148        window: &mut Window,
11149        cx: &mut Context<Self>,
11150    ) {
11151        if self.take_rename(true, window, cx).is_some() {
11152            return;
11153        }
11154
11155        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11156            cx.propagate();
11157            return;
11158        }
11159
11160        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11161
11162        let text_layout_details = &self.text_layout_details(window);
11163
11164        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11165            s.move_with(|map, selection| {
11166                if !selection.is_empty() {
11167                    selection.goal = SelectionGoal::None;
11168                }
11169                let (cursor, goal) = movement::down_by_rows(
11170                    map,
11171                    selection.start,
11172                    action.lines,
11173                    selection.goal,
11174                    false,
11175                    text_layout_details,
11176                );
11177                selection.collapse_to(cursor, goal);
11178            });
11179        })
11180    }
11181
11182    pub fn select_down_by_lines(
11183        &mut self,
11184        action: &SelectDownByLines,
11185        window: &mut Window,
11186        cx: &mut Context<Self>,
11187    ) {
11188        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11189        let text_layout_details = &self.text_layout_details(window);
11190        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11191            s.move_heads_with(|map, head, goal| {
11192                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11193            })
11194        })
11195    }
11196
11197    pub fn select_up_by_lines(
11198        &mut self,
11199        action: &SelectUpByLines,
11200        window: &mut Window,
11201        cx: &mut Context<Self>,
11202    ) {
11203        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11204        let text_layout_details = &self.text_layout_details(window);
11205        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11206            s.move_heads_with(|map, head, goal| {
11207                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11208            })
11209        })
11210    }
11211
11212    pub fn select_page_up(
11213        &mut self,
11214        _: &SelectPageUp,
11215        window: &mut Window,
11216        cx: &mut Context<Self>,
11217    ) {
11218        let Some(row_count) = self.visible_row_count() else {
11219            return;
11220        };
11221
11222        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11223
11224        let text_layout_details = &self.text_layout_details(window);
11225
11226        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11227            s.move_heads_with(|map, head, goal| {
11228                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11229            })
11230        })
11231    }
11232
11233    pub fn move_page_up(
11234        &mut self,
11235        action: &MovePageUp,
11236        window: &mut Window,
11237        cx: &mut Context<Self>,
11238    ) {
11239        if self.take_rename(true, window, cx).is_some() {
11240            return;
11241        }
11242
11243        if self
11244            .context_menu
11245            .borrow_mut()
11246            .as_mut()
11247            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11248            .unwrap_or(false)
11249        {
11250            return;
11251        }
11252
11253        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11254            cx.propagate();
11255            return;
11256        }
11257
11258        let Some(row_count) = self.visible_row_count() else {
11259            return;
11260        };
11261
11262        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11263
11264        let autoscroll = if action.center_cursor {
11265            Autoscroll::center()
11266        } else {
11267            Autoscroll::fit()
11268        };
11269
11270        let text_layout_details = &self.text_layout_details(window);
11271
11272        self.change_selections(Some(autoscroll), window, cx, |s| {
11273            s.move_with(|map, selection| {
11274                if !selection.is_empty() {
11275                    selection.goal = SelectionGoal::None;
11276                }
11277                let (cursor, goal) = movement::up_by_rows(
11278                    map,
11279                    selection.end,
11280                    row_count,
11281                    selection.goal,
11282                    false,
11283                    text_layout_details,
11284                );
11285                selection.collapse_to(cursor, goal);
11286            });
11287        });
11288    }
11289
11290    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11291        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11292        let text_layout_details = &self.text_layout_details(window);
11293        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11294            s.move_heads_with(|map, head, goal| {
11295                movement::up(map, head, goal, false, text_layout_details)
11296            })
11297        })
11298    }
11299
11300    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11301        self.take_rename(true, window, cx);
11302
11303        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11304            cx.propagate();
11305            return;
11306        }
11307
11308        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11309
11310        let text_layout_details = &self.text_layout_details(window);
11311        let selection_count = self.selections.count();
11312        let first_selection = self.selections.first_anchor();
11313
11314        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11315            s.move_with(|map, selection| {
11316                if !selection.is_empty() {
11317                    selection.goal = SelectionGoal::None;
11318                }
11319                let (cursor, goal) = movement::down(
11320                    map,
11321                    selection.end,
11322                    selection.goal,
11323                    false,
11324                    text_layout_details,
11325                );
11326                selection.collapse_to(cursor, goal);
11327            });
11328        });
11329
11330        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11331        {
11332            cx.propagate();
11333        }
11334    }
11335
11336    pub fn select_page_down(
11337        &mut self,
11338        _: &SelectPageDown,
11339        window: &mut Window,
11340        cx: &mut Context<Self>,
11341    ) {
11342        let Some(row_count) = self.visible_row_count() else {
11343            return;
11344        };
11345
11346        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11347
11348        let text_layout_details = &self.text_layout_details(window);
11349
11350        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11351            s.move_heads_with(|map, head, goal| {
11352                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11353            })
11354        })
11355    }
11356
11357    pub fn move_page_down(
11358        &mut self,
11359        action: &MovePageDown,
11360        window: &mut Window,
11361        cx: &mut Context<Self>,
11362    ) {
11363        if self.take_rename(true, window, cx).is_some() {
11364            return;
11365        }
11366
11367        if self
11368            .context_menu
11369            .borrow_mut()
11370            .as_mut()
11371            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11372            .unwrap_or(false)
11373        {
11374            return;
11375        }
11376
11377        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11378            cx.propagate();
11379            return;
11380        }
11381
11382        let Some(row_count) = self.visible_row_count() else {
11383            return;
11384        };
11385
11386        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11387
11388        let autoscroll = if action.center_cursor {
11389            Autoscroll::center()
11390        } else {
11391            Autoscroll::fit()
11392        };
11393
11394        let text_layout_details = &self.text_layout_details(window);
11395        self.change_selections(Some(autoscroll), window, cx, |s| {
11396            s.move_with(|map, selection| {
11397                if !selection.is_empty() {
11398                    selection.goal = SelectionGoal::None;
11399                }
11400                let (cursor, goal) = movement::down_by_rows(
11401                    map,
11402                    selection.end,
11403                    row_count,
11404                    selection.goal,
11405                    false,
11406                    text_layout_details,
11407                );
11408                selection.collapse_to(cursor, goal);
11409            });
11410        });
11411    }
11412
11413    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11414        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11415        let text_layout_details = &self.text_layout_details(window);
11416        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11417            s.move_heads_with(|map, head, goal| {
11418                movement::down(map, head, goal, false, text_layout_details)
11419            })
11420        });
11421    }
11422
11423    pub fn context_menu_first(
11424        &mut self,
11425        _: &ContextMenuFirst,
11426        _window: &mut Window,
11427        cx: &mut Context<Self>,
11428    ) {
11429        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11430            context_menu.select_first(self.completion_provider.as_deref(), cx);
11431        }
11432    }
11433
11434    pub fn context_menu_prev(
11435        &mut self,
11436        _: &ContextMenuPrevious,
11437        _window: &mut Window,
11438        cx: &mut Context<Self>,
11439    ) {
11440        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11441            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11442        }
11443    }
11444
11445    pub fn context_menu_next(
11446        &mut self,
11447        _: &ContextMenuNext,
11448        _window: &mut Window,
11449        cx: &mut Context<Self>,
11450    ) {
11451        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11452            context_menu.select_next(self.completion_provider.as_deref(), cx);
11453        }
11454    }
11455
11456    pub fn context_menu_last(
11457        &mut self,
11458        _: &ContextMenuLast,
11459        _window: &mut Window,
11460        cx: &mut Context<Self>,
11461    ) {
11462        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11463            context_menu.select_last(self.completion_provider.as_deref(), cx);
11464        }
11465    }
11466
11467    pub fn move_to_previous_word_start(
11468        &mut self,
11469        _: &MoveToPreviousWordStart,
11470        window: &mut Window,
11471        cx: &mut Context<Self>,
11472    ) {
11473        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11474        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11475            s.move_cursors_with(|map, head, _| {
11476                (
11477                    movement::previous_word_start(map, head),
11478                    SelectionGoal::None,
11479                )
11480            });
11481        })
11482    }
11483
11484    pub fn move_to_previous_subword_start(
11485        &mut self,
11486        _: &MoveToPreviousSubwordStart,
11487        window: &mut Window,
11488        cx: &mut Context<Self>,
11489    ) {
11490        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11491        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11492            s.move_cursors_with(|map, head, _| {
11493                (
11494                    movement::previous_subword_start(map, head),
11495                    SelectionGoal::None,
11496                )
11497            });
11498        })
11499    }
11500
11501    pub fn select_to_previous_word_start(
11502        &mut self,
11503        _: &SelectToPreviousWordStart,
11504        window: &mut Window,
11505        cx: &mut Context<Self>,
11506    ) {
11507        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11508        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11509            s.move_heads_with(|map, head, _| {
11510                (
11511                    movement::previous_word_start(map, head),
11512                    SelectionGoal::None,
11513                )
11514            });
11515        })
11516    }
11517
11518    pub fn select_to_previous_subword_start(
11519        &mut self,
11520        _: &SelectToPreviousSubwordStart,
11521        window: &mut Window,
11522        cx: &mut Context<Self>,
11523    ) {
11524        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11525        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11526            s.move_heads_with(|map, head, _| {
11527                (
11528                    movement::previous_subword_start(map, head),
11529                    SelectionGoal::None,
11530                )
11531            });
11532        })
11533    }
11534
11535    pub fn delete_to_previous_word_start(
11536        &mut self,
11537        action: &DeleteToPreviousWordStart,
11538        window: &mut Window,
11539        cx: &mut Context<Self>,
11540    ) {
11541        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11542        self.transact(window, cx, |this, window, cx| {
11543            this.select_autoclose_pair(window, cx);
11544            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11545                s.move_with(|map, selection| {
11546                    if selection.is_empty() {
11547                        let cursor = if action.ignore_newlines {
11548                            movement::previous_word_start(map, selection.head())
11549                        } else {
11550                            movement::previous_word_start_or_newline(map, selection.head())
11551                        };
11552                        selection.set_head(cursor, SelectionGoal::None);
11553                    }
11554                });
11555            });
11556            this.insert("", window, cx);
11557        });
11558    }
11559
11560    pub fn delete_to_previous_subword_start(
11561        &mut self,
11562        _: &DeleteToPreviousSubwordStart,
11563        window: &mut Window,
11564        cx: &mut Context<Self>,
11565    ) {
11566        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11567        self.transact(window, cx, |this, window, cx| {
11568            this.select_autoclose_pair(window, cx);
11569            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11570                s.move_with(|map, selection| {
11571                    if selection.is_empty() {
11572                        let cursor = movement::previous_subword_start(map, selection.head());
11573                        selection.set_head(cursor, SelectionGoal::None);
11574                    }
11575                });
11576            });
11577            this.insert("", window, cx);
11578        });
11579    }
11580
11581    pub fn move_to_next_word_end(
11582        &mut self,
11583        _: &MoveToNextWordEnd,
11584        window: &mut Window,
11585        cx: &mut Context<Self>,
11586    ) {
11587        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11588        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11589            s.move_cursors_with(|map, head, _| {
11590                (movement::next_word_end(map, head), SelectionGoal::None)
11591            });
11592        })
11593    }
11594
11595    pub fn move_to_next_subword_end(
11596        &mut self,
11597        _: &MoveToNextSubwordEnd,
11598        window: &mut Window,
11599        cx: &mut Context<Self>,
11600    ) {
11601        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11602        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11603            s.move_cursors_with(|map, head, _| {
11604                (movement::next_subword_end(map, head), SelectionGoal::None)
11605            });
11606        })
11607    }
11608
11609    pub fn select_to_next_word_end(
11610        &mut self,
11611        _: &SelectToNextWordEnd,
11612        window: &mut Window,
11613        cx: &mut Context<Self>,
11614    ) {
11615        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11616        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11617            s.move_heads_with(|map, head, _| {
11618                (movement::next_word_end(map, head), SelectionGoal::None)
11619            });
11620        })
11621    }
11622
11623    pub fn select_to_next_subword_end(
11624        &mut self,
11625        _: &SelectToNextSubwordEnd,
11626        window: &mut Window,
11627        cx: &mut Context<Self>,
11628    ) {
11629        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11630        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11631            s.move_heads_with(|map, head, _| {
11632                (movement::next_subword_end(map, head), SelectionGoal::None)
11633            });
11634        })
11635    }
11636
11637    pub fn delete_to_next_word_end(
11638        &mut self,
11639        action: &DeleteToNextWordEnd,
11640        window: &mut Window,
11641        cx: &mut Context<Self>,
11642    ) {
11643        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11644        self.transact(window, cx, |this, window, cx| {
11645            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11646                s.move_with(|map, selection| {
11647                    if selection.is_empty() {
11648                        let cursor = if action.ignore_newlines {
11649                            movement::next_word_end(map, selection.head())
11650                        } else {
11651                            movement::next_word_end_or_newline(map, selection.head())
11652                        };
11653                        selection.set_head(cursor, SelectionGoal::None);
11654                    }
11655                });
11656            });
11657            this.insert("", window, cx);
11658        });
11659    }
11660
11661    pub fn delete_to_next_subword_end(
11662        &mut self,
11663        _: &DeleteToNextSubwordEnd,
11664        window: &mut Window,
11665        cx: &mut Context<Self>,
11666    ) {
11667        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11668        self.transact(window, cx, |this, window, cx| {
11669            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11670                s.move_with(|map, selection| {
11671                    if selection.is_empty() {
11672                        let cursor = movement::next_subword_end(map, selection.head());
11673                        selection.set_head(cursor, SelectionGoal::None);
11674                    }
11675                });
11676            });
11677            this.insert("", window, cx);
11678        });
11679    }
11680
11681    pub fn move_to_beginning_of_line(
11682        &mut self,
11683        action: &MoveToBeginningOfLine,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11688        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11689            s.move_cursors_with(|map, head, _| {
11690                (
11691                    movement::indented_line_beginning(
11692                        map,
11693                        head,
11694                        action.stop_at_soft_wraps,
11695                        action.stop_at_indent,
11696                    ),
11697                    SelectionGoal::None,
11698                )
11699            });
11700        })
11701    }
11702
11703    pub fn select_to_beginning_of_line(
11704        &mut self,
11705        action: &SelectToBeginningOfLine,
11706        window: &mut Window,
11707        cx: &mut Context<Self>,
11708    ) {
11709        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11710        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11711            s.move_heads_with(|map, head, _| {
11712                (
11713                    movement::indented_line_beginning(
11714                        map,
11715                        head,
11716                        action.stop_at_soft_wraps,
11717                        action.stop_at_indent,
11718                    ),
11719                    SelectionGoal::None,
11720                )
11721            });
11722        });
11723    }
11724
11725    pub fn delete_to_beginning_of_line(
11726        &mut self,
11727        action: &DeleteToBeginningOfLine,
11728        window: &mut Window,
11729        cx: &mut Context<Self>,
11730    ) {
11731        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11732        self.transact(window, cx, |this, window, cx| {
11733            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11734                s.move_with(|_, selection| {
11735                    selection.reversed = true;
11736                });
11737            });
11738
11739            this.select_to_beginning_of_line(
11740                &SelectToBeginningOfLine {
11741                    stop_at_soft_wraps: false,
11742                    stop_at_indent: action.stop_at_indent,
11743                },
11744                window,
11745                cx,
11746            );
11747            this.backspace(&Backspace, window, cx);
11748        });
11749    }
11750
11751    pub fn move_to_end_of_line(
11752        &mut self,
11753        action: &MoveToEndOfLine,
11754        window: &mut Window,
11755        cx: &mut Context<Self>,
11756    ) {
11757        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11758        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11759            s.move_cursors_with(|map, head, _| {
11760                (
11761                    movement::line_end(map, head, action.stop_at_soft_wraps),
11762                    SelectionGoal::None,
11763                )
11764            });
11765        })
11766    }
11767
11768    pub fn select_to_end_of_line(
11769        &mut self,
11770        action: &SelectToEndOfLine,
11771        window: &mut Window,
11772        cx: &mut Context<Self>,
11773    ) {
11774        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11775        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11776            s.move_heads_with(|map, head, _| {
11777                (
11778                    movement::line_end(map, head, action.stop_at_soft_wraps),
11779                    SelectionGoal::None,
11780                )
11781            });
11782        })
11783    }
11784
11785    pub fn delete_to_end_of_line(
11786        &mut self,
11787        _: &DeleteToEndOfLine,
11788        window: &mut Window,
11789        cx: &mut Context<Self>,
11790    ) {
11791        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11792        self.transact(window, cx, |this, window, cx| {
11793            this.select_to_end_of_line(
11794                &SelectToEndOfLine {
11795                    stop_at_soft_wraps: false,
11796                },
11797                window,
11798                cx,
11799            );
11800            this.delete(&Delete, window, cx);
11801        });
11802    }
11803
11804    pub fn cut_to_end_of_line(
11805        &mut self,
11806        _: &CutToEndOfLine,
11807        window: &mut Window,
11808        cx: &mut Context<Self>,
11809    ) {
11810        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11811        self.transact(window, cx, |this, window, cx| {
11812            this.select_to_end_of_line(
11813                &SelectToEndOfLine {
11814                    stop_at_soft_wraps: false,
11815                },
11816                window,
11817                cx,
11818            );
11819            this.cut(&Cut, window, cx);
11820        });
11821    }
11822
11823    pub fn move_to_start_of_paragraph(
11824        &mut self,
11825        _: &MoveToStartOfParagraph,
11826        window: &mut Window,
11827        cx: &mut Context<Self>,
11828    ) {
11829        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11830            cx.propagate();
11831            return;
11832        }
11833        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11834        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11835            s.move_with(|map, selection| {
11836                selection.collapse_to(
11837                    movement::start_of_paragraph(map, selection.head(), 1),
11838                    SelectionGoal::None,
11839                )
11840            });
11841        })
11842    }
11843
11844    pub fn move_to_end_of_paragraph(
11845        &mut self,
11846        _: &MoveToEndOfParagraph,
11847        window: &mut Window,
11848        cx: &mut Context<Self>,
11849    ) {
11850        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11851            cx.propagate();
11852            return;
11853        }
11854        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11855        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11856            s.move_with(|map, selection| {
11857                selection.collapse_to(
11858                    movement::end_of_paragraph(map, selection.head(), 1),
11859                    SelectionGoal::None,
11860                )
11861            });
11862        })
11863    }
11864
11865    pub fn select_to_start_of_paragraph(
11866        &mut self,
11867        _: &SelectToStartOfParagraph,
11868        window: &mut Window,
11869        cx: &mut Context<Self>,
11870    ) {
11871        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11872            cx.propagate();
11873            return;
11874        }
11875        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11876        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11877            s.move_heads_with(|map, head, _| {
11878                (
11879                    movement::start_of_paragraph(map, head, 1),
11880                    SelectionGoal::None,
11881                )
11882            });
11883        })
11884    }
11885
11886    pub fn select_to_end_of_paragraph(
11887        &mut self,
11888        _: &SelectToEndOfParagraph,
11889        window: &mut Window,
11890        cx: &mut Context<Self>,
11891    ) {
11892        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11893            cx.propagate();
11894            return;
11895        }
11896        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11897        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11898            s.move_heads_with(|map, head, _| {
11899                (
11900                    movement::end_of_paragraph(map, head, 1),
11901                    SelectionGoal::None,
11902                )
11903            });
11904        })
11905    }
11906
11907    pub fn move_to_start_of_excerpt(
11908        &mut self,
11909        _: &MoveToStartOfExcerpt,
11910        window: &mut Window,
11911        cx: &mut Context<Self>,
11912    ) {
11913        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11914            cx.propagate();
11915            return;
11916        }
11917        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11918        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11919            s.move_with(|map, selection| {
11920                selection.collapse_to(
11921                    movement::start_of_excerpt(
11922                        map,
11923                        selection.head(),
11924                        workspace::searchable::Direction::Prev,
11925                    ),
11926                    SelectionGoal::None,
11927                )
11928            });
11929        })
11930    }
11931
11932    pub fn move_to_start_of_next_excerpt(
11933        &mut self,
11934        _: &MoveToStartOfNextExcerpt,
11935        window: &mut Window,
11936        cx: &mut Context<Self>,
11937    ) {
11938        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11939            cx.propagate();
11940            return;
11941        }
11942
11943        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11944            s.move_with(|map, selection| {
11945                selection.collapse_to(
11946                    movement::start_of_excerpt(
11947                        map,
11948                        selection.head(),
11949                        workspace::searchable::Direction::Next,
11950                    ),
11951                    SelectionGoal::None,
11952                )
11953            });
11954        })
11955    }
11956
11957    pub fn move_to_end_of_excerpt(
11958        &mut self,
11959        _: &MoveToEndOfExcerpt,
11960        window: &mut Window,
11961        cx: &mut Context<Self>,
11962    ) {
11963        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11964            cx.propagate();
11965            return;
11966        }
11967        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11968        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11969            s.move_with(|map, selection| {
11970                selection.collapse_to(
11971                    movement::end_of_excerpt(
11972                        map,
11973                        selection.head(),
11974                        workspace::searchable::Direction::Next,
11975                    ),
11976                    SelectionGoal::None,
11977                )
11978            });
11979        })
11980    }
11981
11982    pub fn move_to_end_of_previous_excerpt(
11983        &mut self,
11984        _: &MoveToEndOfPreviousExcerpt,
11985        window: &mut Window,
11986        cx: &mut Context<Self>,
11987    ) {
11988        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11989            cx.propagate();
11990            return;
11991        }
11992        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11993        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11994            s.move_with(|map, selection| {
11995                selection.collapse_to(
11996                    movement::end_of_excerpt(
11997                        map,
11998                        selection.head(),
11999                        workspace::searchable::Direction::Prev,
12000                    ),
12001                    SelectionGoal::None,
12002                )
12003            });
12004        })
12005    }
12006
12007    pub fn select_to_start_of_excerpt(
12008        &mut self,
12009        _: &SelectToStartOfExcerpt,
12010        window: &mut Window,
12011        cx: &mut Context<Self>,
12012    ) {
12013        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12014            cx.propagate();
12015            return;
12016        }
12017        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12018        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12019            s.move_heads_with(|map, head, _| {
12020                (
12021                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12022                    SelectionGoal::None,
12023                )
12024            });
12025        })
12026    }
12027
12028    pub fn select_to_start_of_next_excerpt(
12029        &mut self,
12030        _: &SelectToStartOfNextExcerpt,
12031        window: &mut Window,
12032        cx: &mut Context<Self>,
12033    ) {
12034        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12035            cx.propagate();
12036            return;
12037        }
12038        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12039        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12040            s.move_heads_with(|map, head, _| {
12041                (
12042                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12043                    SelectionGoal::None,
12044                )
12045            });
12046        })
12047    }
12048
12049    pub fn select_to_end_of_excerpt(
12050        &mut self,
12051        _: &SelectToEndOfExcerpt,
12052        window: &mut Window,
12053        cx: &mut Context<Self>,
12054    ) {
12055        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12056            cx.propagate();
12057            return;
12058        }
12059        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12060        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12061            s.move_heads_with(|map, head, _| {
12062                (
12063                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12064                    SelectionGoal::None,
12065                )
12066            });
12067        })
12068    }
12069
12070    pub fn select_to_end_of_previous_excerpt(
12071        &mut self,
12072        _: &SelectToEndOfPreviousExcerpt,
12073        window: &mut Window,
12074        cx: &mut Context<Self>,
12075    ) {
12076        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12077            cx.propagate();
12078            return;
12079        }
12080        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12081        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12082            s.move_heads_with(|map, head, _| {
12083                (
12084                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12085                    SelectionGoal::None,
12086                )
12087            });
12088        })
12089    }
12090
12091    pub fn move_to_beginning(
12092        &mut self,
12093        _: &MoveToBeginning,
12094        window: &mut Window,
12095        cx: &mut Context<Self>,
12096    ) {
12097        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12098            cx.propagate();
12099            return;
12100        }
12101        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12102        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12103            s.select_ranges(vec![0..0]);
12104        });
12105    }
12106
12107    pub fn select_to_beginning(
12108        &mut self,
12109        _: &SelectToBeginning,
12110        window: &mut Window,
12111        cx: &mut Context<Self>,
12112    ) {
12113        let mut selection = self.selections.last::<Point>(cx);
12114        selection.set_head(Point::zero(), SelectionGoal::None);
12115        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12116        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12117            s.select(vec![selection]);
12118        });
12119    }
12120
12121    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12122        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12123            cx.propagate();
12124            return;
12125        }
12126        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12127        let cursor = self.buffer.read(cx).read(cx).len();
12128        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12129            s.select_ranges(vec![cursor..cursor])
12130        });
12131    }
12132
12133    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12134        self.nav_history = nav_history;
12135    }
12136
12137    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12138        self.nav_history.as_ref()
12139    }
12140
12141    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12142        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12143    }
12144
12145    fn push_to_nav_history(
12146        &mut self,
12147        cursor_anchor: Anchor,
12148        new_position: Option<Point>,
12149        is_deactivate: bool,
12150        cx: &mut Context<Self>,
12151    ) {
12152        if let Some(nav_history) = self.nav_history.as_mut() {
12153            let buffer = self.buffer.read(cx).read(cx);
12154            let cursor_position = cursor_anchor.to_point(&buffer);
12155            let scroll_state = self.scroll_manager.anchor();
12156            let scroll_top_row = scroll_state.top_row(&buffer);
12157            drop(buffer);
12158
12159            if let Some(new_position) = new_position {
12160                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12161                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12162                    return;
12163                }
12164            }
12165
12166            nav_history.push(
12167                Some(NavigationData {
12168                    cursor_anchor,
12169                    cursor_position,
12170                    scroll_anchor: scroll_state,
12171                    scroll_top_row,
12172                }),
12173                cx,
12174            );
12175            cx.emit(EditorEvent::PushedToNavHistory {
12176                anchor: cursor_anchor,
12177                is_deactivate,
12178            })
12179        }
12180    }
12181
12182    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12183        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12184        let buffer = self.buffer.read(cx).snapshot(cx);
12185        let mut selection = self.selections.first::<usize>(cx);
12186        selection.set_head(buffer.len(), SelectionGoal::None);
12187        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12188            s.select(vec![selection]);
12189        });
12190    }
12191
12192    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12193        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12194        let end = self.buffer.read(cx).read(cx).len();
12195        self.change_selections(None, window, cx, |s| {
12196            s.select_ranges(vec![0..end]);
12197        });
12198    }
12199
12200    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12201        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12202        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12203        let mut selections = self.selections.all::<Point>(cx);
12204        let max_point = display_map.buffer_snapshot.max_point();
12205        for selection in &mut selections {
12206            let rows = selection.spanned_rows(true, &display_map);
12207            selection.start = Point::new(rows.start.0, 0);
12208            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12209            selection.reversed = false;
12210        }
12211        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12212            s.select(selections);
12213        });
12214    }
12215
12216    pub fn split_selection_into_lines(
12217        &mut self,
12218        _: &SplitSelectionIntoLines,
12219        window: &mut Window,
12220        cx: &mut Context<Self>,
12221    ) {
12222        let selections = self
12223            .selections
12224            .all::<Point>(cx)
12225            .into_iter()
12226            .map(|selection| selection.start..selection.end)
12227            .collect::<Vec<_>>();
12228        self.unfold_ranges(&selections, true, true, cx);
12229
12230        let mut new_selection_ranges = Vec::new();
12231        {
12232            let buffer = self.buffer.read(cx).read(cx);
12233            for selection in selections {
12234                for row in selection.start.row..selection.end.row {
12235                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12236                    new_selection_ranges.push(cursor..cursor);
12237                }
12238
12239                let is_multiline_selection = selection.start.row != selection.end.row;
12240                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12241                // so this action feels more ergonomic when paired with other selection operations
12242                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12243                if !should_skip_last {
12244                    new_selection_ranges.push(selection.end..selection.end);
12245                }
12246            }
12247        }
12248        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12249            s.select_ranges(new_selection_ranges);
12250        });
12251    }
12252
12253    pub fn add_selection_above(
12254        &mut self,
12255        _: &AddSelectionAbove,
12256        window: &mut Window,
12257        cx: &mut Context<Self>,
12258    ) {
12259        self.add_selection(true, window, cx);
12260    }
12261
12262    pub fn add_selection_below(
12263        &mut self,
12264        _: &AddSelectionBelow,
12265        window: &mut Window,
12266        cx: &mut Context<Self>,
12267    ) {
12268        self.add_selection(false, window, cx);
12269    }
12270
12271    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12272        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12273
12274        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12275        let mut selections = self.selections.all::<Point>(cx);
12276        let text_layout_details = self.text_layout_details(window);
12277        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12278            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12279            let range = oldest_selection.display_range(&display_map).sorted();
12280
12281            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12282            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12283            let positions = start_x.min(end_x)..start_x.max(end_x);
12284
12285            selections.clear();
12286            let mut stack = Vec::new();
12287            for row in range.start.row().0..=range.end.row().0 {
12288                if let Some(selection) = self.selections.build_columnar_selection(
12289                    &display_map,
12290                    DisplayRow(row),
12291                    &positions,
12292                    oldest_selection.reversed,
12293                    &text_layout_details,
12294                ) {
12295                    stack.push(selection.id);
12296                    selections.push(selection);
12297                }
12298            }
12299
12300            if above {
12301                stack.reverse();
12302            }
12303
12304            AddSelectionsState { above, stack }
12305        });
12306
12307        let last_added_selection = *state.stack.last().unwrap();
12308        let mut new_selections = Vec::new();
12309        if above == state.above {
12310            let end_row = if above {
12311                DisplayRow(0)
12312            } else {
12313                display_map.max_point().row()
12314            };
12315
12316            'outer: for selection in selections {
12317                if selection.id == last_added_selection {
12318                    let range = selection.display_range(&display_map).sorted();
12319                    debug_assert_eq!(range.start.row(), range.end.row());
12320                    let mut row = range.start.row();
12321                    let positions =
12322                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12323                            px(start)..px(end)
12324                        } else {
12325                            let start_x =
12326                                display_map.x_for_display_point(range.start, &text_layout_details);
12327                            let end_x =
12328                                display_map.x_for_display_point(range.end, &text_layout_details);
12329                            start_x.min(end_x)..start_x.max(end_x)
12330                        };
12331
12332                    while row != end_row {
12333                        if above {
12334                            row.0 -= 1;
12335                        } else {
12336                            row.0 += 1;
12337                        }
12338
12339                        if let Some(new_selection) = self.selections.build_columnar_selection(
12340                            &display_map,
12341                            row,
12342                            &positions,
12343                            selection.reversed,
12344                            &text_layout_details,
12345                        ) {
12346                            state.stack.push(new_selection.id);
12347                            if above {
12348                                new_selections.push(new_selection);
12349                                new_selections.push(selection);
12350                            } else {
12351                                new_selections.push(selection);
12352                                new_selections.push(new_selection);
12353                            }
12354
12355                            continue 'outer;
12356                        }
12357                    }
12358                }
12359
12360                new_selections.push(selection);
12361            }
12362        } else {
12363            new_selections = selections;
12364            new_selections.retain(|s| s.id != last_added_selection);
12365            state.stack.pop();
12366        }
12367
12368        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12369            s.select(new_selections);
12370        });
12371        if state.stack.len() > 1 {
12372            self.add_selections_state = Some(state);
12373        }
12374    }
12375
12376    fn select_match_ranges(
12377        &mut self,
12378        range: Range<usize>,
12379        reversed: bool,
12380        replace_newest: bool,
12381        auto_scroll: Option<Autoscroll>,
12382        window: &mut Window,
12383        cx: &mut Context<Editor>,
12384    ) {
12385        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12386        self.change_selections(auto_scroll, window, cx, |s| {
12387            if replace_newest {
12388                s.delete(s.newest_anchor().id);
12389            }
12390            if reversed {
12391                s.insert_range(range.end..range.start);
12392            } else {
12393                s.insert_range(range);
12394            }
12395        });
12396    }
12397
12398    pub fn select_next_match_internal(
12399        &mut self,
12400        display_map: &DisplaySnapshot,
12401        replace_newest: bool,
12402        autoscroll: Option<Autoscroll>,
12403        window: &mut Window,
12404        cx: &mut Context<Self>,
12405    ) -> Result<()> {
12406        let buffer = &display_map.buffer_snapshot;
12407        let mut selections = self.selections.all::<usize>(cx);
12408        if let Some(mut select_next_state) = self.select_next_state.take() {
12409            let query = &select_next_state.query;
12410            if !select_next_state.done {
12411                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12412                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12413                let mut next_selected_range = None;
12414
12415                let bytes_after_last_selection =
12416                    buffer.bytes_in_range(last_selection.end..buffer.len());
12417                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12418                let query_matches = query
12419                    .stream_find_iter(bytes_after_last_selection)
12420                    .map(|result| (last_selection.end, result))
12421                    .chain(
12422                        query
12423                            .stream_find_iter(bytes_before_first_selection)
12424                            .map(|result| (0, result)),
12425                    );
12426
12427                for (start_offset, query_match) in query_matches {
12428                    let query_match = query_match.unwrap(); // can only fail due to I/O
12429                    let offset_range =
12430                        start_offset + query_match.start()..start_offset + query_match.end();
12431                    let display_range = offset_range.start.to_display_point(display_map)
12432                        ..offset_range.end.to_display_point(display_map);
12433
12434                    if !select_next_state.wordwise
12435                        || (!movement::is_inside_word(display_map, display_range.start)
12436                            && !movement::is_inside_word(display_map, display_range.end))
12437                    {
12438                        // TODO: This is n^2, because we might check all the selections
12439                        if !selections
12440                            .iter()
12441                            .any(|selection| selection.range().overlaps(&offset_range))
12442                        {
12443                            next_selected_range = Some(offset_range);
12444                            break;
12445                        }
12446                    }
12447                }
12448
12449                if let Some(next_selected_range) = next_selected_range {
12450                    self.select_match_ranges(
12451                        next_selected_range,
12452                        last_selection.reversed,
12453                        replace_newest,
12454                        autoscroll,
12455                        window,
12456                        cx,
12457                    );
12458                } else {
12459                    select_next_state.done = true;
12460                }
12461            }
12462
12463            self.select_next_state = Some(select_next_state);
12464        } else {
12465            let mut only_carets = true;
12466            let mut same_text_selected = true;
12467            let mut selected_text = None;
12468
12469            let mut selections_iter = selections.iter().peekable();
12470            while let Some(selection) = selections_iter.next() {
12471                if selection.start != selection.end {
12472                    only_carets = false;
12473                }
12474
12475                if same_text_selected {
12476                    if selected_text.is_none() {
12477                        selected_text =
12478                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12479                    }
12480
12481                    if let Some(next_selection) = selections_iter.peek() {
12482                        if next_selection.range().len() == selection.range().len() {
12483                            let next_selected_text = buffer
12484                                .text_for_range(next_selection.range())
12485                                .collect::<String>();
12486                            if Some(next_selected_text) != selected_text {
12487                                same_text_selected = false;
12488                                selected_text = None;
12489                            }
12490                        } else {
12491                            same_text_selected = false;
12492                            selected_text = None;
12493                        }
12494                    }
12495                }
12496            }
12497
12498            if only_carets {
12499                for selection in &mut selections {
12500                    let word_range = movement::surrounding_word(
12501                        display_map,
12502                        selection.start.to_display_point(display_map),
12503                    );
12504                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12505                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12506                    selection.goal = SelectionGoal::None;
12507                    selection.reversed = false;
12508                    self.select_match_ranges(
12509                        selection.start..selection.end,
12510                        selection.reversed,
12511                        replace_newest,
12512                        autoscroll,
12513                        window,
12514                        cx,
12515                    );
12516                }
12517
12518                if selections.len() == 1 {
12519                    let selection = selections
12520                        .last()
12521                        .expect("ensured that there's only one selection");
12522                    let query = buffer
12523                        .text_for_range(selection.start..selection.end)
12524                        .collect::<String>();
12525                    let is_empty = query.is_empty();
12526                    let select_state = SelectNextState {
12527                        query: AhoCorasick::new(&[query])?,
12528                        wordwise: true,
12529                        done: is_empty,
12530                    };
12531                    self.select_next_state = Some(select_state);
12532                } else {
12533                    self.select_next_state = None;
12534                }
12535            } else if let Some(selected_text) = selected_text {
12536                self.select_next_state = Some(SelectNextState {
12537                    query: AhoCorasick::new(&[selected_text])?,
12538                    wordwise: false,
12539                    done: false,
12540                });
12541                self.select_next_match_internal(
12542                    display_map,
12543                    replace_newest,
12544                    autoscroll,
12545                    window,
12546                    cx,
12547                )?;
12548            }
12549        }
12550        Ok(())
12551    }
12552
12553    pub fn select_all_matches(
12554        &mut self,
12555        _action: &SelectAllMatches,
12556        window: &mut Window,
12557        cx: &mut Context<Self>,
12558    ) -> Result<()> {
12559        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12560
12561        self.push_to_selection_history();
12562        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12563
12564        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12565        let Some(select_next_state) = self.select_next_state.as_mut() else {
12566            return Ok(());
12567        };
12568        if select_next_state.done {
12569            return Ok(());
12570        }
12571
12572        let mut new_selections = Vec::new();
12573
12574        let reversed = self.selections.oldest::<usize>(cx).reversed;
12575        let buffer = &display_map.buffer_snapshot;
12576        let query_matches = select_next_state
12577            .query
12578            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12579
12580        for query_match in query_matches.into_iter() {
12581            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12582            let offset_range = if reversed {
12583                query_match.end()..query_match.start()
12584            } else {
12585                query_match.start()..query_match.end()
12586            };
12587            let display_range = offset_range.start.to_display_point(&display_map)
12588                ..offset_range.end.to_display_point(&display_map);
12589
12590            if !select_next_state.wordwise
12591                || (!movement::is_inside_word(&display_map, display_range.start)
12592                    && !movement::is_inside_word(&display_map, display_range.end))
12593            {
12594                new_selections.push(offset_range.start..offset_range.end);
12595            }
12596        }
12597
12598        select_next_state.done = true;
12599        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12600        self.change_selections(None, window, cx, |selections| {
12601            selections.select_ranges(new_selections)
12602        });
12603
12604        Ok(())
12605    }
12606
12607    pub fn select_next(
12608        &mut self,
12609        action: &SelectNext,
12610        window: &mut Window,
12611        cx: &mut Context<Self>,
12612    ) -> Result<()> {
12613        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12614        self.push_to_selection_history();
12615        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12616        self.select_next_match_internal(
12617            &display_map,
12618            action.replace_newest,
12619            Some(Autoscroll::newest()),
12620            window,
12621            cx,
12622        )?;
12623        Ok(())
12624    }
12625
12626    pub fn select_previous(
12627        &mut self,
12628        action: &SelectPrevious,
12629        window: &mut Window,
12630        cx: &mut Context<Self>,
12631    ) -> Result<()> {
12632        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12633        self.push_to_selection_history();
12634        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12635        let buffer = &display_map.buffer_snapshot;
12636        let mut selections = self.selections.all::<usize>(cx);
12637        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12638            let query = &select_prev_state.query;
12639            if !select_prev_state.done {
12640                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12641                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12642                let mut next_selected_range = None;
12643                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12644                let bytes_before_last_selection =
12645                    buffer.reversed_bytes_in_range(0..last_selection.start);
12646                let bytes_after_first_selection =
12647                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12648                let query_matches = query
12649                    .stream_find_iter(bytes_before_last_selection)
12650                    .map(|result| (last_selection.start, result))
12651                    .chain(
12652                        query
12653                            .stream_find_iter(bytes_after_first_selection)
12654                            .map(|result| (buffer.len(), result)),
12655                    );
12656                for (end_offset, query_match) in query_matches {
12657                    let query_match = query_match.unwrap(); // can only fail due to I/O
12658                    let offset_range =
12659                        end_offset - query_match.end()..end_offset - query_match.start();
12660                    let display_range = offset_range.start.to_display_point(&display_map)
12661                        ..offset_range.end.to_display_point(&display_map);
12662
12663                    if !select_prev_state.wordwise
12664                        || (!movement::is_inside_word(&display_map, display_range.start)
12665                            && !movement::is_inside_word(&display_map, display_range.end))
12666                    {
12667                        next_selected_range = Some(offset_range);
12668                        break;
12669                    }
12670                }
12671
12672                if let Some(next_selected_range) = next_selected_range {
12673                    self.select_match_ranges(
12674                        next_selected_range,
12675                        last_selection.reversed,
12676                        action.replace_newest,
12677                        Some(Autoscroll::newest()),
12678                        window,
12679                        cx,
12680                    );
12681                } else {
12682                    select_prev_state.done = true;
12683                }
12684            }
12685
12686            self.select_prev_state = Some(select_prev_state);
12687        } else {
12688            let mut only_carets = true;
12689            let mut same_text_selected = true;
12690            let mut selected_text = None;
12691
12692            let mut selections_iter = selections.iter().peekable();
12693            while let Some(selection) = selections_iter.next() {
12694                if selection.start != selection.end {
12695                    only_carets = false;
12696                }
12697
12698                if same_text_selected {
12699                    if selected_text.is_none() {
12700                        selected_text =
12701                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12702                    }
12703
12704                    if let Some(next_selection) = selections_iter.peek() {
12705                        if next_selection.range().len() == selection.range().len() {
12706                            let next_selected_text = buffer
12707                                .text_for_range(next_selection.range())
12708                                .collect::<String>();
12709                            if Some(next_selected_text) != selected_text {
12710                                same_text_selected = false;
12711                                selected_text = None;
12712                            }
12713                        } else {
12714                            same_text_selected = false;
12715                            selected_text = None;
12716                        }
12717                    }
12718                }
12719            }
12720
12721            if only_carets {
12722                for selection in &mut selections {
12723                    let word_range = movement::surrounding_word(
12724                        &display_map,
12725                        selection.start.to_display_point(&display_map),
12726                    );
12727                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12728                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12729                    selection.goal = SelectionGoal::None;
12730                    selection.reversed = false;
12731                    self.select_match_ranges(
12732                        selection.start..selection.end,
12733                        selection.reversed,
12734                        action.replace_newest,
12735                        Some(Autoscroll::newest()),
12736                        window,
12737                        cx,
12738                    );
12739                }
12740                if selections.len() == 1 {
12741                    let selection = selections
12742                        .last()
12743                        .expect("ensured that there's only one selection");
12744                    let query = buffer
12745                        .text_for_range(selection.start..selection.end)
12746                        .collect::<String>();
12747                    let is_empty = query.is_empty();
12748                    let select_state = SelectNextState {
12749                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12750                        wordwise: true,
12751                        done: is_empty,
12752                    };
12753                    self.select_prev_state = Some(select_state);
12754                } else {
12755                    self.select_prev_state = None;
12756                }
12757            } else if let Some(selected_text) = selected_text {
12758                self.select_prev_state = Some(SelectNextState {
12759                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12760                    wordwise: false,
12761                    done: false,
12762                });
12763                self.select_previous(action, window, cx)?;
12764            }
12765        }
12766        Ok(())
12767    }
12768
12769    pub fn find_next_match(
12770        &mut self,
12771        _: &FindNextMatch,
12772        window: &mut Window,
12773        cx: &mut Context<Self>,
12774    ) -> Result<()> {
12775        let selections = self.selections.disjoint_anchors();
12776        match selections.first() {
12777            Some(first) if selections.len() >= 2 => {
12778                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12779                    s.select_ranges([first.range()]);
12780                });
12781            }
12782            _ => self.select_next(
12783                &SelectNext {
12784                    replace_newest: true,
12785                },
12786                window,
12787                cx,
12788            )?,
12789        }
12790        Ok(())
12791    }
12792
12793    pub fn find_previous_match(
12794        &mut self,
12795        _: &FindPreviousMatch,
12796        window: &mut Window,
12797        cx: &mut Context<Self>,
12798    ) -> Result<()> {
12799        let selections = self.selections.disjoint_anchors();
12800        match selections.last() {
12801            Some(last) if selections.len() >= 2 => {
12802                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12803                    s.select_ranges([last.range()]);
12804                });
12805            }
12806            _ => self.select_previous(
12807                &SelectPrevious {
12808                    replace_newest: true,
12809                },
12810                window,
12811                cx,
12812            )?,
12813        }
12814        Ok(())
12815    }
12816
12817    pub fn toggle_comments(
12818        &mut self,
12819        action: &ToggleComments,
12820        window: &mut Window,
12821        cx: &mut Context<Self>,
12822    ) {
12823        if self.read_only(cx) {
12824            return;
12825        }
12826        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12827        let text_layout_details = &self.text_layout_details(window);
12828        self.transact(window, cx, |this, window, cx| {
12829            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12830            let mut edits = Vec::new();
12831            let mut selection_edit_ranges = Vec::new();
12832            let mut last_toggled_row = None;
12833            let snapshot = this.buffer.read(cx).read(cx);
12834            let empty_str: Arc<str> = Arc::default();
12835            let mut suffixes_inserted = Vec::new();
12836            let ignore_indent = action.ignore_indent;
12837
12838            fn comment_prefix_range(
12839                snapshot: &MultiBufferSnapshot,
12840                row: MultiBufferRow,
12841                comment_prefix: &str,
12842                comment_prefix_whitespace: &str,
12843                ignore_indent: bool,
12844            ) -> Range<Point> {
12845                let indent_size = if ignore_indent {
12846                    0
12847                } else {
12848                    snapshot.indent_size_for_line(row).len
12849                };
12850
12851                let start = Point::new(row.0, indent_size);
12852
12853                let mut line_bytes = snapshot
12854                    .bytes_in_range(start..snapshot.max_point())
12855                    .flatten()
12856                    .copied();
12857
12858                // If this line currently begins with the line comment prefix, then record
12859                // the range containing the prefix.
12860                if line_bytes
12861                    .by_ref()
12862                    .take(comment_prefix.len())
12863                    .eq(comment_prefix.bytes())
12864                {
12865                    // Include any whitespace that matches the comment prefix.
12866                    let matching_whitespace_len = line_bytes
12867                        .zip(comment_prefix_whitespace.bytes())
12868                        .take_while(|(a, b)| a == b)
12869                        .count() as u32;
12870                    let end = Point::new(
12871                        start.row,
12872                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12873                    );
12874                    start..end
12875                } else {
12876                    start..start
12877                }
12878            }
12879
12880            fn comment_suffix_range(
12881                snapshot: &MultiBufferSnapshot,
12882                row: MultiBufferRow,
12883                comment_suffix: &str,
12884                comment_suffix_has_leading_space: bool,
12885            ) -> Range<Point> {
12886                let end = Point::new(row.0, snapshot.line_len(row));
12887                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12888
12889                let mut line_end_bytes = snapshot
12890                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12891                    .flatten()
12892                    .copied();
12893
12894                let leading_space_len = if suffix_start_column > 0
12895                    && line_end_bytes.next() == Some(b' ')
12896                    && comment_suffix_has_leading_space
12897                {
12898                    1
12899                } else {
12900                    0
12901                };
12902
12903                // If this line currently begins with the line comment prefix, then record
12904                // the range containing the prefix.
12905                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12906                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12907                    start..end
12908                } else {
12909                    end..end
12910                }
12911            }
12912
12913            // TODO: Handle selections that cross excerpts
12914            for selection in &mut selections {
12915                let start_column = snapshot
12916                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12917                    .len;
12918                let language = if let Some(language) =
12919                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12920                {
12921                    language
12922                } else {
12923                    continue;
12924                };
12925
12926                selection_edit_ranges.clear();
12927
12928                // If multiple selections contain a given row, avoid processing that
12929                // row more than once.
12930                let mut start_row = MultiBufferRow(selection.start.row);
12931                if last_toggled_row == Some(start_row) {
12932                    start_row = start_row.next_row();
12933                }
12934                let end_row =
12935                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12936                        MultiBufferRow(selection.end.row - 1)
12937                    } else {
12938                        MultiBufferRow(selection.end.row)
12939                    };
12940                last_toggled_row = Some(end_row);
12941
12942                if start_row > end_row {
12943                    continue;
12944                }
12945
12946                // If the language has line comments, toggle those.
12947                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12948
12949                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12950                if ignore_indent {
12951                    full_comment_prefixes = full_comment_prefixes
12952                        .into_iter()
12953                        .map(|s| Arc::from(s.trim_end()))
12954                        .collect();
12955                }
12956
12957                if !full_comment_prefixes.is_empty() {
12958                    let first_prefix = full_comment_prefixes
12959                        .first()
12960                        .expect("prefixes is non-empty");
12961                    let prefix_trimmed_lengths = full_comment_prefixes
12962                        .iter()
12963                        .map(|p| p.trim_end_matches(' ').len())
12964                        .collect::<SmallVec<[usize; 4]>>();
12965
12966                    let mut all_selection_lines_are_comments = true;
12967
12968                    for row in start_row.0..=end_row.0 {
12969                        let row = MultiBufferRow(row);
12970                        if start_row < end_row && snapshot.is_line_blank(row) {
12971                            continue;
12972                        }
12973
12974                        let prefix_range = full_comment_prefixes
12975                            .iter()
12976                            .zip(prefix_trimmed_lengths.iter().copied())
12977                            .map(|(prefix, trimmed_prefix_len)| {
12978                                comment_prefix_range(
12979                                    snapshot.deref(),
12980                                    row,
12981                                    &prefix[..trimmed_prefix_len],
12982                                    &prefix[trimmed_prefix_len..],
12983                                    ignore_indent,
12984                                )
12985                            })
12986                            .max_by_key(|range| range.end.column - range.start.column)
12987                            .expect("prefixes is non-empty");
12988
12989                        if prefix_range.is_empty() {
12990                            all_selection_lines_are_comments = false;
12991                        }
12992
12993                        selection_edit_ranges.push(prefix_range);
12994                    }
12995
12996                    if all_selection_lines_are_comments {
12997                        edits.extend(
12998                            selection_edit_ranges
12999                                .iter()
13000                                .cloned()
13001                                .map(|range| (range, empty_str.clone())),
13002                        );
13003                    } else {
13004                        let min_column = selection_edit_ranges
13005                            .iter()
13006                            .map(|range| range.start.column)
13007                            .min()
13008                            .unwrap_or(0);
13009                        edits.extend(selection_edit_ranges.iter().map(|range| {
13010                            let position = Point::new(range.start.row, min_column);
13011                            (position..position, first_prefix.clone())
13012                        }));
13013                    }
13014                } else if let Some((full_comment_prefix, comment_suffix)) =
13015                    language.block_comment_delimiters()
13016                {
13017                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13018                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13019                    let prefix_range = comment_prefix_range(
13020                        snapshot.deref(),
13021                        start_row,
13022                        comment_prefix,
13023                        comment_prefix_whitespace,
13024                        ignore_indent,
13025                    );
13026                    let suffix_range = comment_suffix_range(
13027                        snapshot.deref(),
13028                        end_row,
13029                        comment_suffix.trim_start_matches(' '),
13030                        comment_suffix.starts_with(' '),
13031                    );
13032
13033                    if prefix_range.is_empty() || suffix_range.is_empty() {
13034                        edits.push((
13035                            prefix_range.start..prefix_range.start,
13036                            full_comment_prefix.clone(),
13037                        ));
13038                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13039                        suffixes_inserted.push((end_row, comment_suffix.len()));
13040                    } else {
13041                        edits.push((prefix_range, empty_str.clone()));
13042                        edits.push((suffix_range, empty_str.clone()));
13043                    }
13044                } else {
13045                    continue;
13046                }
13047            }
13048
13049            drop(snapshot);
13050            this.buffer.update(cx, |buffer, cx| {
13051                buffer.edit(edits, None, cx);
13052            });
13053
13054            // Adjust selections so that they end before any comment suffixes that
13055            // were inserted.
13056            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13057            let mut selections = this.selections.all::<Point>(cx);
13058            let snapshot = this.buffer.read(cx).read(cx);
13059            for selection in &mut selections {
13060                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13061                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13062                        Ordering::Less => {
13063                            suffixes_inserted.next();
13064                            continue;
13065                        }
13066                        Ordering::Greater => break,
13067                        Ordering::Equal => {
13068                            if selection.end.column == snapshot.line_len(row) {
13069                                if selection.is_empty() {
13070                                    selection.start.column -= suffix_len as u32;
13071                                }
13072                                selection.end.column -= suffix_len as u32;
13073                            }
13074                            break;
13075                        }
13076                    }
13077                }
13078            }
13079
13080            drop(snapshot);
13081            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13082                s.select(selections)
13083            });
13084
13085            let selections = this.selections.all::<Point>(cx);
13086            let selections_on_single_row = selections.windows(2).all(|selections| {
13087                selections[0].start.row == selections[1].start.row
13088                    && selections[0].end.row == selections[1].end.row
13089                    && selections[0].start.row == selections[0].end.row
13090            });
13091            let selections_selecting = selections
13092                .iter()
13093                .any(|selection| selection.start != selection.end);
13094            let advance_downwards = action.advance_downwards
13095                && selections_on_single_row
13096                && !selections_selecting
13097                && !matches!(this.mode, EditorMode::SingleLine { .. });
13098
13099            if advance_downwards {
13100                let snapshot = this.buffer.read(cx).snapshot(cx);
13101
13102                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13103                    s.move_cursors_with(|display_snapshot, display_point, _| {
13104                        let mut point = display_point.to_point(display_snapshot);
13105                        point.row += 1;
13106                        point = snapshot.clip_point(point, Bias::Left);
13107                        let display_point = point.to_display_point(display_snapshot);
13108                        let goal = SelectionGoal::HorizontalPosition(
13109                            display_snapshot
13110                                .x_for_display_point(display_point, text_layout_details)
13111                                .into(),
13112                        );
13113                        (display_point, goal)
13114                    })
13115                });
13116            }
13117        });
13118    }
13119
13120    pub fn select_enclosing_symbol(
13121        &mut self,
13122        _: &SelectEnclosingSymbol,
13123        window: &mut Window,
13124        cx: &mut Context<Self>,
13125    ) {
13126        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13127
13128        let buffer = self.buffer.read(cx).snapshot(cx);
13129        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13130
13131        fn update_selection(
13132            selection: &Selection<usize>,
13133            buffer_snap: &MultiBufferSnapshot,
13134        ) -> Option<Selection<usize>> {
13135            let cursor = selection.head();
13136            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13137            for symbol in symbols.iter().rev() {
13138                let start = symbol.range.start.to_offset(buffer_snap);
13139                let end = symbol.range.end.to_offset(buffer_snap);
13140                let new_range = start..end;
13141                if start < selection.start || end > selection.end {
13142                    return Some(Selection {
13143                        id: selection.id,
13144                        start: new_range.start,
13145                        end: new_range.end,
13146                        goal: SelectionGoal::None,
13147                        reversed: selection.reversed,
13148                    });
13149                }
13150            }
13151            None
13152        }
13153
13154        let mut selected_larger_symbol = false;
13155        let new_selections = old_selections
13156            .iter()
13157            .map(|selection| match update_selection(selection, &buffer) {
13158                Some(new_selection) => {
13159                    if new_selection.range() != selection.range() {
13160                        selected_larger_symbol = true;
13161                    }
13162                    new_selection
13163                }
13164                None => selection.clone(),
13165            })
13166            .collect::<Vec<_>>();
13167
13168        if selected_larger_symbol {
13169            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13170                s.select(new_selections);
13171            });
13172        }
13173    }
13174
13175    pub fn select_larger_syntax_node(
13176        &mut self,
13177        _: &SelectLargerSyntaxNode,
13178        window: &mut Window,
13179        cx: &mut Context<Self>,
13180    ) {
13181        let Some(visible_row_count) = self.visible_row_count() else {
13182            return;
13183        };
13184        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13185        if old_selections.is_empty() {
13186            return;
13187        }
13188
13189        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13190
13191        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13192        let buffer = self.buffer.read(cx).snapshot(cx);
13193
13194        let mut selected_larger_node = false;
13195        let mut new_selections = old_selections
13196            .iter()
13197            .map(|selection| {
13198                let old_range = selection.start..selection.end;
13199
13200                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13201                    // manually select word at selection
13202                    if ["string_content", "inline"].contains(&node.kind()) {
13203                        let word_range = {
13204                            let display_point = buffer
13205                                .offset_to_point(old_range.start)
13206                                .to_display_point(&display_map);
13207                            let Range { start, end } =
13208                                movement::surrounding_word(&display_map, display_point);
13209                            start.to_point(&display_map).to_offset(&buffer)
13210                                ..end.to_point(&display_map).to_offset(&buffer)
13211                        };
13212                        // ignore if word is already selected
13213                        if !word_range.is_empty() && old_range != word_range {
13214                            let last_word_range = {
13215                                let display_point = buffer
13216                                    .offset_to_point(old_range.end)
13217                                    .to_display_point(&display_map);
13218                                let Range { start, end } =
13219                                    movement::surrounding_word(&display_map, display_point);
13220                                start.to_point(&display_map).to_offset(&buffer)
13221                                    ..end.to_point(&display_map).to_offset(&buffer)
13222                            };
13223                            // only select word if start and end point belongs to same word
13224                            if word_range == last_word_range {
13225                                selected_larger_node = true;
13226                                return Selection {
13227                                    id: selection.id,
13228                                    start: word_range.start,
13229                                    end: word_range.end,
13230                                    goal: SelectionGoal::None,
13231                                    reversed: selection.reversed,
13232                                };
13233                            }
13234                        }
13235                    }
13236                }
13237
13238                let mut new_range = old_range.clone();
13239                while let Some((_node, containing_range)) =
13240                    buffer.syntax_ancestor(new_range.clone())
13241                {
13242                    new_range = match containing_range {
13243                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13244                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13245                    };
13246                    if !display_map.intersects_fold(new_range.start)
13247                        && !display_map.intersects_fold(new_range.end)
13248                    {
13249                        break;
13250                    }
13251                }
13252
13253                selected_larger_node |= new_range != old_range;
13254                Selection {
13255                    id: selection.id,
13256                    start: new_range.start,
13257                    end: new_range.end,
13258                    goal: SelectionGoal::None,
13259                    reversed: selection.reversed,
13260                }
13261            })
13262            .collect::<Vec<_>>();
13263
13264        if !selected_larger_node {
13265            return; // don't put this call in the history
13266        }
13267
13268        // scroll based on transformation done to the last selection created by the user
13269        let (last_old, last_new) = old_selections
13270            .last()
13271            .zip(new_selections.last().cloned())
13272            .expect("old_selections isn't empty");
13273
13274        // revert selection
13275        let is_selection_reversed = {
13276            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13277            new_selections.last_mut().expect("checked above").reversed =
13278                should_newest_selection_be_reversed;
13279            should_newest_selection_be_reversed
13280        };
13281
13282        if selected_larger_node {
13283            self.select_syntax_node_history.disable_clearing = true;
13284            self.change_selections(None, window, cx, |s| {
13285                s.select(new_selections.clone());
13286            });
13287            self.select_syntax_node_history.disable_clearing = false;
13288        }
13289
13290        let start_row = last_new.start.to_display_point(&display_map).row().0;
13291        let end_row = last_new.end.to_display_point(&display_map).row().0;
13292        let selection_height = end_row - start_row + 1;
13293        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13294
13295        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13296        let scroll_behavior = if fits_on_the_screen {
13297            self.request_autoscroll(Autoscroll::fit(), cx);
13298            SelectSyntaxNodeScrollBehavior::FitSelection
13299        } else if is_selection_reversed {
13300            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13301            SelectSyntaxNodeScrollBehavior::CursorTop
13302        } else {
13303            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13304            SelectSyntaxNodeScrollBehavior::CursorBottom
13305        };
13306
13307        self.select_syntax_node_history.push((
13308            old_selections,
13309            scroll_behavior,
13310            is_selection_reversed,
13311        ));
13312    }
13313
13314    pub fn select_smaller_syntax_node(
13315        &mut self,
13316        _: &SelectSmallerSyntaxNode,
13317        window: &mut Window,
13318        cx: &mut Context<Self>,
13319    ) {
13320        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13321
13322        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13323            self.select_syntax_node_history.pop()
13324        {
13325            if let Some(selection) = selections.last_mut() {
13326                selection.reversed = is_selection_reversed;
13327            }
13328
13329            self.select_syntax_node_history.disable_clearing = true;
13330            self.change_selections(None, window, cx, |s| {
13331                s.select(selections.to_vec());
13332            });
13333            self.select_syntax_node_history.disable_clearing = false;
13334
13335            match scroll_behavior {
13336                SelectSyntaxNodeScrollBehavior::CursorTop => {
13337                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13338                }
13339                SelectSyntaxNodeScrollBehavior::FitSelection => {
13340                    self.request_autoscroll(Autoscroll::fit(), cx);
13341                }
13342                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13343                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13344                }
13345            }
13346        }
13347    }
13348
13349    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13350        if !EditorSettings::get_global(cx).gutter.runnables {
13351            self.clear_tasks();
13352            return Task::ready(());
13353        }
13354        let project = self.project.as_ref().map(Entity::downgrade);
13355        let task_sources = self.lsp_task_sources(cx);
13356        cx.spawn_in(window, async move |editor, cx| {
13357            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13358            let Some(project) = project.and_then(|p| p.upgrade()) else {
13359                return;
13360            };
13361            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13362                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13363            }) else {
13364                return;
13365            };
13366
13367            let hide_runnables = project
13368                .update(cx, |project, cx| {
13369                    // Do not display any test indicators in non-dev server remote projects.
13370                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13371                })
13372                .unwrap_or(true);
13373            if hide_runnables {
13374                return;
13375            }
13376            let new_rows =
13377                cx.background_spawn({
13378                    let snapshot = display_snapshot.clone();
13379                    async move {
13380                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13381                    }
13382                })
13383                    .await;
13384            let Ok(lsp_tasks) =
13385                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13386            else {
13387                return;
13388            };
13389            let lsp_tasks = lsp_tasks.await;
13390
13391            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13392                lsp_tasks
13393                    .into_iter()
13394                    .flat_map(|(kind, tasks)| {
13395                        tasks.into_iter().filter_map(move |(location, task)| {
13396                            Some((kind.clone(), location?, task))
13397                        })
13398                    })
13399                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13400                        let buffer = location.target.buffer;
13401                        let buffer_snapshot = buffer.read(cx).snapshot();
13402                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13403                            |(excerpt_id, snapshot, _)| {
13404                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13405                                    display_snapshot
13406                                        .buffer_snapshot
13407                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13408                                } else {
13409                                    None
13410                                }
13411                            },
13412                        );
13413                        if let Some(offset) = offset {
13414                            let task_buffer_range =
13415                                location.target.range.to_point(&buffer_snapshot);
13416                            let context_buffer_range =
13417                                task_buffer_range.to_offset(&buffer_snapshot);
13418                            let context_range = BufferOffset(context_buffer_range.start)
13419                                ..BufferOffset(context_buffer_range.end);
13420
13421                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13422                                .or_insert_with(|| RunnableTasks {
13423                                    templates: Vec::new(),
13424                                    offset,
13425                                    column: task_buffer_range.start.column,
13426                                    extra_variables: HashMap::default(),
13427                                    context_range,
13428                                })
13429                                .templates
13430                                .push((kind, task.original_task().clone()));
13431                        }
13432
13433                        acc
13434                    })
13435            }) else {
13436                return;
13437            };
13438
13439            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13440            editor
13441                .update(cx, |editor, _| {
13442                    editor.clear_tasks();
13443                    for (key, mut value) in rows {
13444                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13445                            value.templates.extend(lsp_tasks.templates);
13446                        }
13447
13448                        editor.insert_tasks(key, value);
13449                    }
13450                    for (key, value) in lsp_tasks_by_rows {
13451                        editor.insert_tasks(key, value);
13452                    }
13453                })
13454                .ok();
13455        })
13456    }
13457    fn fetch_runnable_ranges(
13458        snapshot: &DisplaySnapshot,
13459        range: Range<Anchor>,
13460    ) -> Vec<language::RunnableRange> {
13461        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13462    }
13463
13464    fn runnable_rows(
13465        project: Entity<Project>,
13466        snapshot: DisplaySnapshot,
13467        runnable_ranges: Vec<RunnableRange>,
13468        mut cx: AsyncWindowContext,
13469    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13470        runnable_ranges
13471            .into_iter()
13472            .filter_map(|mut runnable| {
13473                let tasks = cx
13474                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13475                    .ok()?;
13476                if tasks.is_empty() {
13477                    return None;
13478                }
13479
13480                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13481
13482                let row = snapshot
13483                    .buffer_snapshot
13484                    .buffer_line_for_row(MultiBufferRow(point.row))?
13485                    .1
13486                    .start
13487                    .row;
13488
13489                let context_range =
13490                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13491                Some((
13492                    (runnable.buffer_id, row),
13493                    RunnableTasks {
13494                        templates: tasks,
13495                        offset: snapshot
13496                            .buffer_snapshot
13497                            .anchor_before(runnable.run_range.start),
13498                        context_range,
13499                        column: point.column,
13500                        extra_variables: runnable.extra_captures,
13501                    },
13502                ))
13503            })
13504            .collect()
13505    }
13506
13507    fn templates_with_tags(
13508        project: &Entity<Project>,
13509        runnable: &mut Runnable,
13510        cx: &mut App,
13511    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13512        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13513            let (worktree_id, file) = project
13514                .buffer_for_id(runnable.buffer, cx)
13515                .and_then(|buffer| buffer.read(cx).file())
13516                .map(|file| (file.worktree_id(cx), file.clone()))
13517                .unzip();
13518
13519            (
13520                project.task_store().read(cx).task_inventory().cloned(),
13521                worktree_id,
13522                file,
13523            )
13524        });
13525
13526        let mut templates_with_tags = mem::take(&mut runnable.tags)
13527            .into_iter()
13528            .flat_map(|RunnableTag(tag)| {
13529                inventory
13530                    .as_ref()
13531                    .into_iter()
13532                    .flat_map(|inventory| {
13533                        inventory.read(cx).list_tasks(
13534                            file.clone(),
13535                            Some(runnable.language.clone()),
13536                            worktree_id,
13537                            cx,
13538                        )
13539                    })
13540                    .filter(move |(_, template)| {
13541                        template.tags.iter().any(|source_tag| source_tag == &tag)
13542                    })
13543            })
13544            .sorted_by_key(|(kind, _)| kind.to_owned())
13545            .collect::<Vec<_>>();
13546        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13547            // Strongest source wins; if we have worktree tag binding, prefer that to
13548            // global and language bindings;
13549            // if we have a global binding, prefer that to language binding.
13550            let first_mismatch = templates_with_tags
13551                .iter()
13552                .position(|(tag_source, _)| tag_source != leading_tag_source);
13553            if let Some(index) = first_mismatch {
13554                templates_with_tags.truncate(index);
13555            }
13556        }
13557
13558        templates_with_tags
13559    }
13560
13561    pub fn move_to_enclosing_bracket(
13562        &mut self,
13563        _: &MoveToEnclosingBracket,
13564        window: &mut Window,
13565        cx: &mut Context<Self>,
13566    ) {
13567        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13568        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13569            s.move_offsets_with(|snapshot, selection| {
13570                let Some(enclosing_bracket_ranges) =
13571                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13572                else {
13573                    return;
13574                };
13575
13576                let mut best_length = usize::MAX;
13577                let mut best_inside = false;
13578                let mut best_in_bracket_range = false;
13579                let mut best_destination = None;
13580                for (open, close) in enclosing_bracket_ranges {
13581                    let close = close.to_inclusive();
13582                    let length = close.end() - open.start;
13583                    let inside = selection.start >= open.end && selection.end <= *close.start();
13584                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13585                        || close.contains(&selection.head());
13586
13587                    // If best is next to a bracket and current isn't, skip
13588                    if !in_bracket_range && best_in_bracket_range {
13589                        continue;
13590                    }
13591
13592                    // Prefer smaller lengths unless best is inside and current isn't
13593                    if length > best_length && (best_inside || !inside) {
13594                        continue;
13595                    }
13596
13597                    best_length = length;
13598                    best_inside = inside;
13599                    best_in_bracket_range = in_bracket_range;
13600                    best_destination = Some(
13601                        if close.contains(&selection.start) && close.contains(&selection.end) {
13602                            if inside { open.end } else { open.start }
13603                        } else if inside {
13604                            *close.start()
13605                        } else {
13606                            *close.end()
13607                        },
13608                    );
13609                }
13610
13611                if let Some(destination) = best_destination {
13612                    selection.collapse_to(destination, SelectionGoal::None);
13613                }
13614            })
13615        });
13616    }
13617
13618    pub fn undo_selection(
13619        &mut self,
13620        _: &UndoSelection,
13621        window: &mut Window,
13622        cx: &mut Context<Self>,
13623    ) {
13624        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13625        self.end_selection(window, cx);
13626        self.selection_history.mode = SelectionHistoryMode::Undoing;
13627        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13628            self.change_selections(None, window, cx, |s| {
13629                s.select_anchors(entry.selections.to_vec())
13630            });
13631            self.select_next_state = entry.select_next_state;
13632            self.select_prev_state = entry.select_prev_state;
13633            self.add_selections_state = entry.add_selections_state;
13634            self.request_autoscroll(Autoscroll::newest(), cx);
13635        }
13636        self.selection_history.mode = SelectionHistoryMode::Normal;
13637    }
13638
13639    pub fn redo_selection(
13640        &mut self,
13641        _: &RedoSelection,
13642        window: &mut Window,
13643        cx: &mut Context<Self>,
13644    ) {
13645        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13646        self.end_selection(window, cx);
13647        self.selection_history.mode = SelectionHistoryMode::Redoing;
13648        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13649            self.change_selections(None, window, cx, |s| {
13650                s.select_anchors(entry.selections.to_vec())
13651            });
13652            self.select_next_state = entry.select_next_state;
13653            self.select_prev_state = entry.select_prev_state;
13654            self.add_selections_state = entry.add_selections_state;
13655            self.request_autoscroll(Autoscroll::newest(), cx);
13656        }
13657        self.selection_history.mode = SelectionHistoryMode::Normal;
13658    }
13659
13660    pub fn expand_excerpts(
13661        &mut self,
13662        action: &ExpandExcerpts,
13663        _: &mut Window,
13664        cx: &mut Context<Self>,
13665    ) {
13666        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13667    }
13668
13669    pub fn expand_excerpts_down(
13670        &mut self,
13671        action: &ExpandExcerptsDown,
13672        _: &mut Window,
13673        cx: &mut Context<Self>,
13674    ) {
13675        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13676    }
13677
13678    pub fn expand_excerpts_up(
13679        &mut self,
13680        action: &ExpandExcerptsUp,
13681        _: &mut Window,
13682        cx: &mut Context<Self>,
13683    ) {
13684        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13685    }
13686
13687    pub fn expand_excerpts_for_direction(
13688        &mut self,
13689        lines: u32,
13690        direction: ExpandExcerptDirection,
13691
13692        cx: &mut Context<Self>,
13693    ) {
13694        let selections = self.selections.disjoint_anchors();
13695
13696        let lines = if lines == 0 {
13697            EditorSettings::get_global(cx).expand_excerpt_lines
13698        } else {
13699            lines
13700        };
13701
13702        self.buffer.update(cx, |buffer, cx| {
13703            let snapshot = buffer.snapshot(cx);
13704            let mut excerpt_ids = selections
13705                .iter()
13706                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13707                .collect::<Vec<_>>();
13708            excerpt_ids.sort();
13709            excerpt_ids.dedup();
13710            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13711        })
13712    }
13713
13714    pub fn expand_excerpt(
13715        &mut self,
13716        excerpt: ExcerptId,
13717        direction: ExpandExcerptDirection,
13718        window: &mut Window,
13719        cx: &mut Context<Self>,
13720    ) {
13721        let current_scroll_position = self.scroll_position(cx);
13722        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13723        let mut should_scroll_up = false;
13724
13725        if direction == ExpandExcerptDirection::Down {
13726            let multi_buffer = self.buffer.read(cx);
13727            let snapshot = multi_buffer.snapshot(cx);
13728            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13729                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13730                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13731                        let buffer_snapshot = buffer.read(cx).snapshot();
13732                        let excerpt_end_row =
13733                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13734                        let last_row = buffer_snapshot.max_point().row;
13735                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13736                        should_scroll_up = lines_below >= lines_to_expand;
13737                    }
13738                }
13739            }
13740        }
13741
13742        self.buffer.update(cx, |buffer, cx| {
13743            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13744        });
13745
13746        if should_scroll_up {
13747            let new_scroll_position =
13748                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13749            self.set_scroll_position(new_scroll_position, window, cx);
13750        }
13751    }
13752
13753    pub fn go_to_singleton_buffer_point(
13754        &mut self,
13755        point: Point,
13756        window: &mut Window,
13757        cx: &mut Context<Self>,
13758    ) {
13759        self.go_to_singleton_buffer_range(point..point, window, cx);
13760    }
13761
13762    pub fn go_to_singleton_buffer_range(
13763        &mut self,
13764        range: Range<Point>,
13765        window: &mut Window,
13766        cx: &mut Context<Self>,
13767    ) {
13768        let multibuffer = self.buffer().read(cx);
13769        let Some(buffer) = multibuffer.as_singleton() else {
13770            return;
13771        };
13772        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13773            return;
13774        };
13775        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13776            return;
13777        };
13778        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13779            s.select_anchor_ranges([start..end])
13780        });
13781    }
13782
13783    pub fn go_to_diagnostic(
13784        &mut self,
13785        _: &GoToDiagnostic,
13786        window: &mut Window,
13787        cx: &mut Context<Self>,
13788    ) {
13789        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13790        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13791    }
13792
13793    pub fn go_to_prev_diagnostic(
13794        &mut self,
13795        _: &GoToPreviousDiagnostic,
13796        window: &mut Window,
13797        cx: &mut Context<Self>,
13798    ) {
13799        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13800        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13801    }
13802
13803    pub fn go_to_diagnostic_impl(
13804        &mut self,
13805        direction: Direction,
13806        window: &mut Window,
13807        cx: &mut Context<Self>,
13808    ) {
13809        let buffer = self.buffer.read(cx).snapshot(cx);
13810        let selection = self.selections.newest::<usize>(cx);
13811
13812        let mut active_group_id = None;
13813        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13814            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13815                active_group_id = Some(active_group.group_id);
13816            }
13817        }
13818
13819        fn filtered(
13820            snapshot: EditorSnapshot,
13821            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13822        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13823            diagnostics
13824                .filter(|entry| entry.range.start != entry.range.end)
13825                .filter(|entry| !entry.diagnostic.is_unnecessary)
13826                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13827        }
13828
13829        let snapshot = self.snapshot(window, cx);
13830        let before = filtered(
13831            snapshot.clone(),
13832            buffer
13833                .diagnostics_in_range(0..selection.start)
13834                .filter(|entry| entry.range.start <= selection.start),
13835        );
13836        let after = filtered(
13837            snapshot,
13838            buffer
13839                .diagnostics_in_range(selection.start..buffer.len())
13840                .filter(|entry| entry.range.start >= selection.start),
13841        );
13842
13843        let mut found: Option<DiagnosticEntry<usize>> = None;
13844        if direction == Direction::Prev {
13845            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13846            {
13847                for diagnostic in prev_diagnostics.into_iter().rev() {
13848                    if diagnostic.range.start != selection.start
13849                        || active_group_id
13850                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13851                    {
13852                        found = Some(diagnostic);
13853                        break 'outer;
13854                    }
13855                }
13856            }
13857        } else {
13858            for diagnostic in after.chain(before) {
13859                if diagnostic.range.start != selection.start
13860                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13861                {
13862                    found = Some(diagnostic);
13863                    break;
13864                }
13865            }
13866        }
13867        let Some(next_diagnostic) = found else {
13868            return;
13869        };
13870
13871        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13872            return;
13873        };
13874        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13875            s.select_ranges(vec![
13876                next_diagnostic.range.start..next_diagnostic.range.start,
13877            ])
13878        });
13879        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13880        self.refresh_inline_completion(false, true, window, cx);
13881    }
13882
13883    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13884        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13885        let snapshot = self.snapshot(window, cx);
13886        let selection = self.selections.newest::<Point>(cx);
13887        self.go_to_hunk_before_or_after_position(
13888            &snapshot,
13889            selection.head(),
13890            Direction::Next,
13891            window,
13892            cx,
13893        );
13894    }
13895
13896    pub fn go_to_hunk_before_or_after_position(
13897        &mut self,
13898        snapshot: &EditorSnapshot,
13899        position: Point,
13900        direction: Direction,
13901        window: &mut Window,
13902        cx: &mut Context<Editor>,
13903    ) {
13904        let row = if direction == Direction::Next {
13905            self.hunk_after_position(snapshot, position)
13906                .map(|hunk| hunk.row_range.start)
13907        } else {
13908            self.hunk_before_position(snapshot, position)
13909        };
13910
13911        if let Some(row) = row {
13912            let destination = Point::new(row.0, 0);
13913            let autoscroll = Autoscroll::center();
13914
13915            self.unfold_ranges(&[destination..destination], false, false, cx);
13916            self.change_selections(Some(autoscroll), window, cx, |s| {
13917                s.select_ranges([destination..destination]);
13918            });
13919        }
13920    }
13921
13922    fn hunk_after_position(
13923        &mut self,
13924        snapshot: &EditorSnapshot,
13925        position: Point,
13926    ) -> Option<MultiBufferDiffHunk> {
13927        snapshot
13928            .buffer_snapshot
13929            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13930            .find(|hunk| hunk.row_range.start.0 > position.row)
13931            .or_else(|| {
13932                snapshot
13933                    .buffer_snapshot
13934                    .diff_hunks_in_range(Point::zero()..position)
13935                    .find(|hunk| hunk.row_range.end.0 < position.row)
13936            })
13937    }
13938
13939    fn go_to_prev_hunk(
13940        &mut self,
13941        _: &GoToPreviousHunk,
13942        window: &mut Window,
13943        cx: &mut Context<Self>,
13944    ) {
13945        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13946        let snapshot = self.snapshot(window, cx);
13947        let selection = self.selections.newest::<Point>(cx);
13948        self.go_to_hunk_before_or_after_position(
13949            &snapshot,
13950            selection.head(),
13951            Direction::Prev,
13952            window,
13953            cx,
13954        );
13955    }
13956
13957    fn hunk_before_position(
13958        &mut self,
13959        snapshot: &EditorSnapshot,
13960        position: Point,
13961    ) -> Option<MultiBufferRow> {
13962        snapshot
13963            .buffer_snapshot
13964            .diff_hunk_before(position)
13965            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
13966    }
13967
13968    fn go_to_next_change(
13969        &mut self,
13970        _: &GoToNextChange,
13971        window: &mut Window,
13972        cx: &mut Context<Self>,
13973    ) {
13974        if let Some(selections) = self
13975            .change_list
13976            .next_change(1, Direction::Next)
13977            .map(|s| s.to_vec())
13978        {
13979            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13980                let map = s.display_map();
13981                s.select_display_ranges(selections.iter().map(|a| {
13982                    let point = a.to_display_point(&map);
13983                    point..point
13984                }))
13985            })
13986        }
13987    }
13988
13989    fn go_to_previous_change(
13990        &mut self,
13991        _: &GoToPreviousChange,
13992        window: &mut Window,
13993        cx: &mut Context<Self>,
13994    ) {
13995        if let Some(selections) = self
13996            .change_list
13997            .next_change(1, Direction::Prev)
13998            .map(|s| s.to_vec())
13999        {
14000            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14001                let map = s.display_map();
14002                s.select_display_ranges(selections.iter().map(|a| {
14003                    let point = a.to_display_point(&map);
14004                    point..point
14005                }))
14006            })
14007        }
14008    }
14009
14010    fn go_to_line<T: 'static>(
14011        &mut self,
14012        position: Anchor,
14013        highlight_color: Option<Hsla>,
14014        window: &mut Window,
14015        cx: &mut Context<Self>,
14016    ) {
14017        let snapshot = self.snapshot(window, cx).display_snapshot;
14018        let position = position.to_point(&snapshot.buffer_snapshot);
14019        let start = snapshot
14020            .buffer_snapshot
14021            .clip_point(Point::new(position.row, 0), Bias::Left);
14022        let end = start + Point::new(1, 0);
14023        let start = snapshot.buffer_snapshot.anchor_before(start);
14024        let end = snapshot.buffer_snapshot.anchor_before(end);
14025
14026        self.highlight_rows::<T>(
14027            start..end,
14028            highlight_color
14029                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14030            Default::default(),
14031            cx,
14032        );
14033
14034        if self.buffer.read(cx).is_singleton() {
14035            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14036        }
14037    }
14038
14039    pub fn go_to_definition(
14040        &mut self,
14041        _: &GoToDefinition,
14042        window: &mut Window,
14043        cx: &mut Context<Self>,
14044    ) -> Task<Result<Navigated>> {
14045        let definition =
14046            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14047        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14048        cx.spawn_in(window, async move |editor, cx| {
14049            if definition.await? == Navigated::Yes {
14050                return Ok(Navigated::Yes);
14051            }
14052            match fallback_strategy {
14053                GoToDefinitionFallback::None => Ok(Navigated::No),
14054                GoToDefinitionFallback::FindAllReferences => {
14055                    match editor.update_in(cx, |editor, window, cx| {
14056                        editor.find_all_references(&FindAllReferences, window, cx)
14057                    })? {
14058                        Some(references) => references.await,
14059                        None => Ok(Navigated::No),
14060                    }
14061                }
14062            }
14063        })
14064    }
14065
14066    pub fn go_to_declaration(
14067        &mut self,
14068        _: &GoToDeclaration,
14069        window: &mut Window,
14070        cx: &mut Context<Self>,
14071    ) -> Task<Result<Navigated>> {
14072        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14073    }
14074
14075    pub fn go_to_declaration_split(
14076        &mut self,
14077        _: &GoToDeclaration,
14078        window: &mut Window,
14079        cx: &mut Context<Self>,
14080    ) -> Task<Result<Navigated>> {
14081        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14082    }
14083
14084    pub fn go_to_implementation(
14085        &mut self,
14086        _: &GoToImplementation,
14087        window: &mut Window,
14088        cx: &mut Context<Self>,
14089    ) -> Task<Result<Navigated>> {
14090        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14091    }
14092
14093    pub fn go_to_implementation_split(
14094        &mut self,
14095        _: &GoToImplementationSplit,
14096        window: &mut Window,
14097        cx: &mut Context<Self>,
14098    ) -> Task<Result<Navigated>> {
14099        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14100    }
14101
14102    pub fn go_to_type_definition(
14103        &mut self,
14104        _: &GoToTypeDefinition,
14105        window: &mut Window,
14106        cx: &mut Context<Self>,
14107    ) -> Task<Result<Navigated>> {
14108        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14109    }
14110
14111    pub fn go_to_definition_split(
14112        &mut self,
14113        _: &GoToDefinitionSplit,
14114        window: &mut Window,
14115        cx: &mut Context<Self>,
14116    ) -> Task<Result<Navigated>> {
14117        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14118    }
14119
14120    pub fn go_to_type_definition_split(
14121        &mut self,
14122        _: &GoToTypeDefinitionSplit,
14123        window: &mut Window,
14124        cx: &mut Context<Self>,
14125    ) -> Task<Result<Navigated>> {
14126        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14127    }
14128
14129    fn go_to_definition_of_kind(
14130        &mut self,
14131        kind: GotoDefinitionKind,
14132        split: bool,
14133        window: &mut Window,
14134        cx: &mut Context<Self>,
14135    ) -> Task<Result<Navigated>> {
14136        let Some(provider) = self.semantics_provider.clone() else {
14137            return Task::ready(Ok(Navigated::No));
14138        };
14139        let head = self.selections.newest::<usize>(cx).head();
14140        let buffer = self.buffer.read(cx);
14141        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14142            text_anchor
14143        } else {
14144            return Task::ready(Ok(Navigated::No));
14145        };
14146
14147        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14148            return Task::ready(Ok(Navigated::No));
14149        };
14150
14151        cx.spawn_in(window, async move |editor, cx| {
14152            let definitions = definitions.await?;
14153            let navigated = editor
14154                .update_in(cx, |editor, window, cx| {
14155                    editor.navigate_to_hover_links(
14156                        Some(kind),
14157                        definitions
14158                            .into_iter()
14159                            .filter(|location| {
14160                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14161                            })
14162                            .map(HoverLink::Text)
14163                            .collect::<Vec<_>>(),
14164                        split,
14165                        window,
14166                        cx,
14167                    )
14168                })?
14169                .await?;
14170            anyhow::Ok(navigated)
14171        })
14172    }
14173
14174    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14175        let selection = self.selections.newest_anchor();
14176        let head = selection.head();
14177        let tail = selection.tail();
14178
14179        let Some((buffer, start_position)) =
14180            self.buffer.read(cx).text_anchor_for_position(head, cx)
14181        else {
14182            return;
14183        };
14184
14185        let end_position = if head != tail {
14186            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14187                return;
14188            };
14189            Some(pos)
14190        } else {
14191            None
14192        };
14193
14194        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14195            let url = if let Some(end_pos) = end_position {
14196                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14197            } else {
14198                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14199            };
14200
14201            if let Some(url) = url {
14202                editor.update(cx, |_, cx| {
14203                    cx.open_url(&url);
14204                })
14205            } else {
14206                Ok(())
14207            }
14208        });
14209
14210        url_finder.detach();
14211    }
14212
14213    pub fn open_selected_filename(
14214        &mut self,
14215        _: &OpenSelectedFilename,
14216        window: &mut Window,
14217        cx: &mut Context<Self>,
14218    ) {
14219        let Some(workspace) = self.workspace() else {
14220            return;
14221        };
14222
14223        let position = self.selections.newest_anchor().head();
14224
14225        let Some((buffer, buffer_position)) =
14226            self.buffer.read(cx).text_anchor_for_position(position, cx)
14227        else {
14228            return;
14229        };
14230
14231        let project = self.project.clone();
14232
14233        cx.spawn_in(window, async move |_, cx| {
14234            let result = find_file(&buffer, project, buffer_position, cx).await;
14235
14236            if let Some((_, path)) = result {
14237                workspace
14238                    .update_in(cx, |workspace, window, cx| {
14239                        workspace.open_resolved_path(path, window, cx)
14240                    })?
14241                    .await?;
14242            }
14243            anyhow::Ok(())
14244        })
14245        .detach();
14246    }
14247
14248    pub(crate) fn navigate_to_hover_links(
14249        &mut self,
14250        kind: Option<GotoDefinitionKind>,
14251        mut definitions: Vec<HoverLink>,
14252        split: bool,
14253        window: &mut Window,
14254        cx: &mut Context<Editor>,
14255    ) -> Task<Result<Navigated>> {
14256        // If there is one definition, just open it directly
14257        if definitions.len() == 1 {
14258            let definition = definitions.pop().unwrap();
14259
14260            enum TargetTaskResult {
14261                Location(Option<Location>),
14262                AlreadyNavigated,
14263            }
14264
14265            let target_task = match definition {
14266                HoverLink::Text(link) => {
14267                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14268                }
14269                HoverLink::InlayHint(lsp_location, server_id) => {
14270                    let computation =
14271                        self.compute_target_location(lsp_location, server_id, window, cx);
14272                    cx.background_spawn(async move {
14273                        let location = computation.await?;
14274                        Ok(TargetTaskResult::Location(location))
14275                    })
14276                }
14277                HoverLink::Url(url) => {
14278                    cx.open_url(&url);
14279                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14280                }
14281                HoverLink::File(path) => {
14282                    if let Some(workspace) = self.workspace() {
14283                        cx.spawn_in(window, async move |_, cx| {
14284                            workspace
14285                                .update_in(cx, |workspace, window, cx| {
14286                                    workspace.open_resolved_path(path, window, cx)
14287                                })?
14288                                .await
14289                                .map(|_| TargetTaskResult::AlreadyNavigated)
14290                        })
14291                    } else {
14292                        Task::ready(Ok(TargetTaskResult::Location(None)))
14293                    }
14294                }
14295            };
14296            cx.spawn_in(window, async move |editor, cx| {
14297                let target = match target_task.await.context("target resolution task")? {
14298                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14299                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14300                    TargetTaskResult::Location(Some(target)) => target,
14301                };
14302
14303                editor.update_in(cx, |editor, window, cx| {
14304                    let Some(workspace) = editor.workspace() else {
14305                        return Navigated::No;
14306                    };
14307                    let pane = workspace.read(cx).active_pane().clone();
14308
14309                    let range = target.range.to_point(target.buffer.read(cx));
14310                    let range = editor.range_for_match(&range);
14311                    let range = collapse_multiline_range(range);
14312
14313                    if !split
14314                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14315                    {
14316                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14317                    } else {
14318                        window.defer(cx, move |window, cx| {
14319                            let target_editor: Entity<Self> =
14320                                workspace.update(cx, |workspace, cx| {
14321                                    let pane = if split {
14322                                        workspace.adjacent_pane(window, cx)
14323                                    } else {
14324                                        workspace.active_pane().clone()
14325                                    };
14326
14327                                    workspace.open_project_item(
14328                                        pane,
14329                                        target.buffer.clone(),
14330                                        true,
14331                                        true,
14332                                        window,
14333                                        cx,
14334                                    )
14335                                });
14336                            target_editor.update(cx, |target_editor, cx| {
14337                                // When selecting a definition in a different buffer, disable the nav history
14338                                // to avoid creating a history entry at the previous cursor location.
14339                                pane.update(cx, |pane, _| pane.disable_history());
14340                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14341                                pane.update(cx, |pane, _| pane.enable_history());
14342                            });
14343                        });
14344                    }
14345                    Navigated::Yes
14346                })
14347            })
14348        } else if !definitions.is_empty() {
14349            cx.spawn_in(window, async move |editor, cx| {
14350                let (title, location_tasks, workspace) = editor
14351                    .update_in(cx, |editor, window, cx| {
14352                        let tab_kind = match kind {
14353                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14354                            _ => "Definitions",
14355                        };
14356                        let title = definitions
14357                            .iter()
14358                            .find_map(|definition| match definition {
14359                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14360                                    let buffer = origin.buffer.read(cx);
14361                                    format!(
14362                                        "{} for {}",
14363                                        tab_kind,
14364                                        buffer
14365                                            .text_for_range(origin.range.clone())
14366                                            .collect::<String>()
14367                                    )
14368                                }),
14369                                HoverLink::InlayHint(_, _) => None,
14370                                HoverLink::Url(_) => None,
14371                                HoverLink::File(_) => None,
14372                            })
14373                            .unwrap_or(tab_kind.to_string());
14374                        let location_tasks = definitions
14375                            .into_iter()
14376                            .map(|definition| match definition {
14377                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14378                                HoverLink::InlayHint(lsp_location, server_id) => editor
14379                                    .compute_target_location(lsp_location, server_id, window, cx),
14380                                HoverLink::Url(_) => Task::ready(Ok(None)),
14381                                HoverLink::File(_) => Task::ready(Ok(None)),
14382                            })
14383                            .collect::<Vec<_>>();
14384                        (title, location_tasks, editor.workspace().clone())
14385                    })
14386                    .context("location tasks preparation")?;
14387
14388                let locations = future::join_all(location_tasks)
14389                    .await
14390                    .into_iter()
14391                    .filter_map(|location| location.transpose())
14392                    .collect::<Result<_>>()
14393                    .context("location tasks")?;
14394
14395                let Some(workspace) = workspace else {
14396                    return Ok(Navigated::No);
14397                };
14398                let opened = workspace
14399                    .update_in(cx, |workspace, window, cx| {
14400                        Self::open_locations_in_multibuffer(
14401                            workspace,
14402                            locations,
14403                            title,
14404                            split,
14405                            MultibufferSelectionMode::First,
14406                            window,
14407                            cx,
14408                        )
14409                    })
14410                    .ok();
14411
14412                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14413            })
14414        } else {
14415            Task::ready(Ok(Navigated::No))
14416        }
14417    }
14418
14419    fn compute_target_location(
14420        &self,
14421        lsp_location: lsp::Location,
14422        server_id: LanguageServerId,
14423        window: &mut Window,
14424        cx: &mut Context<Self>,
14425    ) -> Task<anyhow::Result<Option<Location>>> {
14426        let Some(project) = self.project.clone() else {
14427            return Task::ready(Ok(None));
14428        };
14429
14430        cx.spawn_in(window, async move |editor, cx| {
14431            let location_task = editor.update(cx, |_, cx| {
14432                project.update(cx, |project, cx| {
14433                    let language_server_name = project
14434                        .language_server_statuses(cx)
14435                        .find(|(id, _)| server_id == *id)
14436                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14437                    language_server_name.map(|language_server_name| {
14438                        project.open_local_buffer_via_lsp(
14439                            lsp_location.uri.clone(),
14440                            server_id,
14441                            language_server_name,
14442                            cx,
14443                        )
14444                    })
14445                })
14446            })?;
14447            let location = match location_task {
14448                Some(task) => Some({
14449                    let target_buffer_handle = task.await.context("open local buffer")?;
14450                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14451                        let target_start = target_buffer
14452                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14453                        let target_end = target_buffer
14454                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14455                        target_buffer.anchor_after(target_start)
14456                            ..target_buffer.anchor_before(target_end)
14457                    })?;
14458                    Location {
14459                        buffer: target_buffer_handle,
14460                        range,
14461                    }
14462                }),
14463                None => None,
14464            };
14465            Ok(location)
14466        })
14467    }
14468
14469    pub fn find_all_references(
14470        &mut self,
14471        _: &FindAllReferences,
14472        window: &mut Window,
14473        cx: &mut Context<Self>,
14474    ) -> Option<Task<Result<Navigated>>> {
14475        let selection = self.selections.newest::<usize>(cx);
14476        let multi_buffer = self.buffer.read(cx);
14477        let head = selection.head();
14478
14479        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14480        let head_anchor = multi_buffer_snapshot.anchor_at(
14481            head,
14482            if head < selection.tail() {
14483                Bias::Right
14484            } else {
14485                Bias::Left
14486            },
14487        );
14488
14489        match self
14490            .find_all_references_task_sources
14491            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14492        {
14493            Ok(_) => {
14494                log::info!(
14495                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14496                );
14497                return None;
14498            }
14499            Err(i) => {
14500                self.find_all_references_task_sources.insert(i, head_anchor);
14501            }
14502        }
14503
14504        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14505        let workspace = self.workspace()?;
14506        let project = workspace.read(cx).project().clone();
14507        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14508        Some(cx.spawn_in(window, async move |editor, cx| {
14509            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14510                if let Ok(i) = editor
14511                    .find_all_references_task_sources
14512                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14513                {
14514                    editor.find_all_references_task_sources.remove(i);
14515                }
14516            });
14517
14518            let locations = references.await?;
14519            if locations.is_empty() {
14520                return anyhow::Ok(Navigated::No);
14521            }
14522
14523            workspace.update_in(cx, |workspace, window, cx| {
14524                let title = locations
14525                    .first()
14526                    .as_ref()
14527                    .map(|location| {
14528                        let buffer = location.buffer.read(cx);
14529                        format!(
14530                            "References to `{}`",
14531                            buffer
14532                                .text_for_range(location.range.clone())
14533                                .collect::<String>()
14534                        )
14535                    })
14536                    .unwrap();
14537                Self::open_locations_in_multibuffer(
14538                    workspace,
14539                    locations,
14540                    title,
14541                    false,
14542                    MultibufferSelectionMode::First,
14543                    window,
14544                    cx,
14545                );
14546                Navigated::Yes
14547            })
14548        }))
14549    }
14550
14551    /// Opens a multibuffer with the given project locations in it
14552    pub fn open_locations_in_multibuffer(
14553        workspace: &mut Workspace,
14554        mut locations: Vec<Location>,
14555        title: String,
14556        split: bool,
14557        multibuffer_selection_mode: MultibufferSelectionMode,
14558        window: &mut Window,
14559        cx: &mut Context<Workspace>,
14560    ) {
14561        // If there are multiple definitions, open them in a multibuffer
14562        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14563        let mut locations = locations.into_iter().peekable();
14564        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14565        let capability = workspace.project().read(cx).capability();
14566
14567        let excerpt_buffer = cx.new(|cx| {
14568            let mut multibuffer = MultiBuffer::new(capability);
14569            while let Some(location) = locations.next() {
14570                let buffer = location.buffer.read(cx);
14571                let mut ranges_for_buffer = Vec::new();
14572                let range = location.range.to_point(buffer);
14573                ranges_for_buffer.push(range.clone());
14574
14575                while let Some(next_location) = locations.peek() {
14576                    if next_location.buffer == location.buffer {
14577                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14578                        locations.next();
14579                    } else {
14580                        break;
14581                    }
14582                }
14583
14584                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14585                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14586                    PathKey::for_buffer(&location.buffer, cx),
14587                    location.buffer.clone(),
14588                    ranges_for_buffer,
14589                    DEFAULT_MULTIBUFFER_CONTEXT,
14590                    cx,
14591                );
14592                ranges.extend(new_ranges)
14593            }
14594
14595            multibuffer.with_title(title)
14596        });
14597
14598        let editor = cx.new(|cx| {
14599            Editor::for_multibuffer(
14600                excerpt_buffer,
14601                Some(workspace.project().clone()),
14602                window,
14603                cx,
14604            )
14605        });
14606        editor.update(cx, |editor, cx| {
14607            match multibuffer_selection_mode {
14608                MultibufferSelectionMode::First => {
14609                    if let Some(first_range) = ranges.first() {
14610                        editor.change_selections(None, window, cx, |selections| {
14611                            selections.clear_disjoint();
14612                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14613                        });
14614                    }
14615                    editor.highlight_background::<Self>(
14616                        &ranges,
14617                        |theme| theme.editor_highlighted_line_background,
14618                        cx,
14619                    );
14620                }
14621                MultibufferSelectionMode::All => {
14622                    editor.change_selections(None, window, cx, |selections| {
14623                        selections.clear_disjoint();
14624                        selections.select_anchor_ranges(ranges);
14625                    });
14626                }
14627            }
14628            editor.register_buffers_with_language_servers(cx);
14629        });
14630
14631        let item = Box::new(editor);
14632        let item_id = item.item_id();
14633
14634        if split {
14635            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14636        } else {
14637            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14638                let (preview_item_id, preview_item_idx) =
14639                    workspace.active_pane().update(cx, |pane, _| {
14640                        (pane.preview_item_id(), pane.preview_item_idx())
14641                    });
14642
14643                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14644
14645                if let Some(preview_item_id) = preview_item_id {
14646                    workspace.active_pane().update(cx, |pane, cx| {
14647                        pane.remove_item(preview_item_id, false, false, window, cx);
14648                    });
14649                }
14650            } else {
14651                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14652            }
14653        }
14654        workspace.active_pane().update(cx, |pane, cx| {
14655            pane.set_preview_item_id(Some(item_id), cx);
14656        });
14657    }
14658
14659    pub fn rename(
14660        &mut self,
14661        _: &Rename,
14662        window: &mut Window,
14663        cx: &mut Context<Self>,
14664    ) -> Option<Task<Result<()>>> {
14665        use language::ToOffset as _;
14666
14667        let provider = self.semantics_provider.clone()?;
14668        let selection = self.selections.newest_anchor().clone();
14669        let (cursor_buffer, cursor_buffer_position) = self
14670            .buffer
14671            .read(cx)
14672            .text_anchor_for_position(selection.head(), cx)?;
14673        let (tail_buffer, cursor_buffer_position_end) = self
14674            .buffer
14675            .read(cx)
14676            .text_anchor_for_position(selection.tail(), cx)?;
14677        if tail_buffer != cursor_buffer {
14678            return None;
14679        }
14680
14681        let snapshot = cursor_buffer.read(cx).snapshot();
14682        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14683        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14684        let prepare_rename = provider
14685            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14686            .unwrap_or_else(|| Task::ready(Ok(None)));
14687        drop(snapshot);
14688
14689        Some(cx.spawn_in(window, async move |this, cx| {
14690            let rename_range = if let Some(range) = prepare_rename.await? {
14691                Some(range)
14692            } else {
14693                this.update(cx, |this, cx| {
14694                    let buffer = this.buffer.read(cx).snapshot(cx);
14695                    let mut buffer_highlights = this
14696                        .document_highlights_for_position(selection.head(), &buffer)
14697                        .filter(|highlight| {
14698                            highlight.start.excerpt_id == selection.head().excerpt_id
14699                                && highlight.end.excerpt_id == selection.head().excerpt_id
14700                        });
14701                    buffer_highlights
14702                        .next()
14703                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14704                })?
14705            };
14706            if let Some(rename_range) = rename_range {
14707                this.update_in(cx, |this, window, cx| {
14708                    let snapshot = cursor_buffer.read(cx).snapshot();
14709                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14710                    let cursor_offset_in_rename_range =
14711                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14712                    let cursor_offset_in_rename_range_end =
14713                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14714
14715                    this.take_rename(false, window, cx);
14716                    let buffer = this.buffer.read(cx).read(cx);
14717                    let cursor_offset = selection.head().to_offset(&buffer);
14718                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14719                    let rename_end = rename_start + rename_buffer_range.len();
14720                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14721                    let mut old_highlight_id = None;
14722                    let old_name: Arc<str> = buffer
14723                        .chunks(rename_start..rename_end, true)
14724                        .map(|chunk| {
14725                            if old_highlight_id.is_none() {
14726                                old_highlight_id = chunk.syntax_highlight_id;
14727                            }
14728                            chunk.text
14729                        })
14730                        .collect::<String>()
14731                        .into();
14732
14733                    drop(buffer);
14734
14735                    // Position the selection in the rename editor so that it matches the current selection.
14736                    this.show_local_selections = false;
14737                    let rename_editor = cx.new(|cx| {
14738                        let mut editor = Editor::single_line(window, cx);
14739                        editor.buffer.update(cx, |buffer, cx| {
14740                            buffer.edit([(0..0, old_name.clone())], None, cx)
14741                        });
14742                        let rename_selection_range = match cursor_offset_in_rename_range
14743                            .cmp(&cursor_offset_in_rename_range_end)
14744                        {
14745                            Ordering::Equal => {
14746                                editor.select_all(&SelectAll, window, cx);
14747                                return editor;
14748                            }
14749                            Ordering::Less => {
14750                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14751                            }
14752                            Ordering::Greater => {
14753                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14754                            }
14755                        };
14756                        if rename_selection_range.end > old_name.len() {
14757                            editor.select_all(&SelectAll, window, cx);
14758                        } else {
14759                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14760                                s.select_ranges([rename_selection_range]);
14761                            });
14762                        }
14763                        editor
14764                    });
14765                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14766                        if e == &EditorEvent::Focused {
14767                            cx.emit(EditorEvent::FocusedIn)
14768                        }
14769                    })
14770                    .detach();
14771
14772                    let write_highlights =
14773                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14774                    let read_highlights =
14775                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14776                    let ranges = write_highlights
14777                        .iter()
14778                        .flat_map(|(_, ranges)| ranges.iter())
14779                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14780                        .cloned()
14781                        .collect();
14782
14783                    this.highlight_text::<Rename>(
14784                        ranges,
14785                        HighlightStyle {
14786                            fade_out: Some(0.6),
14787                            ..Default::default()
14788                        },
14789                        cx,
14790                    );
14791                    let rename_focus_handle = rename_editor.focus_handle(cx);
14792                    window.focus(&rename_focus_handle);
14793                    let block_id = this.insert_blocks(
14794                        [BlockProperties {
14795                            style: BlockStyle::Flex,
14796                            placement: BlockPlacement::Below(range.start),
14797                            height: Some(1),
14798                            render: Arc::new({
14799                                let rename_editor = rename_editor.clone();
14800                                move |cx: &mut BlockContext| {
14801                                    let mut text_style = cx.editor_style.text.clone();
14802                                    if let Some(highlight_style) = old_highlight_id
14803                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14804                                    {
14805                                        text_style = text_style.highlight(highlight_style);
14806                                    }
14807                                    div()
14808                                        .block_mouse_down()
14809                                        .pl(cx.anchor_x)
14810                                        .child(EditorElement::new(
14811                                            &rename_editor,
14812                                            EditorStyle {
14813                                                background: cx.theme().system().transparent,
14814                                                local_player: cx.editor_style.local_player,
14815                                                text: text_style,
14816                                                scrollbar_width: cx.editor_style.scrollbar_width,
14817                                                syntax: cx.editor_style.syntax.clone(),
14818                                                status: cx.editor_style.status.clone(),
14819                                                inlay_hints_style: HighlightStyle {
14820                                                    font_weight: Some(FontWeight::BOLD),
14821                                                    ..make_inlay_hints_style(cx.app)
14822                                                },
14823                                                inline_completion_styles: make_suggestion_styles(
14824                                                    cx.app,
14825                                                ),
14826                                                ..EditorStyle::default()
14827                                            },
14828                                        ))
14829                                        .into_any_element()
14830                                }
14831                            }),
14832                            priority: 0,
14833                            render_in_minimap: true,
14834                        }],
14835                        Some(Autoscroll::fit()),
14836                        cx,
14837                    )[0];
14838                    this.pending_rename = Some(RenameState {
14839                        range,
14840                        old_name,
14841                        editor: rename_editor,
14842                        block_id,
14843                    });
14844                })?;
14845            }
14846
14847            Ok(())
14848        }))
14849    }
14850
14851    pub fn confirm_rename(
14852        &mut self,
14853        _: &ConfirmRename,
14854        window: &mut Window,
14855        cx: &mut Context<Self>,
14856    ) -> Option<Task<Result<()>>> {
14857        let rename = self.take_rename(false, window, cx)?;
14858        let workspace = self.workspace()?.downgrade();
14859        let (buffer, start) = self
14860            .buffer
14861            .read(cx)
14862            .text_anchor_for_position(rename.range.start, cx)?;
14863        let (end_buffer, _) = self
14864            .buffer
14865            .read(cx)
14866            .text_anchor_for_position(rename.range.end, cx)?;
14867        if buffer != end_buffer {
14868            return None;
14869        }
14870
14871        let old_name = rename.old_name;
14872        let new_name = rename.editor.read(cx).text(cx);
14873
14874        let rename = self.semantics_provider.as_ref()?.perform_rename(
14875            &buffer,
14876            start,
14877            new_name.clone(),
14878            cx,
14879        )?;
14880
14881        Some(cx.spawn_in(window, async move |editor, cx| {
14882            let project_transaction = rename.await?;
14883            Self::open_project_transaction(
14884                &editor,
14885                workspace,
14886                project_transaction,
14887                format!("Rename: {}{}", old_name, new_name),
14888                cx,
14889            )
14890            .await?;
14891
14892            editor.update(cx, |editor, cx| {
14893                editor.refresh_document_highlights(cx);
14894            })?;
14895            Ok(())
14896        }))
14897    }
14898
14899    fn take_rename(
14900        &mut self,
14901        moving_cursor: bool,
14902        window: &mut Window,
14903        cx: &mut Context<Self>,
14904    ) -> Option<RenameState> {
14905        let rename = self.pending_rename.take()?;
14906        if rename.editor.focus_handle(cx).is_focused(window) {
14907            window.focus(&self.focus_handle);
14908        }
14909
14910        self.remove_blocks(
14911            [rename.block_id].into_iter().collect(),
14912            Some(Autoscroll::fit()),
14913            cx,
14914        );
14915        self.clear_highlights::<Rename>(cx);
14916        self.show_local_selections = true;
14917
14918        if moving_cursor {
14919            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14920                editor.selections.newest::<usize>(cx).head()
14921            });
14922
14923            // Update the selection to match the position of the selection inside
14924            // the rename editor.
14925            let snapshot = self.buffer.read(cx).read(cx);
14926            let rename_range = rename.range.to_offset(&snapshot);
14927            let cursor_in_editor = snapshot
14928                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14929                .min(rename_range.end);
14930            drop(snapshot);
14931
14932            self.change_selections(None, window, cx, |s| {
14933                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14934            });
14935        } else {
14936            self.refresh_document_highlights(cx);
14937        }
14938
14939        Some(rename)
14940    }
14941
14942    pub fn pending_rename(&self) -> Option<&RenameState> {
14943        self.pending_rename.as_ref()
14944    }
14945
14946    fn format(
14947        &mut self,
14948        _: &Format,
14949        window: &mut Window,
14950        cx: &mut Context<Self>,
14951    ) -> Option<Task<Result<()>>> {
14952        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14953
14954        let project = match &self.project {
14955            Some(project) => project.clone(),
14956            None => return None,
14957        };
14958
14959        Some(self.perform_format(
14960            project,
14961            FormatTrigger::Manual,
14962            FormatTarget::Buffers,
14963            window,
14964            cx,
14965        ))
14966    }
14967
14968    fn format_selections(
14969        &mut self,
14970        _: &FormatSelections,
14971        window: &mut Window,
14972        cx: &mut Context<Self>,
14973    ) -> Option<Task<Result<()>>> {
14974        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14975
14976        let project = match &self.project {
14977            Some(project) => project.clone(),
14978            None => return None,
14979        };
14980
14981        let ranges = self
14982            .selections
14983            .all_adjusted(cx)
14984            .into_iter()
14985            .map(|selection| selection.range())
14986            .collect_vec();
14987
14988        Some(self.perform_format(
14989            project,
14990            FormatTrigger::Manual,
14991            FormatTarget::Ranges(ranges),
14992            window,
14993            cx,
14994        ))
14995    }
14996
14997    fn perform_format(
14998        &mut self,
14999        project: Entity<Project>,
15000        trigger: FormatTrigger,
15001        target: FormatTarget,
15002        window: &mut Window,
15003        cx: &mut Context<Self>,
15004    ) -> Task<Result<()>> {
15005        let buffer = self.buffer.clone();
15006        let (buffers, target) = match target {
15007            FormatTarget::Buffers => {
15008                let mut buffers = buffer.read(cx).all_buffers();
15009                if trigger == FormatTrigger::Save {
15010                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15011                }
15012                (buffers, LspFormatTarget::Buffers)
15013            }
15014            FormatTarget::Ranges(selection_ranges) => {
15015                let multi_buffer = buffer.read(cx);
15016                let snapshot = multi_buffer.read(cx);
15017                let mut buffers = HashSet::default();
15018                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15019                    BTreeMap::new();
15020                for selection_range in selection_ranges {
15021                    for (buffer, buffer_range, _) in
15022                        snapshot.range_to_buffer_ranges(selection_range)
15023                    {
15024                        let buffer_id = buffer.remote_id();
15025                        let start = buffer.anchor_before(buffer_range.start);
15026                        let end = buffer.anchor_after(buffer_range.end);
15027                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15028                        buffer_id_to_ranges
15029                            .entry(buffer_id)
15030                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15031                            .or_insert_with(|| vec![start..end]);
15032                    }
15033                }
15034                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15035            }
15036        };
15037
15038        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15039        let selections_prev = transaction_id_prev
15040            .and_then(|transaction_id_prev| {
15041                // default to selections as they were after the last edit, if we have them,
15042                // instead of how they are now.
15043                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15044                // will take you back to where you made the last edit, instead of staying where you scrolled
15045                self.selection_history
15046                    .transaction(transaction_id_prev)
15047                    .map(|t| t.0.clone())
15048            })
15049            .unwrap_or_else(|| {
15050                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15051                self.selections.disjoint_anchors()
15052            });
15053
15054        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15055        let format = project.update(cx, |project, cx| {
15056            project.format(buffers, target, true, trigger, cx)
15057        });
15058
15059        cx.spawn_in(window, async move |editor, cx| {
15060            let transaction = futures::select_biased! {
15061                transaction = format.log_err().fuse() => transaction,
15062                () = timeout => {
15063                    log::warn!("timed out waiting for formatting");
15064                    None
15065                }
15066            };
15067
15068            buffer
15069                .update(cx, |buffer, cx| {
15070                    if let Some(transaction) = transaction {
15071                        if !buffer.is_singleton() {
15072                            buffer.push_transaction(&transaction.0, cx);
15073                        }
15074                    }
15075                    cx.notify();
15076                })
15077                .ok();
15078
15079            if let Some(transaction_id_now) =
15080                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15081            {
15082                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15083                if has_new_transaction {
15084                    _ = editor.update(cx, |editor, _| {
15085                        editor
15086                            .selection_history
15087                            .insert_transaction(transaction_id_now, selections_prev);
15088                    });
15089                }
15090            }
15091
15092            Ok(())
15093        })
15094    }
15095
15096    fn organize_imports(
15097        &mut self,
15098        _: &OrganizeImports,
15099        window: &mut Window,
15100        cx: &mut Context<Self>,
15101    ) -> Option<Task<Result<()>>> {
15102        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15103        let project = match &self.project {
15104            Some(project) => project.clone(),
15105            None => return None,
15106        };
15107        Some(self.perform_code_action_kind(
15108            project,
15109            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15110            window,
15111            cx,
15112        ))
15113    }
15114
15115    fn perform_code_action_kind(
15116        &mut self,
15117        project: Entity<Project>,
15118        kind: CodeActionKind,
15119        window: &mut Window,
15120        cx: &mut Context<Self>,
15121    ) -> Task<Result<()>> {
15122        let buffer = self.buffer.clone();
15123        let buffers = buffer.read(cx).all_buffers();
15124        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15125        let apply_action = project.update(cx, |project, cx| {
15126            project.apply_code_action_kind(buffers, kind, true, cx)
15127        });
15128        cx.spawn_in(window, async move |_, cx| {
15129            let transaction = futures::select_biased! {
15130                () = timeout => {
15131                    log::warn!("timed out waiting for executing code action");
15132                    None
15133                }
15134                transaction = apply_action.log_err().fuse() => transaction,
15135            };
15136            buffer
15137                .update(cx, |buffer, cx| {
15138                    // check if we need this
15139                    if let Some(transaction) = transaction {
15140                        if !buffer.is_singleton() {
15141                            buffer.push_transaction(&transaction.0, cx);
15142                        }
15143                    }
15144                    cx.notify();
15145                })
15146                .ok();
15147            Ok(())
15148        })
15149    }
15150
15151    fn restart_language_server(
15152        &mut self,
15153        _: &RestartLanguageServer,
15154        _: &mut Window,
15155        cx: &mut Context<Self>,
15156    ) {
15157        if let Some(project) = self.project.clone() {
15158            self.buffer.update(cx, |multi_buffer, cx| {
15159                project.update(cx, |project, cx| {
15160                    project.restart_language_servers_for_buffers(
15161                        multi_buffer.all_buffers().into_iter().collect(),
15162                        cx,
15163                    );
15164                });
15165            })
15166        }
15167    }
15168
15169    fn stop_language_server(
15170        &mut self,
15171        _: &StopLanguageServer,
15172        _: &mut Window,
15173        cx: &mut Context<Self>,
15174    ) {
15175        if let Some(project) = self.project.clone() {
15176            self.buffer.update(cx, |multi_buffer, cx| {
15177                project.update(cx, |project, cx| {
15178                    project.stop_language_servers_for_buffers(
15179                        multi_buffer.all_buffers().into_iter().collect(),
15180                        cx,
15181                    );
15182                    cx.emit(project::Event::RefreshInlayHints);
15183                });
15184            });
15185        }
15186    }
15187
15188    fn cancel_language_server_work(
15189        workspace: &mut Workspace,
15190        _: &actions::CancelLanguageServerWork,
15191        _: &mut Window,
15192        cx: &mut Context<Workspace>,
15193    ) {
15194        let project = workspace.project();
15195        let buffers = workspace
15196            .active_item(cx)
15197            .and_then(|item| item.act_as::<Editor>(cx))
15198            .map_or(HashSet::default(), |editor| {
15199                editor.read(cx).buffer.read(cx).all_buffers()
15200            });
15201        project.update(cx, |project, cx| {
15202            project.cancel_language_server_work_for_buffers(buffers, cx);
15203        });
15204    }
15205
15206    fn show_character_palette(
15207        &mut self,
15208        _: &ShowCharacterPalette,
15209        window: &mut Window,
15210        _: &mut Context<Self>,
15211    ) {
15212        window.show_character_palette();
15213    }
15214
15215    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15216        if self.mode.is_minimap() {
15217            return;
15218        }
15219
15220        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15221            let buffer = self.buffer.read(cx).snapshot(cx);
15222            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15223            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15224            let is_valid = buffer
15225                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15226                .any(|entry| {
15227                    entry.diagnostic.is_primary
15228                        && !entry.range.is_empty()
15229                        && entry.range.start == primary_range_start
15230                        && entry.diagnostic.message == active_diagnostics.active_message
15231                });
15232
15233            if !is_valid {
15234                self.dismiss_diagnostics(cx);
15235            }
15236        }
15237    }
15238
15239    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15240        match &self.active_diagnostics {
15241            ActiveDiagnostic::Group(group) => Some(group),
15242            _ => None,
15243        }
15244    }
15245
15246    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15247        self.dismiss_diagnostics(cx);
15248        self.active_diagnostics = ActiveDiagnostic::All;
15249    }
15250
15251    fn activate_diagnostics(
15252        &mut self,
15253        buffer_id: BufferId,
15254        diagnostic: DiagnosticEntry<usize>,
15255        window: &mut Window,
15256        cx: &mut Context<Self>,
15257    ) {
15258        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15259            return;
15260        }
15261        self.dismiss_diagnostics(cx);
15262        let snapshot = self.snapshot(window, cx);
15263        let buffer = self.buffer.read(cx).snapshot(cx);
15264        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15265            return;
15266        };
15267
15268        let diagnostic_group = buffer
15269            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15270            .collect::<Vec<_>>();
15271
15272        let blocks =
15273            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15274
15275        let blocks = self.display_map.update(cx, |display_map, cx| {
15276            display_map.insert_blocks(blocks, cx).into_iter().collect()
15277        });
15278        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15279            active_range: buffer.anchor_before(diagnostic.range.start)
15280                ..buffer.anchor_after(diagnostic.range.end),
15281            active_message: diagnostic.diagnostic.message.clone(),
15282            group_id: diagnostic.diagnostic.group_id,
15283            blocks,
15284        });
15285        cx.notify();
15286    }
15287
15288    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15289        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15290            return;
15291        };
15292
15293        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15294        if let ActiveDiagnostic::Group(group) = prev {
15295            self.display_map.update(cx, |display_map, cx| {
15296                display_map.remove_blocks(group.blocks, cx);
15297            });
15298            cx.notify();
15299        }
15300    }
15301
15302    /// Disable inline diagnostics rendering for this editor.
15303    pub fn disable_inline_diagnostics(&mut self) {
15304        self.inline_diagnostics_enabled = false;
15305        self.inline_diagnostics_update = Task::ready(());
15306        self.inline_diagnostics.clear();
15307    }
15308
15309    pub fn diagnostics_enabled(&self) -> bool {
15310        self.mode.is_full()
15311    }
15312
15313    pub fn inline_diagnostics_enabled(&self) -> bool {
15314        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15315    }
15316
15317    pub fn show_inline_diagnostics(&self) -> bool {
15318        self.show_inline_diagnostics
15319    }
15320
15321    pub fn toggle_inline_diagnostics(
15322        &mut self,
15323        _: &ToggleInlineDiagnostics,
15324        window: &mut Window,
15325        cx: &mut Context<Editor>,
15326    ) {
15327        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15328        self.refresh_inline_diagnostics(false, window, cx);
15329    }
15330
15331    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15332        self.diagnostics_max_severity = severity;
15333        self.display_map.update(cx, |display_map, _| {
15334            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15335        });
15336    }
15337
15338    pub fn toggle_diagnostics(
15339        &mut self,
15340        _: &ToggleDiagnostics,
15341        window: &mut Window,
15342        cx: &mut Context<Editor>,
15343    ) {
15344        if !self.diagnostics_enabled() {
15345            return;
15346        }
15347
15348        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15349            EditorSettings::get_global(cx)
15350                .diagnostics_max_severity
15351                .filter(|severity| severity != &DiagnosticSeverity::Off)
15352                .unwrap_or(DiagnosticSeverity::Hint)
15353        } else {
15354            DiagnosticSeverity::Off
15355        };
15356        self.set_max_diagnostics_severity(new_severity, cx);
15357        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15358            self.active_diagnostics = ActiveDiagnostic::None;
15359            self.inline_diagnostics_update = Task::ready(());
15360            self.inline_diagnostics.clear();
15361        } else {
15362            self.refresh_inline_diagnostics(false, window, cx);
15363        }
15364
15365        cx.notify();
15366    }
15367
15368    pub fn toggle_minimap(
15369        &mut self,
15370        _: &ToggleMinimap,
15371        window: &mut Window,
15372        cx: &mut Context<Editor>,
15373    ) {
15374        if self.supports_minimap(cx) {
15375            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15376        }
15377    }
15378
15379    fn refresh_inline_diagnostics(
15380        &mut self,
15381        debounce: bool,
15382        window: &mut Window,
15383        cx: &mut Context<Self>,
15384    ) {
15385        let max_severity = ProjectSettings::get_global(cx)
15386            .diagnostics
15387            .inline
15388            .max_severity
15389            .unwrap_or(self.diagnostics_max_severity);
15390
15391        if self.mode.is_minimap()
15392            || !self.inline_diagnostics_enabled()
15393            || !self.show_inline_diagnostics
15394            || max_severity == DiagnosticSeverity::Off
15395        {
15396            self.inline_diagnostics_update = Task::ready(());
15397            self.inline_diagnostics.clear();
15398            return;
15399        }
15400
15401        let debounce_ms = ProjectSettings::get_global(cx)
15402            .diagnostics
15403            .inline
15404            .update_debounce_ms;
15405        let debounce = if debounce && debounce_ms > 0 {
15406            Some(Duration::from_millis(debounce_ms))
15407        } else {
15408            None
15409        };
15410        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15411            let editor = editor.upgrade().unwrap();
15412
15413            if let Some(debounce) = debounce {
15414                cx.background_executor().timer(debounce).await;
15415            }
15416            let Some(snapshot) = editor
15417                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15418                .ok()
15419            else {
15420                return;
15421            };
15422
15423            let new_inline_diagnostics = cx
15424                .background_spawn(async move {
15425                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15426                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15427                        let message = diagnostic_entry
15428                            .diagnostic
15429                            .message
15430                            .split_once('\n')
15431                            .map(|(line, _)| line)
15432                            .map(SharedString::new)
15433                            .unwrap_or_else(|| {
15434                                SharedString::from(diagnostic_entry.diagnostic.message)
15435                            });
15436                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15437                        let (Ok(i) | Err(i)) = inline_diagnostics
15438                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15439                        inline_diagnostics.insert(
15440                            i,
15441                            (
15442                                start_anchor,
15443                                InlineDiagnostic {
15444                                    message,
15445                                    group_id: diagnostic_entry.diagnostic.group_id,
15446                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15447                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15448                                    severity: diagnostic_entry.diagnostic.severity,
15449                                },
15450                            ),
15451                        );
15452                    }
15453                    inline_diagnostics
15454                })
15455                .await;
15456
15457            editor
15458                .update(cx, |editor, cx| {
15459                    editor.inline_diagnostics = new_inline_diagnostics;
15460                    cx.notify();
15461                })
15462                .ok();
15463        });
15464    }
15465
15466    pub fn set_selections_from_remote(
15467        &mut self,
15468        selections: Vec<Selection<Anchor>>,
15469        pending_selection: Option<Selection<Anchor>>,
15470        window: &mut Window,
15471        cx: &mut Context<Self>,
15472    ) {
15473        let old_cursor_position = self.selections.newest_anchor().head();
15474        self.selections.change_with(cx, |s| {
15475            s.select_anchors(selections);
15476            if let Some(pending_selection) = pending_selection {
15477                s.set_pending(pending_selection, SelectMode::Character);
15478            } else {
15479                s.clear_pending();
15480            }
15481        });
15482        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15483    }
15484
15485    fn push_to_selection_history(&mut self) {
15486        self.selection_history.push(SelectionHistoryEntry {
15487            selections: self.selections.disjoint_anchors(),
15488            select_next_state: self.select_next_state.clone(),
15489            select_prev_state: self.select_prev_state.clone(),
15490            add_selections_state: self.add_selections_state.clone(),
15491        });
15492    }
15493
15494    pub fn transact(
15495        &mut self,
15496        window: &mut Window,
15497        cx: &mut Context<Self>,
15498        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15499    ) -> Option<TransactionId> {
15500        self.start_transaction_at(Instant::now(), window, cx);
15501        update(self, window, cx);
15502        self.end_transaction_at(Instant::now(), cx)
15503    }
15504
15505    pub fn start_transaction_at(
15506        &mut self,
15507        now: Instant,
15508        window: &mut Window,
15509        cx: &mut Context<Self>,
15510    ) {
15511        self.end_selection(window, cx);
15512        if let Some(tx_id) = self
15513            .buffer
15514            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15515        {
15516            self.selection_history
15517                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15518            cx.emit(EditorEvent::TransactionBegun {
15519                transaction_id: tx_id,
15520            })
15521        }
15522    }
15523
15524    pub fn end_transaction_at(
15525        &mut self,
15526        now: Instant,
15527        cx: &mut Context<Self>,
15528    ) -> Option<TransactionId> {
15529        if let Some(transaction_id) = self
15530            .buffer
15531            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15532        {
15533            if let Some((_, end_selections)) =
15534                self.selection_history.transaction_mut(transaction_id)
15535            {
15536                *end_selections = Some(self.selections.disjoint_anchors());
15537            } else {
15538                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15539            }
15540
15541            cx.emit(EditorEvent::Edited { transaction_id });
15542            Some(transaction_id)
15543        } else {
15544            None
15545        }
15546    }
15547
15548    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15549        if self.selection_mark_mode {
15550            self.change_selections(None, window, cx, |s| {
15551                s.move_with(|_, sel| {
15552                    sel.collapse_to(sel.head(), SelectionGoal::None);
15553                });
15554            })
15555        }
15556        self.selection_mark_mode = true;
15557        cx.notify();
15558    }
15559
15560    pub fn swap_selection_ends(
15561        &mut self,
15562        _: &actions::SwapSelectionEnds,
15563        window: &mut Window,
15564        cx: &mut Context<Self>,
15565    ) {
15566        self.change_selections(None, window, cx, |s| {
15567            s.move_with(|_, sel| {
15568                if sel.start != sel.end {
15569                    sel.reversed = !sel.reversed
15570                }
15571            });
15572        });
15573        self.request_autoscroll(Autoscroll::newest(), cx);
15574        cx.notify();
15575    }
15576
15577    pub fn toggle_fold(
15578        &mut self,
15579        _: &actions::ToggleFold,
15580        window: &mut Window,
15581        cx: &mut Context<Self>,
15582    ) {
15583        if self.is_singleton(cx) {
15584            let selection = self.selections.newest::<Point>(cx);
15585
15586            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15587            let range = if selection.is_empty() {
15588                let point = selection.head().to_display_point(&display_map);
15589                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15590                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15591                    .to_point(&display_map);
15592                start..end
15593            } else {
15594                selection.range()
15595            };
15596            if display_map.folds_in_range(range).next().is_some() {
15597                self.unfold_lines(&Default::default(), window, cx)
15598            } else {
15599                self.fold(&Default::default(), window, cx)
15600            }
15601        } else {
15602            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15603            let buffer_ids: HashSet<_> = self
15604                .selections
15605                .disjoint_anchor_ranges()
15606                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15607                .collect();
15608
15609            let should_unfold = buffer_ids
15610                .iter()
15611                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15612
15613            for buffer_id in buffer_ids {
15614                if should_unfold {
15615                    self.unfold_buffer(buffer_id, cx);
15616                } else {
15617                    self.fold_buffer(buffer_id, cx);
15618                }
15619            }
15620        }
15621    }
15622
15623    pub fn toggle_fold_recursive(
15624        &mut self,
15625        _: &actions::ToggleFoldRecursive,
15626        window: &mut Window,
15627        cx: &mut Context<Self>,
15628    ) {
15629        let selection = self.selections.newest::<Point>(cx);
15630
15631        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15632        let range = if selection.is_empty() {
15633            let point = selection.head().to_display_point(&display_map);
15634            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15635            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15636                .to_point(&display_map);
15637            start..end
15638        } else {
15639            selection.range()
15640        };
15641        if display_map.folds_in_range(range).next().is_some() {
15642            self.unfold_recursive(&Default::default(), window, cx)
15643        } else {
15644            self.fold_recursive(&Default::default(), window, cx)
15645        }
15646    }
15647
15648    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15649        if self.is_singleton(cx) {
15650            let mut to_fold = Vec::new();
15651            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15652            let selections = self.selections.all_adjusted(cx);
15653
15654            for selection in selections {
15655                let range = selection.range().sorted();
15656                let buffer_start_row = range.start.row;
15657
15658                if range.start.row != range.end.row {
15659                    let mut found = false;
15660                    let mut row = range.start.row;
15661                    while row <= range.end.row {
15662                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15663                        {
15664                            found = true;
15665                            row = crease.range().end.row + 1;
15666                            to_fold.push(crease);
15667                        } else {
15668                            row += 1
15669                        }
15670                    }
15671                    if found {
15672                        continue;
15673                    }
15674                }
15675
15676                for row in (0..=range.start.row).rev() {
15677                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15678                        if crease.range().end.row >= buffer_start_row {
15679                            to_fold.push(crease);
15680                            if row <= range.start.row {
15681                                break;
15682                            }
15683                        }
15684                    }
15685                }
15686            }
15687
15688            self.fold_creases(to_fold, true, window, cx);
15689        } else {
15690            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15691            let buffer_ids = self
15692                .selections
15693                .disjoint_anchor_ranges()
15694                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15695                .collect::<HashSet<_>>();
15696            for buffer_id in buffer_ids {
15697                self.fold_buffer(buffer_id, cx);
15698            }
15699        }
15700    }
15701
15702    fn fold_at_level(
15703        &mut self,
15704        fold_at: &FoldAtLevel,
15705        window: &mut Window,
15706        cx: &mut Context<Self>,
15707    ) {
15708        if !self.buffer.read(cx).is_singleton() {
15709            return;
15710        }
15711
15712        let fold_at_level = fold_at.0;
15713        let snapshot = self.buffer.read(cx).snapshot(cx);
15714        let mut to_fold = Vec::new();
15715        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15716
15717        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15718            while start_row < end_row {
15719                match self
15720                    .snapshot(window, cx)
15721                    .crease_for_buffer_row(MultiBufferRow(start_row))
15722                {
15723                    Some(crease) => {
15724                        let nested_start_row = crease.range().start.row + 1;
15725                        let nested_end_row = crease.range().end.row;
15726
15727                        if current_level < fold_at_level {
15728                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15729                        } else if current_level == fold_at_level {
15730                            to_fold.push(crease);
15731                        }
15732
15733                        start_row = nested_end_row + 1;
15734                    }
15735                    None => start_row += 1,
15736                }
15737            }
15738        }
15739
15740        self.fold_creases(to_fold, true, window, cx);
15741    }
15742
15743    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15744        if self.buffer.read(cx).is_singleton() {
15745            let mut fold_ranges = Vec::new();
15746            let snapshot = self.buffer.read(cx).snapshot(cx);
15747
15748            for row in 0..snapshot.max_row().0 {
15749                if let Some(foldable_range) = self
15750                    .snapshot(window, cx)
15751                    .crease_for_buffer_row(MultiBufferRow(row))
15752                {
15753                    fold_ranges.push(foldable_range);
15754                }
15755            }
15756
15757            self.fold_creases(fold_ranges, true, window, cx);
15758        } else {
15759            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15760                editor
15761                    .update_in(cx, |editor, _, cx| {
15762                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15763                            editor.fold_buffer(buffer_id, cx);
15764                        }
15765                    })
15766                    .ok();
15767            });
15768        }
15769    }
15770
15771    pub fn fold_function_bodies(
15772        &mut self,
15773        _: &actions::FoldFunctionBodies,
15774        window: &mut Window,
15775        cx: &mut Context<Self>,
15776    ) {
15777        let snapshot = self.buffer.read(cx).snapshot(cx);
15778
15779        let ranges = snapshot
15780            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15781            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15782            .collect::<Vec<_>>();
15783
15784        let creases = ranges
15785            .into_iter()
15786            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15787            .collect();
15788
15789        self.fold_creases(creases, true, window, cx);
15790    }
15791
15792    pub fn fold_recursive(
15793        &mut self,
15794        _: &actions::FoldRecursive,
15795        window: &mut Window,
15796        cx: &mut Context<Self>,
15797    ) {
15798        let mut to_fold = Vec::new();
15799        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15800        let selections = self.selections.all_adjusted(cx);
15801
15802        for selection in selections {
15803            let range = selection.range().sorted();
15804            let buffer_start_row = range.start.row;
15805
15806            if range.start.row != range.end.row {
15807                let mut found = false;
15808                for row in range.start.row..=range.end.row {
15809                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15810                        found = true;
15811                        to_fold.push(crease);
15812                    }
15813                }
15814                if found {
15815                    continue;
15816                }
15817            }
15818
15819            for row in (0..=range.start.row).rev() {
15820                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15821                    if crease.range().end.row >= buffer_start_row {
15822                        to_fold.push(crease);
15823                    } else {
15824                        break;
15825                    }
15826                }
15827            }
15828        }
15829
15830        self.fold_creases(to_fold, true, window, cx);
15831    }
15832
15833    pub fn fold_at(
15834        &mut self,
15835        buffer_row: MultiBufferRow,
15836        window: &mut Window,
15837        cx: &mut Context<Self>,
15838    ) {
15839        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15840
15841        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15842            let autoscroll = self
15843                .selections
15844                .all::<Point>(cx)
15845                .iter()
15846                .any(|selection| crease.range().overlaps(&selection.range()));
15847
15848            self.fold_creases(vec![crease], autoscroll, window, cx);
15849        }
15850    }
15851
15852    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15853        if self.is_singleton(cx) {
15854            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15855            let buffer = &display_map.buffer_snapshot;
15856            let selections = self.selections.all::<Point>(cx);
15857            let ranges = selections
15858                .iter()
15859                .map(|s| {
15860                    let range = s.display_range(&display_map).sorted();
15861                    let mut start = range.start.to_point(&display_map);
15862                    let mut end = range.end.to_point(&display_map);
15863                    start.column = 0;
15864                    end.column = buffer.line_len(MultiBufferRow(end.row));
15865                    start..end
15866                })
15867                .collect::<Vec<_>>();
15868
15869            self.unfold_ranges(&ranges, true, true, cx);
15870        } else {
15871            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15872            let buffer_ids = self
15873                .selections
15874                .disjoint_anchor_ranges()
15875                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15876                .collect::<HashSet<_>>();
15877            for buffer_id in buffer_ids {
15878                self.unfold_buffer(buffer_id, cx);
15879            }
15880        }
15881    }
15882
15883    pub fn unfold_recursive(
15884        &mut self,
15885        _: &UnfoldRecursive,
15886        _window: &mut Window,
15887        cx: &mut Context<Self>,
15888    ) {
15889        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15890        let selections = self.selections.all::<Point>(cx);
15891        let ranges = selections
15892            .iter()
15893            .map(|s| {
15894                let mut range = s.display_range(&display_map).sorted();
15895                *range.start.column_mut() = 0;
15896                *range.end.column_mut() = display_map.line_len(range.end.row());
15897                let start = range.start.to_point(&display_map);
15898                let end = range.end.to_point(&display_map);
15899                start..end
15900            })
15901            .collect::<Vec<_>>();
15902
15903        self.unfold_ranges(&ranges, true, true, cx);
15904    }
15905
15906    pub fn unfold_at(
15907        &mut self,
15908        buffer_row: MultiBufferRow,
15909        _window: &mut Window,
15910        cx: &mut Context<Self>,
15911    ) {
15912        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15913
15914        let intersection_range = Point::new(buffer_row.0, 0)
15915            ..Point::new(
15916                buffer_row.0,
15917                display_map.buffer_snapshot.line_len(buffer_row),
15918            );
15919
15920        let autoscroll = self
15921            .selections
15922            .all::<Point>(cx)
15923            .iter()
15924            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15925
15926        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15927    }
15928
15929    pub fn unfold_all(
15930        &mut self,
15931        _: &actions::UnfoldAll,
15932        _window: &mut Window,
15933        cx: &mut Context<Self>,
15934    ) {
15935        if self.buffer.read(cx).is_singleton() {
15936            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15937            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15938        } else {
15939            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15940                editor
15941                    .update(cx, |editor, cx| {
15942                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15943                            editor.unfold_buffer(buffer_id, cx);
15944                        }
15945                    })
15946                    .ok();
15947            });
15948        }
15949    }
15950
15951    pub fn fold_selected_ranges(
15952        &mut self,
15953        _: &FoldSelectedRanges,
15954        window: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) {
15957        let selections = self.selections.all_adjusted(cx);
15958        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15959        let ranges = selections
15960            .into_iter()
15961            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15962            .collect::<Vec<_>>();
15963        self.fold_creases(ranges, true, window, cx);
15964    }
15965
15966    pub fn fold_ranges<T: ToOffset + Clone>(
15967        &mut self,
15968        ranges: Vec<Range<T>>,
15969        auto_scroll: bool,
15970        window: &mut Window,
15971        cx: &mut Context<Self>,
15972    ) {
15973        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15974        let ranges = ranges
15975            .into_iter()
15976            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
15977            .collect::<Vec<_>>();
15978        self.fold_creases(ranges, auto_scroll, window, cx);
15979    }
15980
15981    pub fn fold_creases<T: ToOffset + Clone>(
15982        &mut self,
15983        creases: Vec<Crease<T>>,
15984        auto_scroll: bool,
15985        _window: &mut Window,
15986        cx: &mut Context<Self>,
15987    ) {
15988        if creases.is_empty() {
15989            return;
15990        }
15991
15992        let mut buffers_affected = HashSet::default();
15993        let multi_buffer = self.buffer().read(cx);
15994        for crease in &creases {
15995            if let Some((_, buffer, _)) =
15996                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
15997            {
15998                buffers_affected.insert(buffer.read(cx).remote_id());
15999            };
16000        }
16001
16002        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16003
16004        if auto_scroll {
16005            self.request_autoscroll(Autoscroll::fit(), cx);
16006        }
16007
16008        cx.notify();
16009
16010        self.scrollbar_marker_state.dirty = true;
16011        self.folds_did_change(cx);
16012    }
16013
16014    /// Removes any folds whose ranges intersect any of the given ranges.
16015    pub fn unfold_ranges<T: ToOffset + Clone>(
16016        &mut self,
16017        ranges: &[Range<T>],
16018        inclusive: bool,
16019        auto_scroll: bool,
16020        cx: &mut Context<Self>,
16021    ) {
16022        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16023            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16024        });
16025        self.folds_did_change(cx);
16026    }
16027
16028    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16029        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16030            return;
16031        }
16032        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16033        self.display_map.update(cx, |display_map, cx| {
16034            display_map.fold_buffers([buffer_id], cx)
16035        });
16036        cx.emit(EditorEvent::BufferFoldToggled {
16037            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16038            folded: true,
16039        });
16040        cx.notify();
16041    }
16042
16043    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16044        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16045            return;
16046        }
16047        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16048        self.display_map.update(cx, |display_map, cx| {
16049            display_map.unfold_buffers([buffer_id], cx);
16050        });
16051        cx.emit(EditorEvent::BufferFoldToggled {
16052            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16053            folded: false,
16054        });
16055        cx.notify();
16056    }
16057
16058    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16059        self.display_map.read(cx).is_buffer_folded(buffer)
16060    }
16061
16062    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16063        self.display_map.read(cx).folded_buffers()
16064    }
16065
16066    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16067        self.display_map.update(cx, |display_map, cx| {
16068            display_map.disable_header_for_buffer(buffer_id, cx);
16069        });
16070        cx.notify();
16071    }
16072
16073    /// Removes any folds with the given ranges.
16074    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16075        &mut self,
16076        ranges: &[Range<T>],
16077        type_id: TypeId,
16078        auto_scroll: bool,
16079        cx: &mut Context<Self>,
16080    ) {
16081        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16082            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16083        });
16084        self.folds_did_change(cx);
16085    }
16086
16087    fn remove_folds_with<T: ToOffset + Clone>(
16088        &mut self,
16089        ranges: &[Range<T>],
16090        auto_scroll: bool,
16091        cx: &mut Context<Self>,
16092        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16093    ) {
16094        if ranges.is_empty() {
16095            return;
16096        }
16097
16098        let mut buffers_affected = HashSet::default();
16099        let multi_buffer = self.buffer().read(cx);
16100        for range in ranges {
16101            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16102                buffers_affected.insert(buffer.read(cx).remote_id());
16103            };
16104        }
16105
16106        self.display_map.update(cx, update);
16107
16108        if auto_scroll {
16109            self.request_autoscroll(Autoscroll::fit(), cx);
16110        }
16111
16112        cx.notify();
16113        self.scrollbar_marker_state.dirty = true;
16114        self.active_indent_guides_state.dirty = true;
16115    }
16116
16117    pub fn update_fold_widths(
16118        &mut self,
16119        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16120        cx: &mut Context<Self>,
16121    ) -> bool {
16122        self.display_map
16123            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16124    }
16125
16126    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16127        self.display_map.read(cx).fold_placeholder.clone()
16128    }
16129
16130    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16131        self.buffer.update(cx, |buffer, cx| {
16132            buffer.set_all_diff_hunks_expanded(cx);
16133        });
16134    }
16135
16136    pub fn expand_all_diff_hunks(
16137        &mut self,
16138        _: &ExpandAllDiffHunks,
16139        _window: &mut Window,
16140        cx: &mut Context<Self>,
16141    ) {
16142        self.buffer.update(cx, |buffer, cx| {
16143            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16144        });
16145    }
16146
16147    pub fn toggle_selected_diff_hunks(
16148        &mut self,
16149        _: &ToggleSelectedDiffHunks,
16150        _window: &mut Window,
16151        cx: &mut Context<Self>,
16152    ) {
16153        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16154        self.toggle_diff_hunks_in_ranges(ranges, cx);
16155    }
16156
16157    pub fn diff_hunks_in_ranges<'a>(
16158        &'a self,
16159        ranges: &'a [Range<Anchor>],
16160        buffer: &'a MultiBufferSnapshot,
16161    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16162        ranges.iter().flat_map(move |range| {
16163            let end_excerpt_id = range.end.excerpt_id;
16164            let range = range.to_point(buffer);
16165            let mut peek_end = range.end;
16166            if range.end.row < buffer.max_row().0 {
16167                peek_end = Point::new(range.end.row + 1, 0);
16168            }
16169            buffer
16170                .diff_hunks_in_range(range.start..peek_end)
16171                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16172        })
16173    }
16174
16175    pub fn has_stageable_diff_hunks_in_ranges(
16176        &self,
16177        ranges: &[Range<Anchor>],
16178        snapshot: &MultiBufferSnapshot,
16179    ) -> bool {
16180        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16181        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16182    }
16183
16184    pub fn toggle_staged_selected_diff_hunks(
16185        &mut self,
16186        _: &::git::ToggleStaged,
16187        _: &mut Window,
16188        cx: &mut Context<Self>,
16189    ) {
16190        let snapshot = self.buffer.read(cx).snapshot(cx);
16191        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16192        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16193        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16194    }
16195
16196    pub fn set_render_diff_hunk_controls(
16197        &mut self,
16198        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16199        cx: &mut Context<Self>,
16200    ) {
16201        self.render_diff_hunk_controls = render_diff_hunk_controls;
16202        cx.notify();
16203    }
16204
16205    pub fn stage_and_next(
16206        &mut self,
16207        _: &::git::StageAndNext,
16208        window: &mut Window,
16209        cx: &mut Context<Self>,
16210    ) {
16211        self.do_stage_or_unstage_and_next(true, window, cx);
16212    }
16213
16214    pub fn unstage_and_next(
16215        &mut self,
16216        _: &::git::UnstageAndNext,
16217        window: &mut Window,
16218        cx: &mut Context<Self>,
16219    ) {
16220        self.do_stage_or_unstage_and_next(false, window, cx);
16221    }
16222
16223    pub fn stage_or_unstage_diff_hunks(
16224        &mut self,
16225        stage: bool,
16226        ranges: Vec<Range<Anchor>>,
16227        cx: &mut Context<Self>,
16228    ) {
16229        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16230        cx.spawn(async move |this, cx| {
16231            task.await?;
16232            this.update(cx, |this, cx| {
16233                let snapshot = this.buffer.read(cx).snapshot(cx);
16234                let chunk_by = this
16235                    .diff_hunks_in_ranges(&ranges, &snapshot)
16236                    .chunk_by(|hunk| hunk.buffer_id);
16237                for (buffer_id, hunks) in &chunk_by {
16238                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16239                }
16240            })
16241        })
16242        .detach_and_log_err(cx);
16243    }
16244
16245    fn save_buffers_for_ranges_if_needed(
16246        &mut self,
16247        ranges: &[Range<Anchor>],
16248        cx: &mut Context<Editor>,
16249    ) -> Task<Result<()>> {
16250        let multibuffer = self.buffer.read(cx);
16251        let snapshot = multibuffer.read(cx);
16252        let buffer_ids: HashSet<_> = ranges
16253            .iter()
16254            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16255            .collect();
16256        drop(snapshot);
16257
16258        let mut buffers = HashSet::default();
16259        for buffer_id in buffer_ids {
16260            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16261                let buffer = buffer_entity.read(cx);
16262                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16263                {
16264                    buffers.insert(buffer_entity);
16265                }
16266            }
16267        }
16268
16269        if let Some(project) = &self.project {
16270            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16271        } else {
16272            Task::ready(Ok(()))
16273        }
16274    }
16275
16276    fn do_stage_or_unstage_and_next(
16277        &mut self,
16278        stage: bool,
16279        window: &mut Window,
16280        cx: &mut Context<Self>,
16281    ) {
16282        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16283
16284        if ranges.iter().any(|range| range.start != range.end) {
16285            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16286            return;
16287        }
16288
16289        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16290        let snapshot = self.snapshot(window, cx);
16291        let position = self.selections.newest::<Point>(cx).head();
16292        let mut row = snapshot
16293            .buffer_snapshot
16294            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16295            .find(|hunk| hunk.row_range.start.0 > position.row)
16296            .map(|hunk| hunk.row_range.start);
16297
16298        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16299        // Outside of the project diff editor, wrap around to the beginning.
16300        if !all_diff_hunks_expanded {
16301            row = row.or_else(|| {
16302                snapshot
16303                    .buffer_snapshot
16304                    .diff_hunks_in_range(Point::zero()..position)
16305                    .find(|hunk| hunk.row_range.end.0 < position.row)
16306                    .map(|hunk| hunk.row_range.start)
16307            });
16308        }
16309
16310        if let Some(row) = row {
16311            let destination = Point::new(row.0, 0);
16312            let autoscroll = Autoscroll::center();
16313
16314            self.unfold_ranges(&[destination..destination], false, false, cx);
16315            self.change_selections(Some(autoscroll), window, cx, |s| {
16316                s.select_ranges([destination..destination]);
16317            });
16318        }
16319    }
16320
16321    fn do_stage_or_unstage(
16322        &self,
16323        stage: bool,
16324        buffer_id: BufferId,
16325        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16326        cx: &mut App,
16327    ) -> Option<()> {
16328        let project = self.project.as_ref()?;
16329        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16330        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16331        let buffer_snapshot = buffer.read(cx).snapshot();
16332        let file_exists = buffer_snapshot
16333            .file()
16334            .is_some_and(|file| file.disk_state().exists());
16335        diff.update(cx, |diff, cx| {
16336            diff.stage_or_unstage_hunks(
16337                stage,
16338                &hunks
16339                    .map(|hunk| buffer_diff::DiffHunk {
16340                        buffer_range: hunk.buffer_range,
16341                        diff_base_byte_range: hunk.diff_base_byte_range,
16342                        secondary_status: hunk.secondary_status,
16343                        range: Point::zero()..Point::zero(), // unused
16344                    })
16345                    .collect::<Vec<_>>(),
16346                &buffer_snapshot,
16347                file_exists,
16348                cx,
16349            )
16350        });
16351        None
16352    }
16353
16354    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16355        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16356        self.buffer
16357            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16358    }
16359
16360    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16361        self.buffer.update(cx, |buffer, cx| {
16362            let ranges = vec![Anchor::min()..Anchor::max()];
16363            if !buffer.all_diff_hunks_expanded()
16364                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16365            {
16366                buffer.collapse_diff_hunks(ranges, cx);
16367                true
16368            } else {
16369                false
16370            }
16371        })
16372    }
16373
16374    fn toggle_diff_hunks_in_ranges(
16375        &mut self,
16376        ranges: Vec<Range<Anchor>>,
16377        cx: &mut Context<Editor>,
16378    ) {
16379        self.buffer.update(cx, |buffer, cx| {
16380            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16381            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16382        })
16383    }
16384
16385    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16386        self.buffer.update(cx, |buffer, cx| {
16387            let snapshot = buffer.snapshot(cx);
16388            let excerpt_id = range.end.excerpt_id;
16389            let point_range = range.to_point(&snapshot);
16390            let expand = !buffer.single_hunk_is_expanded(range, cx);
16391            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16392        })
16393    }
16394
16395    pub(crate) fn apply_all_diff_hunks(
16396        &mut self,
16397        _: &ApplyAllDiffHunks,
16398        window: &mut Window,
16399        cx: &mut Context<Self>,
16400    ) {
16401        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16402
16403        let buffers = self.buffer.read(cx).all_buffers();
16404        for branch_buffer in buffers {
16405            branch_buffer.update(cx, |branch_buffer, cx| {
16406                branch_buffer.merge_into_base(Vec::new(), cx);
16407            });
16408        }
16409
16410        if let Some(project) = self.project.clone() {
16411            self.save(true, project, window, cx).detach_and_log_err(cx);
16412        }
16413    }
16414
16415    pub(crate) fn apply_selected_diff_hunks(
16416        &mut self,
16417        _: &ApplyDiffHunk,
16418        window: &mut Window,
16419        cx: &mut Context<Self>,
16420    ) {
16421        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16422        let snapshot = self.snapshot(window, cx);
16423        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16424        let mut ranges_by_buffer = HashMap::default();
16425        self.transact(window, cx, |editor, _window, cx| {
16426            for hunk in hunks {
16427                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16428                    ranges_by_buffer
16429                        .entry(buffer.clone())
16430                        .or_insert_with(Vec::new)
16431                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16432                }
16433            }
16434
16435            for (buffer, ranges) in ranges_by_buffer {
16436                buffer.update(cx, |buffer, cx| {
16437                    buffer.merge_into_base(ranges, cx);
16438                });
16439            }
16440        });
16441
16442        if let Some(project) = self.project.clone() {
16443            self.save(true, project, window, cx).detach_and_log_err(cx);
16444        }
16445    }
16446
16447    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16448        if hovered != self.gutter_hovered {
16449            self.gutter_hovered = hovered;
16450            cx.notify();
16451        }
16452    }
16453
16454    pub fn insert_blocks(
16455        &mut self,
16456        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16457        autoscroll: Option<Autoscroll>,
16458        cx: &mut Context<Self>,
16459    ) -> Vec<CustomBlockId> {
16460        let blocks = self
16461            .display_map
16462            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16463        if let Some(autoscroll) = autoscroll {
16464            self.request_autoscroll(autoscroll, cx);
16465        }
16466        cx.notify();
16467        blocks
16468    }
16469
16470    pub fn resize_blocks(
16471        &mut self,
16472        heights: HashMap<CustomBlockId, u32>,
16473        autoscroll: Option<Autoscroll>,
16474        cx: &mut Context<Self>,
16475    ) {
16476        self.display_map
16477            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16478        if let Some(autoscroll) = autoscroll {
16479            self.request_autoscroll(autoscroll, cx);
16480        }
16481        cx.notify();
16482    }
16483
16484    pub fn replace_blocks(
16485        &mut self,
16486        renderers: HashMap<CustomBlockId, RenderBlock>,
16487        autoscroll: Option<Autoscroll>,
16488        cx: &mut Context<Self>,
16489    ) {
16490        self.display_map
16491            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16492        if let Some(autoscroll) = autoscroll {
16493            self.request_autoscroll(autoscroll, cx);
16494        }
16495        cx.notify();
16496    }
16497
16498    pub fn remove_blocks(
16499        &mut self,
16500        block_ids: HashSet<CustomBlockId>,
16501        autoscroll: Option<Autoscroll>,
16502        cx: &mut Context<Self>,
16503    ) {
16504        self.display_map.update(cx, |display_map, cx| {
16505            display_map.remove_blocks(block_ids, cx)
16506        });
16507        if let Some(autoscroll) = autoscroll {
16508            self.request_autoscroll(autoscroll, cx);
16509        }
16510        cx.notify();
16511    }
16512
16513    pub fn row_for_block(
16514        &self,
16515        block_id: CustomBlockId,
16516        cx: &mut Context<Self>,
16517    ) -> Option<DisplayRow> {
16518        self.display_map
16519            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16520    }
16521
16522    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16523        self.focused_block = Some(focused_block);
16524    }
16525
16526    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16527        self.focused_block.take()
16528    }
16529
16530    pub fn insert_creases(
16531        &mut self,
16532        creases: impl IntoIterator<Item = Crease<Anchor>>,
16533        cx: &mut Context<Self>,
16534    ) -> Vec<CreaseId> {
16535        self.display_map
16536            .update(cx, |map, cx| map.insert_creases(creases, cx))
16537    }
16538
16539    pub fn remove_creases(
16540        &mut self,
16541        ids: impl IntoIterator<Item = CreaseId>,
16542        cx: &mut Context<Self>,
16543    ) -> Vec<(CreaseId, Range<Anchor>)> {
16544        self.display_map
16545            .update(cx, |map, cx| map.remove_creases(ids, cx))
16546    }
16547
16548    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16549        self.display_map
16550            .update(cx, |map, cx| map.snapshot(cx))
16551            .longest_row()
16552    }
16553
16554    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16555        self.display_map
16556            .update(cx, |map, cx| map.snapshot(cx))
16557            .max_point()
16558    }
16559
16560    pub fn text(&self, cx: &App) -> String {
16561        self.buffer.read(cx).read(cx).text()
16562    }
16563
16564    pub fn is_empty(&self, cx: &App) -> bool {
16565        self.buffer.read(cx).read(cx).is_empty()
16566    }
16567
16568    pub fn text_option(&self, cx: &App) -> Option<String> {
16569        let text = self.text(cx);
16570        let text = text.trim();
16571
16572        if text.is_empty() {
16573            return None;
16574        }
16575
16576        Some(text.to_string())
16577    }
16578
16579    pub fn set_text(
16580        &mut self,
16581        text: impl Into<Arc<str>>,
16582        window: &mut Window,
16583        cx: &mut Context<Self>,
16584    ) {
16585        self.transact(window, cx, |this, _, cx| {
16586            this.buffer
16587                .read(cx)
16588                .as_singleton()
16589                .expect("you can only call set_text on editors for singleton buffers")
16590                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16591        });
16592    }
16593
16594    pub fn display_text(&self, cx: &mut App) -> String {
16595        self.display_map
16596            .update(cx, |map, cx| map.snapshot(cx))
16597            .text()
16598    }
16599
16600    fn create_minimap(
16601        &self,
16602        minimap_settings: MinimapSettings,
16603        window: &mut Window,
16604        cx: &mut Context<Self>,
16605    ) -> Option<Entity<Self>> {
16606        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16607            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16608    }
16609
16610    fn initialize_new_minimap(
16611        &self,
16612        minimap_settings: MinimapSettings,
16613        window: &mut Window,
16614        cx: &mut Context<Self>,
16615    ) -> Entity<Self> {
16616        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16617
16618        let mut minimap = Editor::new_internal(
16619            EditorMode::Minimap {
16620                parent: cx.weak_entity(),
16621            },
16622            self.buffer.clone(),
16623            self.project.clone(),
16624            Some(self.display_map.clone()),
16625            window,
16626            cx,
16627        );
16628        minimap.scroll_manager.clone_state(&self.scroll_manager);
16629        minimap.set_text_style_refinement(TextStyleRefinement {
16630            font_size: Some(MINIMAP_FONT_SIZE),
16631            font_weight: Some(MINIMAP_FONT_WEIGHT),
16632            ..Default::default()
16633        });
16634        minimap.update_minimap_configuration(minimap_settings, cx);
16635        cx.new(|_| minimap)
16636    }
16637
16638    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16639        let current_line_highlight = minimap_settings
16640            .current_line_highlight
16641            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16642        self.set_current_line_highlight(Some(current_line_highlight));
16643    }
16644
16645    pub fn minimap(&self) -> Option<&Entity<Self>> {
16646        self.minimap
16647            .as_ref()
16648            .filter(|_| self.minimap_visibility.visible())
16649    }
16650
16651    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16652        let mut wrap_guides = smallvec::smallvec![];
16653
16654        if self.show_wrap_guides == Some(false) {
16655            return wrap_guides;
16656        }
16657
16658        let settings = self.buffer.read(cx).language_settings(cx);
16659        if settings.show_wrap_guides {
16660            match self.soft_wrap_mode(cx) {
16661                SoftWrap::Column(soft_wrap) => {
16662                    wrap_guides.push((soft_wrap as usize, true));
16663                }
16664                SoftWrap::Bounded(soft_wrap) => {
16665                    wrap_guides.push((soft_wrap as usize, true));
16666                }
16667                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16668            }
16669            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16670        }
16671
16672        wrap_guides
16673    }
16674
16675    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16676        let settings = self.buffer.read(cx).language_settings(cx);
16677        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16678        match mode {
16679            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16680                SoftWrap::None
16681            }
16682            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16683            language_settings::SoftWrap::PreferredLineLength => {
16684                SoftWrap::Column(settings.preferred_line_length)
16685            }
16686            language_settings::SoftWrap::Bounded => {
16687                SoftWrap::Bounded(settings.preferred_line_length)
16688            }
16689        }
16690    }
16691
16692    pub fn set_soft_wrap_mode(
16693        &mut self,
16694        mode: language_settings::SoftWrap,
16695
16696        cx: &mut Context<Self>,
16697    ) {
16698        self.soft_wrap_mode_override = Some(mode);
16699        cx.notify();
16700    }
16701
16702    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16703        self.hard_wrap = hard_wrap;
16704        cx.notify();
16705    }
16706
16707    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16708        self.text_style_refinement = Some(style);
16709    }
16710
16711    /// called by the Element so we know what style we were most recently rendered with.
16712    pub(crate) fn set_style(
16713        &mut self,
16714        style: EditorStyle,
16715        window: &mut Window,
16716        cx: &mut Context<Self>,
16717    ) {
16718        // We intentionally do not inform the display map about the minimap style
16719        // so that wrapping is not recalculated and stays consistent for the editor
16720        // and its linked minimap.
16721        if !self.mode.is_minimap() {
16722            let rem_size = window.rem_size();
16723            self.display_map.update(cx, |map, cx| {
16724                map.set_font(
16725                    style.text.font(),
16726                    style.text.font_size.to_pixels(rem_size),
16727                    cx,
16728                )
16729            });
16730        }
16731        self.style = Some(style);
16732    }
16733
16734    pub fn style(&self) -> Option<&EditorStyle> {
16735        self.style.as_ref()
16736    }
16737
16738    // Called by the element. This method is not designed to be called outside of the editor
16739    // element's layout code because it does not notify when rewrapping is computed synchronously.
16740    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16741        self.display_map
16742            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16743    }
16744
16745    pub fn set_soft_wrap(&mut self) {
16746        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16747    }
16748
16749    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16750        if self.soft_wrap_mode_override.is_some() {
16751            self.soft_wrap_mode_override.take();
16752        } else {
16753            let soft_wrap = match self.soft_wrap_mode(cx) {
16754                SoftWrap::GitDiff => return,
16755                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16756                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16757                    language_settings::SoftWrap::None
16758                }
16759            };
16760            self.soft_wrap_mode_override = Some(soft_wrap);
16761        }
16762        cx.notify();
16763    }
16764
16765    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16766        let Some(workspace) = self.workspace() else {
16767            return;
16768        };
16769        let fs = workspace.read(cx).app_state().fs.clone();
16770        let current_show = TabBarSettings::get_global(cx).show;
16771        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16772            setting.show = Some(!current_show);
16773        });
16774    }
16775
16776    pub fn toggle_indent_guides(
16777        &mut self,
16778        _: &ToggleIndentGuides,
16779        _: &mut Window,
16780        cx: &mut Context<Self>,
16781    ) {
16782        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16783            self.buffer
16784                .read(cx)
16785                .language_settings(cx)
16786                .indent_guides
16787                .enabled
16788        });
16789        self.show_indent_guides = Some(!currently_enabled);
16790        cx.notify();
16791    }
16792
16793    fn should_show_indent_guides(&self) -> Option<bool> {
16794        self.show_indent_guides
16795    }
16796
16797    pub fn toggle_line_numbers(
16798        &mut self,
16799        _: &ToggleLineNumbers,
16800        _: &mut Window,
16801        cx: &mut Context<Self>,
16802    ) {
16803        let mut editor_settings = EditorSettings::get_global(cx).clone();
16804        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16805        EditorSettings::override_global(editor_settings, cx);
16806    }
16807
16808    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16809        if let Some(show_line_numbers) = self.show_line_numbers {
16810            return show_line_numbers;
16811        }
16812        EditorSettings::get_global(cx).gutter.line_numbers
16813    }
16814
16815    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16816        self.use_relative_line_numbers
16817            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16818    }
16819
16820    pub fn toggle_relative_line_numbers(
16821        &mut self,
16822        _: &ToggleRelativeLineNumbers,
16823        _: &mut Window,
16824        cx: &mut Context<Self>,
16825    ) {
16826        let is_relative = self.should_use_relative_line_numbers(cx);
16827        self.set_relative_line_number(Some(!is_relative), cx)
16828    }
16829
16830    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16831        self.use_relative_line_numbers = is_relative;
16832        cx.notify();
16833    }
16834
16835    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16836        self.show_gutter = show_gutter;
16837        cx.notify();
16838    }
16839
16840    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16841        self.show_scrollbars = show_scrollbars;
16842        cx.notify();
16843    }
16844
16845    pub fn set_minimap_visibility(
16846        &mut self,
16847        minimap_visibility: MinimapVisibility,
16848        window: &mut Window,
16849        cx: &mut Context<Self>,
16850    ) {
16851        if self.minimap_visibility != minimap_visibility {
16852            if minimap_visibility.visible() && self.minimap.is_none() {
16853                let minimap_settings = EditorSettings::get_global(cx).minimap;
16854                self.minimap =
16855                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16856            }
16857            self.minimap_visibility = minimap_visibility;
16858            cx.notify();
16859        }
16860    }
16861
16862    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16863        self.set_show_scrollbars(false, cx);
16864        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16865    }
16866
16867    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16868        self.show_line_numbers = Some(show_line_numbers);
16869        cx.notify();
16870    }
16871
16872    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16873        self.disable_expand_excerpt_buttons = true;
16874        cx.notify();
16875    }
16876
16877    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16878        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16879        cx.notify();
16880    }
16881
16882    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16883        self.show_code_actions = Some(show_code_actions);
16884        cx.notify();
16885    }
16886
16887    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16888        self.show_runnables = Some(show_runnables);
16889        cx.notify();
16890    }
16891
16892    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16893        self.show_breakpoints = Some(show_breakpoints);
16894        cx.notify();
16895    }
16896
16897    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16898        if self.display_map.read(cx).masked != masked {
16899            self.display_map.update(cx, |map, _| map.masked = masked);
16900        }
16901        cx.notify()
16902    }
16903
16904    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16905        self.show_wrap_guides = Some(show_wrap_guides);
16906        cx.notify();
16907    }
16908
16909    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16910        self.show_indent_guides = Some(show_indent_guides);
16911        cx.notify();
16912    }
16913
16914    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16915        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16916            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16917                if let Some(dir) = file.abs_path(cx).parent() {
16918                    return Some(dir.to_owned());
16919                }
16920            }
16921
16922            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16923                return Some(project_path.path.to_path_buf());
16924            }
16925        }
16926
16927        None
16928    }
16929
16930    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16931        self.active_excerpt(cx)?
16932            .1
16933            .read(cx)
16934            .file()
16935            .and_then(|f| f.as_local())
16936    }
16937
16938    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16939        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16940            let buffer = buffer.read(cx);
16941            if let Some(project_path) = buffer.project_path(cx) {
16942                let project = self.project.as_ref()?.read(cx);
16943                project.absolute_path(&project_path, cx)
16944            } else {
16945                buffer
16946                    .file()
16947                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16948            }
16949        })
16950    }
16951
16952    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16953        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16954            let project_path = buffer.read(cx).project_path(cx)?;
16955            let project = self.project.as_ref()?.read(cx);
16956            let entry = project.entry_for_path(&project_path, cx)?;
16957            let path = entry.path.to_path_buf();
16958            Some(path)
16959        })
16960    }
16961
16962    pub fn reveal_in_finder(
16963        &mut self,
16964        _: &RevealInFileManager,
16965        _window: &mut Window,
16966        cx: &mut Context<Self>,
16967    ) {
16968        if let Some(target) = self.target_file(cx) {
16969            cx.reveal_path(&target.abs_path(cx));
16970        }
16971    }
16972
16973    pub fn copy_path(
16974        &mut self,
16975        _: &zed_actions::workspace::CopyPath,
16976        _window: &mut Window,
16977        cx: &mut Context<Self>,
16978    ) {
16979        if let Some(path) = self.target_file_abs_path(cx) {
16980            if let Some(path) = path.to_str() {
16981                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16982            }
16983        }
16984    }
16985
16986    pub fn copy_relative_path(
16987        &mut self,
16988        _: &zed_actions::workspace::CopyRelativePath,
16989        _window: &mut Window,
16990        cx: &mut Context<Self>,
16991    ) {
16992        if let Some(path) = self.target_file_path(cx) {
16993            if let Some(path) = path.to_str() {
16994                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
16995            }
16996        }
16997    }
16998
16999    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17000        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17001            buffer.read(cx).project_path(cx)
17002        } else {
17003            None
17004        }
17005    }
17006
17007    // Returns true if the editor handled a go-to-line request
17008    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17009        maybe!({
17010            let breakpoint_store = self.breakpoint_store.as_ref()?;
17011
17012            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17013            else {
17014                self.clear_row_highlights::<ActiveDebugLine>();
17015                return None;
17016            };
17017
17018            let position = active_stack_frame.position;
17019            let buffer_id = position.buffer_id?;
17020            let snapshot = self
17021                .project
17022                .as_ref()?
17023                .read(cx)
17024                .buffer_for_id(buffer_id, cx)?
17025                .read(cx)
17026                .snapshot();
17027
17028            let mut handled = false;
17029            for (id, ExcerptRange { context, .. }) in
17030                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17031            {
17032                if context.start.cmp(&position, &snapshot).is_ge()
17033                    || context.end.cmp(&position, &snapshot).is_lt()
17034                {
17035                    continue;
17036                }
17037                let snapshot = self.buffer.read(cx).snapshot(cx);
17038                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17039
17040                handled = true;
17041                self.clear_row_highlights::<ActiveDebugLine>();
17042
17043                self.go_to_line::<ActiveDebugLine>(
17044                    multibuffer_anchor,
17045                    Some(cx.theme().colors().editor_debugger_active_line_background),
17046                    window,
17047                    cx,
17048                );
17049
17050                cx.notify();
17051            }
17052
17053            handled.then_some(())
17054        })
17055        .is_some()
17056    }
17057
17058    pub fn copy_file_name_without_extension(
17059        &mut self,
17060        _: &CopyFileNameWithoutExtension,
17061        _: &mut Window,
17062        cx: &mut Context<Self>,
17063    ) {
17064        if let Some(file) = self.target_file(cx) {
17065            if let Some(file_stem) = file.path().file_stem() {
17066                if let Some(name) = file_stem.to_str() {
17067                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17068                }
17069            }
17070        }
17071    }
17072
17073    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17074        if let Some(file) = self.target_file(cx) {
17075            if let Some(file_name) = file.path().file_name() {
17076                if let Some(name) = file_name.to_str() {
17077                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17078                }
17079            }
17080        }
17081    }
17082
17083    pub fn toggle_git_blame(
17084        &mut self,
17085        _: &::git::Blame,
17086        window: &mut Window,
17087        cx: &mut Context<Self>,
17088    ) {
17089        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17090
17091        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17092            self.start_git_blame(true, window, cx);
17093        }
17094
17095        cx.notify();
17096    }
17097
17098    pub fn toggle_git_blame_inline(
17099        &mut self,
17100        _: &ToggleGitBlameInline,
17101        window: &mut Window,
17102        cx: &mut Context<Self>,
17103    ) {
17104        self.toggle_git_blame_inline_internal(true, window, cx);
17105        cx.notify();
17106    }
17107
17108    pub fn open_git_blame_commit(
17109        &mut self,
17110        _: &OpenGitBlameCommit,
17111        window: &mut Window,
17112        cx: &mut Context<Self>,
17113    ) {
17114        self.open_git_blame_commit_internal(window, cx);
17115    }
17116
17117    fn open_git_blame_commit_internal(
17118        &mut self,
17119        window: &mut Window,
17120        cx: &mut Context<Self>,
17121    ) -> Option<()> {
17122        let blame = self.blame.as_ref()?;
17123        let snapshot = self.snapshot(window, cx);
17124        let cursor = self.selections.newest::<Point>(cx).head();
17125        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17126        let blame_entry = blame
17127            .update(cx, |blame, cx| {
17128                blame
17129                    .blame_for_rows(
17130                        &[RowInfo {
17131                            buffer_id: Some(buffer.remote_id()),
17132                            buffer_row: Some(point.row),
17133                            ..Default::default()
17134                        }],
17135                        cx,
17136                    )
17137                    .next()
17138            })
17139            .flatten()?;
17140        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17141        let repo = blame.read(cx).repository(cx)?;
17142        let workspace = self.workspace()?.downgrade();
17143        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17144        None
17145    }
17146
17147    pub fn git_blame_inline_enabled(&self) -> bool {
17148        self.git_blame_inline_enabled
17149    }
17150
17151    pub fn toggle_selection_menu(
17152        &mut self,
17153        _: &ToggleSelectionMenu,
17154        _: &mut Window,
17155        cx: &mut Context<Self>,
17156    ) {
17157        self.show_selection_menu = self
17158            .show_selection_menu
17159            .map(|show_selections_menu| !show_selections_menu)
17160            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17161
17162        cx.notify();
17163    }
17164
17165    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17166        self.show_selection_menu
17167            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17168    }
17169
17170    fn start_git_blame(
17171        &mut self,
17172        user_triggered: bool,
17173        window: &mut Window,
17174        cx: &mut Context<Self>,
17175    ) {
17176        if let Some(project) = self.project.as_ref() {
17177            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17178                return;
17179            };
17180
17181            if buffer.read(cx).file().is_none() {
17182                return;
17183            }
17184
17185            let focused = self.focus_handle(cx).contains_focused(window, cx);
17186
17187            let project = project.clone();
17188            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17189            self.blame_subscription =
17190                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17191            self.blame = Some(blame);
17192        }
17193    }
17194
17195    fn toggle_git_blame_inline_internal(
17196        &mut self,
17197        user_triggered: bool,
17198        window: &mut Window,
17199        cx: &mut Context<Self>,
17200    ) {
17201        if self.git_blame_inline_enabled {
17202            self.git_blame_inline_enabled = false;
17203            self.show_git_blame_inline = false;
17204            self.show_git_blame_inline_delay_task.take();
17205        } else {
17206            self.git_blame_inline_enabled = true;
17207            self.start_git_blame_inline(user_triggered, window, cx);
17208        }
17209
17210        cx.notify();
17211    }
17212
17213    fn start_git_blame_inline(
17214        &mut self,
17215        user_triggered: bool,
17216        window: &mut Window,
17217        cx: &mut Context<Self>,
17218    ) {
17219        self.start_git_blame(user_triggered, window, cx);
17220
17221        if ProjectSettings::get_global(cx)
17222            .git
17223            .inline_blame_delay()
17224            .is_some()
17225        {
17226            self.start_inline_blame_timer(window, cx);
17227        } else {
17228            self.show_git_blame_inline = true
17229        }
17230    }
17231
17232    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17233        self.blame.as_ref()
17234    }
17235
17236    pub fn show_git_blame_gutter(&self) -> bool {
17237        self.show_git_blame_gutter
17238    }
17239
17240    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17241        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17242    }
17243
17244    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17245        self.show_git_blame_inline
17246            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17247            && !self.newest_selection_head_on_empty_line(cx)
17248            && self.has_blame_entries(cx)
17249    }
17250
17251    fn has_blame_entries(&self, cx: &App) -> bool {
17252        self.blame()
17253            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17254    }
17255
17256    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17257        let cursor_anchor = self.selections.newest_anchor().head();
17258
17259        let snapshot = self.buffer.read(cx).snapshot(cx);
17260        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17261
17262        snapshot.line_len(buffer_row) == 0
17263    }
17264
17265    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17266        let buffer_and_selection = maybe!({
17267            let selection = self.selections.newest::<Point>(cx);
17268            let selection_range = selection.range();
17269
17270            let multi_buffer = self.buffer().read(cx);
17271            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17272            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17273
17274            let (buffer, range, _) = if selection.reversed {
17275                buffer_ranges.first()
17276            } else {
17277                buffer_ranges.last()
17278            }?;
17279
17280            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17281                ..text::ToPoint::to_point(&range.end, &buffer).row;
17282            Some((
17283                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17284                selection,
17285            ))
17286        });
17287
17288        let Some((buffer, selection)) = buffer_and_selection else {
17289            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17290        };
17291
17292        let Some(project) = self.project.as_ref() else {
17293            return Task::ready(Err(anyhow!("editor does not have project")));
17294        };
17295
17296        project.update(cx, |project, cx| {
17297            project.get_permalink_to_line(&buffer, selection, cx)
17298        })
17299    }
17300
17301    pub fn copy_permalink_to_line(
17302        &mut self,
17303        _: &CopyPermalinkToLine,
17304        window: &mut Window,
17305        cx: &mut Context<Self>,
17306    ) {
17307        let permalink_task = self.get_permalink_to_line(cx);
17308        let workspace = self.workspace();
17309
17310        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17311            Ok(permalink) => {
17312                cx.update(|_, cx| {
17313                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17314                })
17315                .ok();
17316            }
17317            Err(err) => {
17318                let message = format!("Failed to copy permalink: {err}");
17319
17320                Err::<(), anyhow::Error>(err).log_err();
17321
17322                if let Some(workspace) = workspace {
17323                    workspace
17324                        .update_in(cx, |workspace, _, cx| {
17325                            struct CopyPermalinkToLine;
17326
17327                            workspace.show_toast(
17328                                Toast::new(
17329                                    NotificationId::unique::<CopyPermalinkToLine>(),
17330                                    message,
17331                                ),
17332                                cx,
17333                            )
17334                        })
17335                        .ok();
17336                }
17337            }
17338        })
17339        .detach();
17340    }
17341
17342    pub fn copy_file_location(
17343        &mut self,
17344        _: &CopyFileLocation,
17345        _: &mut Window,
17346        cx: &mut Context<Self>,
17347    ) {
17348        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17349        if let Some(file) = self.target_file(cx) {
17350            if let Some(path) = file.path().to_str() {
17351                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17352            }
17353        }
17354    }
17355
17356    pub fn open_permalink_to_line(
17357        &mut self,
17358        _: &OpenPermalinkToLine,
17359        window: &mut Window,
17360        cx: &mut Context<Self>,
17361    ) {
17362        let permalink_task = self.get_permalink_to_line(cx);
17363        let workspace = self.workspace();
17364
17365        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17366            Ok(permalink) => {
17367                cx.update(|_, cx| {
17368                    cx.open_url(permalink.as_ref());
17369                })
17370                .ok();
17371            }
17372            Err(err) => {
17373                let message = format!("Failed to open permalink: {err}");
17374
17375                Err::<(), anyhow::Error>(err).log_err();
17376
17377                if let Some(workspace) = workspace {
17378                    workspace
17379                        .update(cx, |workspace, cx| {
17380                            struct OpenPermalinkToLine;
17381
17382                            workspace.show_toast(
17383                                Toast::new(
17384                                    NotificationId::unique::<OpenPermalinkToLine>(),
17385                                    message,
17386                                ),
17387                                cx,
17388                            )
17389                        })
17390                        .ok();
17391                }
17392            }
17393        })
17394        .detach();
17395    }
17396
17397    pub fn insert_uuid_v4(
17398        &mut self,
17399        _: &InsertUuidV4,
17400        window: &mut Window,
17401        cx: &mut Context<Self>,
17402    ) {
17403        self.insert_uuid(UuidVersion::V4, window, cx);
17404    }
17405
17406    pub fn insert_uuid_v7(
17407        &mut self,
17408        _: &InsertUuidV7,
17409        window: &mut Window,
17410        cx: &mut Context<Self>,
17411    ) {
17412        self.insert_uuid(UuidVersion::V7, window, cx);
17413    }
17414
17415    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17416        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17417        self.transact(window, cx, |this, window, cx| {
17418            let edits = this
17419                .selections
17420                .all::<Point>(cx)
17421                .into_iter()
17422                .map(|selection| {
17423                    let uuid = match version {
17424                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17425                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17426                    };
17427
17428                    (selection.range(), uuid.to_string())
17429                });
17430            this.edit(edits, cx);
17431            this.refresh_inline_completion(true, false, window, cx);
17432        });
17433    }
17434
17435    pub fn open_selections_in_multibuffer(
17436        &mut self,
17437        _: &OpenSelectionsInMultibuffer,
17438        window: &mut Window,
17439        cx: &mut Context<Self>,
17440    ) {
17441        let multibuffer = self.buffer.read(cx);
17442
17443        let Some(buffer) = multibuffer.as_singleton() else {
17444            return;
17445        };
17446
17447        let Some(workspace) = self.workspace() else {
17448            return;
17449        };
17450
17451        let locations = self
17452            .selections
17453            .disjoint_anchors()
17454            .iter()
17455            .map(|range| Location {
17456                buffer: buffer.clone(),
17457                range: range.start.text_anchor..range.end.text_anchor,
17458            })
17459            .collect::<Vec<_>>();
17460
17461        let title = multibuffer.title(cx).to_string();
17462
17463        cx.spawn_in(window, async move |_, cx| {
17464            workspace.update_in(cx, |workspace, window, cx| {
17465                Self::open_locations_in_multibuffer(
17466                    workspace,
17467                    locations,
17468                    format!("Selections for '{title}'"),
17469                    false,
17470                    MultibufferSelectionMode::All,
17471                    window,
17472                    cx,
17473                );
17474            })
17475        })
17476        .detach();
17477    }
17478
17479    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17480    /// last highlight added will be used.
17481    ///
17482    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17483    pub fn highlight_rows<T: 'static>(
17484        &mut self,
17485        range: Range<Anchor>,
17486        color: Hsla,
17487        options: RowHighlightOptions,
17488        cx: &mut Context<Self>,
17489    ) {
17490        let snapshot = self.buffer().read(cx).snapshot(cx);
17491        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17492        let ix = row_highlights.binary_search_by(|highlight| {
17493            Ordering::Equal
17494                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17495                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17496        });
17497
17498        if let Err(mut ix) = ix {
17499            let index = post_inc(&mut self.highlight_order);
17500
17501            // If this range intersects with the preceding highlight, then merge it with
17502            // the preceding highlight. Otherwise insert a new highlight.
17503            let mut merged = false;
17504            if ix > 0 {
17505                let prev_highlight = &mut row_highlights[ix - 1];
17506                if prev_highlight
17507                    .range
17508                    .end
17509                    .cmp(&range.start, &snapshot)
17510                    .is_ge()
17511                {
17512                    ix -= 1;
17513                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17514                        prev_highlight.range.end = range.end;
17515                    }
17516                    merged = true;
17517                    prev_highlight.index = index;
17518                    prev_highlight.color = color;
17519                    prev_highlight.options = options;
17520                }
17521            }
17522
17523            if !merged {
17524                row_highlights.insert(
17525                    ix,
17526                    RowHighlight {
17527                        range: range.clone(),
17528                        index,
17529                        color,
17530                        options,
17531                        type_id: TypeId::of::<T>(),
17532                    },
17533                );
17534            }
17535
17536            // If any of the following highlights intersect with this one, merge them.
17537            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17538                let highlight = &row_highlights[ix];
17539                if next_highlight
17540                    .range
17541                    .start
17542                    .cmp(&highlight.range.end, &snapshot)
17543                    .is_le()
17544                {
17545                    if next_highlight
17546                        .range
17547                        .end
17548                        .cmp(&highlight.range.end, &snapshot)
17549                        .is_gt()
17550                    {
17551                        row_highlights[ix].range.end = next_highlight.range.end;
17552                    }
17553                    row_highlights.remove(ix + 1);
17554                } else {
17555                    break;
17556                }
17557            }
17558        }
17559    }
17560
17561    /// Remove any highlighted row ranges of the given type that intersect the
17562    /// given ranges.
17563    pub fn remove_highlighted_rows<T: 'static>(
17564        &mut self,
17565        ranges_to_remove: Vec<Range<Anchor>>,
17566        cx: &mut Context<Self>,
17567    ) {
17568        let snapshot = self.buffer().read(cx).snapshot(cx);
17569        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17570        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17571        row_highlights.retain(|highlight| {
17572            while let Some(range_to_remove) = ranges_to_remove.peek() {
17573                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17574                    Ordering::Less | Ordering::Equal => {
17575                        ranges_to_remove.next();
17576                    }
17577                    Ordering::Greater => {
17578                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17579                            Ordering::Less | Ordering::Equal => {
17580                                return false;
17581                            }
17582                            Ordering::Greater => break,
17583                        }
17584                    }
17585                }
17586            }
17587
17588            true
17589        })
17590    }
17591
17592    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17593    pub fn clear_row_highlights<T: 'static>(&mut self) {
17594        self.highlighted_rows.remove(&TypeId::of::<T>());
17595    }
17596
17597    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17598    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17599        self.highlighted_rows
17600            .get(&TypeId::of::<T>())
17601            .map_or(&[] as &[_], |vec| vec.as_slice())
17602            .iter()
17603            .map(|highlight| (highlight.range.clone(), highlight.color))
17604    }
17605
17606    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17607    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17608    /// Allows to ignore certain kinds of highlights.
17609    pub fn highlighted_display_rows(
17610        &self,
17611        window: &mut Window,
17612        cx: &mut App,
17613    ) -> BTreeMap<DisplayRow, LineHighlight> {
17614        let snapshot = self.snapshot(window, cx);
17615        let mut used_highlight_orders = HashMap::default();
17616        self.highlighted_rows
17617            .iter()
17618            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17619            .fold(
17620                BTreeMap::<DisplayRow, LineHighlight>::new(),
17621                |mut unique_rows, highlight| {
17622                    let start = highlight.range.start.to_display_point(&snapshot);
17623                    let end = highlight.range.end.to_display_point(&snapshot);
17624                    let start_row = start.row().0;
17625                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17626                        && end.column() == 0
17627                    {
17628                        end.row().0.saturating_sub(1)
17629                    } else {
17630                        end.row().0
17631                    };
17632                    for row in start_row..=end_row {
17633                        let used_index =
17634                            used_highlight_orders.entry(row).or_insert(highlight.index);
17635                        if highlight.index >= *used_index {
17636                            *used_index = highlight.index;
17637                            unique_rows.insert(
17638                                DisplayRow(row),
17639                                LineHighlight {
17640                                    include_gutter: highlight.options.include_gutter,
17641                                    border: None,
17642                                    background: highlight.color.into(),
17643                                    type_id: Some(highlight.type_id),
17644                                },
17645                            );
17646                        }
17647                    }
17648                    unique_rows
17649                },
17650            )
17651    }
17652
17653    pub fn highlighted_display_row_for_autoscroll(
17654        &self,
17655        snapshot: &DisplaySnapshot,
17656    ) -> Option<DisplayRow> {
17657        self.highlighted_rows
17658            .values()
17659            .flat_map(|highlighted_rows| highlighted_rows.iter())
17660            .filter_map(|highlight| {
17661                if highlight.options.autoscroll {
17662                    Some(highlight.range.start.to_display_point(snapshot).row())
17663                } else {
17664                    None
17665                }
17666            })
17667            .min()
17668    }
17669
17670    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17671        self.highlight_background::<SearchWithinRange>(
17672            ranges,
17673            |colors| colors.editor_document_highlight_read_background,
17674            cx,
17675        )
17676    }
17677
17678    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17679        self.breadcrumb_header = Some(new_header);
17680    }
17681
17682    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17683        self.clear_background_highlights::<SearchWithinRange>(cx);
17684    }
17685
17686    pub fn highlight_background<T: 'static>(
17687        &mut self,
17688        ranges: &[Range<Anchor>],
17689        color_fetcher: fn(&ThemeColors) -> Hsla,
17690        cx: &mut Context<Self>,
17691    ) {
17692        self.background_highlights
17693            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17694        self.scrollbar_marker_state.dirty = true;
17695        cx.notify();
17696    }
17697
17698    pub fn clear_background_highlights<T: 'static>(
17699        &mut self,
17700        cx: &mut Context<Self>,
17701    ) -> Option<BackgroundHighlight> {
17702        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17703        if !text_highlights.1.is_empty() {
17704            self.scrollbar_marker_state.dirty = true;
17705            cx.notify();
17706        }
17707        Some(text_highlights)
17708    }
17709
17710    pub fn highlight_gutter<T: 'static>(
17711        &mut self,
17712        ranges: &[Range<Anchor>],
17713        color_fetcher: fn(&App) -> Hsla,
17714        cx: &mut Context<Self>,
17715    ) {
17716        self.gutter_highlights
17717            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17718        cx.notify();
17719    }
17720
17721    pub fn clear_gutter_highlights<T: 'static>(
17722        &mut self,
17723        cx: &mut Context<Self>,
17724    ) -> Option<GutterHighlight> {
17725        cx.notify();
17726        self.gutter_highlights.remove(&TypeId::of::<T>())
17727    }
17728
17729    #[cfg(feature = "test-support")]
17730    pub fn all_text_background_highlights(
17731        &self,
17732        window: &mut Window,
17733        cx: &mut Context<Self>,
17734    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17735        let snapshot = self.snapshot(window, cx);
17736        let buffer = &snapshot.buffer_snapshot;
17737        let start = buffer.anchor_before(0);
17738        let end = buffer.anchor_after(buffer.len());
17739        let theme = cx.theme().colors();
17740        self.background_highlights_in_range(start..end, &snapshot, theme)
17741    }
17742
17743    #[cfg(feature = "test-support")]
17744    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17745        let snapshot = self.buffer().read(cx).snapshot(cx);
17746
17747        let highlights = self
17748            .background_highlights
17749            .get(&TypeId::of::<items::BufferSearchHighlights>());
17750
17751        if let Some((_color, ranges)) = highlights {
17752            ranges
17753                .iter()
17754                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17755                .collect_vec()
17756        } else {
17757            vec![]
17758        }
17759    }
17760
17761    fn document_highlights_for_position<'a>(
17762        &'a self,
17763        position: Anchor,
17764        buffer: &'a MultiBufferSnapshot,
17765    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17766        let read_highlights = self
17767            .background_highlights
17768            .get(&TypeId::of::<DocumentHighlightRead>())
17769            .map(|h| &h.1);
17770        let write_highlights = self
17771            .background_highlights
17772            .get(&TypeId::of::<DocumentHighlightWrite>())
17773            .map(|h| &h.1);
17774        let left_position = position.bias_left(buffer);
17775        let right_position = position.bias_right(buffer);
17776        read_highlights
17777            .into_iter()
17778            .chain(write_highlights)
17779            .flat_map(move |ranges| {
17780                let start_ix = match ranges.binary_search_by(|probe| {
17781                    let cmp = probe.end.cmp(&left_position, buffer);
17782                    if cmp.is_ge() {
17783                        Ordering::Greater
17784                    } else {
17785                        Ordering::Less
17786                    }
17787                }) {
17788                    Ok(i) | Err(i) => i,
17789                };
17790
17791                ranges[start_ix..]
17792                    .iter()
17793                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17794            })
17795    }
17796
17797    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17798        self.background_highlights
17799            .get(&TypeId::of::<T>())
17800            .map_or(false, |(_, highlights)| !highlights.is_empty())
17801    }
17802
17803    pub fn background_highlights_in_range(
17804        &self,
17805        search_range: Range<Anchor>,
17806        display_snapshot: &DisplaySnapshot,
17807        theme: &ThemeColors,
17808    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17809        let mut results = Vec::new();
17810        for (color_fetcher, ranges) in self.background_highlights.values() {
17811            let color = color_fetcher(theme);
17812            let start_ix = match ranges.binary_search_by(|probe| {
17813                let cmp = probe
17814                    .end
17815                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17816                if cmp.is_gt() {
17817                    Ordering::Greater
17818                } else {
17819                    Ordering::Less
17820                }
17821            }) {
17822                Ok(i) | Err(i) => i,
17823            };
17824            for range in &ranges[start_ix..] {
17825                if range
17826                    .start
17827                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17828                    .is_ge()
17829                {
17830                    break;
17831                }
17832
17833                let start = range.start.to_display_point(display_snapshot);
17834                let end = range.end.to_display_point(display_snapshot);
17835                results.push((start..end, color))
17836            }
17837        }
17838        results
17839    }
17840
17841    pub fn background_highlight_row_ranges<T: 'static>(
17842        &self,
17843        search_range: Range<Anchor>,
17844        display_snapshot: &DisplaySnapshot,
17845        count: usize,
17846    ) -> Vec<RangeInclusive<DisplayPoint>> {
17847        let mut results = Vec::new();
17848        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17849            return vec![];
17850        };
17851
17852        let start_ix = match ranges.binary_search_by(|probe| {
17853            let cmp = probe
17854                .end
17855                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17856            if cmp.is_gt() {
17857                Ordering::Greater
17858            } else {
17859                Ordering::Less
17860            }
17861        }) {
17862            Ok(i) | Err(i) => i,
17863        };
17864        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17865            if let (Some(start_display), Some(end_display)) = (start, end) {
17866                results.push(
17867                    start_display.to_display_point(display_snapshot)
17868                        ..=end_display.to_display_point(display_snapshot),
17869                );
17870            }
17871        };
17872        let mut start_row: Option<Point> = None;
17873        let mut end_row: Option<Point> = None;
17874        if ranges.len() > count {
17875            return Vec::new();
17876        }
17877        for range in &ranges[start_ix..] {
17878            if range
17879                .start
17880                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17881                .is_ge()
17882            {
17883                break;
17884            }
17885            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17886            if let Some(current_row) = &end_row {
17887                if end.row == current_row.row {
17888                    continue;
17889                }
17890            }
17891            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17892            if start_row.is_none() {
17893                assert_eq!(end_row, None);
17894                start_row = Some(start);
17895                end_row = Some(end);
17896                continue;
17897            }
17898            if let Some(current_end) = end_row.as_mut() {
17899                if start.row > current_end.row + 1 {
17900                    push_region(start_row, end_row);
17901                    start_row = Some(start);
17902                    end_row = Some(end);
17903                } else {
17904                    // Merge two hunks.
17905                    *current_end = end;
17906                }
17907            } else {
17908                unreachable!();
17909            }
17910        }
17911        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17912        push_region(start_row, end_row);
17913        results
17914    }
17915
17916    pub fn gutter_highlights_in_range(
17917        &self,
17918        search_range: Range<Anchor>,
17919        display_snapshot: &DisplaySnapshot,
17920        cx: &App,
17921    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17922        let mut results = Vec::new();
17923        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17924            let color = color_fetcher(cx);
17925            let start_ix = match ranges.binary_search_by(|probe| {
17926                let cmp = probe
17927                    .end
17928                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17929                if cmp.is_gt() {
17930                    Ordering::Greater
17931                } else {
17932                    Ordering::Less
17933                }
17934            }) {
17935                Ok(i) | Err(i) => i,
17936            };
17937            for range in &ranges[start_ix..] {
17938                if range
17939                    .start
17940                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17941                    .is_ge()
17942                {
17943                    break;
17944                }
17945
17946                let start = range.start.to_display_point(display_snapshot);
17947                let end = range.end.to_display_point(display_snapshot);
17948                results.push((start..end, color))
17949            }
17950        }
17951        results
17952    }
17953
17954    /// Get the text ranges corresponding to the redaction query
17955    pub fn redacted_ranges(
17956        &self,
17957        search_range: Range<Anchor>,
17958        display_snapshot: &DisplaySnapshot,
17959        cx: &App,
17960    ) -> Vec<Range<DisplayPoint>> {
17961        display_snapshot
17962            .buffer_snapshot
17963            .redacted_ranges(search_range, |file| {
17964                if let Some(file) = file {
17965                    file.is_private()
17966                        && EditorSettings::get(
17967                            Some(SettingsLocation {
17968                                worktree_id: file.worktree_id(cx),
17969                                path: file.path().as_ref(),
17970                            }),
17971                            cx,
17972                        )
17973                        .redact_private_values
17974                } else {
17975                    false
17976                }
17977            })
17978            .map(|range| {
17979                range.start.to_display_point(display_snapshot)
17980                    ..range.end.to_display_point(display_snapshot)
17981            })
17982            .collect()
17983    }
17984
17985    pub fn highlight_text<T: 'static>(
17986        &mut self,
17987        ranges: Vec<Range<Anchor>>,
17988        style: HighlightStyle,
17989        cx: &mut Context<Self>,
17990    ) {
17991        self.display_map.update(cx, |map, _| {
17992            map.highlight_text(TypeId::of::<T>(), ranges, style)
17993        });
17994        cx.notify();
17995    }
17996
17997    pub(crate) fn highlight_inlays<T: 'static>(
17998        &mut self,
17999        highlights: Vec<InlayHighlight>,
18000        style: HighlightStyle,
18001        cx: &mut Context<Self>,
18002    ) {
18003        self.display_map.update(cx, |map, _| {
18004            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18005        });
18006        cx.notify();
18007    }
18008
18009    pub fn text_highlights<'a, T: 'static>(
18010        &'a self,
18011        cx: &'a App,
18012    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18013        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18014    }
18015
18016    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18017        let cleared = self
18018            .display_map
18019            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18020        if cleared {
18021            cx.notify();
18022        }
18023    }
18024
18025    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18026        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18027            && self.focus_handle.is_focused(window)
18028    }
18029
18030    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18031        self.show_cursor_when_unfocused = is_enabled;
18032        cx.notify();
18033    }
18034
18035    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18036        cx.notify();
18037    }
18038
18039    fn on_debug_session_event(
18040        &mut self,
18041        _session: Entity<Session>,
18042        event: &SessionEvent,
18043        cx: &mut Context<Self>,
18044    ) {
18045        match event {
18046            SessionEvent::InvalidateInlineValue => {
18047                self.refresh_inline_values(cx);
18048            }
18049            _ => {}
18050        }
18051    }
18052
18053    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18054        let Some(project) = self.project.clone() else {
18055            return;
18056        };
18057
18058        if !self.inline_value_cache.enabled {
18059            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18060            self.splice_inlays(&inlays, Vec::new(), cx);
18061            return;
18062        }
18063
18064        let current_execution_position = self
18065            .highlighted_rows
18066            .get(&TypeId::of::<ActiveDebugLine>())
18067            .and_then(|lines| lines.last().map(|line| line.range.start));
18068
18069        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18070            let inline_values = editor
18071                .update(cx, |editor, cx| {
18072                    let Some(current_execution_position) = current_execution_position else {
18073                        return Some(Task::ready(Ok(Vec::new())));
18074                    };
18075
18076                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18077                        let snapshot = buffer.snapshot(cx);
18078
18079                        let excerpt = snapshot.excerpt_containing(
18080                            current_execution_position..current_execution_position,
18081                        )?;
18082
18083                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18084                    })?;
18085
18086                    let range =
18087                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18088
18089                    project.inline_values(buffer, range, cx)
18090                })
18091                .ok()
18092                .flatten()?
18093                .await
18094                .context("refreshing debugger inlays")
18095                .log_err()?;
18096
18097            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18098
18099            for (buffer_id, inline_value) in inline_values
18100                .into_iter()
18101                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18102            {
18103                buffer_inline_values
18104                    .entry(buffer_id)
18105                    .or_default()
18106                    .push(inline_value);
18107            }
18108
18109            editor
18110                .update(cx, |editor, cx| {
18111                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18112                    let mut new_inlays = Vec::default();
18113
18114                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18115                        let buffer_id = buffer_snapshot.remote_id();
18116                        buffer_inline_values
18117                            .get(&buffer_id)
18118                            .into_iter()
18119                            .flatten()
18120                            .for_each(|hint| {
18121                                let inlay = Inlay::debugger_hint(
18122                                    post_inc(&mut editor.next_inlay_id),
18123                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18124                                    hint.text(),
18125                                );
18126
18127                                new_inlays.push(inlay);
18128                            });
18129                    }
18130
18131                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18132                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18133
18134                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18135                })
18136                .ok()?;
18137            Some(())
18138        });
18139    }
18140
18141    fn on_buffer_event(
18142        &mut self,
18143        multibuffer: &Entity<MultiBuffer>,
18144        event: &multi_buffer::Event,
18145        window: &mut Window,
18146        cx: &mut Context<Self>,
18147    ) {
18148        match event {
18149            multi_buffer::Event::Edited {
18150                singleton_buffer_edited,
18151                edited_buffer: buffer_edited,
18152            } => {
18153                self.scrollbar_marker_state.dirty = true;
18154                self.active_indent_guides_state.dirty = true;
18155                self.refresh_active_diagnostics(cx);
18156                self.refresh_code_actions(window, cx);
18157                self.refresh_selected_text_highlights(true, window, cx);
18158                refresh_matching_bracket_highlights(self, window, cx);
18159                if self.has_active_inline_completion() {
18160                    self.update_visible_inline_completion(window, cx);
18161                }
18162                if let Some(buffer) = buffer_edited {
18163                    let buffer_id = buffer.read(cx).remote_id();
18164                    if !self.registered_buffers.contains_key(&buffer_id) {
18165                        if let Some(project) = self.project.as_ref() {
18166                            project.update(cx, |project, cx| {
18167                                self.registered_buffers.insert(
18168                                    buffer_id,
18169                                    project.register_buffer_with_language_servers(&buffer, cx),
18170                                );
18171                            })
18172                        }
18173                    }
18174                }
18175                cx.emit(EditorEvent::BufferEdited);
18176                cx.emit(SearchEvent::MatchesInvalidated);
18177                if *singleton_buffer_edited {
18178                    if let Some(project) = &self.project {
18179                        #[allow(clippy::mutable_key_type)]
18180                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18181                            multibuffer
18182                                .all_buffers()
18183                                .into_iter()
18184                                .filter_map(|buffer| {
18185                                    buffer.update(cx, |buffer, cx| {
18186                                        let language = buffer.language()?;
18187                                        let should_discard = project.update(cx, |project, cx| {
18188                                            project.is_local()
18189                                                && !project.has_language_servers_for(buffer, cx)
18190                                        });
18191                                        should_discard.not().then_some(language.clone())
18192                                    })
18193                                })
18194                                .collect::<HashSet<_>>()
18195                        });
18196                        if !languages_affected.is_empty() {
18197                            self.refresh_inlay_hints(
18198                                InlayHintRefreshReason::BufferEdited(languages_affected),
18199                                cx,
18200                            );
18201                        }
18202                    }
18203                }
18204
18205                let Some(project) = &self.project else { return };
18206                let (telemetry, is_via_ssh) = {
18207                    let project = project.read(cx);
18208                    let telemetry = project.client().telemetry().clone();
18209                    let is_via_ssh = project.is_via_ssh();
18210                    (telemetry, is_via_ssh)
18211                };
18212                refresh_linked_ranges(self, window, cx);
18213                telemetry.log_edit_event("editor", is_via_ssh);
18214            }
18215            multi_buffer::Event::ExcerptsAdded {
18216                buffer,
18217                predecessor,
18218                excerpts,
18219            } => {
18220                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18221                let buffer_id = buffer.read(cx).remote_id();
18222                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18223                    if let Some(project) = &self.project {
18224                        update_uncommitted_diff_for_buffer(
18225                            cx.entity(),
18226                            project,
18227                            [buffer.clone()],
18228                            self.buffer.clone(),
18229                            cx,
18230                        )
18231                        .detach();
18232                    }
18233                }
18234                cx.emit(EditorEvent::ExcerptsAdded {
18235                    buffer: buffer.clone(),
18236                    predecessor: *predecessor,
18237                    excerpts: excerpts.clone(),
18238                });
18239                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18240            }
18241            multi_buffer::Event::ExcerptsRemoved {
18242                ids,
18243                removed_buffer_ids,
18244            } => {
18245                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18246                let buffer = self.buffer.read(cx);
18247                self.registered_buffers
18248                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18249                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18250                cx.emit(EditorEvent::ExcerptsRemoved {
18251                    ids: ids.clone(),
18252                    removed_buffer_ids: removed_buffer_ids.clone(),
18253                })
18254            }
18255            multi_buffer::Event::ExcerptsEdited {
18256                excerpt_ids,
18257                buffer_ids,
18258            } => {
18259                self.display_map.update(cx, |map, cx| {
18260                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18261                });
18262                cx.emit(EditorEvent::ExcerptsEdited {
18263                    ids: excerpt_ids.clone(),
18264                })
18265            }
18266            multi_buffer::Event::ExcerptsExpanded { ids } => {
18267                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18268                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18269            }
18270            multi_buffer::Event::Reparsed(buffer_id) => {
18271                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18272                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18273
18274                cx.emit(EditorEvent::Reparsed(*buffer_id));
18275            }
18276            multi_buffer::Event::DiffHunksToggled => {
18277                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18278            }
18279            multi_buffer::Event::LanguageChanged(buffer_id) => {
18280                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18281                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18282                cx.emit(EditorEvent::Reparsed(*buffer_id));
18283                cx.notify();
18284            }
18285            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18286            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18287            multi_buffer::Event::FileHandleChanged
18288            | multi_buffer::Event::Reloaded
18289            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18290            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18291            multi_buffer::Event::DiagnosticsUpdated => {
18292                self.refresh_active_diagnostics(cx);
18293                self.refresh_inline_diagnostics(true, window, cx);
18294                self.scrollbar_marker_state.dirty = true;
18295                cx.notify();
18296            }
18297            _ => {}
18298        };
18299    }
18300
18301    pub fn start_temporary_diff_override(&mut self) {
18302        self.load_diff_task.take();
18303        self.temporary_diff_override = true;
18304    }
18305
18306    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18307        self.temporary_diff_override = false;
18308        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18309        self.buffer.update(cx, |buffer, cx| {
18310            buffer.set_all_diff_hunks_collapsed(cx);
18311        });
18312
18313        if let Some(project) = self.project.clone() {
18314            self.load_diff_task = Some(
18315                update_uncommitted_diff_for_buffer(
18316                    cx.entity(),
18317                    &project,
18318                    self.buffer.read(cx).all_buffers(),
18319                    self.buffer.clone(),
18320                    cx,
18321                )
18322                .shared(),
18323            );
18324        }
18325    }
18326
18327    fn on_display_map_changed(
18328        &mut self,
18329        _: Entity<DisplayMap>,
18330        _: &mut Window,
18331        cx: &mut Context<Self>,
18332    ) {
18333        cx.notify();
18334    }
18335
18336    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18337        let new_severity = if self.diagnostics_enabled() {
18338            EditorSettings::get_global(cx)
18339                .diagnostics_max_severity
18340                .unwrap_or(DiagnosticSeverity::Hint)
18341        } else {
18342            DiagnosticSeverity::Off
18343        };
18344        self.set_max_diagnostics_severity(new_severity, cx);
18345        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18346        self.update_edit_prediction_settings(cx);
18347        self.refresh_inline_completion(true, false, window, cx);
18348        self.refresh_inlay_hints(
18349            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18350                self.selections.newest_anchor().head(),
18351                &self.buffer.read(cx).snapshot(cx),
18352                cx,
18353            )),
18354            cx,
18355        );
18356
18357        let old_cursor_shape = self.cursor_shape;
18358
18359        {
18360            let editor_settings = EditorSettings::get_global(cx);
18361            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18362            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18363            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18364            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18365        }
18366
18367        if old_cursor_shape != self.cursor_shape {
18368            cx.emit(EditorEvent::CursorShapeChanged);
18369        }
18370
18371        let project_settings = ProjectSettings::get_global(cx);
18372        self.serialize_dirty_buffers =
18373            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18374
18375        if self.mode.is_full() {
18376            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18377            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18378            if self.show_inline_diagnostics != show_inline_diagnostics {
18379                self.show_inline_diagnostics = show_inline_diagnostics;
18380                self.refresh_inline_diagnostics(false, window, cx);
18381            }
18382
18383            if self.git_blame_inline_enabled != inline_blame_enabled {
18384                self.toggle_git_blame_inline_internal(false, window, cx);
18385            }
18386
18387            let minimap_settings = EditorSettings::get_global(cx).minimap;
18388            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18389                self.set_minimap_visibility(
18390                    self.minimap_visibility.toggle_visibility(),
18391                    window,
18392                    cx,
18393                );
18394            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18395                minimap_entity.update(cx, |minimap_editor, cx| {
18396                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18397                })
18398            }
18399        }
18400
18401        cx.notify();
18402    }
18403
18404    pub fn set_searchable(&mut self, searchable: bool) {
18405        self.searchable = searchable;
18406    }
18407
18408    pub fn searchable(&self) -> bool {
18409        self.searchable
18410    }
18411
18412    fn open_proposed_changes_editor(
18413        &mut self,
18414        _: &OpenProposedChangesEditor,
18415        window: &mut Window,
18416        cx: &mut Context<Self>,
18417    ) {
18418        let Some(workspace) = self.workspace() else {
18419            cx.propagate();
18420            return;
18421        };
18422
18423        let selections = self.selections.all::<usize>(cx);
18424        let multi_buffer = self.buffer.read(cx);
18425        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18426        let mut new_selections_by_buffer = HashMap::default();
18427        for selection in selections {
18428            for (buffer, range, _) in
18429                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18430            {
18431                let mut range = range.to_point(buffer);
18432                range.start.column = 0;
18433                range.end.column = buffer.line_len(range.end.row);
18434                new_selections_by_buffer
18435                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18436                    .or_insert(Vec::new())
18437                    .push(range)
18438            }
18439        }
18440
18441        let proposed_changes_buffers = new_selections_by_buffer
18442            .into_iter()
18443            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18444            .collect::<Vec<_>>();
18445        let proposed_changes_editor = cx.new(|cx| {
18446            ProposedChangesEditor::new(
18447                "Proposed changes",
18448                proposed_changes_buffers,
18449                self.project.clone(),
18450                window,
18451                cx,
18452            )
18453        });
18454
18455        window.defer(cx, move |window, cx| {
18456            workspace.update(cx, |workspace, cx| {
18457                workspace.active_pane().update(cx, |pane, cx| {
18458                    pane.add_item(
18459                        Box::new(proposed_changes_editor),
18460                        true,
18461                        true,
18462                        None,
18463                        window,
18464                        cx,
18465                    );
18466                });
18467            });
18468        });
18469    }
18470
18471    pub fn open_excerpts_in_split(
18472        &mut self,
18473        _: &OpenExcerptsSplit,
18474        window: &mut Window,
18475        cx: &mut Context<Self>,
18476    ) {
18477        self.open_excerpts_common(None, true, window, cx)
18478    }
18479
18480    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18481        self.open_excerpts_common(None, false, window, cx)
18482    }
18483
18484    fn open_excerpts_common(
18485        &mut self,
18486        jump_data: Option<JumpData>,
18487        split: bool,
18488        window: &mut Window,
18489        cx: &mut Context<Self>,
18490    ) {
18491        let Some(workspace) = self.workspace() else {
18492            cx.propagate();
18493            return;
18494        };
18495
18496        if self.buffer.read(cx).is_singleton() {
18497            cx.propagate();
18498            return;
18499        }
18500
18501        let mut new_selections_by_buffer = HashMap::default();
18502        match &jump_data {
18503            Some(JumpData::MultiBufferPoint {
18504                excerpt_id,
18505                position,
18506                anchor,
18507                line_offset_from_top,
18508            }) => {
18509                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18510                if let Some(buffer) = multi_buffer_snapshot
18511                    .buffer_id_for_excerpt(*excerpt_id)
18512                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18513                {
18514                    let buffer_snapshot = buffer.read(cx).snapshot();
18515                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18516                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18517                    } else {
18518                        buffer_snapshot.clip_point(*position, Bias::Left)
18519                    };
18520                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18521                    new_selections_by_buffer.insert(
18522                        buffer,
18523                        (
18524                            vec![jump_to_offset..jump_to_offset],
18525                            Some(*line_offset_from_top),
18526                        ),
18527                    );
18528                }
18529            }
18530            Some(JumpData::MultiBufferRow {
18531                row,
18532                line_offset_from_top,
18533            }) => {
18534                let point = MultiBufferPoint::new(row.0, 0);
18535                if let Some((buffer, buffer_point, _)) =
18536                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18537                {
18538                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18539                    new_selections_by_buffer
18540                        .entry(buffer)
18541                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18542                        .0
18543                        .push(buffer_offset..buffer_offset)
18544                }
18545            }
18546            None => {
18547                let selections = self.selections.all::<usize>(cx);
18548                let multi_buffer = self.buffer.read(cx);
18549                for selection in selections {
18550                    for (snapshot, range, _, anchor) in multi_buffer
18551                        .snapshot(cx)
18552                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18553                    {
18554                        if let Some(anchor) = anchor {
18555                            // selection is in a deleted hunk
18556                            let Some(buffer_id) = anchor.buffer_id else {
18557                                continue;
18558                            };
18559                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18560                                continue;
18561                            };
18562                            let offset = text::ToOffset::to_offset(
18563                                &anchor.text_anchor,
18564                                &buffer_handle.read(cx).snapshot(),
18565                            );
18566                            let range = offset..offset;
18567                            new_selections_by_buffer
18568                                .entry(buffer_handle)
18569                                .or_insert((Vec::new(), None))
18570                                .0
18571                                .push(range)
18572                        } else {
18573                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18574                            else {
18575                                continue;
18576                            };
18577                            new_selections_by_buffer
18578                                .entry(buffer_handle)
18579                                .or_insert((Vec::new(), None))
18580                                .0
18581                                .push(range)
18582                        }
18583                    }
18584                }
18585            }
18586        }
18587
18588        new_selections_by_buffer
18589            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18590
18591        if new_selections_by_buffer.is_empty() {
18592            return;
18593        }
18594
18595        // We defer the pane interaction because we ourselves are a workspace item
18596        // and activating a new item causes the pane to call a method on us reentrantly,
18597        // which panics if we're on the stack.
18598        window.defer(cx, move |window, cx| {
18599            workspace.update(cx, |workspace, cx| {
18600                let pane = if split {
18601                    workspace.adjacent_pane(window, cx)
18602                } else {
18603                    workspace.active_pane().clone()
18604                };
18605
18606                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18607                    let editor = buffer
18608                        .read(cx)
18609                        .file()
18610                        .is_none()
18611                        .then(|| {
18612                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18613                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18614                            // Instead, we try to activate the existing editor in the pane first.
18615                            let (editor, pane_item_index) =
18616                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18617                                    let editor = item.downcast::<Editor>()?;
18618                                    let singleton_buffer =
18619                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18620                                    if singleton_buffer == buffer {
18621                                        Some((editor, i))
18622                                    } else {
18623                                        None
18624                                    }
18625                                })?;
18626                            pane.update(cx, |pane, cx| {
18627                                pane.activate_item(pane_item_index, true, true, window, cx)
18628                            });
18629                            Some(editor)
18630                        })
18631                        .flatten()
18632                        .unwrap_or_else(|| {
18633                            workspace.open_project_item::<Self>(
18634                                pane.clone(),
18635                                buffer,
18636                                true,
18637                                true,
18638                                window,
18639                                cx,
18640                            )
18641                        });
18642
18643                    editor.update(cx, |editor, cx| {
18644                        let autoscroll = match scroll_offset {
18645                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18646                            None => Autoscroll::newest(),
18647                        };
18648                        let nav_history = editor.nav_history.take();
18649                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18650                            s.select_ranges(ranges);
18651                        });
18652                        editor.nav_history = nav_history;
18653                    });
18654                }
18655            })
18656        });
18657    }
18658
18659    // For now, don't allow opening excerpts in buffers that aren't backed by
18660    // regular project files.
18661    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18662        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18663    }
18664
18665    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18666        let snapshot = self.buffer.read(cx).read(cx);
18667        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18668        Some(
18669            ranges
18670                .iter()
18671                .map(move |range| {
18672                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18673                })
18674                .collect(),
18675        )
18676    }
18677
18678    fn selection_replacement_ranges(
18679        &self,
18680        range: Range<OffsetUtf16>,
18681        cx: &mut App,
18682    ) -> Vec<Range<OffsetUtf16>> {
18683        let selections = self.selections.all::<OffsetUtf16>(cx);
18684        let newest_selection = selections
18685            .iter()
18686            .max_by_key(|selection| selection.id)
18687            .unwrap();
18688        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18689        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18690        let snapshot = self.buffer.read(cx).read(cx);
18691        selections
18692            .into_iter()
18693            .map(|mut selection| {
18694                selection.start.0 =
18695                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18696                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18697                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18698                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18699            })
18700            .collect()
18701    }
18702
18703    fn report_editor_event(
18704        &self,
18705        event_type: &'static str,
18706        file_extension: Option<String>,
18707        cx: &App,
18708    ) {
18709        if cfg!(any(test, feature = "test-support")) {
18710            return;
18711        }
18712
18713        let Some(project) = &self.project else { return };
18714
18715        // If None, we are in a file without an extension
18716        let file = self
18717            .buffer
18718            .read(cx)
18719            .as_singleton()
18720            .and_then(|b| b.read(cx).file());
18721        let file_extension = file_extension.or(file
18722            .as_ref()
18723            .and_then(|file| Path::new(file.file_name(cx)).extension())
18724            .and_then(|e| e.to_str())
18725            .map(|a| a.to_string()));
18726
18727        let vim_mode = vim_enabled(cx);
18728
18729        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18730        let copilot_enabled = edit_predictions_provider
18731            == language::language_settings::EditPredictionProvider::Copilot;
18732        let copilot_enabled_for_language = self
18733            .buffer
18734            .read(cx)
18735            .language_settings(cx)
18736            .show_edit_predictions;
18737
18738        let project = project.read(cx);
18739        telemetry::event!(
18740            event_type,
18741            file_extension,
18742            vim_mode,
18743            copilot_enabled,
18744            copilot_enabled_for_language,
18745            edit_predictions_provider,
18746            is_via_ssh = project.is_via_ssh(),
18747        );
18748    }
18749
18750    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18751    /// with each line being an array of {text, highlight} objects.
18752    fn copy_highlight_json(
18753        &mut self,
18754        _: &CopyHighlightJson,
18755        window: &mut Window,
18756        cx: &mut Context<Self>,
18757    ) {
18758        #[derive(Serialize)]
18759        struct Chunk<'a> {
18760            text: String,
18761            highlight: Option<&'a str>,
18762        }
18763
18764        let snapshot = self.buffer.read(cx).snapshot(cx);
18765        let range = self
18766            .selected_text_range(false, window, cx)
18767            .and_then(|selection| {
18768                if selection.range.is_empty() {
18769                    None
18770                } else {
18771                    Some(selection.range)
18772                }
18773            })
18774            .unwrap_or_else(|| 0..snapshot.len());
18775
18776        let chunks = snapshot.chunks(range, true);
18777        let mut lines = Vec::new();
18778        let mut line: VecDeque<Chunk> = VecDeque::new();
18779
18780        let Some(style) = self.style.as_ref() else {
18781            return;
18782        };
18783
18784        for chunk in chunks {
18785            let highlight = chunk
18786                .syntax_highlight_id
18787                .and_then(|id| id.name(&style.syntax));
18788            let mut chunk_lines = chunk.text.split('\n').peekable();
18789            while let Some(text) = chunk_lines.next() {
18790                let mut merged_with_last_token = false;
18791                if let Some(last_token) = line.back_mut() {
18792                    if last_token.highlight == highlight {
18793                        last_token.text.push_str(text);
18794                        merged_with_last_token = true;
18795                    }
18796                }
18797
18798                if !merged_with_last_token {
18799                    line.push_back(Chunk {
18800                        text: text.into(),
18801                        highlight,
18802                    });
18803                }
18804
18805                if chunk_lines.peek().is_some() {
18806                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18807                        line.pop_front();
18808                    }
18809                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18810                        line.pop_back();
18811                    }
18812
18813                    lines.push(mem::take(&mut line));
18814                }
18815            }
18816        }
18817
18818        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18819            return;
18820        };
18821        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18822    }
18823
18824    pub fn open_context_menu(
18825        &mut self,
18826        _: &OpenContextMenu,
18827        window: &mut Window,
18828        cx: &mut Context<Self>,
18829    ) {
18830        self.request_autoscroll(Autoscroll::newest(), cx);
18831        let position = self.selections.newest_display(cx).start;
18832        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18833    }
18834
18835    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18836        &self.inlay_hint_cache
18837    }
18838
18839    pub fn replay_insert_event(
18840        &mut self,
18841        text: &str,
18842        relative_utf16_range: Option<Range<isize>>,
18843        window: &mut Window,
18844        cx: &mut Context<Self>,
18845    ) {
18846        if !self.input_enabled {
18847            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18848            return;
18849        }
18850        if let Some(relative_utf16_range) = relative_utf16_range {
18851            let selections = self.selections.all::<OffsetUtf16>(cx);
18852            self.change_selections(None, window, cx, |s| {
18853                let new_ranges = selections.into_iter().map(|range| {
18854                    let start = OffsetUtf16(
18855                        range
18856                            .head()
18857                            .0
18858                            .saturating_add_signed(relative_utf16_range.start),
18859                    );
18860                    let end = OffsetUtf16(
18861                        range
18862                            .head()
18863                            .0
18864                            .saturating_add_signed(relative_utf16_range.end),
18865                    );
18866                    start..end
18867                });
18868                s.select_ranges(new_ranges);
18869            });
18870        }
18871
18872        self.handle_input(text, window, cx);
18873    }
18874
18875    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18876        let Some(provider) = self.semantics_provider.as_ref() else {
18877            return false;
18878        };
18879
18880        let mut supports = false;
18881        self.buffer().update(cx, |this, cx| {
18882            this.for_each_buffer(|buffer| {
18883                supports |= provider.supports_inlay_hints(buffer, cx);
18884            });
18885        });
18886
18887        supports
18888    }
18889
18890    pub fn is_focused(&self, window: &Window) -> bool {
18891        self.focus_handle.is_focused(window)
18892    }
18893
18894    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18895        cx.emit(EditorEvent::Focused);
18896
18897        if let Some(descendant) = self
18898            .last_focused_descendant
18899            .take()
18900            .and_then(|descendant| descendant.upgrade())
18901        {
18902            window.focus(&descendant);
18903        } else {
18904            if let Some(blame) = self.blame.as_ref() {
18905                blame.update(cx, GitBlame::focus)
18906            }
18907
18908            self.blink_manager.update(cx, BlinkManager::enable);
18909            self.show_cursor_names(window, cx);
18910            self.buffer.update(cx, |buffer, cx| {
18911                buffer.finalize_last_transaction(cx);
18912                if self.leader_id.is_none() {
18913                    buffer.set_active_selections(
18914                        &self.selections.disjoint_anchors(),
18915                        self.selections.line_mode,
18916                        self.cursor_shape,
18917                        cx,
18918                    );
18919                }
18920            });
18921        }
18922    }
18923
18924    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18925        cx.emit(EditorEvent::FocusedIn)
18926    }
18927
18928    fn handle_focus_out(
18929        &mut self,
18930        event: FocusOutEvent,
18931        _window: &mut Window,
18932        cx: &mut Context<Self>,
18933    ) {
18934        if event.blurred != self.focus_handle {
18935            self.last_focused_descendant = Some(event.blurred);
18936        }
18937        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18938    }
18939
18940    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18941        self.blink_manager.update(cx, BlinkManager::disable);
18942        self.buffer
18943            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18944
18945        if let Some(blame) = self.blame.as_ref() {
18946            blame.update(cx, GitBlame::blur)
18947        }
18948        if !self.hover_state.focused(window, cx) {
18949            hide_hover(self, cx);
18950        }
18951        if !self
18952            .context_menu
18953            .borrow()
18954            .as_ref()
18955            .is_some_and(|context_menu| context_menu.focused(window, cx))
18956        {
18957            self.hide_context_menu(window, cx);
18958        }
18959        self.discard_inline_completion(false, cx);
18960        cx.emit(EditorEvent::Blurred);
18961        cx.notify();
18962    }
18963
18964    pub fn register_action<A: Action>(
18965        &mut self,
18966        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
18967    ) -> Subscription {
18968        let id = self.next_editor_action_id.post_inc();
18969        let listener = Arc::new(listener);
18970        self.editor_actions.borrow_mut().insert(
18971            id,
18972            Box::new(move |window, _| {
18973                let listener = listener.clone();
18974                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
18975                    let action = action.downcast_ref().unwrap();
18976                    if phase == DispatchPhase::Bubble {
18977                        listener(action, window, cx)
18978                    }
18979                })
18980            }),
18981        );
18982
18983        let editor_actions = self.editor_actions.clone();
18984        Subscription::new(move || {
18985            editor_actions.borrow_mut().remove(&id);
18986        })
18987    }
18988
18989    pub fn file_header_size(&self) -> u32 {
18990        FILE_HEADER_HEIGHT
18991    }
18992
18993    pub fn restore(
18994        &mut self,
18995        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
18996        window: &mut Window,
18997        cx: &mut Context<Self>,
18998    ) {
18999        let workspace = self.workspace();
19000        let project = self.project.as_ref();
19001        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19002            let mut tasks = Vec::new();
19003            for (buffer_id, changes) in revert_changes {
19004                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19005                    buffer.update(cx, |buffer, cx| {
19006                        buffer.edit(
19007                            changes
19008                                .into_iter()
19009                                .map(|(range, text)| (range, text.to_string())),
19010                            None,
19011                            cx,
19012                        );
19013                    });
19014
19015                    if let Some(project) =
19016                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19017                    {
19018                        project.update(cx, |project, cx| {
19019                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19020                        })
19021                    }
19022                }
19023            }
19024            tasks
19025        });
19026        cx.spawn_in(window, async move |_, cx| {
19027            for (buffer, task) in save_tasks {
19028                let result = task.await;
19029                if result.is_err() {
19030                    let Some(path) = buffer
19031                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19032                        .ok()
19033                    else {
19034                        continue;
19035                    };
19036                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19037                        let Some(task) = cx
19038                            .update_window_entity(&workspace, |workspace, window, cx| {
19039                                workspace
19040                                    .open_path_preview(path, None, false, false, false, window, cx)
19041                            })
19042                            .ok()
19043                        else {
19044                            continue;
19045                        };
19046                        task.await.log_err();
19047                    }
19048                }
19049            }
19050        })
19051        .detach();
19052        self.change_selections(None, window, cx, |selections| selections.refresh());
19053    }
19054
19055    pub fn to_pixel_point(
19056        &self,
19057        source: multi_buffer::Anchor,
19058        editor_snapshot: &EditorSnapshot,
19059        window: &mut Window,
19060    ) -> Option<gpui::Point<Pixels>> {
19061        let source_point = source.to_display_point(editor_snapshot);
19062        self.display_to_pixel_point(source_point, editor_snapshot, window)
19063    }
19064
19065    pub fn display_to_pixel_point(
19066        &self,
19067        source: DisplayPoint,
19068        editor_snapshot: &EditorSnapshot,
19069        window: &mut Window,
19070    ) -> Option<gpui::Point<Pixels>> {
19071        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19072        let text_layout_details = self.text_layout_details(window);
19073        let scroll_top = text_layout_details
19074            .scroll_anchor
19075            .scroll_position(editor_snapshot)
19076            .y;
19077
19078        if source.row().as_f32() < scroll_top.floor() {
19079            return None;
19080        }
19081        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19082        let source_y = line_height * (source.row().as_f32() - scroll_top);
19083        Some(gpui::Point::new(source_x, source_y))
19084    }
19085
19086    pub fn has_visible_completions_menu(&self) -> bool {
19087        !self.edit_prediction_preview_is_active()
19088            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19089                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19090            })
19091    }
19092
19093    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19094        if self.mode.is_minimap() {
19095            return;
19096        }
19097        self.addons
19098            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19099    }
19100
19101    pub fn unregister_addon<T: Addon>(&mut self) {
19102        self.addons.remove(&std::any::TypeId::of::<T>());
19103    }
19104
19105    pub fn addon<T: Addon>(&self) -> Option<&T> {
19106        let type_id = std::any::TypeId::of::<T>();
19107        self.addons
19108            .get(&type_id)
19109            .and_then(|item| item.to_any().downcast_ref::<T>())
19110    }
19111
19112    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19113        let type_id = std::any::TypeId::of::<T>();
19114        self.addons
19115            .get_mut(&type_id)
19116            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19117    }
19118
19119    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19120        let text_layout_details = self.text_layout_details(window);
19121        let style = &text_layout_details.editor_style;
19122        let font_id = window.text_system().resolve_font(&style.text.font());
19123        let font_size = style.text.font_size.to_pixels(window.rem_size());
19124        let line_height = style.text.line_height_in_pixels(window.rem_size());
19125        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19126
19127        gpui::Size::new(em_width, line_height)
19128    }
19129
19130    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19131        self.load_diff_task.clone()
19132    }
19133
19134    fn read_metadata_from_db(
19135        &mut self,
19136        item_id: u64,
19137        workspace_id: WorkspaceId,
19138        window: &mut Window,
19139        cx: &mut Context<Editor>,
19140    ) {
19141        if self.is_singleton(cx)
19142            && !self.mode.is_minimap()
19143            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19144        {
19145            let buffer_snapshot = OnceCell::new();
19146
19147            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19148                if !folds.is_empty() {
19149                    let snapshot =
19150                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19151                    self.fold_ranges(
19152                        folds
19153                            .into_iter()
19154                            .map(|(start, end)| {
19155                                snapshot.clip_offset(start, Bias::Left)
19156                                    ..snapshot.clip_offset(end, Bias::Right)
19157                            })
19158                            .collect(),
19159                        false,
19160                        window,
19161                        cx,
19162                    );
19163                }
19164            }
19165
19166            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19167                if !selections.is_empty() {
19168                    let snapshot =
19169                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19170                    self.change_selections(None, window, cx, |s| {
19171                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19172                            snapshot.clip_offset(start, Bias::Left)
19173                                ..snapshot.clip_offset(end, Bias::Right)
19174                        }));
19175                    });
19176                }
19177            };
19178        }
19179
19180        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19181    }
19182}
19183
19184fn vim_enabled(cx: &App) -> bool {
19185    cx.global::<SettingsStore>()
19186        .raw_user_settings()
19187        .get("vim_mode")
19188        == Some(&serde_json::Value::Bool(true))
19189}
19190
19191// Consider user intent and default settings
19192fn choose_completion_range(
19193    completion: &Completion,
19194    intent: CompletionIntent,
19195    buffer: &Entity<Buffer>,
19196    cx: &mut Context<Editor>,
19197) -> Range<usize> {
19198    fn should_replace(
19199        completion: &Completion,
19200        insert_range: &Range<text::Anchor>,
19201        intent: CompletionIntent,
19202        completion_mode_setting: LspInsertMode,
19203        buffer: &Buffer,
19204    ) -> bool {
19205        // specific actions take precedence over settings
19206        match intent {
19207            CompletionIntent::CompleteWithInsert => return false,
19208            CompletionIntent::CompleteWithReplace => return true,
19209            CompletionIntent::Complete | CompletionIntent::Compose => {}
19210        }
19211
19212        match completion_mode_setting {
19213            LspInsertMode::Insert => false,
19214            LspInsertMode::Replace => true,
19215            LspInsertMode::ReplaceSubsequence => {
19216                let mut text_to_replace = buffer.chars_for_range(
19217                    buffer.anchor_before(completion.replace_range.start)
19218                        ..buffer.anchor_after(completion.replace_range.end),
19219                );
19220                let mut completion_text = completion.new_text.chars();
19221
19222                // is `text_to_replace` a subsequence of `completion_text`
19223                text_to_replace
19224                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19225            }
19226            LspInsertMode::ReplaceSuffix => {
19227                let range_after_cursor = insert_range.end..completion.replace_range.end;
19228
19229                let text_after_cursor = buffer
19230                    .text_for_range(
19231                        buffer.anchor_before(range_after_cursor.start)
19232                            ..buffer.anchor_after(range_after_cursor.end),
19233                    )
19234                    .collect::<String>();
19235                completion.new_text.ends_with(&text_after_cursor)
19236            }
19237        }
19238    }
19239
19240    let buffer = buffer.read(cx);
19241
19242    if let CompletionSource::Lsp {
19243        insert_range: Some(insert_range),
19244        ..
19245    } = &completion.source
19246    {
19247        let completion_mode_setting =
19248            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19249                .completions
19250                .lsp_insert_mode;
19251
19252        if !should_replace(
19253            completion,
19254            &insert_range,
19255            intent,
19256            completion_mode_setting,
19257            buffer,
19258        ) {
19259            return insert_range.to_offset(buffer);
19260        }
19261    }
19262
19263    completion.replace_range.to_offset(buffer)
19264}
19265
19266fn insert_extra_newline_brackets(
19267    buffer: &MultiBufferSnapshot,
19268    range: Range<usize>,
19269    language: &language::LanguageScope,
19270) -> bool {
19271    let leading_whitespace_len = buffer
19272        .reversed_chars_at(range.start)
19273        .take_while(|c| c.is_whitespace() && *c != '\n')
19274        .map(|c| c.len_utf8())
19275        .sum::<usize>();
19276    let trailing_whitespace_len = buffer
19277        .chars_at(range.end)
19278        .take_while(|c| c.is_whitespace() && *c != '\n')
19279        .map(|c| c.len_utf8())
19280        .sum::<usize>();
19281    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19282
19283    language.brackets().any(|(pair, enabled)| {
19284        let pair_start = pair.start.trim_end();
19285        let pair_end = pair.end.trim_start();
19286
19287        enabled
19288            && pair.newline
19289            && buffer.contains_str_at(range.end, pair_end)
19290            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19291    })
19292}
19293
19294fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19295    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19296        [(buffer, range, _)] => (*buffer, range.clone()),
19297        _ => return false,
19298    };
19299    let pair = {
19300        let mut result: Option<BracketMatch> = None;
19301
19302        for pair in buffer
19303            .all_bracket_ranges(range.clone())
19304            .filter(move |pair| {
19305                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19306            })
19307        {
19308            let len = pair.close_range.end - pair.open_range.start;
19309
19310            if let Some(existing) = &result {
19311                let existing_len = existing.close_range.end - existing.open_range.start;
19312                if len > existing_len {
19313                    continue;
19314                }
19315            }
19316
19317            result = Some(pair);
19318        }
19319
19320        result
19321    };
19322    let Some(pair) = pair else {
19323        return false;
19324    };
19325    pair.newline_only
19326        && buffer
19327            .chars_for_range(pair.open_range.end..range.start)
19328            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19329            .all(|c| c.is_whitespace() && c != '\n')
19330}
19331
19332fn update_uncommitted_diff_for_buffer(
19333    editor: Entity<Editor>,
19334    project: &Entity<Project>,
19335    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19336    buffer: Entity<MultiBuffer>,
19337    cx: &mut App,
19338) -> Task<()> {
19339    let mut tasks = Vec::new();
19340    project.update(cx, |project, cx| {
19341        for buffer in buffers {
19342            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19343                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19344            }
19345        }
19346    });
19347    cx.spawn(async move |cx| {
19348        let diffs = future::join_all(tasks).await;
19349        if editor
19350            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19351            .unwrap_or(false)
19352        {
19353            return;
19354        }
19355
19356        buffer
19357            .update(cx, |buffer, cx| {
19358                for diff in diffs.into_iter().flatten() {
19359                    buffer.add_diff(diff, cx);
19360                }
19361            })
19362            .ok();
19363    })
19364}
19365
19366fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19367    let tab_size = tab_size.get() as usize;
19368    let mut width = offset;
19369
19370    for ch in text.chars() {
19371        width += if ch == '\t' {
19372            tab_size - (width % tab_size)
19373        } else {
19374            1
19375        };
19376    }
19377
19378    width - offset
19379}
19380
19381#[cfg(test)]
19382mod tests {
19383    use super::*;
19384
19385    #[test]
19386    fn test_string_size_with_expanded_tabs() {
19387        let nz = |val| NonZeroU32::new(val).unwrap();
19388        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19389        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19390        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19391        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19392        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19393        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19394        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19395        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19396    }
19397}
19398
19399/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19400struct WordBreakingTokenizer<'a> {
19401    input: &'a str,
19402}
19403
19404impl<'a> WordBreakingTokenizer<'a> {
19405    fn new(input: &'a str) -> Self {
19406        Self { input }
19407    }
19408}
19409
19410fn is_char_ideographic(ch: char) -> bool {
19411    use unicode_script::Script::*;
19412    use unicode_script::UnicodeScript;
19413    matches!(ch.script(), Han | Tangut | Yi)
19414}
19415
19416fn is_grapheme_ideographic(text: &str) -> bool {
19417    text.chars().any(is_char_ideographic)
19418}
19419
19420fn is_grapheme_whitespace(text: &str) -> bool {
19421    text.chars().any(|x| x.is_whitespace())
19422}
19423
19424fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19425    text.chars().next().map_or(false, |ch| {
19426        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19427    })
19428}
19429
19430#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19431enum WordBreakToken<'a> {
19432    Word { token: &'a str, grapheme_len: usize },
19433    InlineWhitespace { token: &'a str, grapheme_len: usize },
19434    Newline,
19435}
19436
19437impl<'a> Iterator for WordBreakingTokenizer<'a> {
19438    /// Yields a span, the count of graphemes in the token, and whether it was
19439    /// whitespace. Note that it also breaks at word boundaries.
19440    type Item = WordBreakToken<'a>;
19441
19442    fn next(&mut self) -> Option<Self::Item> {
19443        use unicode_segmentation::UnicodeSegmentation;
19444        if self.input.is_empty() {
19445            return None;
19446        }
19447
19448        let mut iter = self.input.graphemes(true).peekable();
19449        let mut offset = 0;
19450        let mut grapheme_len = 0;
19451        if let Some(first_grapheme) = iter.next() {
19452            let is_newline = first_grapheme == "\n";
19453            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19454            offset += first_grapheme.len();
19455            grapheme_len += 1;
19456            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19457                if let Some(grapheme) = iter.peek().copied() {
19458                    if should_stay_with_preceding_ideograph(grapheme) {
19459                        offset += grapheme.len();
19460                        grapheme_len += 1;
19461                    }
19462                }
19463            } else {
19464                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19465                let mut next_word_bound = words.peek().copied();
19466                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19467                    next_word_bound = words.next();
19468                }
19469                while let Some(grapheme) = iter.peek().copied() {
19470                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19471                        break;
19472                    };
19473                    if is_grapheme_whitespace(grapheme) != is_whitespace
19474                        || (grapheme == "\n") != is_newline
19475                    {
19476                        break;
19477                    };
19478                    offset += grapheme.len();
19479                    grapheme_len += 1;
19480                    iter.next();
19481                }
19482            }
19483            let token = &self.input[..offset];
19484            self.input = &self.input[offset..];
19485            if token == "\n" {
19486                Some(WordBreakToken::Newline)
19487            } else if is_whitespace {
19488                Some(WordBreakToken::InlineWhitespace {
19489                    token,
19490                    grapheme_len,
19491                })
19492            } else {
19493                Some(WordBreakToken::Word {
19494                    token,
19495                    grapheme_len,
19496                })
19497            }
19498        } else {
19499            None
19500        }
19501    }
19502}
19503
19504#[test]
19505fn test_word_breaking_tokenizer() {
19506    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19507        ("", &[]),
19508        ("  ", &[whitespace("  ", 2)]),
19509        ("Ʒ", &[word("Ʒ", 1)]),
19510        ("Ǽ", &[word("Ǽ", 1)]),
19511        ("", &[word("", 1)]),
19512        ("⋑⋑", &[word("⋑⋑", 2)]),
19513        (
19514            "原理,进而",
19515            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19516        ),
19517        (
19518            "hello world",
19519            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19520        ),
19521        (
19522            "hello, world",
19523            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19524        ),
19525        (
19526            "  hello world",
19527            &[
19528                whitespace("  ", 2),
19529                word("hello", 5),
19530                whitespace(" ", 1),
19531                word("world", 5),
19532            ],
19533        ),
19534        (
19535            "这是什么 \n 钢笔",
19536            &[
19537                word("", 1),
19538                word("", 1),
19539                word("", 1),
19540                word("", 1),
19541                whitespace(" ", 1),
19542                newline(),
19543                whitespace(" ", 1),
19544                word("", 1),
19545                word("", 1),
19546            ],
19547        ),
19548        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19549    ];
19550
19551    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19552        WordBreakToken::Word {
19553            token,
19554            grapheme_len,
19555        }
19556    }
19557
19558    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19559        WordBreakToken::InlineWhitespace {
19560            token,
19561            grapheme_len,
19562        }
19563    }
19564
19565    fn newline() -> WordBreakToken<'static> {
19566        WordBreakToken::Newline
19567    }
19568
19569    for (input, result) in tests {
19570        assert_eq!(
19571            WordBreakingTokenizer::new(input)
19572                .collect::<Vec<_>>()
19573                .as_slice(),
19574            *result,
19575        );
19576    }
19577}
19578
19579fn wrap_with_prefix(
19580    line_prefix: String,
19581    unwrapped_text: String,
19582    wrap_column: usize,
19583    tab_size: NonZeroU32,
19584    preserve_existing_whitespace: bool,
19585) -> String {
19586    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19587    let mut wrapped_text = String::new();
19588    let mut current_line = line_prefix.clone();
19589
19590    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19591    let mut current_line_len = line_prefix_len;
19592    let mut in_whitespace = false;
19593    for token in tokenizer {
19594        let have_preceding_whitespace = in_whitespace;
19595        match token {
19596            WordBreakToken::Word {
19597                token,
19598                grapheme_len,
19599            } => {
19600                in_whitespace = false;
19601                if current_line_len + grapheme_len > wrap_column
19602                    && current_line_len != line_prefix_len
19603                {
19604                    wrapped_text.push_str(current_line.trim_end());
19605                    wrapped_text.push('\n');
19606                    current_line.truncate(line_prefix.len());
19607                    current_line_len = line_prefix_len;
19608                }
19609                current_line.push_str(token);
19610                current_line_len += grapheme_len;
19611            }
19612            WordBreakToken::InlineWhitespace {
19613                mut token,
19614                mut grapheme_len,
19615            } => {
19616                in_whitespace = true;
19617                if have_preceding_whitespace && !preserve_existing_whitespace {
19618                    continue;
19619                }
19620                if !preserve_existing_whitespace {
19621                    token = " ";
19622                    grapheme_len = 1;
19623                }
19624                if current_line_len + grapheme_len > wrap_column {
19625                    wrapped_text.push_str(current_line.trim_end());
19626                    wrapped_text.push('\n');
19627                    current_line.truncate(line_prefix.len());
19628                    current_line_len = line_prefix_len;
19629                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19630                    current_line.push_str(token);
19631                    current_line_len += grapheme_len;
19632                }
19633            }
19634            WordBreakToken::Newline => {
19635                in_whitespace = true;
19636                if preserve_existing_whitespace {
19637                    wrapped_text.push_str(current_line.trim_end());
19638                    wrapped_text.push('\n');
19639                    current_line.truncate(line_prefix.len());
19640                    current_line_len = line_prefix_len;
19641                } else if have_preceding_whitespace {
19642                    continue;
19643                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19644                {
19645                    wrapped_text.push_str(current_line.trim_end());
19646                    wrapped_text.push('\n');
19647                    current_line.truncate(line_prefix.len());
19648                    current_line_len = line_prefix_len;
19649                } else if current_line_len != line_prefix_len {
19650                    current_line.push(' ');
19651                    current_line_len += 1;
19652                }
19653            }
19654        }
19655    }
19656
19657    if !current_line.is_empty() {
19658        wrapped_text.push_str(&current_line);
19659    }
19660    wrapped_text
19661}
19662
19663#[test]
19664fn test_wrap_with_prefix() {
19665    assert_eq!(
19666        wrap_with_prefix(
19667            "# ".to_string(),
19668            "abcdefg".to_string(),
19669            4,
19670            NonZeroU32::new(4).unwrap(),
19671            false,
19672        ),
19673        "# abcdefg"
19674    );
19675    assert_eq!(
19676        wrap_with_prefix(
19677            "".to_string(),
19678            "\thello world".to_string(),
19679            8,
19680            NonZeroU32::new(4).unwrap(),
19681            false,
19682        ),
19683        "hello\nworld"
19684    );
19685    assert_eq!(
19686        wrap_with_prefix(
19687            "// ".to_string(),
19688            "xx \nyy zz aa bb cc".to_string(),
19689            12,
19690            NonZeroU32::new(4).unwrap(),
19691            false,
19692        ),
19693        "// xx yy zz\n// aa bb cc"
19694    );
19695    assert_eq!(
19696        wrap_with_prefix(
19697            String::new(),
19698            "这是什么 \n 钢笔".to_string(),
19699            3,
19700            NonZeroU32::new(4).unwrap(),
19701            false,
19702        ),
19703        "这是什\n么 钢\n"
19704    );
19705}
19706
19707pub trait CollaborationHub {
19708    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19709    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19710    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19711}
19712
19713impl CollaborationHub for Entity<Project> {
19714    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19715        self.read(cx).collaborators()
19716    }
19717
19718    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19719        self.read(cx).user_store().read(cx).participant_indices()
19720    }
19721
19722    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19723        let this = self.read(cx);
19724        let user_ids = this.collaborators().values().map(|c| c.user_id);
19725        this.user_store().read_with(cx, |user_store, cx| {
19726            user_store.participant_names(user_ids, cx)
19727        })
19728    }
19729}
19730
19731pub trait SemanticsProvider {
19732    fn hover(
19733        &self,
19734        buffer: &Entity<Buffer>,
19735        position: text::Anchor,
19736        cx: &mut App,
19737    ) -> Option<Task<Vec<project::Hover>>>;
19738
19739    fn inline_values(
19740        &self,
19741        buffer_handle: Entity<Buffer>,
19742        range: Range<text::Anchor>,
19743        cx: &mut App,
19744    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19745
19746    fn inlay_hints(
19747        &self,
19748        buffer_handle: Entity<Buffer>,
19749        range: Range<text::Anchor>,
19750        cx: &mut App,
19751    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19752
19753    fn resolve_inlay_hint(
19754        &self,
19755        hint: InlayHint,
19756        buffer_handle: Entity<Buffer>,
19757        server_id: LanguageServerId,
19758        cx: &mut App,
19759    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19760
19761    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19762
19763    fn document_highlights(
19764        &self,
19765        buffer: &Entity<Buffer>,
19766        position: text::Anchor,
19767        cx: &mut App,
19768    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19769
19770    fn definitions(
19771        &self,
19772        buffer: &Entity<Buffer>,
19773        position: text::Anchor,
19774        kind: GotoDefinitionKind,
19775        cx: &mut App,
19776    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19777
19778    fn range_for_rename(
19779        &self,
19780        buffer: &Entity<Buffer>,
19781        position: text::Anchor,
19782        cx: &mut App,
19783    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19784
19785    fn perform_rename(
19786        &self,
19787        buffer: &Entity<Buffer>,
19788        position: text::Anchor,
19789        new_name: String,
19790        cx: &mut App,
19791    ) -> Option<Task<Result<ProjectTransaction>>>;
19792}
19793
19794pub trait CompletionProvider {
19795    fn completions(
19796        &self,
19797        excerpt_id: ExcerptId,
19798        buffer: &Entity<Buffer>,
19799        buffer_position: text::Anchor,
19800        trigger: CompletionContext,
19801        window: &mut Window,
19802        cx: &mut Context<Editor>,
19803    ) -> Task<Result<Option<Vec<Completion>>>>;
19804
19805    fn resolve_completions(
19806        &self,
19807        buffer: Entity<Buffer>,
19808        completion_indices: Vec<usize>,
19809        completions: Rc<RefCell<Box<[Completion]>>>,
19810        cx: &mut Context<Editor>,
19811    ) -> Task<Result<bool>>;
19812
19813    fn apply_additional_edits_for_completion(
19814        &self,
19815        _buffer: Entity<Buffer>,
19816        _completions: Rc<RefCell<Box<[Completion]>>>,
19817        _completion_index: usize,
19818        _push_to_history: bool,
19819        _cx: &mut Context<Editor>,
19820    ) -> Task<Result<Option<language::Transaction>>> {
19821        Task::ready(Ok(None))
19822    }
19823
19824    fn is_completion_trigger(
19825        &self,
19826        buffer: &Entity<Buffer>,
19827        position: language::Anchor,
19828        text: &str,
19829        trigger_in_words: bool,
19830        cx: &mut Context<Editor>,
19831    ) -> bool;
19832
19833    fn sort_completions(&self) -> bool {
19834        true
19835    }
19836
19837    fn filter_completions(&self) -> bool {
19838        true
19839    }
19840}
19841
19842pub trait CodeActionProvider {
19843    fn id(&self) -> Arc<str>;
19844
19845    fn code_actions(
19846        &self,
19847        buffer: &Entity<Buffer>,
19848        range: Range<text::Anchor>,
19849        window: &mut Window,
19850        cx: &mut App,
19851    ) -> Task<Result<Vec<CodeAction>>>;
19852
19853    fn apply_code_action(
19854        &self,
19855        buffer_handle: Entity<Buffer>,
19856        action: CodeAction,
19857        excerpt_id: ExcerptId,
19858        push_to_history: bool,
19859        window: &mut Window,
19860        cx: &mut App,
19861    ) -> Task<Result<ProjectTransaction>>;
19862}
19863
19864impl CodeActionProvider for Entity<Project> {
19865    fn id(&self) -> Arc<str> {
19866        "project".into()
19867    }
19868
19869    fn code_actions(
19870        &self,
19871        buffer: &Entity<Buffer>,
19872        range: Range<text::Anchor>,
19873        _window: &mut Window,
19874        cx: &mut App,
19875    ) -> Task<Result<Vec<CodeAction>>> {
19876        self.update(cx, |project, cx| {
19877            let code_lens = project.code_lens(buffer, range.clone(), cx);
19878            let code_actions = project.code_actions(buffer, range, None, cx);
19879            cx.background_spawn(async move {
19880                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19881                Ok(code_lens
19882                    .context("code lens fetch")?
19883                    .into_iter()
19884                    .chain(code_actions.context("code action fetch")?)
19885                    .collect())
19886            })
19887        })
19888    }
19889
19890    fn apply_code_action(
19891        &self,
19892        buffer_handle: Entity<Buffer>,
19893        action: CodeAction,
19894        _excerpt_id: ExcerptId,
19895        push_to_history: bool,
19896        _window: &mut Window,
19897        cx: &mut App,
19898    ) -> Task<Result<ProjectTransaction>> {
19899        self.update(cx, |project, cx| {
19900            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19901        })
19902    }
19903}
19904
19905fn snippet_completions(
19906    project: &Project,
19907    buffer: &Entity<Buffer>,
19908    buffer_position: text::Anchor,
19909    cx: &mut App,
19910) -> Task<Result<Vec<Completion>>> {
19911    let languages = buffer.read(cx).languages_at(buffer_position);
19912    let snippet_store = project.snippets().read(cx);
19913
19914    let scopes: Vec<_> = languages
19915        .iter()
19916        .filter_map(|language| {
19917            let language_name = language.lsp_id();
19918            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19919
19920            if snippets.is_empty() {
19921                None
19922            } else {
19923                Some((language.default_scope(), snippets))
19924            }
19925        })
19926        .collect();
19927
19928    if scopes.is_empty() {
19929        return Task::ready(Ok(vec![]));
19930    }
19931
19932    let snapshot = buffer.read(cx).text_snapshot();
19933    let chars: String = snapshot
19934        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19935        .collect();
19936    let executor = cx.background_executor().clone();
19937
19938    cx.background_spawn(async move {
19939        let mut all_results: Vec<Completion> = Vec::new();
19940        for (scope, snippets) in scopes.into_iter() {
19941            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19942            let mut last_word = chars
19943                .chars()
19944                .take_while(|c| classifier.is_word(*c))
19945                .collect::<String>();
19946            last_word = last_word.chars().rev().collect();
19947
19948            if last_word.is_empty() {
19949                return Ok(vec![]);
19950            }
19951
19952            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19953            let to_lsp = |point: &text::Anchor| {
19954                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19955                point_to_lsp(end)
19956            };
19957            let lsp_end = to_lsp(&buffer_position);
19958
19959            let candidates = snippets
19960                .iter()
19961                .enumerate()
19962                .flat_map(|(ix, snippet)| {
19963                    snippet
19964                        .prefix
19965                        .iter()
19966                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
19967                })
19968                .collect::<Vec<StringMatchCandidate>>();
19969
19970            let mut matches = fuzzy::match_strings(
19971                &candidates,
19972                &last_word,
19973                last_word.chars().any(|c| c.is_uppercase()),
19974                100,
19975                &Default::default(),
19976                executor.clone(),
19977            )
19978            .await;
19979
19980            // Remove all candidates where the query's start does not match the start of any word in the candidate
19981            if let Some(query_start) = last_word.chars().next() {
19982                matches.retain(|string_match| {
19983                    split_words(&string_match.string).any(|word| {
19984                        // Check that the first codepoint of the word as lowercase matches the first
19985                        // codepoint of the query as lowercase
19986                        word.chars()
19987                            .flat_map(|codepoint| codepoint.to_lowercase())
19988                            .zip(query_start.to_lowercase())
19989                            .all(|(word_cp, query_cp)| word_cp == query_cp)
19990                    })
19991                });
19992            }
19993
19994            let matched_strings = matches
19995                .into_iter()
19996                .map(|m| m.string)
19997                .collect::<HashSet<_>>();
19998
19999            let mut result: Vec<Completion> = snippets
20000                .iter()
20001                .filter_map(|snippet| {
20002                    let matching_prefix = snippet
20003                        .prefix
20004                        .iter()
20005                        .find(|prefix| matched_strings.contains(*prefix))?;
20006                    let start = as_offset - last_word.len();
20007                    let start = snapshot.anchor_before(start);
20008                    let range = start..buffer_position;
20009                    let lsp_start = to_lsp(&start);
20010                    let lsp_range = lsp::Range {
20011                        start: lsp_start,
20012                        end: lsp_end,
20013                    };
20014                    Some(Completion {
20015                        replace_range: range,
20016                        new_text: snippet.body.clone(),
20017                        source: CompletionSource::Lsp {
20018                            insert_range: None,
20019                            server_id: LanguageServerId(usize::MAX),
20020                            resolved: true,
20021                            lsp_completion: Box::new(lsp::CompletionItem {
20022                                label: snippet.prefix.first().unwrap().clone(),
20023                                kind: Some(CompletionItemKind::SNIPPET),
20024                                label_details: snippet.description.as_ref().map(|description| {
20025                                    lsp::CompletionItemLabelDetails {
20026                                        detail: Some(description.clone()),
20027                                        description: None,
20028                                    }
20029                                }),
20030                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20031                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20032                                    lsp::InsertReplaceEdit {
20033                                        new_text: snippet.body.clone(),
20034                                        insert: lsp_range,
20035                                        replace: lsp_range,
20036                                    },
20037                                )),
20038                                filter_text: Some(snippet.body.clone()),
20039                                sort_text: Some(char::MAX.to_string()),
20040                                ..lsp::CompletionItem::default()
20041                            }),
20042                            lsp_defaults: None,
20043                        },
20044                        label: CodeLabel {
20045                            text: matching_prefix.clone(),
20046                            runs: Vec::new(),
20047                            filter_range: 0..matching_prefix.len(),
20048                        },
20049                        icon_path: None,
20050                        documentation: Some(
20051                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20052                                single_line: snippet.name.clone().into(),
20053                                plain_text: snippet
20054                                    .description
20055                                    .clone()
20056                                    .map(|description| description.into()),
20057                            },
20058                        ),
20059                        insert_text_mode: None,
20060                        confirm: None,
20061                    })
20062                })
20063                .collect();
20064
20065            all_results.append(&mut result);
20066        }
20067
20068        Ok(all_results)
20069    })
20070}
20071
20072impl CompletionProvider for Entity<Project> {
20073    fn completions(
20074        &self,
20075        _excerpt_id: ExcerptId,
20076        buffer: &Entity<Buffer>,
20077        buffer_position: text::Anchor,
20078        options: CompletionContext,
20079        _window: &mut Window,
20080        cx: &mut Context<Editor>,
20081    ) -> Task<Result<Option<Vec<Completion>>>> {
20082        self.update(cx, |project, cx| {
20083            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20084            let project_completions = project.completions(buffer, buffer_position, options, cx);
20085            cx.background_spawn(async move {
20086                let snippets_completions = snippets.await?;
20087                match project_completions.await? {
20088                    Some(mut completions) => {
20089                        completions.extend(snippets_completions);
20090                        Ok(Some(completions))
20091                    }
20092                    None => {
20093                        if snippets_completions.is_empty() {
20094                            Ok(None)
20095                        } else {
20096                            Ok(Some(snippets_completions))
20097                        }
20098                    }
20099                }
20100            })
20101        })
20102    }
20103
20104    fn resolve_completions(
20105        &self,
20106        buffer: Entity<Buffer>,
20107        completion_indices: Vec<usize>,
20108        completions: Rc<RefCell<Box<[Completion]>>>,
20109        cx: &mut Context<Editor>,
20110    ) -> Task<Result<bool>> {
20111        self.update(cx, |project, cx| {
20112            project.lsp_store().update(cx, |lsp_store, cx| {
20113                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20114            })
20115        })
20116    }
20117
20118    fn apply_additional_edits_for_completion(
20119        &self,
20120        buffer: Entity<Buffer>,
20121        completions: Rc<RefCell<Box<[Completion]>>>,
20122        completion_index: usize,
20123        push_to_history: bool,
20124        cx: &mut Context<Editor>,
20125    ) -> Task<Result<Option<language::Transaction>>> {
20126        self.update(cx, |project, cx| {
20127            project.lsp_store().update(cx, |lsp_store, cx| {
20128                lsp_store.apply_additional_edits_for_completion(
20129                    buffer,
20130                    completions,
20131                    completion_index,
20132                    push_to_history,
20133                    cx,
20134                )
20135            })
20136        })
20137    }
20138
20139    fn is_completion_trigger(
20140        &self,
20141        buffer: &Entity<Buffer>,
20142        position: language::Anchor,
20143        text: &str,
20144        trigger_in_words: bool,
20145        cx: &mut Context<Editor>,
20146    ) -> bool {
20147        let mut chars = text.chars();
20148        let char = if let Some(char) = chars.next() {
20149            char
20150        } else {
20151            return false;
20152        };
20153        if chars.next().is_some() {
20154            return false;
20155        }
20156
20157        let buffer = buffer.read(cx);
20158        let snapshot = buffer.snapshot();
20159        if !snapshot.settings_at(position, cx).show_completions_on_input {
20160            return false;
20161        }
20162        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20163        if trigger_in_words && classifier.is_word(char) {
20164            return true;
20165        }
20166
20167        buffer.completion_triggers().contains(text)
20168    }
20169}
20170
20171impl SemanticsProvider for Entity<Project> {
20172    fn hover(
20173        &self,
20174        buffer: &Entity<Buffer>,
20175        position: text::Anchor,
20176        cx: &mut App,
20177    ) -> Option<Task<Vec<project::Hover>>> {
20178        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20179    }
20180
20181    fn document_highlights(
20182        &self,
20183        buffer: &Entity<Buffer>,
20184        position: text::Anchor,
20185        cx: &mut App,
20186    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20187        Some(self.update(cx, |project, cx| {
20188            project.document_highlights(buffer, position, cx)
20189        }))
20190    }
20191
20192    fn definitions(
20193        &self,
20194        buffer: &Entity<Buffer>,
20195        position: text::Anchor,
20196        kind: GotoDefinitionKind,
20197        cx: &mut App,
20198    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20199        Some(self.update(cx, |project, cx| match kind {
20200            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20201            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20202            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20203            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20204        }))
20205    }
20206
20207    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20208        // TODO: make this work for remote projects
20209        self.update(cx, |project, cx| {
20210            if project
20211                .active_debug_session(cx)
20212                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20213            {
20214                return true;
20215            }
20216
20217            buffer.update(cx, |buffer, cx| {
20218                project.any_language_server_supports_inlay_hints(buffer, cx)
20219            })
20220        })
20221    }
20222
20223    fn inline_values(
20224        &self,
20225        buffer_handle: Entity<Buffer>,
20226        range: Range<text::Anchor>,
20227        cx: &mut App,
20228    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20229        self.update(cx, |project, cx| {
20230            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20231
20232            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20233        })
20234    }
20235
20236    fn inlay_hints(
20237        &self,
20238        buffer_handle: Entity<Buffer>,
20239        range: Range<text::Anchor>,
20240        cx: &mut App,
20241    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20242        Some(self.update(cx, |project, cx| {
20243            project.inlay_hints(buffer_handle, range, cx)
20244        }))
20245    }
20246
20247    fn resolve_inlay_hint(
20248        &self,
20249        hint: InlayHint,
20250        buffer_handle: Entity<Buffer>,
20251        server_id: LanguageServerId,
20252        cx: &mut App,
20253    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20254        Some(self.update(cx, |project, cx| {
20255            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20256        }))
20257    }
20258
20259    fn range_for_rename(
20260        &self,
20261        buffer: &Entity<Buffer>,
20262        position: text::Anchor,
20263        cx: &mut App,
20264    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20265        Some(self.update(cx, |project, cx| {
20266            let buffer = buffer.clone();
20267            let task = project.prepare_rename(buffer.clone(), position, cx);
20268            cx.spawn(async move |_, cx| {
20269                Ok(match task.await? {
20270                    PrepareRenameResponse::Success(range) => Some(range),
20271                    PrepareRenameResponse::InvalidPosition => None,
20272                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20273                        // Fallback on using TreeSitter info to determine identifier range
20274                        buffer.update(cx, |buffer, _| {
20275                            let snapshot = buffer.snapshot();
20276                            let (range, kind) = snapshot.surrounding_word(position);
20277                            if kind != Some(CharKind::Word) {
20278                                return None;
20279                            }
20280                            Some(
20281                                snapshot.anchor_before(range.start)
20282                                    ..snapshot.anchor_after(range.end),
20283                            )
20284                        })?
20285                    }
20286                })
20287            })
20288        }))
20289    }
20290
20291    fn perform_rename(
20292        &self,
20293        buffer: &Entity<Buffer>,
20294        position: text::Anchor,
20295        new_name: String,
20296        cx: &mut App,
20297    ) -> Option<Task<Result<ProjectTransaction>>> {
20298        Some(self.update(cx, |project, cx| {
20299            project.perform_rename(buffer.clone(), position, new_name, cx)
20300        }))
20301    }
20302}
20303
20304fn inlay_hint_settings(
20305    location: Anchor,
20306    snapshot: &MultiBufferSnapshot,
20307    cx: &mut Context<Editor>,
20308) -> InlayHintSettings {
20309    let file = snapshot.file_at(location);
20310    let language = snapshot.language_at(location).map(|l| l.name());
20311    language_settings(language, file, cx).inlay_hints
20312}
20313
20314fn consume_contiguous_rows(
20315    contiguous_row_selections: &mut Vec<Selection<Point>>,
20316    selection: &Selection<Point>,
20317    display_map: &DisplaySnapshot,
20318    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20319) -> (MultiBufferRow, MultiBufferRow) {
20320    contiguous_row_selections.push(selection.clone());
20321    let start_row = MultiBufferRow(selection.start.row);
20322    let mut end_row = ending_row(selection, display_map);
20323
20324    while let Some(next_selection) = selections.peek() {
20325        if next_selection.start.row <= end_row.0 {
20326            end_row = ending_row(next_selection, display_map);
20327            contiguous_row_selections.push(selections.next().unwrap().clone());
20328        } else {
20329            break;
20330        }
20331    }
20332    (start_row, end_row)
20333}
20334
20335fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20336    if next_selection.end.column > 0 || next_selection.is_empty() {
20337        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20338    } else {
20339        MultiBufferRow(next_selection.end.row)
20340    }
20341}
20342
20343impl EditorSnapshot {
20344    pub fn remote_selections_in_range<'a>(
20345        &'a self,
20346        range: &'a Range<Anchor>,
20347        collaboration_hub: &dyn CollaborationHub,
20348        cx: &'a App,
20349    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20350        let participant_names = collaboration_hub.user_names(cx);
20351        let participant_indices = collaboration_hub.user_participant_indices(cx);
20352        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20353        let collaborators_by_replica_id = collaborators_by_peer_id
20354            .values()
20355            .map(|collaborator| (collaborator.replica_id, collaborator))
20356            .collect::<HashMap<_, _>>();
20357        self.buffer_snapshot
20358            .selections_in_range(range, false)
20359            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20360                if replica_id == AGENT_REPLICA_ID {
20361                    Some(RemoteSelection {
20362                        replica_id,
20363                        selection,
20364                        cursor_shape,
20365                        line_mode,
20366                        collaborator_id: CollaboratorId::Agent,
20367                        user_name: Some("Agent".into()),
20368                        color: cx.theme().players().agent(),
20369                    })
20370                } else {
20371                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20372                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20373                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20374                    Some(RemoteSelection {
20375                        replica_id,
20376                        selection,
20377                        cursor_shape,
20378                        line_mode,
20379                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20380                        user_name,
20381                        color: if let Some(index) = participant_index {
20382                            cx.theme().players().color_for_participant(index.0)
20383                        } else {
20384                            cx.theme().players().absent()
20385                        },
20386                    })
20387                }
20388            })
20389    }
20390
20391    pub fn hunks_for_ranges(
20392        &self,
20393        ranges: impl IntoIterator<Item = Range<Point>>,
20394    ) -> Vec<MultiBufferDiffHunk> {
20395        let mut hunks = Vec::new();
20396        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20397            HashMap::default();
20398        for query_range in ranges {
20399            let query_rows =
20400                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20401            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20402                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20403            ) {
20404                // Include deleted hunks that are adjacent to the query range, because
20405                // otherwise they would be missed.
20406                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20407                if hunk.status().is_deleted() {
20408                    intersects_range |= hunk.row_range.start == query_rows.end;
20409                    intersects_range |= hunk.row_range.end == query_rows.start;
20410                }
20411                if intersects_range {
20412                    if !processed_buffer_rows
20413                        .entry(hunk.buffer_id)
20414                        .or_default()
20415                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20416                    {
20417                        continue;
20418                    }
20419                    hunks.push(hunk);
20420                }
20421            }
20422        }
20423
20424        hunks
20425    }
20426
20427    fn display_diff_hunks_for_rows<'a>(
20428        &'a self,
20429        display_rows: Range<DisplayRow>,
20430        folded_buffers: &'a HashSet<BufferId>,
20431    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20432        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20433        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20434
20435        self.buffer_snapshot
20436            .diff_hunks_in_range(buffer_start..buffer_end)
20437            .filter_map(|hunk| {
20438                if folded_buffers.contains(&hunk.buffer_id) {
20439                    return None;
20440                }
20441
20442                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20443                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20444
20445                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20446                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20447
20448                let display_hunk = if hunk_display_start.column() != 0 {
20449                    DisplayDiffHunk::Folded {
20450                        display_row: hunk_display_start.row(),
20451                    }
20452                } else {
20453                    let mut end_row = hunk_display_end.row();
20454                    if hunk_display_end.column() > 0 {
20455                        end_row.0 += 1;
20456                    }
20457                    let is_created_file = hunk.is_created_file();
20458                    DisplayDiffHunk::Unfolded {
20459                        status: hunk.status(),
20460                        diff_base_byte_range: hunk.diff_base_byte_range,
20461                        display_row_range: hunk_display_start.row()..end_row,
20462                        multi_buffer_range: Anchor::range_in_buffer(
20463                            hunk.excerpt_id,
20464                            hunk.buffer_id,
20465                            hunk.buffer_range,
20466                        ),
20467                        is_created_file,
20468                    }
20469                };
20470
20471                Some(display_hunk)
20472            })
20473    }
20474
20475    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20476        self.display_snapshot.buffer_snapshot.language_at(position)
20477    }
20478
20479    pub fn is_focused(&self) -> bool {
20480        self.is_focused
20481    }
20482
20483    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20484        self.placeholder_text.as_ref()
20485    }
20486
20487    pub fn scroll_position(&self) -> gpui::Point<f32> {
20488        self.scroll_anchor.scroll_position(&self.display_snapshot)
20489    }
20490
20491    fn gutter_dimensions(
20492        &self,
20493        font_id: FontId,
20494        font_size: Pixels,
20495        max_line_number_width: Pixels,
20496        cx: &App,
20497    ) -> Option<GutterDimensions> {
20498        if !self.show_gutter {
20499            return None;
20500        }
20501
20502        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20503        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20504
20505        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20506            matches!(
20507                ProjectSettings::get_global(cx).git.git_gutter,
20508                Some(GitGutterSetting::TrackedFiles)
20509            )
20510        });
20511        let gutter_settings = EditorSettings::get_global(cx).gutter;
20512        let show_line_numbers = self
20513            .show_line_numbers
20514            .unwrap_or(gutter_settings.line_numbers);
20515        let line_gutter_width = if show_line_numbers {
20516            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20517            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20518            max_line_number_width.max(min_width_for_number_on_gutter)
20519        } else {
20520            0.0.into()
20521        };
20522
20523        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20524        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20525
20526        let git_blame_entries_width =
20527            self.git_blame_gutter_max_author_length
20528                .map(|max_author_length| {
20529                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20530                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20531
20532                    /// The number of characters to dedicate to gaps and margins.
20533                    const SPACING_WIDTH: usize = 4;
20534
20535                    let max_char_count = max_author_length.min(renderer.max_author_length())
20536                        + ::git::SHORT_SHA_LENGTH
20537                        + MAX_RELATIVE_TIMESTAMP.len()
20538                        + SPACING_WIDTH;
20539
20540                    em_advance * max_char_count
20541                });
20542
20543        let is_singleton = self.buffer_snapshot.is_singleton();
20544
20545        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20546        left_padding += if !is_singleton {
20547            em_width * 4.0
20548        } else if show_runnables || show_breakpoints {
20549            em_width * 3.0
20550        } else if show_git_gutter && show_line_numbers {
20551            em_width * 2.0
20552        } else if show_git_gutter || show_line_numbers {
20553            em_width
20554        } else {
20555            px(0.)
20556        };
20557
20558        let shows_folds = is_singleton && gutter_settings.folds;
20559
20560        let right_padding = if shows_folds && show_line_numbers {
20561            em_width * 4.0
20562        } else if shows_folds || (!is_singleton && show_line_numbers) {
20563            em_width * 3.0
20564        } else if show_line_numbers {
20565            em_width
20566        } else {
20567            px(0.)
20568        };
20569
20570        Some(GutterDimensions {
20571            left_padding,
20572            right_padding,
20573            width: line_gutter_width + left_padding + right_padding,
20574            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20575            git_blame_entries_width,
20576        })
20577    }
20578
20579    pub fn render_crease_toggle(
20580        &self,
20581        buffer_row: MultiBufferRow,
20582        row_contains_cursor: bool,
20583        editor: Entity<Editor>,
20584        window: &mut Window,
20585        cx: &mut App,
20586    ) -> Option<AnyElement> {
20587        let folded = self.is_line_folded(buffer_row);
20588        let mut is_foldable = false;
20589
20590        if let Some(crease) = self
20591            .crease_snapshot
20592            .query_row(buffer_row, &self.buffer_snapshot)
20593        {
20594            is_foldable = true;
20595            match crease {
20596                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20597                    if let Some(render_toggle) = render_toggle {
20598                        let toggle_callback =
20599                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20600                                if folded {
20601                                    editor.update(cx, |editor, cx| {
20602                                        editor.fold_at(buffer_row, window, cx)
20603                                    });
20604                                } else {
20605                                    editor.update(cx, |editor, cx| {
20606                                        editor.unfold_at(buffer_row, window, cx)
20607                                    });
20608                                }
20609                            });
20610                        return Some((render_toggle)(
20611                            buffer_row,
20612                            folded,
20613                            toggle_callback,
20614                            window,
20615                            cx,
20616                        ));
20617                    }
20618                }
20619            }
20620        }
20621
20622        is_foldable |= self.starts_indent(buffer_row);
20623
20624        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20625            Some(
20626                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20627                    .toggle_state(folded)
20628                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20629                        if folded {
20630                            this.unfold_at(buffer_row, window, cx);
20631                        } else {
20632                            this.fold_at(buffer_row, window, cx);
20633                        }
20634                    }))
20635                    .into_any_element(),
20636            )
20637        } else {
20638            None
20639        }
20640    }
20641
20642    pub fn render_crease_trailer(
20643        &self,
20644        buffer_row: MultiBufferRow,
20645        window: &mut Window,
20646        cx: &mut App,
20647    ) -> Option<AnyElement> {
20648        let folded = self.is_line_folded(buffer_row);
20649        if let Crease::Inline { render_trailer, .. } = self
20650            .crease_snapshot
20651            .query_row(buffer_row, &self.buffer_snapshot)?
20652        {
20653            let render_trailer = render_trailer.as_ref()?;
20654            Some(render_trailer(buffer_row, folded, window, cx))
20655        } else {
20656            None
20657        }
20658    }
20659}
20660
20661impl Deref for EditorSnapshot {
20662    type Target = DisplaySnapshot;
20663
20664    fn deref(&self) -> &Self::Target {
20665        &self.display_snapshot
20666    }
20667}
20668
20669#[derive(Clone, Debug, PartialEq, Eq)]
20670pub enum EditorEvent {
20671    InputIgnored {
20672        text: Arc<str>,
20673    },
20674    InputHandled {
20675        utf16_range_to_replace: Option<Range<isize>>,
20676        text: Arc<str>,
20677    },
20678    ExcerptsAdded {
20679        buffer: Entity<Buffer>,
20680        predecessor: ExcerptId,
20681        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20682    },
20683    ExcerptsRemoved {
20684        ids: Vec<ExcerptId>,
20685        removed_buffer_ids: Vec<BufferId>,
20686    },
20687    BufferFoldToggled {
20688        ids: Vec<ExcerptId>,
20689        folded: bool,
20690    },
20691    ExcerptsEdited {
20692        ids: Vec<ExcerptId>,
20693    },
20694    ExcerptsExpanded {
20695        ids: Vec<ExcerptId>,
20696    },
20697    BufferEdited,
20698    Edited {
20699        transaction_id: clock::Lamport,
20700    },
20701    Reparsed(BufferId),
20702    Focused,
20703    FocusedIn,
20704    Blurred,
20705    DirtyChanged,
20706    Saved,
20707    TitleChanged,
20708    DiffBaseChanged,
20709    SelectionsChanged {
20710        local: bool,
20711    },
20712    ScrollPositionChanged {
20713        local: bool,
20714        autoscroll: bool,
20715    },
20716    Closed,
20717    TransactionUndone {
20718        transaction_id: clock::Lamport,
20719    },
20720    TransactionBegun {
20721        transaction_id: clock::Lamport,
20722    },
20723    Reloaded,
20724    CursorShapeChanged,
20725    PushedToNavHistory {
20726        anchor: Anchor,
20727        is_deactivate: bool,
20728    },
20729}
20730
20731impl EventEmitter<EditorEvent> for Editor {}
20732
20733impl Focusable for Editor {
20734    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20735        self.focus_handle.clone()
20736    }
20737}
20738
20739impl Render for Editor {
20740    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20741        let settings = ThemeSettings::get_global(cx);
20742
20743        let mut text_style = match self.mode {
20744            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20745                color: cx.theme().colors().editor_foreground,
20746                font_family: settings.ui_font.family.clone(),
20747                font_features: settings.ui_font.features.clone(),
20748                font_fallbacks: settings.ui_font.fallbacks.clone(),
20749                font_size: rems(0.875).into(),
20750                font_weight: settings.ui_font.weight,
20751                line_height: relative(settings.buffer_line_height.value()),
20752                ..Default::default()
20753            },
20754            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20755                color: cx.theme().colors().editor_foreground,
20756                font_family: settings.buffer_font.family.clone(),
20757                font_features: settings.buffer_font.features.clone(),
20758                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20759                font_size: settings.buffer_font_size(cx).into(),
20760                font_weight: settings.buffer_font.weight,
20761                line_height: relative(settings.buffer_line_height.value()),
20762                ..Default::default()
20763            },
20764        };
20765        if let Some(text_style_refinement) = &self.text_style_refinement {
20766            text_style.refine(text_style_refinement)
20767        }
20768
20769        let background = match self.mode {
20770            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20771            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20772            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20773            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20774        };
20775
20776        EditorElement::new(
20777            &cx.entity(),
20778            EditorStyle {
20779                background,
20780                local_player: cx.theme().players().local(),
20781                text: text_style,
20782                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20783                syntax: cx.theme().syntax().clone(),
20784                status: cx.theme().status().clone(),
20785                inlay_hints_style: make_inlay_hints_style(cx),
20786                inline_completion_styles: make_suggestion_styles(cx),
20787                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20788                show_underlines: !self.mode.is_minimap(),
20789            },
20790        )
20791    }
20792}
20793
20794impl EntityInputHandler for Editor {
20795    fn text_for_range(
20796        &mut self,
20797        range_utf16: Range<usize>,
20798        adjusted_range: &mut Option<Range<usize>>,
20799        _: &mut Window,
20800        cx: &mut Context<Self>,
20801    ) -> Option<String> {
20802        let snapshot = self.buffer.read(cx).read(cx);
20803        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20804        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20805        if (start.0..end.0) != range_utf16 {
20806            adjusted_range.replace(start.0..end.0);
20807        }
20808        Some(snapshot.text_for_range(start..end).collect())
20809    }
20810
20811    fn selected_text_range(
20812        &mut self,
20813        ignore_disabled_input: bool,
20814        _: &mut Window,
20815        cx: &mut Context<Self>,
20816    ) -> Option<UTF16Selection> {
20817        // Prevent the IME menu from appearing when holding down an alphabetic key
20818        // while input is disabled.
20819        if !ignore_disabled_input && !self.input_enabled {
20820            return None;
20821        }
20822
20823        let selection = self.selections.newest::<OffsetUtf16>(cx);
20824        let range = selection.range();
20825
20826        Some(UTF16Selection {
20827            range: range.start.0..range.end.0,
20828            reversed: selection.reversed,
20829        })
20830    }
20831
20832    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20833        let snapshot = self.buffer.read(cx).read(cx);
20834        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20835        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20836    }
20837
20838    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20839        self.clear_highlights::<InputComposition>(cx);
20840        self.ime_transaction.take();
20841    }
20842
20843    fn replace_text_in_range(
20844        &mut self,
20845        range_utf16: Option<Range<usize>>,
20846        text: &str,
20847        window: &mut Window,
20848        cx: &mut Context<Self>,
20849    ) {
20850        if !self.input_enabled {
20851            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20852            return;
20853        }
20854
20855        self.transact(window, cx, |this, window, cx| {
20856            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20857                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20858                Some(this.selection_replacement_ranges(range_utf16, cx))
20859            } else {
20860                this.marked_text_ranges(cx)
20861            };
20862
20863            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20864                let newest_selection_id = this.selections.newest_anchor().id;
20865                this.selections
20866                    .all::<OffsetUtf16>(cx)
20867                    .iter()
20868                    .zip(ranges_to_replace.iter())
20869                    .find_map(|(selection, range)| {
20870                        if selection.id == newest_selection_id {
20871                            Some(
20872                                (range.start.0 as isize - selection.head().0 as isize)
20873                                    ..(range.end.0 as isize - selection.head().0 as isize),
20874                            )
20875                        } else {
20876                            None
20877                        }
20878                    })
20879            });
20880
20881            cx.emit(EditorEvent::InputHandled {
20882                utf16_range_to_replace: range_to_replace,
20883                text: text.into(),
20884            });
20885
20886            if let Some(new_selected_ranges) = new_selected_ranges {
20887                this.change_selections(None, window, cx, |selections| {
20888                    selections.select_ranges(new_selected_ranges)
20889                });
20890                this.backspace(&Default::default(), window, cx);
20891            }
20892
20893            this.handle_input(text, window, cx);
20894        });
20895
20896        if let Some(transaction) = self.ime_transaction {
20897            self.buffer.update(cx, |buffer, cx| {
20898                buffer.group_until_transaction(transaction, cx);
20899            });
20900        }
20901
20902        self.unmark_text(window, cx);
20903    }
20904
20905    fn replace_and_mark_text_in_range(
20906        &mut self,
20907        range_utf16: Option<Range<usize>>,
20908        text: &str,
20909        new_selected_range_utf16: Option<Range<usize>>,
20910        window: &mut Window,
20911        cx: &mut Context<Self>,
20912    ) {
20913        if !self.input_enabled {
20914            return;
20915        }
20916
20917        let transaction = self.transact(window, cx, |this, window, cx| {
20918            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20919                let snapshot = this.buffer.read(cx).read(cx);
20920                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20921                    for marked_range in &mut marked_ranges {
20922                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20923                        marked_range.start.0 += relative_range_utf16.start;
20924                        marked_range.start =
20925                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20926                        marked_range.end =
20927                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20928                    }
20929                }
20930                Some(marked_ranges)
20931            } else if let Some(range_utf16) = range_utf16 {
20932                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20933                Some(this.selection_replacement_ranges(range_utf16, cx))
20934            } else {
20935                None
20936            };
20937
20938            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20939                let newest_selection_id = this.selections.newest_anchor().id;
20940                this.selections
20941                    .all::<OffsetUtf16>(cx)
20942                    .iter()
20943                    .zip(ranges_to_replace.iter())
20944                    .find_map(|(selection, range)| {
20945                        if selection.id == newest_selection_id {
20946                            Some(
20947                                (range.start.0 as isize - selection.head().0 as isize)
20948                                    ..(range.end.0 as isize - selection.head().0 as isize),
20949                            )
20950                        } else {
20951                            None
20952                        }
20953                    })
20954            });
20955
20956            cx.emit(EditorEvent::InputHandled {
20957                utf16_range_to_replace: range_to_replace,
20958                text: text.into(),
20959            });
20960
20961            if let Some(ranges) = ranges_to_replace {
20962                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
20963            }
20964
20965            let marked_ranges = {
20966                let snapshot = this.buffer.read(cx).read(cx);
20967                this.selections
20968                    .disjoint_anchors()
20969                    .iter()
20970                    .map(|selection| {
20971                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
20972                    })
20973                    .collect::<Vec<_>>()
20974            };
20975
20976            if text.is_empty() {
20977                this.unmark_text(window, cx);
20978            } else {
20979                this.highlight_text::<InputComposition>(
20980                    marked_ranges.clone(),
20981                    HighlightStyle {
20982                        underline: Some(UnderlineStyle {
20983                            thickness: px(1.),
20984                            color: None,
20985                            wavy: false,
20986                        }),
20987                        ..Default::default()
20988                    },
20989                    cx,
20990                );
20991            }
20992
20993            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
20994            let use_autoclose = this.use_autoclose;
20995            let use_auto_surround = this.use_auto_surround;
20996            this.set_use_autoclose(false);
20997            this.set_use_auto_surround(false);
20998            this.handle_input(text, window, cx);
20999            this.set_use_autoclose(use_autoclose);
21000            this.set_use_auto_surround(use_auto_surround);
21001
21002            if let Some(new_selected_range) = new_selected_range_utf16 {
21003                let snapshot = this.buffer.read(cx).read(cx);
21004                let new_selected_ranges = marked_ranges
21005                    .into_iter()
21006                    .map(|marked_range| {
21007                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21008                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21009                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21010                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21011                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21012                    })
21013                    .collect::<Vec<_>>();
21014
21015                drop(snapshot);
21016                this.change_selections(None, window, cx, |selections| {
21017                    selections.select_ranges(new_selected_ranges)
21018                });
21019            }
21020        });
21021
21022        self.ime_transaction = self.ime_transaction.or(transaction);
21023        if let Some(transaction) = self.ime_transaction {
21024            self.buffer.update(cx, |buffer, cx| {
21025                buffer.group_until_transaction(transaction, cx);
21026            });
21027        }
21028
21029        if self.text_highlights::<InputComposition>(cx).is_none() {
21030            self.ime_transaction.take();
21031        }
21032    }
21033
21034    fn bounds_for_range(
21035        &mut self,
21036        range_utf16: Range<usize>,
21037        element_bounds: gpui::Bounds<Pixels>,
21038        window: &mut Window,
21039        cx: &mut Context<Self>,
21040    ) -> Option<gpui::Bounds<Pixels>> {
21041        let text_layout_details = self.text_layout_details(window);
21042        let gpui::Size {
21043            width: em_width,
21044            height: line_height,
21045        } = self.character_size(window);
21046
21047        let snapshot = self.snapshot(window, cx);
21048        let scroll_position = snapshot.scroll_position();
21049        let scroll_left = scroll_position.x * em_width;
21050
21051        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21052        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21053            + self.gutter_dimensions.width
21054            + self.gutter_dimensions.margin;
21055        let y = line_height * (start.row().as_f32() - scroll_position.y);
21056
21057        Some(Bounds {
21058            origin: element_bounds.origin + point(x, y),
21059            size: size(em_width, line_height),
21060        })
21061    }
21062
21063    fn character_index_for_point(
21064        &mut self,
21065        point: gpui::Point<Pixels>,
21066        _window: &mut Window,
21067        _cx: &mut Context<Self>,
21068    ) -> Option<usize> {
21069        let position_map = self.last_position_map.as_ref()?;
21070        if !position_map.text_hitbox.contains(&point) {
21071            return None;
21072        }
21073        let display_point = position_map.point_for_position(point).previous_valid;
21074        let anchor = position_map
21075            .snapshot
21076            .display_point_to_anchor(display_point, Bias::Left);
21077        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21078        Some(utf16_offset.0)
21079    }
21080}
21081
21082trait SelectionExt {
21083    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21084    fn spanned_rows(
21085        &self,
21086        include_end_if_at_line_start: bool,
21087        map: &DisplaySnapshot,
21088    ) -> Range<MultiBufferRow>;
21089}
21090
21091impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21092    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21093        let start = self
21094            .start
21095            .to_point(&map.buffer_snapshot)
21096            .to_display_point(map);
21097        let end = self
21098            .end
21099            .to_point(&map.buffer_snapshot)
21100            .to_display_point(map);
21101        if self.reversed {
21102            end..start
21103        } else {
21104            start..end
21105        }
21106    }
21107
21108    fn spanned_rows(
21109        &self,
21110        include_end_if_at_line_start: bool,
21111        map: &DisplaySnapshot,
21112    ) -> Range<MultiBufferRow> {
21113        let start = self.start.to_point(&map.buffer_snapshot);
21114        let mut end = self.end.to_point(&map.buffer_snapshot);
21115        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21116            end.row -= 1;
21117        }
21118
21119        let buffer_start = map.prev_line_boundary(start).0;
21120        let buffer_end = map.next_line_boundary(end).0;
21121        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21122    }
21123}
21124
21125impl<T: InvalidationRegion> InvalidationStack<T> {
21126    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21127    where
21128        S: Clone + ToOffset,
21129    {
21130        while let Some(region) = self.last() {
21131            let all_selections_inside_invalidation_ranges =
21132                if selections.len() == region.ranges().len() {
21133                    selections
21134                        .iter()
21135                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21136                        .all(|(selection, invalidation_range)| {
21137                            let head = selection.head().to_offset(buffer);
21138                            invalidation_range.start <= head && invalidation_range.end >= head
21139                        })
21140                } else {
21141                    false
21142                };
21143
21144            if all_selections_inside_invalidation_ranges {
21145                break;
21146            } else {
21147                self.pop();
21148            }
21149        }
21150    }
21151}
21152
21153impl<T> Default for InvalidationStack<T> {
21154    fn default() -> Self {
21155        Self(Default::default())
21156    }
21157}
21158
21159impl<T> Deref for InvalidationStack<T> {
21160    type Target = Vec<T>;
21161
21162    fn deref(&self) -> &Self::Target {
21163        &self.0
21164    }
21165}
21166
21167impl<T> DerefMut for InvalidationStack<T> {
21168    fn deref_mut(&mut self) -> &mut Self::Target {
21169        &mut self.0
21170    }
21171}
21172
21173impl InvalidationRegion for SnippetState {
21174    fn ranges(&self) -> &[Range<Anchor>] {
21175        &self.ranges[self.active_index]
21176    }
21177}
21178
21179fn inline_completion_edit_text(
21180    current_snapshot: &BufferSnapshot,
21181    edits: &[(Range<Anchor>, String)],
21182    edit_preview: &EditPreview,
21183    include_deletions: bool,
21184    cx: &App,
21185) -> HighlightedText {
21186    let edits = edits
21187        .iter()
21188        .map(|(anchor, text)| {
21189            (
21190                anchor.start.text_anchor..anchor.end.text_anchor,
21191                text.clone(),
21192            )
21193        })
21194        .collect::<Vec<_>>();
21195
21196    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21197}
21198
21199pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21200    match severity {
21201        lsp::DiagnosticSeverity::ERROR => colors.error,
21202        lsp::DiagnosticSeverity::WARNING => colors.warning,
21203        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21204        lsp::DiagnosticSeverity::HINT => colors.info,
21205        _ => colors.ignored,
21206    }
21207}
21208
21209pub fn styled_runs_for_code_label<'a>(
21210    label: &'a CodeLabel,
21211    syntax_theme: &'a theme::SyntaxTheme,
21212) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21213    let fade_out = HighlightStyle {
21214        fade_out: Some(0.35),
21215        ..Default::default()
21216    };
21217
21218    let mut prev_end = label.filter_range.end;
21219    label
21220        .runs
21221        .iter()
21222        .enumerate()
21223        .flat_map(move |(ix, (range, highlight_id))| {
21224            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21225                style
21226            } else {
21227                return Default::default();
21228            };
21229            let mut muted_style = style;
21230            muted_style.highlight(fade_out);
21231
21232            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21233            if range.start >= label.filter_range.end {
21234                if range.start > prev_end {
21235                    runs.push((prev_end..range.start, fade_out));
21236                }
21237                runs.push((range.clone(), muted_style));
21238            } else if range.end <= label.filter_range.end {
21239                runs.push((range.clone(), style));
21240            } else {
21241                runs.push((range.start..label.filter_range.end, style));
21242                runs.push((label.filter_range.end..range.end, muted_style));
21243            }
21244            prev_end = cmp::max(prev_end, range.end);
21245
21246            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21247                runs.push((prev_end..label.text.len(), fade_out));
21248            }
21249
21250            runs
21251        })
21252}
21253
21254pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21255    let mut prev_index = 0;
21256    let mut prev_codepoint: Option<char> = None;
21257    text.char_indices()
21258        .chain([(text.len(), '\0')])
21259        .filter_map(move |(index, codepoint)| {
21260            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21261            let is_boundary = index == text.len()
21262                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21263                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21264            if is_boundary {
21265                let chunk = &text[prev_index..index];
21266                prev_index = index;
21267                Some(chunk)
21268            } else {
21269                None
21270            }
21271        })
21272}
21273
21274pub trait RangeToAnchorExt: Sized {
21275    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21276
21277    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21278        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21279        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21280    }
21281}
21282
21283impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21284    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21285        let start_offset = self.start.to_offset(snapshot);
21286        let end_offset = self.end.to_offset(snapshot);
21287        if start_offset == end_offset {
21288            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21289        } else {
21290            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21291        }
21292    }
21293}
21294
21295pub trait RowExt {
21296    fn as_f32(&self) -> f32;
21297
21298    fn next_row(&self) -> Self;
21299
21300    fn previous_row(&self) -> Self;
21301
21302    fn minus(&self, other: Self) -> u32;
21303}
21304
21305impl RowExt for DisplayRow {
21306    fn as_f32(&self) -> f32 {
21307        self.0 as f32
21308    }
21309
21310    fn next_row(&self) -> Self {
21311        Self(self.0 + 1)
21312    }
21313
21314    fn previous_row(&self) -> Self {
21315        Self(self.0.saturating_sub(1))
21316    }
21317
21318    fn minus(&self, other: Self) -> u32 {
21319        self.0 - other.0
21320    }
21321}
21322
21323impl RowExt for MultiBufferRow {
21324    fn as_f32(&self) -> f32 {
21325        self.0 as f32
21326    }
21327
21328    fn next_row(&self) -> Self {
21329        Self(self.0 + 1)
21330    }
21331
21332    fn previous_row(&self) -> Self {
21333        Self(self.0.saturating_sub(1))
21334    }
21335
21336    fn minus(&self, other: Self) -> u32 {
21337        self.0 - other.0
21338    }
21339}
21340
21341trait RowRangeExt {
21342    type Row;
21343
21344    fn len(&self) -> usize;
21345
21346    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21347}
21348
21349impl RowRangeExt for Range<MultiBufferRow> {
21350    type Row = MultiBufferRow;
21351
21352    fn len(&self) -> usize {
21353        (self.end.0 - self.start.0) as usize
21354    }
21355
21356    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21357        (self.start.0..self.end.0).map(MultiBufferRow)
21358    }
21359}
21360
21361impl RowRangeExt for Range<DisplayRow> {
21362    type Row = DisplayRow;
21363
21364    fn len(&self) -> usize {
21365        (self.end.0 - self.start.0) as usize
21366    }
21367
21368    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21369        (self.start.0..self.end.0).map(DisplayRow)
21370    }
21371}
21372
21373/// If select range has more than one line, we
21374/// just point the cursor to range.start.
21375fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21376    if range.start.row == range.end.row {
21377        range
21378    } else {
21379        range.start..range.start
21380    }
21381}
21382pub struct KillRing(ClipboardItem);
21383impl Global for KillRing {}
21384
21385const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21386
21387enum BreakpointPromptEditAction {
21388    Log,
21389    Condition,
21390    HitCondition,
21391}
21392
21393struct BreakpointPromptEditor {
21394    pub(crate) prompt: Entity<Editor>,
21395    editor: WeakEntity<Editor>,
21396    breakpoint_anchor: Anchor,
21397    breakpoint: Breakpoint,
21398    edit_action: BreakpointPromptEditAction,
21399    block_ids: HashSet<CustomBlockId>,
21400    editor_margins: Arc<Mutex<EditorMargins>>,
21401    _subscriptions: Vec<Subscription>,
21402}
21403
21404impl BreakpointPromptEditor {
21405    const MAX_LINES: u8 = 4;
21406
21407    fn new(
21408        editor: WeakEntity<Editor>,
21409        breakpoint_anchor: Anchor,
21410        breakpoint: Breakpoint,
21411        edit_action: BreakpointPromptEditAction,
21412        window: &mut Window,
21413        cx: &mut Context<Self>,
21414    ) -> Self {
21415        let base_text = match edit_action {
21416            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21417            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21418            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21419        }
21420        .map(|msg| msg.to_string())
21421        .unwrap_or_default();
21422
21423        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21424        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21425
21426        let prompt = cx.new(|cx| {
21427            let mut prompt = Editor::new(
21428                EditorMode::AutoHeight {
21429                    max_lines: Self::MAX_LINES as usize,
21430                },
21431                buffer,
21432                None,
21433                window,
21434                cx,
21435            );
21436            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21437            prompt.set_show_cursor_when_unfocused(false, cx);
21438            prompt.set_placeholder_text(
21439                match edit_action {
21440                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21441                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21442                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21443                },
21444                cx,
21445            );
21446
21447            prompt
21448        });
21449
21450        Self {
21451            prompt,
21452            editor,
21453            breakpoint_anchor,
21454            breakpoint,
21455            edit_action,
21456            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21457            block_ids: Default::default(),
21458            _subscriptions: vec![],
21459        }
21460    }
21461
21462    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21463        self.block_ids.extend(block_ids)
21464    }
21465
21466    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21467        if let Some(editor) = self.editor.upgrade() {
21468            let message = self
21469                .prompt
21470                .read(cx)
21471                .buffer
21472                .read(cx)
21473                .as_singleton()
21474                .expect("A multi buffer in breakpoint prompt isn't possible")
21475                .read(cx)
21476                .as_rope()
21477                .to_string();
21478
21479            editor.update(cx, |editor, cx| {
21480                editor.edit_breakpoint_at_anchor(
21481                    self.breakpoint_anchor,
21482                    self.breakpoint.clone(),
21483                    match self.edit_action {
21484                        BreakpointPromptEditAction::Log => {
21485                            BreakpointEditAction::EditLogMessage(message.into())
21486                        }
21487                        BreakpointPromptEditAction::Condition => {
21488                            BreakpointEditAction::EditCondition(message.into())
21489                        }
21490                        BreakpointPromptEditAction::HitCondition => {
21491                            BreakpointEditAction::EditHitCondition(message.into())
21492                        }
21493                    },
21494                    cx,
21495                );
21496
21497                editor.remove_blocks(self.block_ids.clone(), None, cx);
21498                cx.focus_self(window);
21499            });
21500        }
21501    }
21502
21503    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21504        self.editor
21505            .update(cx, |editor, cx| {
21506                editor.remove_blocks(self.block_ids.clone(), None, cx);
21507                window.focus(&editor.focus_handle);
21508            })
21509            .log_err();
21510    }
21511
21512    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21513        let settings = ThemeSettings::get_global(cx);
21514        let text_style = TextStyle {
21515            color: if self.prompt.read(cx).read_only(cx) {
21516                cx.theme().colors().text_disabled
21517            } else {
21518                cx.theme().colors().text
21519            },
21520            font_family: settings.buffer_font.family.clone(),
21521            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21522            font_size: settings.buffer_font_size(cx).into(),
21523            font_weight: settings.buffer_font.weight,
21524            line_height: relative(settings.buffer_line_height.value()),
21525            ..Default::default()
21526        };
21527        EditorElement::new(
21528            &self.prompt,
21529            EditorStyle {
21530                background: cx.theme().colors().editor_background,
21531                local_player: cx.theme().players().local(),
21532                text: text_style,
21533                ..Default::default()
21534            },
21535        )
21536    }
21537}
21538
21539impl Render for BreakpointPromptEditor {
21540    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21541        let editor_margins = *self.editor_margins.lock();
21542        let gutter_dimensions = editor_margins.gutter;
21543        h_flex()
21544            .key_context("Editor")
21545            .bg(cx.theme().colors().editor_background)
21546            .border_y_1()
21547            .border_color(cx.theme().status().info_border)
21548            .size_full()
21549            .py(window.line_height() / 2.5)
21550            .on_action(cx.listener(Self::confirm))
21551            .on_action(cx.listener(Self::cancel))
21552            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21553            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21554    }
21555}
21556
21557impl Focusable for BreakpointPromptEditor {
21558    fn focus_handle(&self, cx: &App) -> FocusHandle {
21559        self.prompt.focus_handle(cx)
21560    }
21561}
21562
21563fn all_edits_insertions_or_deletions(
21564    edits: &Vec<(Range<Anchor>, String)>,
21565    snapshot: &MultiBufferSnapshot,
21566) -> bool {
21567    let mut all_insertions = true;
21568    let mut all_deletions = true;
21569
21570    for (range, new_text) in edits.iter() {
21571        let range_is_empty = range.to_offset(&snapshot).is_empty();
21572        let text_is_empty = new_text.is_empty();
21573
21574        if range_is_empty != text_is_empty {
21575            if range_is_empty {
21576                all_deletions = false;
21577            } else {
21578                all_insertions = false;
21579            }
21580        } else {
21581            return false;
21582        }
21583
21584        if !all_insertions && !all_deletions {
21585            return false;
21586        }
21587    }
21588    all_insertions || all_deletions
21589}
21590
21591struct MissingEditPredictionKeybindingTooltip;
21592
21593impl Render for MissingEditPredictionKeybindingTooltip {
21594    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21595        ui::tooltip_container(window, cx, |container, _, cx| {
21596            container
21597                .flex_shrink_0()
21598                .max_w_80()
21599                .min_h(rems_from_px(124.))
21600                .justify_between()
21601                .child(
21602                    v_flex()
21603                        .flex_1()
21604                        .text_ui_sm(cx)
21605                        .child(Label::new("Conflict with Accept Keybinding"))
21606                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21607                )
21608                .child(
21609                    h_flex()
21610                        .pb_1()
21611                        .gap_1()
21612                        .items_end()
21613                        .w_full()
21614                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21615                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21616                        }))
21617                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21618                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21619                        })),
21620                )
21621        })
21622    }
21623}
21624
21625#[derive(Debug, Clone, Copy, PartialEq)]
21626pub struct LineHighlight {
21627    pub background: Background,
21628    pub border: Option<gpui::Hsla>,
21629    pub include_gutter: bool,
21630    pub type_id: Option<TypeId>,
21631}
21632
21633fn render_diff_hunk_controls(
21634    row: u32,
21635    status: &DiffHunkStatus,
21636    hunk_range: Range<Anchor>,
21637    is_created_file: bool,
21638    line_height: Pixels,
21639    editor: &Entity<Editor>,
21640    _window: &mut Window,
21641    cx: &mut App,
21642) -> AnyElement {
21643    h_flex()
21644        .h(line_height)
21645        .mr_1()
21646        .gap_1()
21647        .px_0p5()
21648        .pb_1()
21649        .border_x_1()
21650        .border_b_1()
21651        .border_color(cx.theme().colors().border_variant)
21652        .rounded_b_lg()
21653        .bg(cx.theme().colors().editor_background)
21654        .gap_1()
21655        .occlude()
21656        .shadow_md()
21657        .child(if status.has_secondary_hunk() {
21658            Button::new(("stage", row as u64), "Stage")
21659                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21660                .tooltip({
21661                    let focus_handle = editor.focus_handle(cx);
21662                    move |window, cx| {
21663                        Tooltip::for_action_in(
21664                            "Stage Hunk",
21665                            &::git::ToggleStaged,
21666                            &focus_handle,
21667                            window,
21668                            cx,
21669                        )
21670                    }
21671                })
21672                .on_click({
21673                    let editor = editor.clone();
21674                    move |_event, _window, cx| {
21675                        editor.update(cx, |editor, cx| {
21676                            editor.stage_or_unstage_diff_hunks(
21677                                true,
21678                                vec![hunk_range.start..hunk_range.start],
21679                                cx,
21680                            );
21681                        });
21682                    }
21683                })
21684        } else {
21685            Button::new(("unstage", row as u64), "Unstage")
21686                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21687                .tooltip({
21688                    let focus_handle = editor.focus_handle(cx);
21689                    move |window, cx| {
21690                        Tooltip::for_action_in(
21691                            "Unstage Hunk",
21692                            &::git::ToggleStaged,
21693                            &focus_handle,
21694                            window,
21695                            cx,
21696                        )
21697                    }
21698                })
21699                .on_click({
21700                    let editor = editor.clone();
21701                    move |_event, _window, cx| {
21702                        editor.update(cx, |editor, cx| {
21703                            editor.stage_or_unstage_diff_hunks(
21704                                false,
21705                                vec![hunk_range.start..hunk_range.start],
21706                                cx,
21707                            );
21708                        });
21709                    }
21710                })
21711        })
21712        .child(
21713            Button::new(("restore", row as u64), "Restore")
21714                .tooltip({
21715                    let focus_handle = editor.focus_handle(cx);
21716                    move |window, cx| {
21717                        Tooltip::for_action_in(
21718                            "Restore Hunk",
21719                            &::git::Restore,
21720                            &focus_handle,
21721                            window,
21722                            cx,
21723                        )
21724                    }
21725                })
21726                .on_click({
21727                    let editor = editor.clone();
21728                    move |_event, window, cx| {
21729                        editor.update(cx, |editor, cx| {
21730                            let snapshot = editor.snapshot(window, cx);
21731                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21732                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21733                        });
21734                    }
21735                })
21736                .disabled(is_created_file),
21737        )
21738        .when(
21739            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21740            |el| {
21741                el.child(
21742                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21743                        .shape(IconButtonShape::Square)
21744                        .icon_size(IconSize::Small)
21745                        // .disabled(!has_multiple_hunks)
21746                        .tooltip({
21747                            let focus_handle = editor.focus_handle(cx);
21748                            move |window, cx| {
21749                                Tooltip::for_action_in(
21750                                    "Next Hunk",
21751                                    &GoToHunk,
21752                                    &focus_handle,
21753                                    window,
21754                                    cx,
21755                                )
21756                            }
21757                        })
21758                        .on_click({
21759                            let editor = editor.clone();
21760                            move |_event, window, cx| {
21761                                editor.update(cx, |editor, cx| {
21762                                    let snapshot = editor.snapshot(window, cx);
21763                                    let position =
21764                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21765                                    editor.go_to_hunk_before_or_after_position(
21766                                        &snapshot,
21767                                        position,
21768                                        Direction::Next,
21769                                        window,
21770                                        cx,
21771                                    );
21772                                    editor.expand_selected_diff_hunks(cx);
21773                                });
21774                            }
21775                        }),
21776                )
21777                .child(
21778                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21779                        .shape(IconButtonShape::Square)
21780                        .icon_size(IconSize::Small)
21781                        // .disabled(!has_multiple_hunks)
21782                        .tooltip({
21783                            let focus_handle = editor.focus_handle(cx);
21784                            move |window, cx| {
21785                                Tooltip::for_action_in(
21786                                    "Previous Hunk",
21787                                    &GoToPreviousHunk,
21788                                    &focus_handle,
21789                                    window,
21790                                    cx,
21791                                )
21792                            }
21793                        })
21794                        .on_click({
21795                            let editor = editor.clone();
21796                            move |_event, window, cx| {
21797                                editor.update(cx, |editor, cx| {
21798                                    let snapshot = editor.snapshot(window, cx);
21799                                    let point =
21800                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21801                                    editor.go_to_hunk_before_or_after_position(
21802                                        &snapshot,
21803                                        point,
21804                                        Direction::Prev,
21805                                        window,
21806                                        cx,
21807                                    );
21808                                    editor.expand_selected_diff_hunks(cx);
21809                                });
21810                            }
21811                        }),
21812                )
21813            },
21814        )
21815        .into_any_element()
21816}