editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_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 dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt,
   78    future::{self, Shared, join},
   79};
   80use fuzzy::{StringMatch, StringMatchCandidate};
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, CompletionResponse, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  141use std::{cell::OnceCell, iter::Peekable, ops::Not};
  142use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  143
  144pub use lsp::CompletionContext;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId, LanguageServerName,
  148};
  149
  150use language::BufferSnapshot;
  151pub use lsp_ext::lsp_tasks;
  152use movement::TextLayoutDetails;
  153pub use multi_buffer::{
  154    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  155    RowInfo, ToOffset, ToPoint,
  156};
  157use multi_buffer::{
  158    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  159    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  160};
  161use parking_lot::Mutex;
  162use project::{
  163    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  164    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  165    TaskSourceKind,
  166    debugger::breakpoint_store::Breakpoint,
  167    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  168    project_settings::{GitGutterSetting, ProjectSettings},
  169};
  170use rand::prelude::*;
  171use rpc::{ErrorExt, proto::*};
  172use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  173use selections_collection::{
  174    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  175};
  176use serde::{Deserialize, Serialize};
  177use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  178use smallvec::{SmallVec, smallvec};
  179use snippet::Snippet;
  180use std::sync::Arc;
  181use std::{
  182    any::TypeId,
  183    borrow::Cow,
  184    cell::RefCell,
  185    cmp::{self, Ordering, Reverse},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    time::{Duration, Instant},
  192};
  193pub use sum_tree::Bias;
  194use sum_tree::TreeMap;
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  196use theme::{
  197    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemHandle, PreviewTabsSettings},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::SearchEvent,
  212};
  213
  214use crate::hover_links::{find_url, find_url_from_range};
  215use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  216
  217pub const FILE_HEADER_HEIGHT: u32 = 2;
  218pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  219pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  220const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  221const MAX_LINE_LEN: usize = 1024;
  222const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  223const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  224pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  225#[doc(hidden)]
  226pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  227const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  228
  229pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  232
  233pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  234pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  235pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  236pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  237
  238pub type RenderDiffHunkControlsFn = Arc<
  239    dyn Fn(
  240        u32,
  241        &DiffHunkStatus,
  242        Range<Anchor>,
  243        bool,
  244        Pixels,
  245        &Entity<Editor>,
  246        &mut Window,
  247        &mut App,
  248    ) -> AnyElement,
  249>;
  250
  251const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  252    alt: true,
  253    shift: true,
  254    control: false,
  255    platform: false,
  256    function: false,
  257};
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    Hint(usize),
  279    DebuggerValue(usize),
  280}
  281
  282impl InlayId {
  283    fn id(&self) -> usize {
  284        match self {
  285            Self::InlineCompletion(id) => *id,
  286            Self::Hint(id) => *id,
  287            Self::DebuggerValue(id) => *id,
  288        }
  289    }
  290}
  291
  292pub enum ActiveDebugLine {}
  293pub enum DebugStackFrameLine {}
  294enum DocumentHighlightRead {}
  295enum DocumentHighlightWrite {}
  296enum InputComposition {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug)]
  465pub enum SelectMode {
  466    Character,
  467    Word(Range<Anchor>),
  468    Line(Range<Anchor>),
  469    All,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine {
  475        auto_width: bool,
  476    },
  477    AutoHeight {
  478        max_lines: usize,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// When set to `true`, the editor's height will be determined by its content.
  486        sized_by_content: bool,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sized_by_content: false,
  499        }
  500    }
  501
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub local_player: PlayerColor,
  532    pub text: TextStyle,
  533    pub scrollbar_width: Pixels,
  534    pub syntax: Arc<SyntaxTheme>,
  535    pub status: StatusColors,
  536    pub inlay_hints_style: HighlightStyle,
  537    pub inline_completion_styles: InlineCompletionStyles,
  538    pub unnecessary_code_fade: f32,
  539    pub show_underlines: bool,
  540}
  541
  542impl Default for EditorStyle {
  543    fn default() -> Self {
  544        Self {
  545            background: Hsla::default(),
  546            local_player: PlayerColor::default(),
  547            text: TextStyle::default(),
  548            scrollbar_width: Pixels::default(),
  549            syntax: Default::default(),
  550            // HACK: Status colors don't have a real default.
  551            // We should look into removing the status colors from the editor
  552            // style and retrieve them directly from the theme.
  553            status: StatusColors::dark(),
  554            inlay_hints_style: HighlightStyle::default(),
  555            inline_completion_styles: InlineCompletionStyles {
  556                insertion: HighlightStyle::default(),
  557                whitespace: HighlightStyle::default(),
  558            },
  559            unnecessary_code_fade: Default::default(),
  560            show_underlines: true,
  561        }
  562    }
  563}
  564
  565pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  566    let show_background = language_settings::language_settings(None, None, cx)
  567        .inlay_hints
  568        .show_background;
  569
  570    HighlightStyle {
  571        color: Some(cx.theme().status().hint),
  572        background_color: show_background.then(|| cx.theme().status().hint_background),
  573        ..HighlightStyle::default()
  574    }
  575}
  576
  577pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  578    InlineCompletionStyles {
  579        insertion: HighlightStyle {
  580            color: Some(cx.theme().status().predictive),
  581            ..HighlightStyle::default()
  582        },
  583        whitespace: HighlightStyle {
  584            background_color: Some(cx.theme().status().created_background),
  585            ..HighlightStyle::default()
  586        },
  587    }
  588}
  589
  590type CompletionId = usize;
  591
  592pub(crate) enum EditDisplayMode {
  593    TabAccept,
  594    DiffPopover,
  595    Inline,
  596}
  597
  598enum InlineCompletion {
  599    Edit {
  600        edits: Vec<(Range<Anchor>, String)>,
  601        edit_preview: Option<EditPreview>,
  602        display_mode: EditDisplayMode,
  603        snapshot: BufferSnapshot,
  604    },
  605    Move {
  606        target: Anchor,
  607        snapshot: BufferSnapshot,
  608    },
  609}
  610
  611struct InlineCompletionState {
  612    inlay_ids: Vec<InlayId>,
  613    completion: InlineCompletion,
  614    completion_id: Option<SharedString>,
  615    invalidation_range: Range<Anchor>,
  616}
  617
  618enum EditPredictionSettings {
  619    Disabled,
  620    Enabled {
  621        show_in_menu: bool,
  622        preview_requires_modifier: bool,
  623    },
  624}
  625
  626enum InlineCompletionHighlight {}
  627
  628#[derive(Debug, Clone)]
  629struct InlineDiagnostic {
  630    message: SharedString,
  631    group_id: usize,
  632    is_primary: bool,
  633    start: Point,
  634    severity: lsp::DiagnosticSeverity,
  635}
  636
  637pub enum MenuInlineCompletionsPolicy {
  638    Never,
  639    ByProvider,
  640}
  641
  642pub enum EditPredictionPreview {
  643    /// Modifier is not pressed
  644    Inactive { released_too_fast: bool },
  645    /// Modifier pressed
  646    Active {
  647        since: Instant,
  648        previous_scroll_position: Option<ScrollAnchor>,
  649    },
  650}
  651
  652impl EditPredictionPreview {
  653    pub fn released_too_fast(&self) -> bool {
  654        match self {
  655            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  656            EditPredictionPreview::Active { .. } => false,
  657        }
  658    }
  659
  660    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  661        if let EditPredictionPreview::Active {
  662            previous_scroll_position,
  663            ..
  664        } = self
  665        {
  666            *previous_scroll_position = scroll_position;
  667        }
  668    }
  669}
  670
  671pub struct ContextMenuOptions {
  672    pub min_entries_visible: usize,
  673    pub max_entries_visible: usize,
  674    pub placement: Option<ContextMenuPlacement>,
  675}
  676
  677#[derive(Debug, Clone, PartialEq, Eq)]
  678pub enum ContextMenuPlacement {
  679    Above,
  680    Below,
  681}
  682
  683#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  684struct EditorActionId(usize);
  685
  686impl EditorActionId {
  687    pub fn post_inc(&mut self) -> Self {
  688        let answer = self.0;
  689
  690        *self = Self(answer + 1);
  691
  692        Self(answer)
  693    }
  694}
  695
  696// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  697// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  698
  699type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  700type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled {
  720        /// The configuration currently present in the users settings.
  721        setting_configuration: bool,
  722        /// Whether to override the currently set visibility from the users setting.
  723        toggle_override: bool,
  724    },
  725}
  726
  727impl MinimapVisibility {
  728    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  729        if mode.is_full() {
  730            Self::Enabled {
  731                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  732                toggle_override: false,
  733            }
  734        } else {
  735            Self::Disabled
  736        }
  737    }
  738
  739    fn hidden(&self) -> Self {
  740        match *self {
  741            Self::Enabled {
  742                setting_configuration,
  743                ..
  744            } => Self::Enabled {
  745                setting_configuration,
  746                toggle_override: setting_configuration,
  747            },
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751
  752    fn disabled(&self) -> bool {
  753        match *self {
  754            Self::Disabled => true,
  755            _ => false,
  756        }
  757    }
  758
  759    fn settings_visibility(&self) -> bool {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => setting_configuration,
  765            _ => false,
  766        }
  767    }
  768
  769    fn visible(&self) -> bool {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                toggle_override,
  774            } => setting_configuration ^ toggle_override,
  775            _ => false,
  776        }
  777    }
  778
  779    fn toggle_visibility(&self) -> Self {
  780        match *self {
  781            Self::Enabled {
  782                toggle_override,
  783                setting_configuration,
  784            } => Self::Enabled {
  785                setting_configuration,
  786                toggle_override: !toggle_override,
  787            },
  788            Self::Disabled => Self::Disabled,
  789        }
  790    }
  791}
  792
  793#[derive(Clone, Debug)]
  794struct RunnableTasks {
  795    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  796    offset: multi_buffer::Anchor,
  797    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  798    column: u32,
  799    // Values of all named captures, including those starting with '_'
  800    extra_variables: HashMap<String, String>,
  801    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  802    context_range: Range<BufferOffset>,
  803}
  804
  805impl RunnableTasks {
  806    fn resolve<'a>(
  807        &'a self,
  808        cx: &'a task::TaskContext,
  809    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  810        self.templates.iter().filter_map(|(kind, template)| {
  811            template
  812                .resolve_task(&kind.to_id_base(), cx)
  813                .map(|task| (kind.clone(), task))
  814        })
  815    }
  816}
  817
  818#[derive(Clone)]
  819pub struct ResolvedTasks {
  820    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  821    position: Anchor,
  822}
  823
  824#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  825struct BufferOffset(usize);
  826
  827// Addons allow storing per-editor state in other crates (e.g. Vim)
  828pub trait Addon: 'static {
  829    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  830
  831    fn render_buffer_header_controls(
  832        &self,
  833        _: &ExcerptInfo,
  834        _: &Window,
  835        _: &App,
  836    ) -> Option<AnyElement> {
  837        None
  838    }
  839
  840    fn to_any(&self) -> &dyn std::any::Any;
  841
  842    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  843        None
  844    }
  845}
  846
  847/// A set of caret positions, registered when the editor was edited.
  848pub struct ChangeList {
  849    changes: Vec<Vec<Anchor>>,
  850    /// Currently "selected" change.
  851    position: Option<usize>,
  852}
  853
  854impl ChangeList {
  855    pub fn new() -> Self {
  856        Self {
  857            changes: Vec::new(),
  858            position: None,
  859        }
  860    }
  861
  862    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  863    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  864    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  865        if self.changes.is_empty() {
  866            return None;
  867        }
  868
  869        let prev = self.position.unwrap_or(self.changes.len());
  870        let next = if direction == Direction::Prev {
  871            prev.saturating_sub(count)
  872        } else {
  873            (prev + count).min(self.changes.len() - 1)
  874        };
  875        self.position = Some(next);
  876        self.changes.get(next).map(|anchors| anchors.as_slice())
  877    }
  878
  879    /// Adds a new change to the list, resetting the change list position.
  880    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  881        self.position.take();
  882        if pop_state {
  883            self.changes.pop();
  884        }
  885        self.changes.push(new_positions.clone());
  886    }
  887
  888    pub fn last(&self) -> Option<&[Anchor]> {
  889        self.changes.last().map(|anchors| anchors.as_slice())
  890    }
  891}
  892
  893#[derive(Clone)]
  894struct InlineBlamePopoverState {
  895    scroll_handle: ScrollHandle,
  896    commit_message: Option<ParsedCommitMessage>,
  897    markdown: Entity<Markdown>,
  898}
  899
  900struct InlineBlamePopover {
  901    position: gpui::Point<Pixels>,
  902    show_task: Option<Task<()>>,
  903    hide_task: Option<Task<()>>,
  904    popover_bounds: Option<Bounds<Pixels>>,
  905    popover_state: InlineBlamePopoverState,
  906}
  907
  908/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  909/// a breakpoint on them.
  910#[derive(Clone, Copy, Debug)]
  911struct PhantomBreakpointIndicator {
  912    display_row: DisplayRow,
  913    /// There's a small debounce between hovering over the line and showing the indicator.
  914    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  915    is_active: bool,
  916    collides_with_existing_breakpoint: bool,
  917}
  918/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  919///
  920/// See the [module level documentation](self) for more information.
  921pub struct Editor {
  922    focus_handle: FocusHandle,
  923    last_focused_descendant: Option<WeakFocusHandle>,
  924    /// The text buffer being edited
  925    buffer: Entity<MultiBuffer>,
  926    /// Map of how text in the buffer should be displayed.
  927    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  928    pub display_map: Entity<DisplayMap>,
  929    pub selections: SelectionsCollection,
  930    pub scroll_manager: ScrollManager,
  931    /// When inline assist editors are linked, they all render cursors because
  932    /// typing enters text into each of them, even the ones that aren't focused.
  933    pub(crate) show_cursor_when_unfocused: bool,
  934    columnar_selection_tail: Option<Anchor>,
  935    columnar_display_point: Option<DisplayPoint>,
  936    add_selections_state: Option<AddSelectionsState>,
  937    select_next_state: Option<SelectNextState>,
  938    select_prev_state: Option<SelectNextState>,
  939    selection_history: SelectionHistory,
  940    defer_selection_effects: bool,
  941    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  942    autoclose_regions: Vec<AutocloseRegion>,
  943    snippet_stack: InvalidationStack<SnippetState>,
  944    select_syntax_node_history: SelectSyntaxNodeHistory,
  945    ime_transaction: Option<TransactionId>,
  946    pub diagnostics_max_severity: DiagnosticSeverity,
  947    active_diagnostics: ActiveDiagnostic,
  948    show_inline_diagnostics: bool,
  949    inline_diagnostics_update: Task<()>,
  950    inline_diagnostics_enabled: bool,
  951    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  952    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  953    hard_wrap: Option<usize>,
  954
  955    // TODO: make this a access method
  956    pub project: Option<Entity<Project>>,
  957    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  958    completion_provider: Option<Rc<dyn CompletionProvider>>,
  959    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  960    blink_manager: Entity<BlinkManager>,
  961    show_cursor_names: bool,
  962    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  963    pub show_local_selections: bool,
  964    mode: EditorMode,
  965    show_breadcrumbs: bool,
  966    show_gutter: bool,
  967    show_scrollbars: ScrollbarAxes,
  968    minimap_visibility: MinimapVisibility,
  969    offset_content: bool,
  970    disable_expand_excerpt_buttons: bool,
  971    show_line_numbers: Option<bool>,
  972    use_relative_line_numbers: Option<bool>,
  973    show_git_diff_gutter: Option<bool>,
  974    show_code_actions: Option<bool>,
  975    show_runnables: Option<bool>,
  976    show_breakpoints: Option<bool>,
  977    show_wrap_guides: Option<bool>,
  978    show_indent_guides: Option<bool>,
  979    placeholder_text: Option<Arc<str>>,
  980    highlight_order: usize,
  981    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  982    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  983    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  984    scrollbar_marker_state: ScrollbarMarkerState,
  985    active_indent_guides_state: ActiveIndentGuidesState,
  986    nav_history: Option<ItemNavHistory>,
  987    context_menu: RefCell<Option<CodeContextMenu>>,
  988    context_menu_options: Option<ContextMenuOptions>,
  989    mouse_context_menu: Option<MouseContextMenu>,
  990    completion_tasks: Vec<(CompletionId, Task<()>)>,
  991    inline_blame_popover: Option<InlineBlamePopover>,
  992    signature_help_state: SignatureHelpState,
  993    auto_signature_help: Option<bool>,
  994    find_all_references_task_sources: Vec<Anchor>,
  995    next_completion_id: CompletionId,
  996    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  997    code_actions_task: Option<Task<Result<()>>>,
  998    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  999    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1000    document_highlights_task: Option<Task<()>>,
 1001    linked_editing_range_task: Option<Task<Option<()>>>,
 1002    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1003    pending_rename: Option<RenameState>,
 1004    searchable: bool,
 1005    cursor_shape: CursorShape,
 1006    current_line_highlight: Option<CurrentLineHighlight>,
 1007    collapse_matches: bool,
 1008    autoindent_mode: Option<AutoindentMode>,
 1009    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1010    input_enabled: bool,
 1011    use_modal_editing: bool,
 1012    read_only: bool,
 1013    leader_id: Option<CollaboratorId>,
 1014    remote_id: Option<ViewId>,
 1015    pub hover_state: HoverState,
 1016    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1017    gutter_hovered: bool,
 1018    hovered_link_state: Option<HoveredLinkState>,
 1019    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1020    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1021    active_inline_completion: Option<InlineCompletionState>,
 1022    /// Used to prevent flickering as the user types while the menu is open
 1023    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1024    edit_prediction_settings: EditPredictionSettings,
 1025    inline_completions_hidden_for_vim_mode: bool,
 1026    show_inline_completions_override: Option<bool>,
 1027    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1028    edit_prediction_preview: EditPredictionPreview,
 1029    edit_prediction_indent_conflict: bool,
 1030    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1031    inlay_hint_cache: InlayHintCache,
 1032    next_inlay_id: usize,
 1033    _subscriptions: Vec<Subscription>,
 1034    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1035    gutter_dimensions: GutterDimensions,
 1036    style: Option<EditorStyle>,
 1037    text_style_refinement: Option<TextStyleRefinement>,
 1038    next_editor_action_id: EditorActionId,
 1039    editor_actions:
 1040        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1041    use_autoclose: bool,
 1042    use_auto_surround: bool,
 1043    auto_replace_emoji_shortcode: bool,
 1044    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1045    show_git_blame_gutter: bool,
 1046    show_git_blame_inline: bool,
 1047    show_git_blame_inline_delay_task: Option<Task<()>>,
 1048    git_blame_inline_enabled: bool,
 1049    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1050    serialize_dirty_buffers: bool,
 1051    show_selection_menu: Option<bool>,
 1052    blame: Option<Entity<GitBlame>>,
 1053    blame_subscription: Option<Subscription>,
 1054    custom_context_menu: Option<
 1055        Box<
 1056            dyn 'static
 1057                + Fn(
 1058                    &mut Self,
 1059                    DisplayPoint,
 1060                    &mut Window,
 1061                    &mut Context<Self>,
 1062                ) -> Option<Entity<ui::ContextMenu>>,
 1063        >,
 1064    >,
 1065    last_bounds: Option<Bounds<Pixels>>,
 1066    last_position_map: Option<Rc<PositionMap>>,
 1067    expect_bounds_change: Option<Bounds<Pixels>>,
 1068    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1069    tasks_update_task: Option<Task<()>>,
 1070    breakpoint_store: Option<Entity<BreakpointStore>>,
 1071    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1072    in_project_search: bool,
 1073    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1074    breadcrumb_header: Option<String>,
 1075    focused_block: Option<FocusedBlock>,
 1076    next_scroll_position: NextScrollCursorCenterTopBottom,
 1077    addons: HashMap<TypeId, Box<dyn Addon>>,
 1078    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1079    load_diff_task: Option<Shared<Task<()>>>,
 1080    /// Whether we are temporarily displaying a diff other than git's
 1081    temporary_diff_override: bool,
 1082    selection_mark_mode: bool,
 1083    toggle_fold_multiple_buffers: Task<()>,
 1084    _scroll_cursor_center_top_bottom_task: Task<()>,
 1085    serialize_selections: Task<()>,
 1086    serialize_folds: Task<()>,
 1087    mouse_cursor_hidden: bool,
 1088    minimap: Option<Entity<Self>>,
 1089    hide_mouse_mode: HideMouseMode,
 1090    pub change_list: ChangeList,
 1091    inline_value_cache: InlineValueCache,
 1092}
 1093
 1094#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1095enum NextScrollCursorCenterTopBottom {
 1096    #[default]
 1097    Center,
 1098    Top,
 1099    Bottom,
 1100}
 1101
 1102impl NextScrollCursorCenterTopBottom {
 1103    fn next(&self) -> Self {
 1104        match self {
 1105            Self::Center => Self::Top,
 1106            Self::Top => Self::Bottom,
 1107            Self::Bottom => Self::Center,
 1108        }
 1109    }
 1110}
 1111
 1112#[derive(Clone)]
 1113pub struct EditorSnapshot {
 1114    pub mode: EditorMode,
 1115    show_gutter: bool,
 1116    show_line_numbers: Option<bool>,
 1117    show_git_diff_gutter: Option<bool>,
 1118    show_code_actions: Option<bool>,
 1119    show_runnables: Option<bool>,
 1120    show_breakpoints: Option<bool>,
 1121    git_blame_gutter_max_author_length: Option<usize>,
 1122    pub display_snapshot: DisplaySnapshot,
 1123    pub placeholder_text: Option<Arc<str>>,
 1124    is_focused: bool,
 1125    scroll_anchor: ScrollAnchor,
 1126    ongoing_scroll: OngoingScroll,
 1127    current_line_highlight: CurrentLineHighlight,
 1128    gutter_hovered: bool,
 1129}
 1130
 1131#[derive(Default, Debug, Clone, Copy)]
 1132pub struct GutterDimensions {
 1133    pub left_padding: Pixels,
 1134    pub right_padding: Pixels,
 1135    pub width: Pixels,
 1136    pub margin: Pixels,
 1137    pub git_blame_entries_width: Option<Pixels>,
 1138}
 1139
 1140impl GutterDimensions {
 1141    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1142        Self {
 1143            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1144            ..Default::default()
 1145        }
 1146    }
 1147
 1148    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1149        -cx.text_system().descent(font_id, font_size)
 1150    }
 1151    /// The full width of the space taken up by the gutter.
 1152    pub fn full_width(&self) -> Pixels {
 1153        self.margin + self.width
 1154    }
 1155
 1156    /// The width of the space reserved for the fold indicators,
 1157    /// use alongside 'justify_end' and `gutter_width` to
 1158    /// right align content with the line numbers
 1159    pub fn fold_area_width(&self) -> Pixels {
 1160        self.margin + self.right_padding
 1161    }
 1162}
 1163
 1164#[derive(Debug)]
 1165pub struct RemoteSelection {
 1166    pub replica_id: ReplicaId,
 1167    pub selection: Selection<Anchor>,
 1168    pub cursor_shape: CursorShape,
 1169    pub collaborator_id: CollaboratorId,
 1170    pub line_mode: bool,
 1171    pub user_name: Option<SharedString>,
 1172    pub color: PlayerColor,
 1173}
 1174
 1175#[derive(Clone, Debug)]
 1176struct SelectionHistoryEntry {
 1177    selections: Arc<[Selection<Anchor>]>,
 1178    select_next_state: Option<SelectNextState>,
 1179    select_prev_state: Option<SelectNextState>,
 1180    add_selections_state: Option<AddSelectionsState>,
 1181}
 1182
 1183enum SelectionHistoryMode {
 1184    Normal,
 1185    Undoing,
 1186    Redoing,
 1187}
 1188
 1189#[derive(Clone, PartialEq, Eq, Hash)]
 1190struct HoveredCursor {
 1191    replica_id: u16,
 1192    selection_id: usize,
 1193}
 1194
 1195impl Default for SelectionHistoryMode {
 1196    fn default() -> Self {
 1197        Self::Normal
 1198    }
 1199}
 1200
 1201struct DeferredSelectionEffectsState {
 1202    changed: bool,
 1203    should_update_completions: bool,
 1204    autoscroll: Option<Autoscroll>,
 1205    old_cursor_position: Anchor,
 1206    history_entry: SelectionHistoryEntry,
 1207}
 1208
 1209#[derive(Default)]
 1210struct SelectionHistory {
 1211    #[allow(clippy::type_complexity)]
 1212    selections_by_transaction:
 1213        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1214    mode: SelectionHistoryMode,
 1215    undo_stack: VecDeque<SelectionHistoryEntry>,
 1216    redo_stack: VecDeque<SelectionHistoryEntry>,
 1217}
 1218
 1219impl SelectionHistory {
 1220    fn insert_transaction(
 1221        &mut self,
 1222        transaction_id: TransactionId,
 1223        selections: Arc<[Selection<Anchor>]>,
 1224    ) {
 1225        self.selections_by_transaction
 1226            .insert(transaction_id, (selections, None));
 1227    }
 1228
 1229    #[allow(clippy::type_complexity)]
 1230    fn transaction(
 1231        &self,
 1232        transaction_id: TransactionId,
 1233    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1234        self.selections_by_transaction.get(&transaction_id)
 1235    }
 1236
 1237    #[allow(clippy::type_complexity)]
 1238    fn transaction_mut(
 1239        &mut self,
 1240        transaction_id: TransactionId,
 1241    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1242        self.selections_by_transaction.get_mut(&transaction_id)
 1243    }
 1244
 1245    fn push(&mut self, entry: SelectionHistoryEntry) {
 1246        if !entry.selections.is_empty() {
 1247            match self.mode {
 1248                SelectionHistoryMode::Normal => {
 1249                    self.push_undo(entry);
 1250                    self.redo_stack.clear();
 1251                }
 1252                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1253                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1254            }
 1255        }
 1256    }
 1257
 1258    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1259        if self
 1260            .undo_stack
 1261            .back()
 1262            .map_or(true, |e| e.selections != entry.selections)
 1263        {
 1264            self.undo_stack.push_back(entry);
 1265            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1266                self.undo_stack.pop_front();
 1267            }
 1268        }
 1269    }
 1270
 1271    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1272        if self
 1273            .redo_stack
 1274            .back()
 1275            .map_or(true, |e| e.selections != entry.selections)
 1276        {
 1277            self.redo_stack.push_back(entry);
 1278            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1279                self.redo_stack.pop_front();
 1280            }
 1281        }
 1282    }
 1283}
 1284
 1285#[derive(Clone, Copy)]
 1286pub struct RowHighlightOptions {
 1287    pub autoscroll: bool,
 1288    pub include_gutter: bool,
 1289}
 1290
 1291impl Default for RowHighlightOptions {
 1292    fn default() -> Self {
 1293        Self {
 1294            autoscroll: Default::default(),
 1295            include_gutter: true,
 1296        }
 1297    }
 1298}
 1299
 1300struct RowHighlight {
 1301    index: usize,
 1302    range: Range<Anchor>,
 1303    color: Hsla,
 1304    options: RowHighlightOptions,
 1305    type_id: TypeId,
 1306}
 1307
 1308#[derive(Clone, Debug)]
 1309struct AddSelectionsState {
 1310    above: bool,
 1311    stack: Vec<usize>,
 1312}
 1313
 1314#[derive(Clone)]
 1315struct SelectNextState {
 1316    query: AhoCorasick,
 1317    wordwise: bool,
 1318    done: bool,
 1319}
 1320
 1321impl std::fmt::Debug for SelectNextState {
 1322    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1323        f.debug_struct(std::any::type_name::<Self>())
 1324            .field("wordwise", &self.wordwise)
 1325            .field("done", &self.done)
 1326            .finish()
 1327    }
 1328}
 1329
 1330#[derive(Debug)]
 1331struct AutocloseRegion {
 1332    selection_id: usize,
 1333    range: Range<Anchor>,
 1334    pair: BracketPair,
 1335}
 1336
 1337#[derive(Debug)]
 1338struct SnippetState {
 1339    ranges: Vec<Vec<Range<Anchor>>>,
 1340    active_index: usize,
 1341    choices: Vec<Option<Vec<String>>>,
 1342}
 1343
 1344#[doc(hidden)]
 1345pub struct RenameState {
 1346    pub range: Range<Anchor>,
 1347    pub old_name: Arc<str>,
 1348    pub editor: Entity<Editor>,
 1349    block_id: CustomBlockId,
 1350}
 1351
 1352struct InvalidationStack<T>(Vec<T>);
 1353
 1354struct RegisteredInlineCompletionProvider {
 1355    provider: Arc<dyn InlineCompletionProviderHandle>,
 1356    _subscription: Subscription,
 1357}
 1358
 1359#[derive(Debug, PartialEq, Eq)]
 1360pub struct ActiveDiagnosticGroup {
 1361    pub active_range: Range<Anchor>,
 1362    pub active_message: String,
 1363    pub group_id: usize,
 1364    pub blocks: HashSet<CustomBlockId>,
 1365}
 1366
 1367#[derive(Debug, PartialEq, Eq)]
 1368
 1369pub(crate) enum ActiveDiagnostic {
 1370    None,
 1371    All,
 1372    Group(ActiveDiagnosticGroup),
 1373}
 1374
 1375#[derive(Serialize, Deserialize, Clone, Debug)]
 1376pub struct ClipboardSelection {
 1377    /// The number of bytes in this selection.
 1378    pub len: usize,
 1379    /// Whether this was a full-line selection.
 1380    pub is_entire_line: bool,
 1381    /// The indentation of the first line when this content was originally copied.
 1382    pub first_line_indent: u32,
 1383}
 1384
 1385// selections, scroll behavior, was newest selection reversed
 1386type SelectSyntaxNodeHistoryState = (
 1387    Box<[Selection<usize>]>,
 1388    SelectSyntaxNodeScrollBehavior,
 1389    bool,
 1390);
 1391
 1392#[derive(Default)]
 1393struct SelectSyntaxNodeHistory {
 1394    stack: Vec<SelectSyntaxNodeHistoryState>,
 1395    // disable temporarily to allow changing selections without losing the stack
 1396    pub disable_clearing: bool,
 1397}
 1398
 1399impl SelectSyntaxNodeHistory {
 1400    pub fn try_clear(&mut self) {
 1401        if !self.disable_clearing {
 1402            self.stack.clear();
 1403        }
 1404    }
 1405
 1406    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1407        self.stack.push(selection);
 1408    }
 1409
 1410    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1411        self.stack.pop()
 1412    }
 1413}
 1414
 1415enum SelectSyntaxNodeScrollBehavior {
 1416    CursorTop,
 1417    FitSelection,
 1418    CursorBottom,
 1419}
 1420
 1421#[derive(Debug)]
 1422pub(crate) struct NavigationData {
 1423    cursor_anchor: Anchor,
 1424    cursor_position: Point,
 1425    scroll_anchor: ScrollAnchor,
 1426    scroll_top_row: u32,
 1427}
 1428
 1429#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1430pub enum GotoDefinitionKind {
 1431    Symbol,
 1432    Declaration,
 1433    Type,
 1434    Implementation,
 1435}
 1436
 1437#[derive(Debug, Clone)]
 1438enum InlayHintRefreshReason {
 1439    ModifiersChanged(bool),
 1440    Toggle(bool),
 1441    SettingsChange(InlayHintSettings),
 1442    NewLinesShown,
 1443    BufferEdited(HashSet<Arc<Language>>),
 1444    RefreshRequested,
 1445    ExcerptsRemoved(Vec<ExcerptId>),
 1446}
 1447
 1448impl InlayHintRefreshReason {
 1449    fn description(&self) -> &'static str {
 1450        match self {
 1451            Self::ModifiersChanged(_) => "modifiers changed",
 1452            Self::Toggle(_) => "toggle",
 1453            Self::SettingsChange(_) => "settings change",
 1454            Self::NewLinesShown => "new lines shown",
 1455            Self::BufferEdited(_) => "buffer edited",
 1456            Self::RefreshRequested => "refresh requested",
 1457            Self::ExcerptsRemoved(_) => "excerpts removed",
 1458        }
 1459    }
 1460}
 1461
 1462pub enum FormatTarget {
 1463    Buffers,
 1464    Ranges(Vec<Range<MultiBufferPoint>>),
 1465}
 1466
 1467pub(crate) struct FocusedBlock {
 1468    id: BlockId,
 1469    focus_handle: WeakFocusHandle,
 1470}
 1471
 1472#[derive(Clone)]
 1473enum JumpData {
 1474    MultiBufferRow {
 1475        row: MultiBufferRow,
 1476        line_offset_from_top: u32,
 1477    },
 1478    MultiBufferPoint {
 1479        excerpt_id: ExcerptId,
 1480        position: Point,
 1481        anchor: text::Anchor,
 1482        line_offset_from_top: u32,
 1483    },
 1484}
 1485
 1486pub enum MultibufferSelectionMode {
 1487    First,
 1488    All,
 1489}
 1490
 1491#[derive(Clone, Copy, Debug, Default)]
 1492pub struct RewrapOptions {
 1493    pub override_language_settings: bool,
 1494    pub preserve_existing_whitespace: bool,
 1495}
 1496
 1497impl Editor {
 1498    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1499        let buffer = cx.new(|cx| Buffer::local("", cx));
 1500        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1501        Self::new(
 1502            EditorMode::SingleLine { auto_width: false },
 1503            buffer,
 1504            None,
 1505            window,
 1506            cx,
 1507        )
 1508    }
 1509
 1510    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1511        let buffer = cx.new(|cx| Buffer::local("", cx));
 1512        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1513        Self::new(EditorMode::full(), buffer, None, window, cx)
 1514    }
 1515
 1516    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1517        let buffer = cx.new(|cx| Buffer::local("", cx));
 1518        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1519        Self::new(
 1520            EditorMode::SingleLine { auto_width: true },
 1521            buffer,
 1522            None,
 1523            window,
 1524            cx,
 1525        )
 1526    }
 1527
 1528    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1529        let buffer = cx.new(|cx| Buffer::local("", cx));
 1530        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1531        Self::new(
 1532            EditorMode::AutoHeight { max_lines },
 1533            buffer,
 1534            None,
 1535            window,
 1536            cx,
 1537        )
 1538    }
 1539
 1540    pub fn for_buffer(
 1541        buffer: Entity<Buffer>,
 1542        project: Option<Entity<Project>>,
 1543        window: &mut Window,
 1544        cx: &mut Context<Self>,
 1545    ) -> Self {
 1546        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1547        Self::new(EditorMode::full(), buffer, project, window, cx)
 1548    }
 1549
 1550    pub fn for_multibuffer(
 1551        buffer: Entity<MultiBuffer>,
 1552        project: Option<Entity<Project>>,
 1553        window: &mut Window,
 1554        cx: &mut Context<Self>,
 1555    ) -> Self {
 1556        Self::new(EditorMode::full(), buffer, project, window, cx)
 1557    }
 1558
 1559    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1560        let mut clone = Self::new(
 1561            self.mode.clone(),
 1562            self.buffer.clone(),
 1563            self.project.clone(),
 1564            window,
 1565            cx,
 1566        );
 1567        self.display_map.update(cx, |display_map, cx| {
 1568            let snapshot = display_map.snapshot(cx);
 1569            clone.display_map.update(cx, |display_map, cx| {
 1570                display_map.set_state(&snapshot, cx);
 1571            });
 1572        });
 1573        clone.folds_did_change(cx);
 1574        clone.selections.clone_state(&self.selections);
 1575        clone.scroll_manager.clone_state(&self.scroll_manager);
 1576        clone.searchable = self.searchable;
 1577        clone.read_only = self.read_only;
 1578        clone
 1579    }
 1580
 1581    pub fn new(
 1582        mode: EditorMode,
 1583        buffer: Entity<MultiBuffer>,
 1584        project: Option<Entity<Project>>,
 1585        window: &mut Window,
 1586        cx: &mut Context<Self>,
 1587    ) -> Self {
 1588        Editor::new_internal(mode, buffer, project, None, window, cx)
 1589    }
 1590
 1591    fn new_internal(
 1592        mode: EditorMode,
 1593        buffer: Entity<MultiBuffer>,
 1594        project: Option<Entity<Project>>,
 1595        display_map: Option<Entity<DisplayMap>>,
 1596        window: &mut Window,
 1597        cx: &mut Context<Self>,
 1598    ) -> Self {
 1599        debug_assert!(
 1600            display_map.is_none() || mode.is_minimap(),
 1601            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1602        );
 1603
 1604        let full_mode = mode.is_full();
 1605        let diagnostics_max_severity = if full_mode {
 1606            EditorSettings::get_global(cx)
 1607                .diagnostics_max_severity
 1608                .unwrap_or(DiagnosticSeverity::Hint)
 1609        } else {
 1610            DiagnosticSeverity::Off
 1611        };
 1612        let style = window.text_style();
 1613        let font_size = style.font_size.to_pixels(window.rem_size());
 1614        let editor = cx.entity().downgrade();
 1615        let fold_placeholder = FoldPlaceholder {
 1616            constrain_width: true,
 1617            render: Arc::new(move |fold_id, fold_range, cx| {
 1618                let editor = editor.clone();
 1619                div()
 1620                    .id(fold_id)
 1621                    .bg(cx.theme().colors().ghost_element_background)
 1622                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1623                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1624                    .rounded_xs()
 1625                    .size_full()
 1626                    .cursor_pointer()
 1627                    .child("")
 1628                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1629                    .on_click(move |_, _window, cx| {
 1630                        editor
 1631                            .update(cx, |editor, cx| {
 1632                                editor.unfold_ranges(
 1633                                    &[fold_range.start..fold_range.end],
 1634                                    true,
 1635                                    false,
 1636                                    cx,
 1637                                );
 1638                                cx.stop_propagation();
 1639                            })
 1640                            .ok();
 1641                    })
 1642                    .into_any()
 1643            }),
 1644            merge_adjacent: true,
 1645            ..FoldPlaceholder::default()
 1646        };
 1647        let display_map = display_map.unwrap_or_else(|| {
 1648            cx.new(|cx| {
 1649                DisplayMap::new(
 1650                    buffer.clone(),
 1651                    style.font(),
 1652                    font_size,
 1653                    None,
 1654                    FILE_HEADER_HEIGHT,
 1655                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1656                    fold_placeholder,
 1657                    diagnostics_max_severity,
 1658                    cx,
 1659                )
 1660            })
 1661        });
 1662
 1663        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1664
 1665        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1666
 1667        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1668            .then(|| language_settings::SoftWrap::None);
 1669
 1670        let mut project_subscriptions = Vec::new();
 1671        if mode.is_full() {
 1672            if let Some(project) = project.as_ref() {
 1673                project_subscriptions.push(cx.subscribe_in(
 1674                    project,
 1675                    window,
 1676                    |editor, _, event, window, cx| match event {
 1677                        project::Event::RefreshCodeLens => {
 1678                            // we always query lens with actions, without storing them, always refreshing them
 1679                        }
 1680                        project::Event::RefreshInlayHints => {
 1681                            editor
 1682                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1683                        }
 1684                        project::Event::LanguageServerAdded(..)
 1685                        | project::Event::LanguageServerRemoved(..) => {
 1686                            if editor.tasks_update_task.is_none() {
 1687                                editor.tasks_update_task =
 1688                                    Some(editor.refresh_runnables(window, cx));
 1689                            }
 1690                        }
 1691                        project::Event::SnippetEdit(id, snippet_edits) => {
 1692                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1693                                let focus_handle = editor.focus_handle(cx);
 1694                                if focus_handle.is_focused(window) {
 1695                                    let snapshot = buffer.read(cx).snapshot();
 1696                                    for (range, snippet) in snippet_edits {
 1697                                        let editor_range =
 1698                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1699                                        editor
 1700                                            .insert_snippet(
 1701                                                &[editor_range],
 1702                                                snippet.clone(),
 1703                                                window,
 1704                                                cx,
 1705                                            )
 1706                                            .ok();
 1707                                    }
 1708                                }
 1709                            }
 1710                        }
 1711                        _ => {}
 1712                    },
 1713                ));
 1714                if let Some(task_inventory) = project
 1715                    .read(cx)
 1716                    .task_store()
 1717                    .read(cx)
 1718                    .task_inventory()
 1719                    .cloned()
 1720                {
 1721                    project_subscriptions.push(cx.observe_in(
 1722                        &task_inventory,
 1723                        window,
 1724                        |editor, _, window, cx| {
 1725                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1726                        },
 1727                    ));
 1728                };
 1729
 1730                project_subscriptions.push(cx.subscribe_in(
 1731                    &project.read(cx).breakpoint_store(),
 1732                    window,
 1733                    |editor, _, event, window, cx| match event {
 1734                        BreakpointStoreEvent::ClearDebugLines => {
 1735                            editor.clear_row_highlights::<ActiveDebugLine>();
 1736                            editor.refresh_inline_values(cx);
 1737                        }
 1738                        BreakpointStoreEvent::SetDebugLine => {
 1739                            if editor.go_to_active_debug_line(window, cx) {
 1740                                cx.stop_propagation();
 1741                            }
 1742
 1743                            editor.refresh_inline_values(cx);
 1744                        }
 1745                        _ => {}
 1746                    },
 1747                ));
 1748            }
 1749        }
 1750
 1751        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1752
 1753        let inlay_hint_settings =
 1754            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1755        let focus_handle = cx.focus_handle();
 1756        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1757            .detach();
 1758        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1759            .detach();
 1760        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1761            .detach();
 1762        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1763            .detach();
 1764
 1765        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1766            Some(false)
 1767        } else {
 1768            None
 1769        };
 1770
 1771        let breakpoint_store = match (&mode, project.as_ref()) {
 1772            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1773            _ => None,
 1774        };
 1775
 1776        let mut code_action_providers = Vec::new();
 1777        let mut load_uncommitted_diff = None;
 1778        if let Some(project) = project.clone() {
 1779            load_uncommitted_diff = Some(
 1780                update_uncommitted_diff_for_buffer(
 1781                    cx.entity(),
 1782                    &project,
 1783                    buffer.read(cx).all_buffers(),
 1784                    buffer.clone(),
 1785                    cx,
 1786                )
 1787                .shared(),
 1788            );
 1789            code_action_providers.push(Rc::new(project) as Rc<_>);
 1790        }
 1791
 1792        let mut this = Self {
 1793            focus_handle,
 1794            show_cursor_when_unfocused: false,
 1795            last_focused_descendant: None,
 1796            buffer: buffer.clone(),
 1797            display_map: display_map.clone(),
 1798            selections,
 1799            scroll_manager: ScrollManager::new(cx),
 1800            columnar_selection_tail: None,
 1801            columnar_display_point: None,
 1802            add_selections_state: None,
 1803            select_next_state: None,
 1804            select_prev_state: None,
 1805            selection_history: SelectionHistory::default(),
 1806            defer_selection_effects: false,
 1807            deferred_selection_effects_state: None,
 1808            autoclose_regions: Vec::new(),
 1809            snippet_stack: InvalidationStack::default(),
 1810            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1811            ime_transaction: None,
 1812            active_diagnostics: ActiveDiagnostic::None,
 1813            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1814            inline_diagnostics_update: Task::ready(()),
 1815            inline_diagnostics: Vec::new(),
 1816            soft_wrap_mode_override,
 1817            diagnostics_max_severity,
 1818            hard_wrap: None,
 1819            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1820            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1821            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1822            project,
 1823            blink_manager: blink_manager.clone(),
 1824            show_local_selections: true,
 1825            show_scrollbars: ScrollbarAxes {
 1826                horizontal: full_mode,
 1827                vertical: full_mode,
 1828            },
 1829            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1830            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1831            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1832            show_gutter: mode.is_full(),
 1833            show_line_numbers: None,
 1834            use_relative_line_numbers: None,
 1835            disable_expand_excerpt_buttons: false,
 1836            show_git_diff_gutter: None,
 1837            show_code_actions: None,
 1838            show_runnables: None,
 1839            show_breakpoints: None,
 1840            show_wrap_guides: None,
 1841            show_indent_guides,
 1842            placeholder_text: None,
 1843            highlight_order: 0,
 1844            highlighted_rows: HashMap::default(),
 1845            background_highlights: TreeMap::default(),
 1846            gutter_highlights: TreeMap::default(),
 1847            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1848            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1849            nav_history: None,
 1850            context_menu: RefCell::new(None),
 1851            context_menu_options: None,
 1852            mouse_context_menu: None,
 1853            completion_tasks: Vec::new(),
 1854            inline_blame_popover: None,
 1855            signature_help_state: SignatureHelpState::default(),
 1856            auto_signature_help: None,
 1857            find_all_references_task_sources: Vec::new(),
 1858            next_completion_id: 0,
 1859            next_inlay_id: 0,
 1860            code_action_providers,
 1861            available_code_actions: None,
 1862            code_actions_task: None,
 1863            quick_selection_highlight_task: None,
 1864            debounced_selection_highlight_task: None,
 1865            document_highlights_task: None,
 1866            linked_editing_range_task: None,
 1867            pending_rename: None,
 1868            searchable: true,
 1869            cursor_shape: EditorSettings::get_global(cx)
 1870                .cursor_shape
 1871                .unwrap_or_default(),
 1872            current_line_highlight: None,
 1873            autoindent_mode: Some(AutoindentMode::EachLine),
 1874            collapse_matches: false,
 1875            workspace: None,
 1876            input_enabled: true,
 1877            use_modal_editing: mode.is_full(),
 1878            read_only: mode.is_minimap(),
 1879            use_autoclose: true,
 1880            use_auto_surround: true,
 1881            auto_replace_emoji_shortcode: false,
 1882            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1883            leader_id: None,
 1884            remote_id: None,
 1885            hover_state: HoverState::default(),
 1886            pending_mouse_down: None,
 1887            hovered_link_state: None,
 1888            edit_prediction_provider: None,
 1889            active_inline_completion: None,
 1890            stale_inline_completion_in_menu: None,
 1891            edit_prediction_preview: EditPredictionPreview::Inactive {
 1892                released_too_fast: false,
 1893            },
 1894            inline_diagnostics_enabled: mode.is_full(),
 1895            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1896            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1897
 1898            gutter_hovered: false,
 1899            pixel_position_of_newest_cursor: None,
 1900            last_bounds: None,
 1901            last_position_map: None,
 1902            expect_bounds_change: None,
 1903            gutter_dimensions: GutterDimensions::default(),
 1904            style: None,
 1905            show_cursor_names: false,
 1906            hovered_cursors: HashMap::default(),
 1907            next_editor_action_id: EditorActionId::default(),
 1908            editor_actions: Rc::default(),
 1909            inline_completions_hidden_for_vim_mode: false,
 1910            show_inline_completions_override: None,
 1911            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1912            edit_prediction_settings: EditPredictionSettings::Disabled,
 1913            edit_prediction_indent_conflict: false,
 1914            edit_prediction_requires_modifier_in_indent_conflict: true,
 1915            custom_context_menu: None,
 1916            show_git_blame_gutter: false,
 1917            show_git_blame_inline: false,
 1918            show_selection_menu: None,
 1919            show_git_blame_inline_delay_task: None,
 1920            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1921            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1922            serialize_dirty_buffers: !mode.is_minimap()
 1923                && ProjectSettings::get_global(cx)
 1924                    .session
 1925                    .restore_unsaved_buffers,
 1926            blame: None,
 1927            blame_subscription: None,
 1928            tasks: BTreeMap::default(),
 1929
 1930            breakpoint_store,
 1931            gutter_breakpoint_indicator: (None, None),
 1932            _subscriptions: vec![
 1933                cx.observe(&buffer, Self::on_buffer_changed),
 1934                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1935                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1936                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1937                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1938                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1939                cx.observe_window_activation(window, |editor, window, cx| {
 1940                    let active = window.is_window_active();
 1941                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1942                        if active {
 1943                            blink_manager.enable(cx);
 1944                        } else {
 1945                            blink_manager.disable(cx);
 1946                        }
 1947                    });
 1948                    if active {
 1949                        editor.show_mouse_cursor();
 1950                    }
 1951                }),
 1952            ],
 1953            tasks_update_task: None,
 1954            linked_edit_ranges: Default::default(),
 1955            in_project_search: false,
 1956            previous_search_ranges: None,
 1957            breadcrumb_header: None,
 1958            focused_block: None,
 1959            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1960            addons: HashMap::default(),
 1961            registered_buffers: HashMap::default(),
 1962            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1963            selection_mark_mode: false,
 1964            toggle_fold_multiple_buffers: Task::ready(()),
 1965            serialize_selections: Task::ready(()),
 1966            serialize_folds: Task::ready(()),
 1967            text_style_refinement: None,
 1968            load_diff_task: load_uncommitted_diff,
 1969            temporary_diff_override: false,
 1970            mouse_cursor_hidden: false,
 1971            minimap: None,
 1972            hide_mouse_mode: EditorSettings::get_global(cx)
 1973                .hide_mouse
 1974                .unwrap_or_default(),
 1975            change_list: ChangeList::new(),
 1976            mode,
 1977        };
 1978        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1979            this._subscriptions
 1980                .push(cx.observe(breakpoints, |_, _, cx| {
 1981                    cx.notify();
 1982                }));
 1983        }
 1984        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1985        this._subscriptions.extend(project_subscriptions);
 1986
 1987        this._subscriptions.push(cx.subscribe_in(
 1988            &cx.entity(),
 1989            window,
 1990            |editor, _, e: &EditorEvent, window, cx| match e {
 1991                EditorEvent::ScrollPositionChanged { local, .. } => {
 1992                    if *local {
 1993                        let new_anchor = editor.scroll_manager.anchor();
 1994                        let snapshot = editor.snapshot(window, cx);
 1995                        editor.update_restoration_data(cx, move |data| {
 1996                            data.scroll_position = (
 1997                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1998                                new_anchor.offset,
 1999                            );
 2000                        });
 2001                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2002                        editor.inline_blame_popover.take();
 2003                    }
 2004                }
 2005                EditorEvent::Edited { .. } => {
 2006                    if !vim_enabled(cx) {
 2007                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2008                        let pop_state = editor
 2009                            .change_list
 2010                            .last()
 2011                            .map(|previous| {
 2012                                previous.len() == selections.len()
 2013                                    && previous.iter().enumerate().all(|(ix, p)| {
 2014                                        p.to_display_point(&map).row()
 2015                                            == selections[ix].head().row()
 2016                                    })
 2017                            })
 2018                            .unwrap_or(false);
 2019                        let new_positions = selections
 2020                            .into_iter()
 2021                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2022                            .collect();
 2023                        editor
 2024                            .change_list
 2025                            .push_to_change_list(pop_state, new_positions);
 2026                    }
 2027                }
 2028                _ => (),
 2029            },
 2030        ));
 2031
 2032        if let Some(dap_store) = this
 2033            .project
 2034            .as_ref()
 2035            .map(|project| project.read(cx).dap_store())
 2036        {
 2037            let weak_editor = cx.weak_entity();
 2038
 2039            this._subscriptions
 2040                .push(
 2041                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2042                        let session_entity = cx.entity();
 2043                        weak_editor
 2044                            .update(cx, |editor, cx| {
 2045                                editor._subscriptions.push(
 2046                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2047                                );
 2048                            })
 2049                            .ok();
 2050                    }),
 2051                );
 2052
 2053            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2054                this._subscriptions
 2055                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2056            }
 2057        }
 2058
 2059        this.end_selection(window, cx);
 2060        this.scroll_manager.show_scrollbars(window, cx);
 2061        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 2062
 2063        if full_mode {
 2064            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2065            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2066
 2067            if this.git_blame_inline_enabled {
 2068                this.start_git_blame_inline(false, window, cx);
 2069            }
 2070
 2071            this.go_to_active_debug_line(window, cx);
 2072
 2073            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2074                if let Some(project) = this.project.as_ref() {
 2075                    let handle = project.update(cx, |project, cx| {
 2076                        project.register_buffer_with_language_servers(&buffer, cx)
 2077                    });
 2078                    this.registered_buffers
 2079                        .insert(buffer.read(cx).remote_id(), handle);
 2080                }
 2081            }
 2082
 2083            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2084        }
 2085
 2086        this.report_editor_event("Editor Opened", None, cx);
 2087        this
 2088    }
 2089
 2090    pub fn deploy_mouse_context_menu(
 2091        &mut self,
 2092        position: gpui::Point<Pixels>,
 2093        context_menu: Entity<ContextMenu>,
 2094        window: &mut Window,
 2095        cx: &mut Context<Self>,
 2096    ) {
 2097        self.mouse_context_menu = Some(MouseContextMenu::new(
 2098            self,
 2099            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2100            context_menu,
 2101            window,
 2102            cx,
 2103        ));
 2104    }
 2105
 2106    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2107        self.mouse_context_menu
 2108            .as_ref()
 2109            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2110    }
 2111
 2112    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2113        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2114    }
 2115
 2116    fn key_context_internal(
 2117        &self,
 2118        has_active_edit_prediction: bool,
 2119        window: &Window,
 2120        cx: &App,
 2121    ) -> KeyContext {
 2122        let mut key_context = KeyContext::new_with_defaults();
 2123        key_context.add("Editor");
 2124        let mode = match self.mode {
 2125            EditorMode::SingleLine { .. } => "single_line",
 2126            EditorMode::AutoHeight { .. } => "auto_height",
 2127            EditorMode::Minimap { .. } => "minimap",
 2128            EditorMode::Full { .. } => "full",
 2129        };
 2130
 2131        if EditorSettings::jupyter_enabled(cx) {
 2132            key_context.add("jupyter");
 2133        }
 2134
 2135        key_context.set("mode", mode);
 2136        if self.pending_rename.is_some() {
 2137            key_context.add("renaming");
 2138        }
 2139
 2140        match self.context_menu.borrow().as_ref() {
 2141            Some(CodeContextMenu::Completions(_)) => {
 2142                key_context.add("menu");
 2143                key_context.add("showing_completions");
 2144            }
 2145            Some(CodeContextMenu::CodeActions(_)) => {
 2146                key_context.add("menu");
 2147                key_context.add("showing_code_actions")
 2148            }
 2149            None => {}
 2150        }
 2151
 2152        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2153        if !self.focus_handle(cx).contains_focused(window, cx)
 2154            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2155        {
 2156            for addon in self.addons.values() {
 2157                addon.extend_key_context(&mut key_context, cx)
 2158            }
 2159        }
 2160
 2161        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2162            if let Some(extension) = singleton_buffer
 2163                .read(cx)
 2164                .file()
 2165                .and_then(|file| file.path().extension()?.to_str())
 2166            {
 2167                key_context.set("extension", extension.to_string());
 2168            }
 2169        } else {
 2170            key_context.add("multibuffer");
 2171        }
 2172
 2173        if has_active_edit_prediction {
 2174            if self.edit_prediction_in_conflict() {
 2175                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2176            } else {
 2177                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2178                key_context.add("copilot_suggestion");
 2179            }
 2180        }
 2181
 2182        if self.selection_mark_mode {
 2183            key_context.add("selection_mode");
 2184        }
 2185
 2186        key_context
 2187    }
 2188
 2189    fn show_mouse_cursor(&mut self) {
 2190        self.mouse_cursor_hidden = false;
 2191    }
 2192
 2193    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2194        self.mouse_cursor_hidden = match origin {
 2195            HideMouseCursorOrigin::TypingAction => {
 2196                matches!(
 2197                    self.hide_mouse_mode,
 2198                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2199                )
 2200            }
 2201            HideMouseCursorOrigin::MovementAction => {
 2202                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2203            }
 2204        };
 2205    }
 2206
 2207    pub fn edit_prediction_in_conflict(&self) -> bool {
 2208        if !self.show_edit_predictions_in_menu() {
 2209            return false;
 2210        }
 2211
 2212        let showing_completions = self
 2213            .context_menu
 2214            .borrow()
 2215            .as_ref()
 2216            .map_or(false, |context| {
 2217                matches!(context, CodeContextMenu::Completions(_))
 2218            });
 2219
 2220        showing_completions
 2221            || self.edit_prediction_requires_modifier()
 2222            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2223            // bindings to insert tab characters.
 2224            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2225    }
 2226
 2227    pub fn accept_edit_prediction_keybind(
 2228        &self,
 2229        window: &Window,
 2230        cx: &App,
 2231    ) -> AcceptEditPredictionBinding {
 2232        let key_context = self.key_context_internal(true, window, cx);
 2233        let in_conflict = self.edit_prediction_in_conflict();
 2234
 2235        AcceptEditPredictionBinding(
 2236            window
 2237                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2238                .into_iter()
 2239                .filter(|binding| {
 2240                    !in_conflict
 2241                        || binding
 2242                            .keystrokes()
 2243                            .first()
 2244                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2245                })
 2246                .rev()
 2247                .min_by_key(|binding| {
 2248                    binding
 2249                        .keystrokes()
 2250                        .first()
 2251                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2252                }),
 2253        )
 2254    }
 2255
 2256    pub fn new_file(
 2257        workspace: &mut Workspace,
 2258        _: &workspace::NewFile,
 2259        window: &mut Window,
 2260        cx: &mut Context<Workspace>,
 2261    ) {
 2262        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2263            "Failed to create buffer",
 2264            window,
 2265            cx,
 2266            |e, _, _| match e.error_code() {
 2267                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2268                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2269                e.error_tag("required").unwrap_or("the latest version")
 2270            )),
 2271                _ => None,
 2272            },
 2273        );
 2274    }
 2275
 2276    pub fn new_in_workspace(
 2277        workspace: &mut Workspace,
 2278        window: &mut Window,
 2279        cx: &mut Context<Workspace>,
 2280    ) -> Task<Result<Entity<Editor>>> {
 2281        let project = workspace.project().clone();
 2282        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2283
 2284        cx.spawn_in(window, async move |workspace, cx| {
 2285            let buffer = create.await?;
 2286            workspace.update_in(cx, |workspace, window, cx| {
 2287                let editor =
 2288                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2289                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2290                editor
 2291            })
 2292        })
 2293    }
 2294
 2295    fn new_file_vertical(
 2296        workspace: &mut Workspace,
 2297        _: &workspace::NewFileSplitVertical,
 2298        window: &mut Window,
 2299        cx: &mut Context<Workspace>,
 2300    ) {
 2301        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2302    }
 2303
 2304    fn new_file_horizontal(
 2305        workspace: &mut Workspace,
 2306        _: &workspace::NewFileSplitHorizontal,
 2307        window: &mut Window,
 2308        cx: &mut Context<Workspace>,
 2309    ) {
 2310        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2311    }
 2312
 2313    fn new_file_in_direction(
 2314        workspace: &mut Workspace,
 2315        direction: SplitDirection,
 2316        window: &mut Window,
 2317        cx: &mut Context<Workspace>,
 2318    ) {
 2319        let project = workspace.project().clone();
 2320        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2321
 2322        cx.spawn_in(window, async move |workspace, cx| {
 2323            let buffer = create.await?;
 2324            workspace.update_in(cx, move |workspace, window, cx| {
 2325                workspace.split_item(
 2326                    direction,
 2327                    Box::new(
 2328                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2329                    ),
 2330                    window,
 2331                    cx,
 2332                )
 2333            })?;
 2334            anyhow::Ok(())
 2335        })
 2336        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2337            match e.error_code() {
 2338                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2339                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2340                e.error_tag("required").unwrap_or("the latest version")
 2341            )),
 2342                _ => None,
 2343            }
 2344        });
 2345    }
 2346
 2347    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2348        self.leader_id
 2349    }
 2350
 2351    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2352        &self.buffer
 2353    }
 2354
 2355    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2356        self.workspace.as_ref()?.0.upgrade()
 2357    }
 2358
 2359    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2360        self.buffer().read(cx).title(cx)
 2361    }
 2362
 2363    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2364        let git_blame_gutter_max_author_length = self
 2365            .render_git_blame_gutter(cx)
 2366            .then(|| {
 2367                if let Some(blame) = self.blame.as_ref() {
 2368                    let max_author_length =
 2369                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2370                    Some(max_author_length)
 2371                } else {
 2372                    None
 2373                }
 2374            })
 2375            .flatten();
 2376
 2377        EditorSnapshot {
 2378            mode: self.mode.clone(),
 2379            show_gutter: self.show_gutter,
 2380            show_line_numbers: self.show_line_numbers,
 2381            show_git_diff_gutter: self.show_git_diff_gutter,
 2382            show_code_actions: self.show_code_actions,
 2383            show_runnables: self.show_runnables,
 2384            show_breakpoints: self.show_breakpoints,
 2385            git_blame_gutter_max_author_length,
 2386            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2387            scroll_anchor: self.scroll_manager.anchor(),
 2388            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2389            placeholder_text: self.placeholder_text.clone(),
 2390            is_focused: self.focus_handle.is_focused(window),
 2391            current_line_highlight: self
 2392                .current_line_highlight
 2393                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2394            gutter_hovered: self.gutter_hovered,
 2395        }
 2396    }
 2397
 2398    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2399        self.buffer.read(cx).language_at(point, cx)
 2400    }
 2401
 2402    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2403        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2404    }
 2405
 2406    pub fn active_excerpt(
 2407        &self,
 2408        cx: &App,
 2409    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2410        self.buffer
 2411            .read(cx)
 2412            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2413    }
 2414
 2415    pub fn mode(&self) -> &EditorMode {
 2416        &self.mode
 2417    }
 2418
 2419    pub fn set_mode(&mut self, mode: EditorMode) {
 2420        self.mode = mode;
 2421    }
 2422
 2423    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2424        self.collaboration_hub.as_deref()
 2425    }
 2426
 2427    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2428        self.collaboration_hub = Some(hub);
 2429    }
 2430
 2431    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2432        self.in_project_search = in_project_search;
 2433    }
 2434
 2435    pub fn set_custom_context_menu(
 2436        &mut self,
 2437        f: impl 'static
 2438        + Fn(
 2439            &mut Self,
 2440            DisplayPoint,
 2441            &mut Window,
 2442            &mut Context<Self>,
 2443        ) -> Option<Entity<ui::ContextMenu>>,
 2444    ) {
 2445        self.custom_context_menu = Some(Box::new(f))
 2446    }
 2447
 2448    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2449        self.completion_provider = provider;
 2450    }
 2451
 2452    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2453        self.semantics_provider.clone()
 2454    }
 2455
 2456    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2457        self.semantics_provider = provider;
 2458    }
 2459
 2460    pub fn set_edit_prediction_provider<T>(
 2461        &mut self,
 2462        provider: Option<Entity<T>>,
 2463        window: &mut Window,
 2464        cx: &mut Context<Self>,
 2465    ) where
 2466        T: EditPredictionProvider,
 2467    {
 2468        self.edit_prediction_provider =
 2469            provider.map(|provider| RegisteredInlineCompletionProvider {
 2470                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2471                    if this.focus_handle.is_focused(window) {
 2472                        this.update_visible_inline_completion(window, cx);
 2473                    }
 2474                }),
 2475                provider: Arc::new(provider),
 2476            });
 2477        self.update_edit_prediction_settings(cx);
 2478        self.refresh_inline_completion(false, false, window, cx);
 2479    }
 2480
 2481    pub fn placeholder_text(&self) -> Option<&str> {
 2482        self.placeholder_text.as_deref()
 2483    }
 2484
 2485    pub fn set_placeholder_text(
 2486        &mut self,
 2487        placeholder_text: impl Into<Arc<str>>,
 2488        cx: &mut Context<Self>,
 2489    ) {
 2490        let placeholder_text = Some(placeholder_text.into());
 2491        if self.placeholder_text != placeholder_text {
 2492            self.placeholder_text = placeholder_text;
 2493            cx.notify();
 2494        }
 2495    }
 2496
 2497    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2498        self.cursor_shape = cursor_shape;
 2499
 2500        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2501        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2502
 2503        cx.notify();
 2504    }
 2505
 2506    pub fn set_current_line_highlight(
 2507        &mut self,
 2508        current_line_highlight: Option<CurrentLineHighlight>,
 2509    ) {
 2510        self.current_line_highlight = current_line_highlight;
 2511    }
 2512
 2513    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2514        self.collapse_matches = collapse_matches;
 2515    }
 2516
 2517    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2518        let buffers = self.buffer.read(cx).all_buffers();
 2519        let Some(project) = self.project.as_ref() else {
 2520            return;
 2521        };
 2522        project.update(cx, |project, cx| {
 2523            for buffer in buffers {
 2524                self.registered_buffers
 2525                    .entry(buffer.read(cx).remote_id())
 2526                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2527            }
 2528        })
 2529    }
 2530
 2531    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2532        if self.collapse_matches {
 2533            return range.start..range.start;
 2534        }
 2535        range.clone()
 2536    }
 2537
 2538    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2539        if self.display_map.read(cx).clip_at_line_ends != clip {
 2540            self.display_map
 2541                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2542        }
 2543    }
 2544
 2545    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2546        self.input_enabled = input_enabled;
 2547    }
 2548
 2549    pub fn set_inline_completions_hidden_for_vim_mode(
 2550        &mut self,
 2551        hidden: bool,
 2552        window: &mut Window,
 2553        cx: &mut Context<Self>,
 2554    ) {
 2555        if hidden != self.inline_completions_hidden_for_vim_mode {
 2556            self.inline_completions_hidden_for_vim_mode = hidden;
 2557            if hidden {
 2558                self.update_visible_inline_completion(window, cx);
 2559            } else {
 2560                self.refresh_inline_completion(true, false, window, cx);
 2561            }
 2562        }
 2563    }
 2564
 2565    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2566        self.menu_inline_completions_policy = value;
 2567    }
 2568
 2569    pub fn set_autoindent(&mut self, autoindent: bool) {
 2570        if autoindent {
 2571            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2572        } else {
 2573            self.autoindent_mode = None;
 2574        }
 2575    }
 2576
 2577    pub fn read_only(&self, cx: &App) -> bool {
 2578        self.read_only || self.buffer.read(cx).read_only()
 2579    }
 2580
 2581    pub fn set_read_only(&mut self, read_only: bool) {
 2582        self.read_only = read_only;
 2583    }
 2584
 2585    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2586        self.use_autoclose = autoclose;
 2587    }
 2588
 2589    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2590        self.use_auto_surround = auto_surround;
 2591    }
 2592
 2593    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2594        self.auto_replace_emoji_shortcode = auto_replace;
 2595    }
 2596
 2597    pub fn toggle_edit_predictions(
 2598        &mut self,
 2599        _: &ToggleEditPrediction,
 2600        window: &mut Window,
 2601        cx: &mut Context<Self>,
 2602    ) {
 2603        if self.show_inline_completions_override.is_some() {
 2604            self.set_show_edit_predictions(None, window, cx);
 2605        } else {
 2606            let show_edit_predictions = !self.edit_predictions_enabled();
 2607            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2608        }
 2609    }
 2610
 2611    pub fn set_show_edit_predictions(
 2612        &mut self,
 2613        show_edit_predictions: Option<bool>,
 2614        window: &mut Window,
 2615        cx: &mut Context<Self>,
 2616    ) {
 2617        self.show_inline_completions_override = show_edit_predictions;
 2618        self.update_edit_prediction_settings(cx);
 2619
 2620        if let Some(false) = show_edit_predictions {
 2621            self.discard_inline_completion(false, cx);
 2622        } else {
 2623            self.refresh_inline_completion(false, true, window, cx);
 2624        }
 2625    }
 2626
 2627    fn inline_completions_disabled_in_scope(
 2628        &self,
 2629        buffer: &Entity<Buffer>,
 2630        buffer_position: language::Anchor,
 2631        cx: &App,
 2632    ) -> bool {
 2633        let snapshot = buffer.read(cx).snapshot();
 2634        let settings = snapshot.settings_at(buffer_position, cx);
 2635
 2636        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2637            return false;
 2638        };
 2639
 2640        scope.override_name().map_or(false, |scope_name| {
 2641            settings
 2642                .edit_predictions_disabled_in
 2643                .iter()
 2644                .any(|s| s == scope_name)
 2645        })
 2646    }
 2647
 2648    pub fn set_use_modal_editing(&mut self, to: bool) {
 2649        self.use_modal_editing = to;
 2650    }
 2651
 2652    pub fn use_modal_editing(&self) -> bool {
 2653        self.use_modal_editing
 2654    }
 2655
 2656    fn selections_did_change(
 2657        &mut self,
 2658        local: bool,
 2659        old_cursor_position: &Anchor,
 2660        should_update_completions: bool,
 2661        window: &mut Window,
 2662        cx: &mut Context<Self>,
 2663    ) {
 2664        window.invalidate_character_coordinates();
 2665
 2666        // Copy selections to primary selection buffer
 2667        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2668        if local {
 2669            let selections = self.selections.all::<usize>(cx);
 2670            let buffer_handle = self.buffer.read(cx).read(cx);
 2671
 2672            let mut text = String::new();
 2673            for (index, selection) in selections.iter().enumerate() {
 2674                let text_for_selection = buffer_handle
 2675                    .text_for_range(selection.start..selection.end)
 2676                    .collect::<String>();
 2677
 2678                text.push_str(&text_for_selection);
 2679                if index != selections.len() - 1 {
 2680                    text.push('\n');
 2681                }
 2682            }
 2683
 2684            if !text.is_empty() {
 2685                cx.write_to_primary(ClipboardItem::new_string(text));
 2686            }
 2687        }
 2688
 2689        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2690            self.buffer.update(cx, |buffer, cx| {
 2691                buffer.set_active_selections(
 2692                    &self.selections.disjoint_anchors(),
 2693                    self.selections.line_mode,
 2694                    self.cursor_shape,
 2695                    cx,
 2696                )
 2697            });
 2698        }
 2699        let display_map = self
 2700            .display_map
 2701            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2702        let buffer = &display_map.buffer_snapshot;
 2703        self.add_selections_state = None;
 2704        self.select_next_state = None;
 2705        self.select_prev_state = None;
 2706        self.select_syntax_node_history.try_clear();
 2707        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2708        self.snippet_stack
 2709            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2710        self.take_rename(false, window, cx);
 2711
 2712        let new_cursor_position = self.selections.newest_anchor().head();
 2713
 2714        self.push_to_nav_history(
 2715            *old_cursor_position,
 2716            Some(new_cursor_position.to_point(buffer)),
 2717            false,
 2718            cx,
 2719        );
 2720
 2721        if local {
 2722            let new_cursor_position = self.selections.newest_anchor().head();
 2723
 2724            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2725                if !self.registered_buffers.contains_key(&buffer_id) {
 2726                    if let Some(project) = self.project.as_ref() {
 2727                        project.update(cx, |project, cx| {
 2728                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2729                                return;
 2730                            };
 2731                            self.registered_buffers.insert(
 2732                                buffer_id,
 2733                                project.register_buffer_with_language_servers(&buffer, cx),
 2734                            );
 2735                        })
 2736                    }
 2737                }
 2738            }
 2739
 2740            let mut context_menu = self.context_menu.borrow_mut();
 2741            let completion_menu = match context_menu.as_ref() {
 2742                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2743                Some(CodeContextMenu::CodeActions(_)) => {
 2744                    *context_menu = None;
 2745                    None
 2746                }
 2747                None => None,
 2748            };
 2749            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2750            drop(context_menu);
 2751
 2752            if should_update_completions {
 2753                if let Some(completion_position) = completion_position {
 2754                    let new_cursor_offset = new_cursor_position.to_offset(buffer);
 2755                    let position_matches =
 2756                        new_cursor_offset == completion_position.to_offset(buffer);
 2757                    let continue_showing = if position_matches {
 2758                        let (word_range, kind) = buffer.surrounding_word(new_cursor_offset, true);
 2759                        if let Some(CharKind::Word) = kind {
 2760                            word_range.start < new_cursor_offset
 2761                        } else {
 2762                            false
 2763                        }
 2764                    } else {
 2765                        false
 2766                    };
 2767
 2768                    if continue_showing {
 2769                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2770                    } else {
 2771                        self.hide_context_menu(window, cx);
 2772                    }
 2773                }
 2774            }
 2775
 2776            hide_hover(self, cx);
 2777
 2778            if old_cursor_position.to_display_point(&display_map).row()
 2779                != new_cursor_position.to_display_point(&display_map).row()
 2780            {
 2781                self.available_code_actions.take();
 2782            }
 2783            self.refresh_code_actions(window, cx);
 2784            self.refresh_document_highlights(cx);
 2785            self.refresh_selected_text_highlights(false, window, cx);
 2786            refresh_matching_bracket_highlights(self, window, cx);
 2787            self.update_visible_inline_completion(window, cx);
 2788            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2789            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2790            self.inline_blame_popover.take();
 2791            if self.git_blame_inline_enabled {
 2792                self.start_inline_blame_timer(window, cx);
 2793            }
 2794        }
 2795
 2796        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2797        cx.emit(EditorEvent::SelectionsChanged { local });
 2798
 2799        let selections = &self.selections.disjoint;
 2800        if selections.len() == 1 {
 2801            cx.emit(SearchEvent::ActiveMatchChanged)
 2802        }
 2803        if local {
 2804            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2805                let inmemory_selections = selections
 2806                    .iter()
 2807                    .map(|s| {
 2808                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2809                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2810                    })
 2811                    .collect();
 2812                self.update_restoration_data(cx, |data| {
 2813                    data.selections = inmemory_selections;
 2814                });
 2815
 2816                if WorkspaceSettings::get(None, cx).restore_on_startup
 2817                    != RestoreOnStartupBehavior::None
 2818                {
 2819                    if let Some(workspace_id) =
 2820                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2821                    {
 2822                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2823                        let selections = selections.clone();
 2824                        let background_executor = cx.background_executor().clone();
 2825                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2826                        self.serialize_selections = cx.background_spawn(async move {
 2827                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2828                    let db_selections = selections
 2829                        .iter()
 2830                        .map(|selection| {
 2831                            (
 2832                                selection.start.to_offset(&snapshot),
 2833                                selection.end.to_offset(&snapshot),
 2834                            )
 2835                        })
 2836                        .collect();
 2837
 2838                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2839                        .await
 2840                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2841                        .log_err();
 2842                });
 2843                    }
 2844                }
 2845            }
 2846        }
 2847
 2848        cx.notify();
 2849    }
 2850
 2851    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2852        use text::ToOffset as _;
 2853        use text::ToPoint as _;
 2854
 2855        if self.mode.is_minimap()
 2856            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2857        {
 2858            return;
 2859        }
 2860
 2861        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2862            return;
 2863        };
 2864
 2865        let snapshot = singleton.read(cx).snapshot();
 2866        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2867            let display_snapshot = display_map.snapshot(cx);
 2868
 2869            display_snapshot
 2870                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2871                .map(|fold| {
 2872                    fold.range.start.text_anchor.to_point(&snapshot)
 2873                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2874                })
 2875                .collect()
 2876        });
 2877        self.update_restoration_data(cx, |data| {
 2878            data.folds = inmemory_folds;
 2879        });
 2880
 2881        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2882            return;
 2883        };
 2884        let background_executor = cx.background_executor().clone();
 2885        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2886        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2887            display_map
 2888                .snapshot(cx)
 2889                .folds_in_range(0..snapshot.len())
 2890                .map(|fold| {
 2891                    (
 2892                        fold.range.start.text_anchor.to_offset(&snapshot),
 2893                        fold.range.end.text_anchor.to_offset(&snapshot),
 2894                    )
 2895                })
 2896                .collect()
 2897        });
 2898        self.serialize_folds = cx.background_spawn(async move {
 2899            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2900            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2901                .await
 2902                .with_context(|| {
 2903                    format!(
 2904                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2905                    )
 2906                })
 2907                .log_err();
 2908        });
 2909    }
 2910
 2911    pub fn sync_selections(
 2912        &mut self,
 2913        other: Entity<Editor>,
 2914        cx: &mut Context<Self>,
 2915    ) -> gpui::Subscription {
 2916        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2917        self.selections.change_with(cx, |selections| {
 2918            selections.select_anchors(other_selections);
 2919        });
 2920
 2921        let other_subscription =
 2922            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2923                EditorEvent::SelectionsChanged { local: true } => {
 2924                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2925                    if other_selections.is_empty() {
 2926                        return;
 2927                    }
 2928                    this.selections.change_with(cx, |selections| {
 2929                        selections.select_anchors(other_selections);
 2930                    });
 2931                }
 2932                _ => {}
 2933            });
 2934
 2935        let this_subscription =
 2936            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2937                EditorEvent::SelectionsChanged { local: true } => {
 2938                    let these_selections = this.selections.disjoint.to_vec();
 2939                    if these_selections.is_empty() {
 2940                        return;
 2941                    }
 2942                    other.update(cx, |other_editor, cx| {
 2943                        other_editor.selections.change_with(cx, |selections| {
 2944                            selections.select_anchors(these_selections);
 2945                        })
 2946                    });
 2947                }
 2948                _ => {}
 2949            });
 2950
 2951        Subscription::join(other_subscription, this_subscription)
 2952    }
 2953
 2954    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 2955    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 2956    /// effects of selection change occur at the end of the transaction.
 2957    pub fn change_selections<R>(
 2958        &mut self,
 2959        autoscroll: Option<Autoscroll>,
 2960        window: &mut Window,
 2961        cx: &mut Context<Self>,
 2962        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2963    ) -> R {
 2964        self.change_selections_inner(true, autoscroll, window, cx, change)
 2965    }
 2966
 2967    pub(crate) fn change_selections_without_updating_completions<R>(
 2968        &mut self,
 2969        autoscroll: Option<Autoscroll>,
 2970        window: &mut Window,
 2971        cx: &mut Context<Self>,
 2972        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2973    ) -> R {
 2974        self.change_selections_inner(false, autoscroll, window, cx, change)
 2975    }
 2976
 2977    fn change_selections_inner<R>(
 2978        &mut self,
 2979        should_update_completions: bool,
 2980        autoscroll: Option<Autoscroll>,
 2981        window: &mut Window,
 2982        cx: &mut Context<Self>,
 2983        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2984    ) -> R {
 2985        if let Some(state) = &mut self.deferred_selection_effects_state {
 2986            state.autoscroll = autoscroll.or(state.autoscroll);
 2987            state.should_update_completions = should_update_completions;
 2988            let (changed, result) = self.selections.change_with(cx, change);
 2989            state.changed |= changed;
 2990            return result;
 2991        }
 2992        let mut state = DeferredSelectionEffectsState {
 2993            changed: false,
 2994            should_update_completions,
 2995            autoscroll,
 2996            old_cursor_position: self.selections.newest_anchor().head(),
 2997            history_entry: SelectionHistoryEntry {
 2998                selections: self.selections.disjoint_anchors(),
 2999                select_next_state: self.select_next_state.clone(),
 3000                select_prev_state: self.select_prev_state.clone(),
 3001                add_selections_state: self.add_selections_state.clone(),
 3002            },
 3003        };
 3004        let (changed, result) = self.selections.change_with(cx, change);
 3005        state.changed = state.changed || changed;
 3006        if self.defer_selection_effects {
 3007            self.deferred_selection_effects_state = Some(state);
 3008        } else {
 3009            self.apply_selection_effects(state, window, cx);
 3010        }
 3011        result
 3012    }
 3013
 3014    /// Defers the effects of selection change, so that the effects of multiple calls to
 3015    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3016    /// to selection history and the state of popovers based on selection position aren't
 3017    /// erroneously updated.
 3018    pub fn with_selection_effects_deferred<R>(
 3019        &mut self,
 3020        window: &mut Window,
 3021        cx: &mut Context<Self>,
 3022        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3023    ) -> R {
 3024        let already_deferred = self.defer_selection_effects;
 3025        self.defer_selection_effects = true;
 3026        let result = update(self, window, cx);
 3027        if !already_deferred {
 3028            self.defer_selection_effects = false;
 3029            if let Some(state) = self.deferred_selection_effects_state.take() {
 3030                self.apply_selection_effects(state, window, cx);
 3031            }
 3032        }
 3033        result
 3034    }
 3035
 3036    fn apply_selection_effects(
 3037        &mut self,
 3038        state: DeferredSelectionEffectsState,
 3039        window: &mut Window,
 3040        cx: &mut Context<Self>,
 3041    ) {
 3042        if state.changed {
 3043            self.selection_history.push(state.history_entry);
 3044
 3045            if let Some(autoscroll) = state.autoscroll {
 3046                self.request_autoscroll(autoscroll, cx);
 3047            }
 3048
 3049            let old_cursor_position = &state.old_cursor_position;
 3050
 3051            self.selections_did_change(
 3052                true,
 3053                &old_cursor_position,
 3054                state.should_update_completions,
 3055                window,
 3056                cx,
 3057            );
 3058
 3059            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3060                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3061            }
 3062        }
 3063    }
 3064
 3065    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3066    where
 3067        I: IntoIterator<Item = (Range<S>, T)>,
 3068        S: ToOffset,
 3069        T: Into<Arc<str>>,
 3070    {
 3071        if self.read_only(cx) {
 3072            return;
 3073        }
 3074
 3075        self.buffer
 3076            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3077    }
 3078
 3079    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3080    where
 3081        I: IntoIterator<Item = (Range<S>, T)>,
 3082        S: ToOffset,
 3083        T: Into<Arc<str>>,
 3084    {
 3085        if self.read_only(cx) {
 3086            return;
 3087        }
 3088
 3089        self.buffer.update(cx, |buffer, cx| {
 3090            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3091        });
 3092    }
 3093
 3094    pub fn edit_with_block_indent<I, S, T>(
 3095        &mut self,
 3096        edits: I,
 3097        original_indent_columns: Vec<Option<u32>>,
 3098        cx: &mut Context<Self>,
 3099    ) where
 3100        I: IntoIterator<Item = (Range<S>, T)>,
 3101        S: ToOffset,
 3102        T: Into<Arc<str>>,
 3103    {
 3104        if self.read_only(cx) {
 3105            return;
 3106        }
 3107
 3108        self.buffer.update(cx, |buffer, cx| {
 3109            buffer.edit(
 3110                edits,
 3111                Some(AutoindentMode::Block {
 3112                    original_indent_columns,
 3113                }),
 3114                cx,
 3115            )
 3116        });
 3117    }
 3118
 3119    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3120        self.hide_context_menu(window, cx);
 3121
 3122        match phase {
 3123            SelectPhase::Begin {
 3124                position,
 3125                add,
 3126                click_count,
 3127            } => self.begin_selection(position, add, click_count, window, cx),
 3128            SelectPhase::BeginColumnar {
 3129                position,
 3130                goal_column,
 3131                reset,
 3132            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3133            SelectPhase::Extend {
 3134                position,
 3135                click_count,
 3136            } => self.extend_selection(position, click_count, window, cx),
 3137            SelectPhase::Update {
 3138                position,
 3139                goal_column,
 3140                scroll_delta,
 3141            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3142            SelectPhase::End => self.end_selection(window, cx),
 3143        }
 3144    }
 3145
 3146    fn extend_selection(
 3147        &mut self,
 3148        position: DisplayPoint,
 3149        click_count: usize,
 3150        window: &mut Window,
 3151        cx: &mut Context<Self>,
 3152    ) {
 3153        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3154        let tail = self.selections.newest::<usize>(cx).tail();
 3155        self.begin_selection(position, false, click_count, window, cx);
 3156
 3157        let position = position.to_offset(&display_map, Bias::Left);
 3158        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3159
 3160        let mut pending_selection = self
 3161            .selections
 3162            .pending_anchor()
 3163            .expect("extend_selection not called with pending selection");
 3164        if position >= tail {
 3165            pending_selection.start = tail_anchor;
 3166        } else {
 3167            pending_selection.end = tail_anchor;
 3168            pending_selection.reversed = true;
 3169        }
 3170
 3171        let mut pending_mode = self.selections.pending_mode().unwrap();
 3172        match &mut pending_mode {
 3173            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3174            _ => {}
 3175        }
 3176
 3177        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3178
 3179        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3180            s.set_pending(pending_selection, pending_mode)
 3181        });
 3182    }
 3183
 3184    fn begin_selection(
 3185        &mut self,
 3186        position: DisplayPoint,
 3187        add: bool,
 3188        click_count: usize,
 3189        window: &mut Window,
 3190        cx: &mut Context<Self>,
 3191    ) {
 3192        if !self.focus_handle.is_focused(window) {
 3193            self.last_focused_descendant = None;
 3194            window.focus(&self.focus_handle);
 3195        }
 3196
 3197        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3198        let buffer = &display_map.buffer_snapshot;
 3199        let position = display_map.clip_point(position, Bias::Left);
 3200
 3201        let start;
 3202        let end;
 3203        let mode;
 3204        let mut auto_scroll;
 3205        match click_count {
 3206            1 => {
 3207                start = buffer.anchor_before(position.to_point(&display_map));
 3208                end = start;
 3209                mode = SelectMode::Character;
 3210                auto_scroll = true;
 3211            }
 3212            2 => {
 3213                let range = movement::surrounding_word(&display_map, position);
 3214                start = buffer.anchor_before(range.start.to_point(&display_map));
 3215                end = buffer.anchor_before(range.end.to_point(&display_map));
 3216                mode = SelectMode::Word(start..end);
 3217                auto_scroll = true;
 3218            }
 3219            3 => {
 3220                let position = display_map
 3221                    .clip_point(position, Bias::Left)
 3222                    .to_point(&display_map);
 3223                let line_start = display_map.prev_line_boundary(position).0;
 3224                let next_line_start = buffer.clip_point(
 3225                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3226                    Bias::Left,
 3227                );
 3228                start = buffer.anchor_before(line_start);
 3229                end = buffer.anchor_before(next_line_start);
 3230                mode = SelectMode::Line(start..end);
 3231                auto_scroll = true;
 3232            }
 3233            _ => {
 3234                start = buffer.anchor_before(0);
 3235                end = buffer.anchor_before(buffer.len());
 3236                mode = SelectMode::All;
 3237                auto_scroll = false;
 3238            }
 3239        }
 3240        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3241
 3242        let point_to_delete: Option<usize> = {
 3243            let selected_points: Vec<Selection<Point>> =
 3244                self.selections.disjoint_in_range(start..end, cx);
 3245
 3246            if !add || click_count > 1 {
 3247                None
 3248            } else if !selected_points.is_empty() {
 3249                Some(selected_points[0].id)
 3250            } else {
 3251                let clicked_point_already_selected =
 3252                    self.selections.disjoint.iter().find(|selection| {
 3253                        selection.start.to_point(buffer) == start.to_point(buffer)
 3254                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3255                    });
 3256
 3257                clicked_point_already_selected.map(|selection| selection.id)
 3258            }
 3259        };
 3260
 3261        let selections_count = self.selections.count();
 3262
 3263        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3264            if let Some(point_to_delete) = point_to_delete {
 3265                s.delete(point_to_delete);
 3266
 3267                if selections_count == 1 {
 3268                    s.set_pending_anchor_range(start..end, mode);
 3269                }
 3270            } else {
 3271                if !add {
 3272                    s.clear_disjoint();
 3273                }
 3274
 3275                s.set_pending_anchor_range(start..end, mode);
 3276            }
 3277        });
 3278    }
 3279
 3280    fn begin_columnar_selection(
 3281        &mut self,
 3282        position: DisplayPoint,
 3283        goal_column: u32,
 3284        reset: bool,
 3285        window: &mut Window,
 3286        cx: &mut Context<Self>,
 3287    ) {
 3288        if !self.focus_handle.is_focused(window) {
 3289            self.last_focused_descendant = None;
 3290            window.focus(&self.focus_handle);
 3291        }
 3292
 3293        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3294
 3295        if reset {
 3296            let pointer_position = display_map
 3297                .buffer_snapshot
 3298                .anchor_before(position.to_point(&display_map));
 3299
 3300            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3301                s.clear_disjoint();
 3302                s.set_pending_anchor_range(
 3303                    pointer_position..pointer_position,
 3304                    SelectMode::Character,
 3305                );
 3306            });
 3307            if position.column() != goal_column {
 3308                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3309            } else {
 3310                self.columnar_display_point = None;
 3311            }
 3312        }
 3313
 3314        let tail = self.selections.newest::<Point>(cx).tail();
 3315        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3316
 3317        if !reset {
 3318            self.columnar_display_point = None;
 3319            self.select_columns(
 3320                tail.to_display_point(&display_map),
 3321                position,
 3322                goal_column,
 3323                &display_map,
 3324                window,
 3325                cx,
 3326            );
 3327        }
 3328    }
 3329
 3330    fn update_selection(
 3331        &mut self,
 3332        position: DisplayPoint,
 3333        goal_column: u32,
 3334        scroll_delta: gpui::Point<f32>,
 3335        window: &mut Window,
 3336        cx: &mut Context<Self>,
 3337    ) {
 3338        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3339
 3340        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3341            let tail = self
 3342                .columnar_display_point
 3343                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3344            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3345        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3346            let buffer = self.buffer.read(cx).snapshot(cx);
 3347            let head;
 3348            let tail;
 3349            let mode = self.selections.pending_mode().unwrap();
 3350            match &mode {
 3351                SelectMode::Character => {
 3352                    head = position.to_point(&display_map);
 3353                    tail = pending.tail().to_point(&buffer);
 3354                }
 3355                SelectMode::Word(original_range) => {
 3356                    let original_display_range = original_range.start.to_display_point(&display_map)
 3357                        ..original_range.end.to_display_point(&display_map);
 3358                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3359                        ..original_display_range.end.to_point(&display_map);
 3360                    if movement::is_inside_word(&display_map, position)
 3361                        || original_display_range.contains(&position)
 3362                    {
 3363                        let word_range = movement::surrounding_word(&display_map, position);
 3364                        if word_range.start < original_display_range.start {
 3365                            head = word_range.start.to_point(&display_map);
 3366                        } else {
 3367                            head = word_range.end.to_point(&display_map);
 3368                        }
 3369                    } else {
 3370                        head = position.to_point(&display_map);
 3371                    }
 3372
 3373                    if head <= original_buffer_range.start {
 3374                        tail = original_buffer_range.end;
 3375                    } else {
 3376                        tail = original_buffer_range.start;
 3377                    }
 3378                }
 3379                SelectMode::Line(original_range) => {
 3380                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3381
 3382                    let position = display_map
 3383                        .clip_point(position, Bias::Left)
 3384                        .to_point(&display_map);
 3385                    let line_start = display_map.prev_line_boundary(position).0;
 3386                    let next_line_start = buffer.clip_point(
 3387                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3388                        Bias::Left,
 3389                    );
 3390
 3391                    if line_start < original_range.start {
 3392                        head = line_start
 3393                    } else {
 3394                        head = next_line_start
 3395                    }
 3396
 3397                    if head <= original_range.start {
 3398                        tail = original_range.end;
 3399                    } else {
 3400                        tail = original_range.start;
 3401                    }
 3402                }
 3403                SelectMode::All => {
 3404                    return;
 3405                }
 3406            };
 3407
 3408            if head < tail {
 3409                pending.start = buffer.anchor_before(head);
 3410                pending.end = buffer.anchor_before(tail);
 3411                pending.reversed = true;
 3412            } else {
 3413                pending.start = buffer.anchor_before(tail);
 3414                pending.end = buffer.anchor_before(head);
 3415                pending.reversed = false;
 3416            }
 3417
 3418            self.change_selections(None, window, cx, |s| {
 3419                s.set_pending(pending, mode);
 3420            });
 3421        } else {
 3422            log::error!("update_selection dispatched with no pending selection");
 3423            return;
 3424        }
 3425
 3426        self.apply_scroll_delta(scroll_delta, window, cx);
 3427        cx.notify();
 3428    }
 3429
 3430    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3431        self.columnar_selection_tail.take();
 3432        if self.selections.pending_anchor().is_some() {
 3433            let selections = self.selections.all::<usize>(cx);
 3434            self.change_selections(None, window, cx, |s| {
 3435                s.select(selections);
 3436                s.clear_pending();
 3437            });
 3438        }
 3439    }
 3440
 3441    fn select_columns(
 3442        &mut self,
 3443        tail: DisplayPoint,
 3444        head: DisplayPoint,
 3445        goal_column: u32,
 3446        display_map: &DisplaySnapshot,
 3447        window: &mut Window,
 3448        cx: &mut Context<Self>,
 3449    ) {
 3450        let start_row = cmp::min(tail.row(), head.row());
 3451        let end_row = cmp::max(tail.row(), head.row());
 3452        let start_column = cmp::min(tail.column(), goal_column);
 3453        let end_column = cmp::max(tail.column(), goal_column);
 3454        let reversed = start_column < tail.column();
 3455
 3456        let selection_ranges = (start_row.0..=end_row.0)
 3457            .map(DisplayRow)
 3458            .filter_map(|row| {
 3459                if !display_map.is_block_line(row) {
 3460                    let start = display_map
 3461                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3462                        .to_point(display_map);
 3463                    let end = display_map
 3464                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3465                        .to_point(display_map);
 3466                    if reversed {
 3467                        Some(end..start)
 3468                    } else {
 3469                        Some(start..end)
 3470                    }
 3471                } else {
 3472                    None
 3473                }
 3474            })
 3475            .collect::<Vec<_>>();
 3476
 3477        let mut non_empty_ranges = selection_ranges
 3478            .iter()
 3479            .filter(|selection_range| selection_range.start != selection_range.end)
 3480            .peekable();
 3481
 3482        let ranges = if non_empty_ranges.peek().is_some() {
 3483            non_empty_ranges.cloned().collect()
 3484        } else {
 3485            selection_ranges
 3486        };
 3487
 3488        self.change_selections(None, window, cx, |s| {
 3489            s.select_ranges(ranges);
 3490        });
 3491        cx.notify();
 3492    }
 3493
 3494    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3495        self.selections
 3496            .all_adjusted(cx)
 3497            .iter()
 3498            .any(|selection| !selection.is_empty())
 3499    }
 3500
 3501    pub fn has_pending_nonempty_selection(&self) -> bool {
 3502        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3503            Some(Selection { start, end, .. }) => start != end,
 3504            None => false,
 3505        };
 3506
 3507        pending_nonempty_selection
 3508            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3509    }
 3510
 3511    pub fn has_pending_selection(&self) -> bool {
 3512        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3513    }
 3514
 3515    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3516        self.selection_mark_mode = false;
 3517
 3518        if self.clear_expanded_diff_hunks(cx) {
 3519            cx.notify();
 3520            return;
 3521        }
 3522        if self.dismiss_menus_and_popups(true, window, cx) {
 3523            return;
 3524        }
 3525
 3526        if self.mode.is_full()
 3527            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3528        {
 3529            return;
 3530        }
 3531
 3532        cx.propagate();
 3533    }
 3534
 3535    pub fn dismiss_menus_and_popups(
 3536        &mut self,
 3537        is_user_requested: bool,
 3538        window: &mut Window,
 3539        cx: &mut Context<Self>,
 3540    ) -> bool {
 3541        if self.take_rename(false, window, cx).is_some() {
 3542            return true;
 3543        }
 3544
 3545        if hide_hover(self, cx) {
 3546            return true;
 3547        }
 3548
 3549        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3550            return true;
 3551        }
 3552
 3553        if self.hide_context_menu(window, cx).is_some() {
 3554            return true;
 3555        }
 3556
 3557        if self.mouse_context_menu.take().is_some() {
 3558            return true;
 3559        }
 3560
 3561        if is_user_requested && self.discard_inline_completion(true, cx) {
 3562            return true;
 3563        }
 3564
 3565        if self.snippet_stack.pop().is_some() {
 3566            return true;
 3567        }
 3568
 3569        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3570            self.dismiss_diagnostics(cx);
 3571            return true;
 3572        }
 3573
 3574        false
 3575    }
 3576
 3577    fn linked_editing_ranges_for(
 3578        &self,
 3579        selection: Range<text::Anchor>,
 3580        cx: &App,
 3581    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3582        if self.linked_edit_ranges.is_empty() {
 3583            return None;
 3584        }
 3585        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3586            selection.end.buffer_id.and_then(|end_buffer_id| {
 3587                if selection.start.buffer_id != Some(end_buffer_id) {
 3588                    return None;
 3589                }
 3590                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3591                let snapshot = buffer.read(cx).snapshot();
 3592                self.linked_edit_ranges
 3593                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3594                    .map(|ranges| (ranges, snapshot, buffer))
 3595            })?;
 3596        use text::ToOffset as TO;
 3597        // find offset from the start of current range to current cursor position
 3598        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3599
 3600        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3601        let start_difference = start_offset - start_byte_offset;
 3602        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3603        let end_difference = end_offset - start_byte_offset;
 3604        // Current range has associated linked ranges.
 3605        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3606        for range in linked_ranges.iter() {
 3607            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3608            let end_offset = start_offset + end_difference;
 3609            let start_offset = start_offset + start_difference;
 3610            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3611                continue;
 3612            }
 3613            if self.selections.disjoint_anchor_ranges().any(|s| {
 3614                if s.start.buffer_id != selection.start.buffer_id
 3615                    || s.end.buffer_id != selection.end.buffer_id
 3616                {
 3617                    return false;
 3618                }
 3619                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3620                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3621            }) {
 3622                continue;
 3623            }
 3624            let start = buffer_snapshot.anchor_after(start_offset);
 3625            let end = buffer_snapshot.anchor_after(end_offset);
 3626            linked_edits
 3627                .entry(buffer.clone())
 3628                .or_default()
 3629                .push(start..end);
 3630        }
 3631        Some(linked_edits)
 3632    }
 3633
 3634    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3635        let text: Arc<str> = text.into();
 3636
 3637        if self.read_only(cx) {
 3638            return;
 3639        }
 3640
 3641        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3642
 3643        let selections = self.selections.all_adjusted(cx);
 3644        let mut bracket_inserted = false;
 3645        let mut edits = Vec::new();
 3646        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3647        let mut new_selections = Vec::with_capacity(selections.len());
 3648        let mut new_autoclose_regions = Vec::new();
 3649        let snapshot = self.buffer.read(cx).read(cx);
 3650        let mut clear_linked_edit_ranges = false;
 3651
 3652        for (selection, autoclose_region) in
 3653            self.selections_with_autoclose_regions(selections, &snapshot)
 3654        {
 3655            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3656                // Determine if the inserted text matches the opening or closing
 3657                // bracket of any of this language's bracket pairs.
 3658                let mut bracket_pair = None;
 3659                let mut is_bracket_pair_start = false;
 3660                let mut is_bracket_pair_end = false;
 3661                if !text.is_empty() {
 3662                    let mut bracket_pair_matching_end = None;
 3663                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3664                    //  and they are removing the character that triggered IME popup.
 3665                    for (pair, enabled) in scope.brackets() {
 3666                        if !pair.close && !pair.surround {
 3667                            continue;
 3668                        }
 3669
 3670                        if enabled && pair.start.ends_with(text.as_ref()) {
 3671                            let prefix_len = pair.start.len() - text.len();
 3672                            let preceding_text_matches_prefix = prefix_len == 0
 3673                                || (selection.start.column >= (prefix_len as u32)
 3674                                    && snapshot.contains_str_at(
 3675                                        Point::new(
 3676                                            selection.start.row,
 3677                                            selection.start.column - (prefix_len as u32),
 3678                                        ),
 3679                                        &pair.start[..prefix_len],
 3680                                    ));
 3681                            if preceding_text_matches_prefix {
 3682                                bracket_pair = Some(pair.clone());
 3683                                is_bracket_pair_start = true;
 3684                                break;
 3685                            }
 3686                        }
 3687                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3688                        {
 3689                            // take first bracket pair matching end, but don't break in case a later bracket
 3690                            // pair matches start
 3691                            bracket_pair_matching_end = Some(pair.clone());
 3692                        }
 3693                    }
 3694                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3695                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3696                        is_bracket_pair_end = true;
 3697                    }
 3698                }
 3699
 3700                if let Some(bracket_pair) = bracket_pair {
 3701                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3702                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3703                    let auto_surround =
 3704                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3705                    if selection.is_empty() {
 3706                        if is_bracket_pair_start {
 3707                            // If the inserted text is a suffix of an opening bracket and the
 3708                            // selection is preceded by the rest of the opening bracket, then
 3709                            // insert the closing bracket.
 3710                            let following_text_allows_autoclose = snapshot
 3711                                .chars_at(selection.start)
 3712                                .next()
 3713                                .map_or(true, |c| scope.should_autoclose_before(c));
 3714
 3715                            let preceding_text_allows_autoclose = selection.start.column == 0
 3716                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3717                                    true,
 3718                                    |c| {
 3719                                        bracket_pair.start != bracket_pair.end
 3720                                            || !snapshot
 3721                                                .char_classifier_at(selection.start)
 3722                                                .is_word(c)
 3723                                    },
 3724                                );
 3725
 3726                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3727                                && bracket_pair.start.len() == 1
 3728                            {
 3729                                let target = bracket_pair.start.chars().next().unwrap();
 3730                                let current_line_count = snapshot
 3731                                    .reversed_chars_at(selection.start)
 3732                                    .take_while(|&c| c != '\n')
 3733                                    .filter(|&c| c == target)
 3734                                    .count();
 3735                                current_line_count % 2 == 1
 3736                            } else {
 3737                                false
 3738                            };
 3739
 3740                            if autoclose
 3741                                && bracket_pair.close
 3742                                && following_text_allows_autoclose
 3743                                && preceding_text_allows_autoclose
 3744                                && !is_closing_quote
 3745                            {
 3746                                let anchor = snapshot.anchor_before(selection.end);
 3747                                new_selections.push((selection.map(|_| anchor), text.len()));
 3748                                new_autoclose_regions.push((
 3749                                    anchor,
 3750                                    text.len(),
 3751                                    selection.id,
 3752                                    bracket_pair.clone(),
 3753                                ));
 3754                                edits.push((
 3755                                    selection.range(),
 3756                                    format!("{}{}", text, bracket_pair.end).into(),
 3757                                ));
 3758                                bracket_inserted = true;
 3759                                continue;
 3760                            }
 3761                        }
 3762
 3763                        if let Some(region) = autoclose_region {
 3764                            // If the selection is followed by an auto-inserted closing bracket,
 3765                            // then don't insert that closing bracket again; just move the selection
 3766                            // past the closing bracket.
 3767                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3768                                && text.as_ref() == region.pair.end.as_str();
 3769                            if should_skip {
 3770                                let anchor = snapshot.anchor_after(selection.end);
 3771                                new_selections
 3772                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3773                                continue;
 3774                            }
 3775                        }
 3776
 3777                        let always_treat_brackets_as_autoclosed = snapshot
 3778                            .language_settings_at(selection.start, cx)
 3779                            .always_treat_brackets_as_autoclosed;
 3780                        if always_treat_brackets_as_autoclosed
 3781                            && is_bracket_pair_end
 3782                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3783                        {
 3784                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3785                            // and the inserted text is a closing bracket and the selection is followed
 3786                            // by the closing bracket then move the selection past the closing bracket.
 3787                            let anchor = snapshot.anchor_after(selection.end);
 3788                            new_selections.push((selection.map(|_| anchor), text.len()));
 3789                            continue;
 3790                        }
 3791                    }
 3792                    // If an opening bracket is 1 character long and is typed while
 3793                    // text is selected, then surround that text with the bracket pair.
 3794                    else if auto_surround
 3795                        && bracket_pair.surround
 3796                        && is_bracket_pair_start
 3797                        && bracket_pair.start.chars().count() == 1
 3798                    {
 3799                        edits.push((selection.start..selection.start, text.clone()));
 3800                        edits.push((
 3801                            selection.end..selection.end,
 3802                            bracket_pair.end.as_str().into(),
 3803                        ));
 3804                        bracket_inserted = true;
 3805                        new_selections.push((
 3806                            Selection {
 3807                                id: selection.id,
 3808                                start: snapshot.anchor_after(selection.start),
 3809                                end: snapshot.anchor_before(selection.end),
 3810                                reversed: selection.reversed,
 3811                                goal: selection.goal,
 3812                            },
 3813                            0,
 3814                        ));
 3815                        continue;
 3816                    }
 3817                }
 3818            }
 3819
 3820            if self.auto_replace_emoji_shortcode
 3821                && selection.is_empty()
 3822                && text.as_ref().ends_with(':')
 3823            {
 3824                if let Some(possible_emoji_short_code) =
 3825                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3826                {
 3827                    if !possible_emoji_short_code.is_empty() {
 3828                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3829                            let emoji_shortcode_start = Point::new(
 3830                                selection.start.row,
 3831                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3832                            );
 3833
 3834                            // Remove shortcode from buffer
 3835                            edits.push((
 3836                                emoji_shortcode_start..selection.start,
 3837                                "".to_string().into(),
 3838                            ));
 3839                            new_selections.push((
 3840                                Selection {
 3841                                    id: selection.id,
 3842                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3843                                    end: snapshot.anchor_before(selection.start),
 3844                                    reversed: selection.reversed,
 3845                                    goal: selection.goal,
 3846                                },
 3847                                0,
 3848                            ));
 3849
 3850                            // Insert emoji
 3851                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3852                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3853                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3854
 3855                            continue;
 3856                        }
 3857                    }
 3858                }
 3859            }
 3860
 3861            // If not handling any auto-close operation, then just replace the selected
 3862            // text with the given input and move the selection to the end of the
 3863            // newly inserted text.
 3864            let anchor = snapshot.anchor_after(selection.end);
 3865            if !self.linked_edit_ranges.is_empty() {
 3866                let start_anchor = snapshot.anchor_before(selection.start);
 3867
 3868                let is_word_char = text.chars().next().map_or(true, |char| {
 3869                    let classifier = snapshot
 3870                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3871                        .ignore_punctuation(true);
 3872                    classifier.is_word(char)
 3873                });
 3874
 3875                if is_word_char {
 3876                    if let Some(ranges) = self
 3877                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3878                    {
 3879                        for (buffer, edits) in ranges {
 3880                            linked_edits
 3881                                .entry(buffer.clone())
 3882                                .or_default()
 3883                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3884                        }
 3885                    }
 3886                } else {
 3887                    clear_linked_edit_ranges = true;
 3888                }
 3889            }
 3890
 3891            new_selections.push((selection.map(|_| anchor), 0));
 3892            edits.push((selection.start..selection.end, text.clone()));
 3893        }
 3894
 3895        drop(snapshot);
 3896
 3897        self.transact(window, cx, |this, window, cx| {
 3898            if clear_linked_edit_ranges {
 3899                this.linked_edit_ranges.clear();
 3900            }
 3901            let initial_buffer_versions =
 3902                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3903
 3904            this.buffer.update(cx, |buffer, cx| {
 3905                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3906            });
 3907            for (buffer, edits) in linked_edits {
 3908                buffer.update(cx, |buffer, cx| {
 3909                    let snapshot = buffer.snapshot();
 3910                    let edits = edits
 3911                        .into_iter()
 3912                        .map(|(range, text)| {
 3913                            use text::ToPoint as TP;
 3914                            let end_point = TP::to_point(&range.end, &snapshot);
 3915                            let start_point = TP::to_point(&range.start, &snapshot);
 3916                            (start_point..end_point, text)
 3917                        })
 3918                        .sorted_by_key(|(range, _)| range.start);
 3919                    buffer.edit(edits, None, cx);
 3920                })
 3921            }
 3922            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3923            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3924            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3925            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3926                .zip(new_selection_deltas)
 3927                .map(|(selection, delta)| Selection {
 3928                    id: selection.id,
 3929                    start: selection.start + delta,
 3930                    end: selection.end + delta,
 3931                    reversed: selection.reversed,
 3932                    goal: SelectionGoal::None,
 3933                })
 3934                .collect::<Vec<_>>();
 3935
 3936            let mut i = 0;
 3937            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3938                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3939                let start = map.buffer_snapshot.anchor_before(position);
 3940                let end = map.buffer_snapshot.anchor_after(position);
 3941                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3942                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3943                        Ordering::Less => i += 1,
 3944                        Ordering::Greater => break,
 3945                        Ordering::Equal => {
 3946                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3947                                Ordering::Less => i += 1,
 3948                                Ordering::Equal => break,
 3949                                Ordering::Greater => break,
 3950                            }
 3951                        }
 3952                    }
 3953                }
 3954                this.autoclose_regions.insert(
 3955                    i,
 3956                    AutocloseRegion {
 3957                        selection_id,
 3958                        range: start..end,
 3959                        pair,
 3960                    },
 3961                );
 3962            }
 3963
 3964            let had_active_inline_completion = this.has_active_inline_completion();
 3965            this.change_selections_without_updating_completions(
 3966                Some(Autoscroll::fit()),
 3967                window,
 3968                cx,
 3969                |s| s.select(new_selections),
 3970            );
 3971
 3972            if !bracket_inserted {
 3973                if let Some(on_type_format_task) =
 3974                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3975                {
 3976                    on_type_format_task.detach_and_log_err(cx);
 3977                }
 3978            }
 3979
 3980            let editor_settings = EditorSettings::get_global(cx);
 3981            if bracket_inserted
 3982                && (editor_settings.auto_signature_help
 3983                    || editor_settings.show_signature_help_after_edits)
 3984            {
 3985                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3986            }
 3987
 3988            let trigger_in_words =
 3989                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3990            if this.hard_wrap.is_some() {
 3991                let latest: Range<Point> = this.selections.newest(cx).range();
 3992                if latest.is_empty()
 3993                    && this
 3994                        .buffer()
 3995                        .read(cx)
 3996                        .snapshot(cx)
 3997                        .line_len(MultiBufferRow(latest.start.row))
 3998                        == latest.start.column
 3999                {
 4000                    this.rewrap_impl(
 4001                        RewrapOptions {
 4002                            override_language_settings: true,
 4003                            preserve_existing_whitespace: true,
 4004                        },
 4005                        cx,
 4006                    )
 4007                }
 4008            }
 4009            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4010            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4011            this.refresh_inline_completion(true, false, window, cx);
 4012            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4013        });
 4014    }
 4015
 4016    fn find_possible_emoji_shortcode_at_position(
 4017        snapshot: &MultiBufferSnapshot,
 4018        position: Point,
 4019    ) -> Option<String> {
 4020        let mut chars = Vec::new();
 4021        let mut found_colon = false;
 4022        for char in snapshot.reversed_chars_at(position).take(100) {
 4023            // Found a possible emoji shortcode in the middle of the buffer
 4024            if found_colon {
 4025                if char.is_whitespace() {
 4026                    chars.reverse();
 4027                    return Some(chars.iter().collect());
 4028                }
 4029                // If the previous character is not a whitespace, we are in the middle of a word
 4030                // and we only want to complete the shortcode if the word is made up of other emojis
 4031                let mut containing_word = String::new();
 4032                for ch in snapshot
 4033                    .reversed_chars_at(position)
 4034                    .skip(chars.len() + 1)
 4035                    .take(100)
 4036                {
 4037                    if ch.is_whitespace() {
 4038                        break;
 4039                    }
 4040                    containing_word.push(ch);
 4041                }
 4042                let containing_word = containing_word.chars().rev().collect::<String>();
 4043                if util::word_consists_of_emojis(containing_word.as_str()) {
 4044                    chars.reverse();
 4045                    return Some(chars.iter().collect());
 4046                }
 4047            }
 4048
 4049            if char.is_whitespace() || !char.is_ascii() {
 4050                return None;
 4051            }
 4052            if char == ':' {
 4053                found_colon = true;
 4054            } else {
 4055                chars.push(char);
 4056            }
 4057        }
 4058        // Found a possible emoji shortcode at the beginning of the buffer
 4059        chars.reverse();
 4060        Some(chars.iter().collect())
 4061    }
 4062
 4063    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4064        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4065        self.transact(window, cx, |this, window, cx| {
 4066            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4067                let selections = this.selections.all::<usize>(cx);
 4068                let multi_buffer = this.buffer.read(cx);
 4069                let buffer = multi_buffer.snapshot(cx);
 4070                selections
 4071                    .iter()
 4072                    .map(|selection| {
 4073                        let start_point = selection.start.to_point(&buffer);
 4074                        let mut existing_indent =
 4075                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4076                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4077                        let start = selection.start;
 4078                        let end = selection.end;
 4079                        let selection_is_empty = start == end;
 4080                        let language_scope = buffer.language_scope_at(start);
 4081                        let (
 4082                            comment_delimiter,
 4083                            doc_delimiter,
 4084                            insert_extra_newline,
 4085                            indent_on_newline,
 4086                            indent_on_extra_newline,
 4087                        ) = if let Some(language) = &language_scope {
 4088                            let mut insert_extra_newline =
 4089                                insert_extra_newline_brackets(&buffer, start..end, language)
 4090                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4091
 4092                            // Comment extension on newline is allowed only for cursor selections
 4093                            let comment_delimiter = maybe!({
 4094                                if !selection_is_empty {
 4095                                    return None;
 4096                                }
 4097
 4098                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4099                                    return None;
 4100                                }
 4101
 4102                                let delimiters = language.line_comment_prefixes();
 4103                                let max_len_of_delimiter =
 4104                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4105                                let (snapshot, range) =
 4106                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4107
 4108                                let num_of_whitespaces = snapshot
 4109                                    .chars_for_range(range.clone())
 4110                                    .take_while(|c| c.is_whitespace())
 4111                                    .count();
 4112                                let comment_candidate = snapshot
 4113                                    .chars_for_range(range)
 4114                                    .skip(num_of_whitespaces)
 4115                                    .take(max_len_of_delimiter)
 4116                                    .collect::<String>();
 4117                                let (delimiter, trimmed_len) = delimiters
 4118                                    .iter()
 4119                                    .filter_map(|delimiter| {
 4120                                        let prefix = delimiter.trim_end();
 4121                                        if comment_candidate.starts_with(prefix) {
 4122                                            Some((delimiter, prefix.len()))
 4123                                        } else {
 4124                                            None
 4125                                        }
 4126                                    })
 4127                                    .max_by_key(|(_, len)| *len)?;
 4128
 4129                                let cursor_is_placed_after_comment_marker =
 4130                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4131                                if cursor_is_placed_after_comment_marker {
 4132                                    Some(delimiter.clone())
 4133                                } else {
 4134                                    None
 4135                                }
 4136                            });
 4137
 4138                            let mut indent_on_newline = IndentSize::spaces(0);
 4139                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4140
 4141                            let doc_delimiter = maybe!({
 4142                                if !selection_is_empty {
 4143                                    return None;
 4144                                }
 4145
 4146                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4147                                    return None;
 4148                                }
 4149
 4150                                let DocumentationConfig {
 4151                                    start: start_tag,
 4152                                    end: end_tag,
 4153                                    prefix: delimiter,
 4154                                    tab_size: len,
 4155                                } = language.documentation()?;
 4156
 4157                                let is_within_block_comment = buffer
 4158                                    .language_scope_at(start_point)
 4159                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4160                                if !is_within_block_comment {
 4161                                    return None;
 4162                                }
 4163
 4164                                let (snapshot, range) =
 4165                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4166
 4167                                let num_of_whitespaces = snapshot
 4168                                    .chars_for_range(range.clone())
 4169                                    .take_while(|c| c.is_whitespace())
 4170                                    .count();
 4171
 4172                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4173                                let column = start_point.column;
 4174                                let cursor_is_after_start_tag = {
 4175                                    let start_tag_len = start_tag.len();
 4176                                    let start_tag_line = snapshot
 4177                                        .chars_for_range(range.clone())
 4178                                        .skip(num_of_whitespaces)
 4179                                        .take(start_tag_len)
 4180                                        .collect::<String>();
 4181                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4182                                        num_of_whitespaces + start_tag_len <= column as usize
 4183                                    } else {
 4184                                        false
 4185                                    }
 4186                                };
 4187
 4188                                let cursor_is_after_delimiter = {
 4189                                    let delimiter_trim = delimiter.trim_end();
 4190                                    let delimiter_line = snapshot
 4191                                        .chars_for_range(range.clone())
 4192                                        .skip(num_of_whitespaces)
 4193                                        .take(delimiter_trim.len())
 4194                                        .collect::<String>();
 4195                                    if delimiter_line.starts_with(delimiter_trim) {
 4196                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4197                                    } else {
 4198                                        false
 4199                                    }
 4200                                };
 4201
 4202                                let cursor_is_before_end_tag_if_exists = {
 4203                                    let mut char_position = 0u32;
 4204                                    let mut end_tag_offset = None;
 4205
 4206                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4207                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4208                                            let chars_before_match =
 4209                                                chunk[..byte_pos].chars().count() as u32;
 4210                                            end_tag_offset =
 4211                                                Some(char_position + chars_before_match);
 4212                                            break 'outer;
 4213                                        }
 4214                                        char_position += chunk.chars().count() as u32;
 4215                                    }
 4216
 4217                                    if let Some(end_tag_offset) = end_tag_offset {
 4218                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4219                                        if cursor_is_after_start_tag {
 4220                                            if cursor_is_before_end_tag {
 4221                                                insert_extra_newline = true;
 4222                                            }
 4223                                            let cursor_is_at_start_of_end_tag =
 4224                                                column == end_tag_offset;
 4225                                            if cursor_is_at_start_of_end_tag {
 4226                                                indent_on_extra_newline.len = (*len).into();
 4227                                            }
 4228                                        }
 4229                                        cursor_is_before_end_tag
 4230                                    } else {
 4231                                        true
 4232                                    }
 4233                                };
 4234
 4235                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4236                                    && cursor_is_before_end_tag_if_exists
 4237                                {
 4238                                    if cursor_is_after_start_tag {
 4239                                        indent_on_newline.len = (*len).into();
 4240                                    }
 4241                                    Some(delimiter.clone())
 4242                                } else {
 4243                                    None
 4244                                }
 4245                            });
 4246
 4247                            (
 4248                                comment_delimiter,
 4249                                doc_delimiter,
 4250                                insert_extra_newline,
 4251                                indent_on_newline,
 4252                                indent_on_extra_newline,
 4253                            )
 4254                        } else {
 4255                            (
 4256                                None,
 4257                                None,
 4258                                false,
 4259                                IndentSize::default(),
 4260                                IndentSize::default(),
 4261                            )
 4262                        };
 4263
 4264                        let prevent_auto_indent = doc_delimiter.is_some();
 4265                        let delimiter = comment_delimiter.or(doc_delimiter);
 4266
 4267                        let capacity_for_delimiter =
 4268                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4269                        let mut new_text = String::with_capacity(
 4270                            1 + capacity_for_delimiter
 4271                                + existing_indent.len as usize
 4272                                + indent_on_newline.len as usize
 4273                                + indent_on_extra_newline.len as usize,
 4274                        );
 4275                        new_text.push('\n');
 4276                        new_text.extend(existing_indent.chars());
 4277                        new_text.extend(indent_on_newline.chars());
 4278
 4279                        if let Some(delimiter) = &delimiter {
 4280                            new_text.push_str(delimiter);
 4281                        }
 4282
 4283                        if insert_extra_newline {
 4284                            new_text.push('\n');
 4285                            new_text.extend(existing_indent.chars());
 4286                            new_text.extend(indent_on_extra_newline.chars());
 4287                        }
 4288
 4289                        let anchor = buffer.anchor_after(end);
 4290                        let new_selection = selection.map(|_| anchor);
 4291                        (
 4292                            ((start..end, new_text), prevent_auto_indent),
 4293                            (insert_extra_newline, new_selection),
 4294                        )
 4295                    })
 4296                    .unzip()
 4297            };
 4298
 4299            let mut auto_indent_edits = Vec::new();
 4300            let mut edits = Vec::new();
 4301            for (edit, prevent_auto_indent) in edits_with_flags {
 4302                if prevent_auto_indent {
 4303                    edits.push(edit);
 4304                } else {
 4305                    auto_indent_edits.push(edit);
 4306                }
 4307            }
 4308            if !edits.is_empty() {
 4309                this.edit(edits, cx);
 4310            }
 4311            if !auto_indent_edits.is_empty() {
 4312                this.edit_with_autoindent(auto_indent_edits, cx);
 4313            }
 4314
 4315            let buffer = this.buffer.read(cx).snapshot(cx);
 4316            let new_selections = selection_info
 4317                .into_iter()
 4318                .map(|(extra_newline_inserted, new_selection)| {
 4319                    let mut cursor = new_selection.end.to_point(&buffer);
 4320                    if extra_newline_inserted {
 4321                        cursor.row -= 1;
 4322                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4323                    }
 4324                    new_selection.map(|_| cursor)
 4325                })
 4326                .collect();
 4327
 4328            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4329                s.select(new_selections)
 4330            });
 4331            this.refresh_inline_completion(true, false, window, cx);
 4332        });
 4333    }
 4334
 4335    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4336        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4337
 4338        let buffer = self.buffer.read(cx);
 4339        let snapshot = buffer.snapshot(cx);
 4340
 4341        let mut edits = Vec::new();
 4342        let mut rows = Vec::new();
 4343
 4344        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4345            let cursor = selection.head();
 4346            let row = cursor.row;
 4347
 4348            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4349
 4350            let newline = "\n".to_string();
 4351            edits.push((start_of_line..start_of_line, newline));
 4352
 4353            rows.push(row + rows_inserted as u32);
 4354        }
 4355
 4356        self.transact(window, cx, |editor, window, cx| {
 4357            editor.edit(edits, cx);
 4358
 4359            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4360                let mut index = 0;
 4361                s.move_cursors_with(|map, _, _| {
 4362                    let row = rows[index];
 4363                    index += 1;
 4364
 4365                    let point = Point::new(row, 0);
 4366                    let boundary = map.next_line_boundary(point).1;
 4367                    let clipped = map.clip_point(boundary, Bias::Left);
 4368
 4369                    (clipped, SelectionGoal::None)
 4370                });
 4371            });
 4372
 4373            let mut indent_edits = Vec::new();
 4374            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4375            for row in rows {
 4376                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4377                for (row, indent) in indents {
 4378                    if indent.len == 0 {
 4379                        continue;
 4380                    }
 4381
 4382                    let text = match indent.kind {
 4383                        IndentKind::Space => " ".repeat(indent.len as usize),
 4384                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4385                    };
 4386                    let point = Point::new(row.0, 0);
 4387                    indent_edits.push((point..point, text));
 4388                }
 4389            }
 4390            editor.edit(indent_edits, cx);
 4391        });
 4392    }
 4393
 4394    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4395        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4396
 4397        let buffer = self.buffer.read(cx);
 4398        let snapshot = buffer.snapshot(cx);
 4399
 4400        let mut edits = Vec::new();
 4401        let mut rows = Vec::new();
 4402        let mut rows_inserted = 0;
 4403
 4404        for selection in self.selections.all_adjusted(cx) {
 4405            let cursor = selection.head();
 4406            let row = cursor.row;
 4407
 4408            let point = Point::new(row + 1, 0);
 4409            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4410
 4411            let newline = "\n".to_string();
 4412            edits.push((start_of_line..start_of_line, newline));
 4413
 4414            rows_inserted += 1;
 4415            rows.push(row + rows_inserted);
 4416        }
 4417
 4418        self.transact(window, cx, |editor, window, cx| {
 4419            editor.edit(edits, cx);
 4420
 4421            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4422                let mut index = 0;
 4423                s.move_cursors_with(|map, _, _| {
 4424                    let row = rows[index];
 4425                    index += 1;
 4426
 4427                    let point = Point::new(row, 0);
 4428                    let boundary = map.next_line_boundary(point).1;
 4429                    let clipped = map.clip_point(boundary, Bias::Left);
 4430
 4431                    (clipped, SelectionGoal::None)
 4432                });
 4433            });
 4434
 4435            let mut indent_edits = Vec::new();
 4436            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4437            for row in rows {
 4438                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4439                for (row, indent) in indents {
 4440                    if indent.len == 0 {
 4441                        continue;
 4442                    }
 4443
 4444                    let text = match indent.kind {
 4445                        IndentKind::Space => " ".repeat(indent.len as usize),
 4446                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4447                    };
 4448                    let point = Point::new(row.0, 0);
 4449                    indent_edits.push((point..point, text));
 4450                }
 4451            }
 4452            editor.edit(indent_edits, cx);
 4453        });
 4454    }
 4455
 4456    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4457        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4458            original_indent_columns: Vec::new(),
 4459        });
 4460        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4461    }
 4462
 4463    fn insert_with_autoindent_mode(
 4464        &mut self,
 4465        text: &str,
 4466        autoindent_mode: Option<AutoindentMode>,
 4467        window: &mut Window,
 4468        cx: &mut Context<Self>,
 4469    ) {
 4470        if self.read_only(cx) {
 4471            return;
 4472        }
 4473
 4474        let text: Arc<str> = text.into();
 4475        self.transact(window, cx, |this, window, cx| {
 4476            let old_selections = this.selections.all_adjusted(cx);
 4477            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4478                let anchors = {
 4479                    let snapshot = buffer.read(cx);
 4480                    old_selections
 4481                        .iter()
 4482                        .map(|s| {
 4483                            let anchor = snapshot.anchor_after(s.head());
 4484                            s.map(|_| anchor)
 4485                        })
 4486                        .collect::<Vec<_>>()
 4487                };
 4488                buffer.edit(
 4489                    old_selections
 4490                        .iter()
 4491                        .map(|s| (s.start..s.end, text.clone())),
 4492                    autoindent_mode,
 4493                    cx,
 4494                );
 4495                anchors
 4496            });
 4497
 4498            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4499                s.select_anchors(selection_anchors);
 4500            });
 4501
 4502            cx.notify();
 4503        });
 4504    }
 4505
 4506    fn trigger_completion_on_input(
 4507        &mut self,
 4508        text: &str,
 4509        trigger_in_words: bool,
 4510        window: &mut Window,
 4511        cx: &mut Context<Self>,
 4512    ) {
 4513        let ignore_completion_provider = self
 4514            .context_menu
 4515            .borrow()
 4516            .as_ref()
 4517            .map(|menu| match menu {
 4518                CodeContextMenu::Completions(completions_menu) => {
 4519                    completions_menu.ignore_completion_provider
 4520                }
 4521                CodeContextMenu::CodeActions(_) => false,
 4522            })
 4523            .unwrap_or(false);
 4524
 4525        if ignore_completion_provider {
 4526            self.show_word_completions(&ShowWordCompletions, window, cx);
 4527        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4528            self.show_completions(
 4529                &ShowCompletions {
 4530                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4531                },
 4532                window,
 4533                cx,
 4534            );
 4535        } else {
 4536            self.hide_context_menu(window, cx);
 4537        }
 4538    }
 4539
 4540    fn is_completion_trigger(
 4541        &self,
 4542        text: &str,
 4543        trigger_in_words: bool,
 4544        cx: &mut Context<Self>,
 4545    ) -> bool {
 4546        let position = self.selections.newest_anchor().head();
 4547        let multibuffer = self.buffer.read(cx);
 4548        let Some(buffer) = position
 4549            .buffer_id
 4550            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4551        else {
 4552            return false;
 4553        };
 4554
 4555        if let Some(completion_provider) = &self.completion_provider {
 4556            completion_provider.is_completion_trigger(
 4557                &buffer,
 4558                position.text_anchor,
 4559                text,
 4560                trigger_in_words,
 4561                cx,
 4562            )
 4563        } else {
 4564            false
 4565        }
 4566    }
 4567
 4568    /// If any empty selections is touching the start of its innermost containing autoclose
 4569    /// region, expand it to select the brackets.
 4570    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4571        let selections = self.selections.all::<usize>(cx);
 4572        let buffer = self.buffer.read(cx).read(cx);
 4573        let new_selections = self
 4574            .selections_with_autoclose_regions(selections, &buffer)
 4575            .map(|(mut selection, region)| {
 4576                if !selection.is_empty() {
 4577                    return selection;
 4578                }
 4579
 4580                if let Some(region) = region {
 4581                    let mut range = region.range.to_offset(&buffer);
 4582                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4583                        range.start -= region.pair.start.len();
 4584                        if buffer.contains_str_at(range.start, &region.pair.start)
 4585                            && buffer.contains_str_at(range.end, &region.pair.end)
 4586                        {
 4587                            range.end += region.pair.end.len();
 4588                            selection.start = range.start;
 4589                            selection.end = range.end;
 4590
 4591                            return selection;
 4592                        }
 4593                    }
 4594                }
 4595
 4596                let always_treat_brackets_as_autoclosed = buffer
 4597                    .language_settings_at(selection.start, cx)
 4598                    .always_treat_brackets_as_autoclosed;
 4599
 4600                if !always_treat_brackets_as_autoclosed {
 4601                    return selection;
 4602                }
 4603
 4604                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4605                    for (pair, enabled) in scope.brackets() {
 4606                        if !enabled || !pair.close {
 4607                            continue;
 4608                        }
 4609
 4610                        if buffer.contains_str_at(selection.start, &pair.end) {
 4611                            let pair_start_len = pair.start.len();
 4612                            if buffer.contains_str_at(
 4613                                selection.start.saturating_sub(pair_start_len),
 4614                                &pair.start,
 4615                            ) {
 4616                                selection.start -= pair_start_len;
 4617                                selection.end += pair.end.len();
 4618
 4619                                return selection;
 4620                            }
 4621                        }
 4622                    }
 4623                }
 4624
 4625                selection
 4626            })
 4627            .collect();
 4628
 4629        drop(buffer);
 4630        self.change_selections(None, window, cx, |selections| {
 4631            selections.select(new_selections)
 4632        });
 4633    }
 4634
 4635    /// Iterate the given selections, and for each one, find the smallest surrounding
 4636    /// autoclose region. This uses the ordering of the selections and the autoclose
 4637    /// regions to avoid repeated comparisons.
 4638    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4639        &'a self,
 4640        selections: impl IntoIterator<Item = Selection<D>>,
 4641        buffer: &'a MultiBufferSnapshot,
 4642    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4643        let mut i = 0;
 4644        let mut regions = self.autoclose_regions.as_slice();
 4645        selections.into_iter().map(move |selection| {
 4646            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4647
 4648            let mut enclosing = None;
 4649            while let Some(pair_state) = regions.get(i) {
 4650                if pair_state.range.end.to_offset(buffer) < range.start {
 4651                    regions = &regions[i + 1..];
 4652                    i = 0;
 4653                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4654                    break;
 4655                } else {
 4656                    if pair_state.selection_id == selection.id {
 4657                        enclosing = Some(pair_state);
 4658                    }
 4659                    i += 1;
 4660                }
 4661            }
 4662
 4663            (selection, enclosing)
 4664        })
 4665    }
 4666
 4667    /// Remove any autoclose regions that no longer contain their selection.
 4668    fn invalidate_autoclose_regions(
 4669        &mut self,
 4670        mut selections: &[Selection<Anchor>],
 4671        buffer: &MultiBufferSnapshot,
 4672    ) {
 4673        self.autoclose_regions.retain(|state| {
 4674            let mut i = 0;
 4675            while let Some(selection) = selections.get(i) {
 4676                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4677                    selections = &selections[1..];
 4678                    continue;
 4679                }
 4680                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4681                    break;
 4682                }
 4683                if selection.id == state.selection_id {
 4684                    return true;
 4685                } else {
 4686                    i += 1;
 4687                }
 4688            }
 4689            false
 4690        });
 4691    }
 4692
 4693    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4694        let offset = position.to_offset(buffer);
 4695        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4696        if offset > word_range.start && kind == Some(CharKind::Word) {
 4697            Some(
 4698                buffer
 4699                    .text_for_range(word_range.start..offset)
 4700                    .collect::<String>(),
 4701            )
 4702        } else {
 4703            None
 4704        }
 4705    }
 4706
 4707    pub fn toggle_inline_values(
 4708        &mut self,
 4709        _: &ToggleInlineValues,
 4710        _: &mut Window,
 4711        cx: &mut Context<Self>,
 4712    ) {
 4713        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4714
 4715        self.refresh_inline_values(cx);
 4716    }
 4717
 4718    pub fn toggle_inlay_hints(
 4719        &mut self,
 4720        _: &ToggleInlayHints,
 4721        _: &mut Window,
 4722        cx: &mut Context<Self>,
 4723    ) {
 4724        self.refresh_inlay_hints(
 4725            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4726            cx,
 4727        );
 4728    }
 4729
 4730    pub fn inlay_hints_enabled(&self) -> bool {
 4731        self.inlay_hint_cache.enabled
 4732    }
 4733
 4734    pub fn inline_values_enabled(&self) -> bool {
 4735        self.inline_value_cache.enabled
 4736    }
 4737
 4738    #[cfg(any(test, feature = "test-support"))]
 4739    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4740        self.display_map
 4741            .read(cx)
 4742            .current_inlays()
 4743            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4744            .cloned()
 4745            .collect()
 4746    }
 4747
 4748    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4749        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4750            return;
 4751        }
 4752
 4753        let reason_description = reason.description();
 4754        let ignore_debounce = matches!(
 4755            reason,
 4756            InlayHintRefreshReason::SettingsChange(_)
 4757                | InlayHintRefreshReason::Toggle(_)
 4758                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4759                | InlayHintRefreshReason::ModifiersChanged(_)
 4760        );
 4761        let (invalidate_cache, required_languages) = match reason {
 4762            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4763                match self.inlay_hint_cache.modifiers_override(enabled) {
 4764                    Some(enabled) => {
 4765                        if enabled {
 4766                            (InvalidationStrategy::RefreshRequested, None)
 4767                        } else {
 4768                            self.splice_inlays(
 4769                                &self
 4770                                    .visible_inlay_hints(cx)
 4771                                    .iter()
 4772                                    .map(|inlay| inlay.id)
 4773                                    .collect::<Vec<InlayId>>(),
 4774                                Vec::new(),
 4775                                cx,
 4776                            );
 4777                            return;
 4778                        }
 4779                    }
 4780                    None => return,
 4781                }
 4782            }
 4783            InlayHintRefreshReason::Toggle(enabled) => {
 4784                if self.inlay_hint_cache.toggle(enabled) {
 4785                    if enabled {
 4786                        (InvalidationStrategy::RefreshRequested, None)
 4787                    } else {
 4788                        self.splice_inlays(
 4789                            &self
 4790                                .visible_inlay_hints(cx)
 4791                                .iter()
 4792                                .map(|inlay| inlay.id)
 4793                                .collect::<Vec<InlayId>>(),
 4794                            Vec::new(),
 4795                            cx,
 4796                        );
 4797                        return;
 4798                    }
 4799                } else {
 4800                    return;
 4801                }
 4802            }
 4803            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4804                match self.inlay_hint_cache.update_settings(
 4805                    &self.buffer,
 4806                    new_settings,
 4807                    self.visible_inlay_hints(cx),
 4808                    cx,
 4809                ) {
 4810                    ControlFlow::Break(Some(InlaySplice {
 4811                        to_remove,
 4812                        to_insert,
 4813                    })) => {
 4814                        self.splice_inlays(&to_remove, to_insert, cx);
 4815                        return;
 4816                    }
 4817                    ControlFlow::Break(None) => return,
 4818                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4819                }
 4820            }
 4821            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4822                if let Some(InlaySplice {
 4823                    to_remove,
 4824                    to_insert,
 4825                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4826                {
 4827                    self.splice_inlays(&to_remove, to_insert, cx);
 4828                }
 4829                self.display_map.update(cx, |display_map, _| {
 4830                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4831                });
 4832                return;
 4833            }
 4834            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4835            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4836                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4837            }
 4838            InlayHintRefreshReason::RefreshRequested => {
 4839                (InvalidationStrategy::RefreshRequested, None)
 4840            }
 4841        };
 4842
 4843        if let Some(InlaySplice {
 4844            to_remove,
 4845            to_insert,
 4846        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4847            reason_description,
 4848            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4849            invalidate_cache,
 4850            ignore_debounce,
 4851            cx,
 4852        ) {
 4853            self.splice_inlays(&to_remove, to_insert, cx);
 4854        }
 4855    }
 4856
 4857    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4858        self.display_map
 4859            .read(cx)
 4860            .current_inlays()
 4861            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4862            .cloned()
 4863            .collect()
 4864    }
 4865
 4866    pub fn excerpts_for_inlay_hints_query(
 4867        &self,
 4868        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4869        cx: &mut Context<Editor>,
 4870    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4871        let Some(project) = self.project.as_ref() else {
 4872            return HashMap::default();
 4873        };
 4874        let project = project.read(cx);
 4875        let multi_buffer = self.buffer().read(cx);
 4876        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4877        let multi_buffer_visible_start = self
 4878            .scroll_manager
 4879            .anchor()
 4880            .anchor
 4881            .to_point(&multi_buffer_snapshot);
 4882        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4883            multi_buffer_visible_start
 4884                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4885            Bias::Left,
 4886        );
 4887        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4888        multi_buffer_snapshot
 4889            .range_to_buffer_ranges(multi_buffer_visible_range)
 4890            .into_iter()
 4891            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4892            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4893                let buffer_file = project::File::from_dyn(buffer.file())?;
 4894                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4895                let worktree_entry = buffer_worktree
 4896                    .read(cx)
 4897                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4898                if worktree_entry.is_ignored {
 4899                    return None;
 4900                }
 4901
 4902                let language = buffer.language()?;
 4903                if let Some(restrict_to_languages) = restrict_to_languages {
 4904                    if !restrict_to_languages.contains(language) {
 4905                        return None;
 4906                    }
 4907                }
 4908                Some((
 4909                    excerpt_id,
 4910                    (
 4911                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4912                        buffer.version().clone(),
 4913                        excerpt_visible_range,
 4914                    ),
 4915                ))
 4916            })
 4917            .collect()
 4918    }
 4919
 4920    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4921        TextLayoutDetails {
 4922            text_system: window.text_system().clone(),
 4923            editor_style: self.style.clone().unwrap(),
 4924            rem_size: window.rem_size(),
 4925            scroll_anchor: self.scroll_manager.anchor(),
 4926            visible_rows: self.visible_line_count(),
 4927            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4928        }
 4929    }
 4930
 4931    pub fn splice_inlays(
 4932        &self,
 4933        to_remove: &[InlayId],
 4934        to_insert: Vec<Inlay>,
 4935        cx: &mut Context<Self>,
 4936    ) {
 4937        self.display_map.update(cx, |display_map, cx| {
 4938            display_map.splice_inlays(to_remove, to_insert, cx)
 4939        });
 4940        cx.notify();
 4941    }
 4942
 4943    fn trigger_on_type_formatting(
 4944        &self,
 4945        input: String,
 4946        window: &mut Window,
 4947        cx: &mut Context<Self>,
 4948    ) -> Option<Task<Result<()>>> {
 4949        if input.len() != 1 {
 4950            return None;
 4951        }
 4952
 4953        let project = self.project.as_ref()?;
 4954        let position = self.selections.newest_anchor().head();
 4955        let (buffer, buffer_position) = self
 4956            .buffer
 4957            .read(cx)
 4958            .text_anchor_for_position(position, cx)?;
 4959
 4960        let settings = language_settings::language_settings(
 4961            buffer
 4962                .read(cx)
 4963                .language_at(buffer_position)
 4964                .map(|l| l.name()),
 4965            buffer.read(cx).file(),
 4966            cx,
 4967        );
 4968        if !settings.use_on_type_format {
 4969            return None;
 4970        }
 4971
 4972        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4973        // hence we do LSP request & edit on host side only — add formats to host's history.
 4974        let push_to_lsp_host_history = true;
 4975        // If this is not the host, append its history with new edits.
 4976        let push_to_client_history = project.read(cx).is_via_collab();
 4977
 4978        let on_type_formatting = project.update(cx, |project, cx| {
 4979            project.on_type_format(
 4980                buffer.clone(),
 4981                buffer_position,
 4982                input,
 4983                push_to_lsp_host_history,
 4984                cx,
 4985            )
 4986        });
 4987        Some(cx.spawn_in(window, async move |editor, cx| {
 4988            if let Some(transaction) = on_type_formatting.await? {
 4989                if push_to_client_history {
 4990                    buffer
 4991                        .update(cx, |buffer, _| {
 4992                            buffer.push_transaction(transaction, Instant::now());
 4993                            buffer.finalize_last_transaction();
 4994                        })
 4995                        .ok();
 4996                }
 4997                editor.update(cx, |editor, cx| {
 4998                    editor.refresh_document_highlights(cx);
 4999                })?;
 5000            }
 5001            Ok(())
 5002        }))
 5003    }
 5004
 5005    pub fn show_word_completions(
 5006        &mut self,
 5007        _: &ShowWordCompletions,
 5008        window: &mut Window,
 5009        cx: &mut Context<Self>,
 5010    ) {
 5011        self.open_or_update_completions_menu(true, None, window, cx);
 5012    }
 5013
 5014    pub fn show_completions(
 5015        &mut self,
 5016        options: &ShowCompletions,
 5017        window: &mut Window,
 5018        cx: &mut Context<Self>,
 5019    ) {
 5020        self.open_or_update_completions_menu(false, options.trigger.as_deref(), window, cx);
 5021    }
 5022
 5023    fn open_or_update_completions_menu(
 5024        &mut self,
 5025        ignore_completion_provider: bool,
 5026        trigger: Option<&str>,
 5027        window: &mut Window,
 5028        cx: &mut Context<Self>,
 5029    ) {
 5030        if self.pending_rename.is_some() {
 5031            return;
 5032        }
 5033
 5034        let position = self.selections.newest_anchor().head();
 5035        if position.diff_base_anchor.is_some() {
 5036            return;
 5037        }
 5038        let (buffer, buffer_position) =
 5039            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5040                output
 5041            } else {
 5042                return;
 5043            };
 5044        let buffer_snapshot = buffer.read(cx).snapshot();
 5045
 5046        let query: Option<Arc<String>> =
 5047            Self::completion_query(&self.buffer.read(cx).read(cx), position)
 5048                .map(|query| query.into());
 5049
 5050        let provider = if ignore_completion_provider {
 5051            None
 5052        } else {
 5053            self.completion_provider.clone()
 5054        };
 5055
 5056        let sort_completions = provider
 5057            .as_ref()
 5058            .map_or(false, |provider| provider.sort_completions());
 5059
 5060        let filter_completions = provider
 5061            .as_ref()
 5062            .map_or(true, |provider| provider.filter_completions());
 5063
 5064        // When `is_incomplete` is false, can filter completions instead of re-querying when the
 5065        // current query is a suffix of the initial query.
 5066        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5067            if !menu.is_incomplete && filter_completions {
 5068                // If the new query is a suffix of the old query (typing more characters) and
 5069                // the previous result was complete, the existing completions can be filtered.
 5070                //
 5071                // Note that this is always true for snippet completions.
 5072                let query_matches = match (&menu.initial_query, &query) {
 5073                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5074                    (None, _) => true,
 5075                    _ => false,
 5076                };
 5077                if query_matches {
 5078                    let position_matches = if menu.initial_position == position {
 5079                        true
 5080                    } else {
 5081                        let snapshot = self.buffer.read(cx).read(cx);
 5082                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5083                    };
 5084                    if position_matches {
 5085                        menu.filter(query.clone(), provider.clone(), window, cx);
 5086                        return;
 5087                    }
 5088                }
 5089            }
 5090        };
 5091
 5092        let trigger_kind = match trigger {
 5093            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5094                CompletionTriggerKind::TRIGGER_CHARACTER
 5095            }
 5096            _ => CompletionTriggerKind::INVOKED,
 5097        };
 5098        let completion_context = CompletionContext {
 5099            trigger_character: trigger.and_then(|trigger| {
 5100                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5101                    Some(String::from(trigger))
 5102                } else {
 5103                    None
 5104                }
 5105            }),
 5106            trigger_kind,
 5107        };
 5108
 5109        let (replace_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 5110        let (replace_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 5111            let word_to_exclude = buffer_snapshot
 5112                .text_for_range(replace_range.clone())
 5113                .collect::<String>();
 5114            (
 5115                buffer_snapshot.anchor_before(replace_range.start)
 5116                    ..buffer_snapshot.anchor_after(replace_range.end),
 5117                Some(word_to_exclude),
 5118            )
 5119        } else {
 5120            (buffer_position..buffer_position, None)
 5121        };
 5122
 5123        let language = buffer_snapshot
 5124            .language_at(buffer_position)
 5125            .map(|language| language.name());
 5126
 5127        let completion_settings =
 5128            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5129
 5130        let show_completion_documentation = buffer_snapshot
 5131            .settings_at(buffer_position, cx)
 5132            .show_completion_documentation;
 5133
 5134        // The document can be large, so stay in reasonable bounds when searching for words,
 5135        // otherwise completion pop-up might be slow to appear.
 5136        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5137        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5138        let min_word_search = buffer_snapshot.clip_point(
 5139            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5140            Bias::Left,
 5141        );
 5142        let max_word_search = buffer_snapshot.clip_point(
 5143            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5144            Bias::Right,
 5145        );
 5146        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5147            ..buffer_snapshot.point_to_offset(max_word_search);
 5148
 5149        let skip_digits = query
 5150            .as_ref()
 5151            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5152
 5153        let (mut words, provider_responses) = match &provider {
 5154            Some(provider) => {
 5155                let provider_responses = provider.completions(
 5156                    position.excerpt_id,
 5157                    &buffer,
 5158                    buffer_position,
 5159                    completion_context,
 5160                    window,
 5161                    cx,
 5162                );
 5163
 5164                let words = match completion_settings.words {
 5165                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5166                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5167                        .background_spawn(async move {
 5168                            buffer_snapshot.words_in_range(WordsQuery {
 5169                                fuzzy_contents: None,
 5170                                range: word_search_range,
 5171                                skip_digits,
 5172                            })
 5173                        }),
 5174                };
 5175
 5176                (words, provider_responses)
 5177            }
 5178            None => (
 5179                cx.background_spawn(async move {
 5180                    buffer_snapshot.words_in_range(WordsQuery {
 5181                        fuzzy_contents: None,
 5182                        range: word_search_range,
 5183                        skip_digits,
 5184                    })
 5185                }),
 5186                Task::ready(Ok(Vec::new())),
 5187            ),
 5188        };
 5189
 5190        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5191
 5192        let id = post_inc(&mut self.next_completion_id);
 5193        let task = cx.spawn_in(window, async move |editor, cx| {
 5194            let Ok(()) = editor.update(cx, |this, _| {
 5195                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5196            }) else {
 5197                return;
 5198            };
 5199
 5200            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5201            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5202            let mut completions = Vec::new();
 5203            let mut is_incomplete = false;
 5204            if let Some(provider_responses) = provider_responses.await.log_err() {
 5205                if !provider_responses.is_empty() {
 5206                    for response in provider_responses {
 5207                        completions.extend(response.completions);
 5208                        is_incomplete = is_incomplete || response.is_incomplete;
 5209                    }
 5210                    if completion_settings.words == WordsCompletionMode::Fallback {
 5211                        words = Task::ready(BTreeMap::default());
 5212                    }
 5213                }
 5214            }
 5215
 5216            let mut words = words.await;
 5217            if let Some(word_to_exclude) = &word_to_exclude {
 5218                words.remove(word_to_exclude);
 5219            }
 5220            for lsp_completion in &completions {
 5221                words.remove(&lsp_completion.new_text);
 5222            }
 5223            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5224                replace_range: replace_range.clone(),
 5225                new_text: word.clone(),
 5226                label: CodeLabel::plain(word, None),
 5227                icon_path: None,
 5228                documentation: None,
 5229                source: CompletionSource::BufferWord {
 5230                    word_range,
 5231                    resolved: false,
 5232                },
 5233                insert_text_mode: Some(InsertTextMode::AS_IS),
 5234                confirm: None,
 5235            }));
 5236
 5237            let menu = if completions.is_empty() {
 5238                None
 5239            } else {
 5240                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5241                    let languages = editor
 5242                        .workspace
 5243                        .as_ref()
 5244                        .and_then(|(workspace, _)| workspace.upgrade())
 5245                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5246                    let menu = CompletionsMenu::new(
 5247                        id,
 5248                        sort_completions,
 5249                        show_completion_documentation,
 5250                        ignore_completion_provider,
 5251                        position,
 5252                        query.clone(),
 5253                        is_incomplete,
 5254                        buffer.clone(),
 5255                        completions.into(),
 5256                        snippet_sort_order,
 5257                        languages,
 5258                        language,
 5259                        cx,
 5260                    );
 5261
 5262                    let query = if filter_completions { query } else { None };
 5263                    let matches_task = if let Some(query) = query {
 5264                        menu.do_async_filtering(query, cx)
 5265                    } else {
 5266                        Task::ready(menu.unfiltered_matches())
 5267                    };
 5268                    (menu, matches_task)
 5269                }) else {
 5270                    return;
 5271                };
 5272
 5273                let matches = matches_task.await;
 5274
 5275                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5276                    // Newer menu already set, so exit.
 5277                    match editor.context_menu.borrow().as_ref() {
 5278                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5279                            if prev_menu.id > id {
 5280                                return;
 5281                            }
 5282                        }
 5283                        _ => {}
 5284                    };
 5285
 5286                    // Only valid to take prev_menu because it the new menu is immediately set
 5287                    // below, or the menu is hidden.
 5288                    match editor.context_menu.borrow_mut().take() {
 5289                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5290                            let position_matches =
 5291                                if prev_menu.initial_position == menu.initial_position {
 5292                                    true
 5293                                } else {
 5294                                    let snapshot = editor.buffer.read(cx).read(cx);
 5295                                    prev_menu.initial_position.to_offset(&snapshot)
 5296                                        == menu.initial_position.to_offset(&snapshot)
 5297                                };
 5298                            if position_matches {
 5299                                // Preserve markdown cache before `set_filter_results` because it will
 5300                                // try to populate the documentation cache.
 5301                                menu.preserve_markdown_cache(prev_menu);
 5302                            }
 5303                        }
 5304                        _ => {}
 5305                    };
 5306
 5307                    menu.set_filter_results(matches, provider, window, cx);
 5308                }) else {
 5309                    return;
 5310                };
 5311
 5312                menu.visible().then_some(menu)
 5313            };
 5314
 5315            editor
 5316                .update_in(cx, |editor, window, cx| {
 5317                    if editor.focus_handle.is_focused(window) {
 5318                        if let Some(menu) = menu {
 5319                            *editor.context_menu.borrow_mut() =
 5320                                Some(CodeContextMenu::Completions(menu));
 5321
 5322                            crate::hover_popover::hide_hover(editor, cx);
 5323                            if editor.show_edit_predictions_in_menu() {
 5324                                editor.update_visible_inline_completion(window, cx);
 5325                            } else {
 5326                                editor.discard_inline_completion(false, cx);
 5327                            }
 5328
 5329                            cx.notify();
 5330                            return;
 5331                        }
 5332                    }
 5333
 5334                    if editor.completion_tasks.len() <= 1 {
 5335                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5336                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5337                        // If it was already hidden and we don't show inline completions in the menu, we should
 5338                        // also show the inline-completion when available.
 5339                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5340                            editor.update_visible_inline_completion(window, cx);
 5341                        }
 5342                    }
 5343                })
 5344                .ok();
 5345        });
 5346
 5347        self.completion_tasks.push((id, task));
 5348    }
 5349
 5350    #[cfg(feature = "test-support")]
 5351    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5352        let menu = self.context_menu.borrow();
 5353        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5354            let completions = menu.completions.borrow();
 5355            Some(completions.to_vec())
 5356        } else {
 5357            None
 5358        }
 5359    }
 5360
 5361    pub fn with_completions_menu_matching_id<R>(
 5362        &self,
 5363        id: CompletionId,
 5364        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5365    ) -> R {
 5366        let mut context_menu = self.context_menu.borrow_mut();
 5367        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5368            return f(None);
 5369        };
 5370        if completions_menu.id != id {
 5371            return f(None);
 5372        }
 5373        f(Some(completions_menu))
 5374    }
 5375
 5376    pub fn confirm_completion(
 5377        &mut self,
 5378        action: &ConfirmCompletion,
 5379        window: &mut Window,
 5380        cx: &mut Context<Self>,
 5381    ) -> Option<Task<Result<()>>> {
 5382        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5383        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5384    }
 5385
 5386    pub fn confirm_completion_insert(
 5387        &mut self,
 5388        _: &ConfirmCompletionInsert,
 5389        window: &mut Window,
 5390        cx: &mut Context<Self>,
 5391    ) -> Option<Task<Result<()>>> {
 5392        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5393        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5394    }
 5395
 5396    pub fn confirm_completion_replace(
 5397        &mut self,
 5398        _: &ConfirmCompletionReplace,
 5399        window: &mut Window,
 5400        cx: &mut Context<Self>,
 5401    ) -> Option<Task<Result<()>>> {
 5402        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5403        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5404    }
 5405
 5406    pub fn compose_completion(
 5407        &mut self,
 5408        action: &ComposeCompletion,
 5409        window: &mut Window,
 5410        cx: &mut Context<Self>,
 5411    ) -> Option<Task<Result<()>>> {
 5412        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5413        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5414    }
 5415
 5416    fn do_completion(
 5417        &mut self,
 5418        item_ix: Option<usize>,
 5419        intent: CompletionIntent,
 5420        window: &mut Window,
 5421        cx: &mut Context<Editor>,
 5422    ) -> Option<Task<Result<()>>> {
 5423        use language::ToOffset as _;
 5424
 5425        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5426        else {
 5427            return None;
 5428        };
 5429
 5430        let candidate_id = {
 5431            let entries = completions_menu.entries.borrow();
 5432            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5433            if self.show_edit_predictions_in_menu() {
 5434                self.discard_inline_completion(true, cx);
 5435            }
 5436            mat.candidate_id
 5437        };
 5438
 5439        let completion = completions_menu
 5440            .completions
 5441            .borrow()
 5442            .get(candidate_id)?
 5443            .clone();
 5444        cx.stop_propagation();
 5445
 5446        let buffer_handle = completions_menu.buffer.clone();
 5447
 5448        let CompletionEdit {
 5449            new_text,
 5450            snippet,
 5451            replace_range,
 5452        } = process_completion_for_edit(
 5453            &completion,
 5454            intent,
 5455            &buffer_handle,
 5456            &completions_menu.initial_position.text_anchor,
 5457            cx,
 5458        );
 5459
 5460        let buffer = buffer_handle.read(cx);
 5461        let snapshot = self.buffer.read(cx).snapshot(cx);
 5462        let newest_anchor = self.selections.newest_anchor();
 5463        let replace_range_multibuffer = {
 5464            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5465            let multibuffer_anchor = snapshot
 5466                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5467                .unwrap()
 5468                ..snapshot
 5469                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5470                    .unwrap();
 5471            multibuffer_anchor.start.to_offset(&snapshot)
 5472                ..multibuffer_anchor.end.to_offset(&snapshot)
 5473        };
 5474        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5475            return None;
 5476        }
 5477
 5478        let old_text = buffer
 5479            .text_for_range(replace_range.clone())
 5480            .collect::<String>();
 5481        let lookbehind = newest_anchor
 5482            .start
 5483            .text_anchor
 5484            .to_offset(buffer)
 5485            .saturating_sub(replace_range.start);
 5486        let lookahead = replace_range
 5487            .end
 5488            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5489        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5490        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5491
 5492        let selections = self.selections.all::<usize>(cx);
 5493        let mut ranges = Vec::new();
 5494        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5495
 5496        for selection in &selections {
 5497            let range = if selection.id == newest_anchor.id {
 5498                replace_range_multibuffer.clone()
 5499            } else {
 5500                let mut range = selection.range();
 5501
 5502                // if prefix is present, don't duplicate it
 5503                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5504                    range.start = range.start.saturating_sub(lookbehind);
 5505
 5506                    // if suffix is also present, mimic the newest cursor and replace it
 5507                    if selection.id != newest_anchor.id
 5508                        && snapshot.contains_str_at(range.end, suffix)
 5509                    {
 5510                        range.end += lookahead;
 5511                    }
 5512                }
 5513                range
 5514            };
 5515
 5516            ranges.push(range.clone());
 5517
 5518            if !self.linked_edit_ranges.is_empty() {
 5519                let start_anchor = snapshot.anchor_before(range.start);
 5520                let end_anchor = snapshot.anchor_after(range.end);
 5521                if let Some(ranges) = self
 5522                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5523                {
 5524                    for (buffer, edits) in ranges {
 5525                        linked_edits
 5526                            .entry(buffer.clone())
 5527                            .or_default()
 5528                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5529                    }
 5530                }
 5531            }
 5532        }
 5533
 5534        cx.emit(EditorEvent::InputHandled {
 5535            utf16_range_to_replace: None,
 5536            text: new_text.clone().into(),
 5537        });
 5538
 5539        self.transact(window, cx, |this, window, cx| {
 5540            if let Some(mut snippet) = snippet {
 5541                snippet.text = new_text.to_string();
 5542                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5543            } else {
 5544                this.buffer.update(cx, |buffer, cx| {
 5545                    let auto_indent = match completion.insert_text_mode {
 5546                        Some(InsertTextMode::AS_IS) => None,
 5547                        _ => this.autoindent_mode.clone(),
 5548                    };
 5549                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5550                    buffer.edit(edits, auto_indent, cx);
 5551                });
 5552            }
 5553            for (buffer, edits) in linked_edits {
 5554                buffer.update(cx, |buffer, cx| {
 5555                    let snapshot = buffer.snapshot();
 5556                    let edits = edits
 5557                        .into_iter()
 5558                        .map(|(range, text)| {
 5559                            use text::ToPoint as TP;
 5560                            let end_point = TP::to_point(&range.end, &snapshot);
 5561                            let start_point = TP::to_point(&range.start, &snapshot);
 5562                            (start_point..end_point, text)
 5563                        })
 5564                        .sorted_by_key(|(range, _)| range.start);
 5565                    buffer.edit(edits, None, cx);
 5566                })
 5567            }
 5568
 5569            this.refresh_inline_completion(true, false, window, cx);
 5570        });
 5571
 5572        let show_new_completions_on_confirm = completion
 5573            .confirm
 5574            .as_ref()
 5575            .map_or(false, |confirm| confirm(intent, window, cx));
 5576        if show_new_completions_on_confirm {
 5577            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5578        }
 5579
 5580        let provider = self.completion_provider.as_ref()?;
 5581        drop(completion);
 5582        let apply_edits = provider.apply_additional_edits_for_completion(
 5583            buffer_handle,
 5584            completions_menu.completions.clone(),
 5585            candidate_id,
 5586            true,
 5587            cx,
 5588        );
 5589
 5590        let editor_settings = EditorSettings::get_global(cx);
 5591        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5592            // After the code completion is finished, users often want to know what signatures are needed.
 5593            // so we should automatically call signature_help
 5594            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5595        }
 5596
 5597        Some(cx.foreground_executor().spawn(async move {
 5598            apply_edits.await?;
 5599            Ok(())
 5600        }))
 5601    }
 5602
 5603    pub fn toggle_code_actions(
 5604        &mut self,
 5605        action: &ToggleCodeActions,
 5606        window: &mut Window,
 5607        cx: &mut Context<Self>,
 5608    ) {
 5609        let quick_launch = action.quick_launch;
 5610        let mut context_menu = self.context_menu.borrow_mut();
 5611        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5612            if code_actions.deployed_from == action.deployed_from {
 5613                // Toggle if we're selecting the same one
 5614                *context_menu = None;
 5615                cx.notify();
 5616                return;
 5617            } else {
 5618                // Otherwise, clear it and start a new one
 5619                *context_menu = None;
 5620                cx.notify();
 5621            }
 5622        }
 5623        drop(context_menu);
 5624        let snapshot = self.snapshot(window, cx);
 5625        let deployed_from = action.deployed_from.clone();
 5626        let mut task = self.code_actions_task.take();
 5627        let action = action.clone();
 5628        cx.spawn_in(window, async move |editor, cx| {
 5629            while let Some(prev_task) = task {
 5630                prev_task.await.log_err();
 5631                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5632            }
 5633
 5634            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5635                if editor.focus_handle.is_focused(window) {
 5636                    let multibuffer_point = match &action.deployed_from {
 5637                        Some(CodeActionSource::Indicator(row)) => {
 5638                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5639                        }
 5640                        _ => editor.selections.newest::<Point>(cx).head(),
 5641                    };
 5642                    let (buffer, buffer_row) = snapshot
 5643                        .buffer_snapshot
 5644                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5645                        .and_then(|(buffer_snapshot, range)| {
 5646                            editor
 5647                                .buffer
 5648                                .read(cx)
 5649                                .buffer(buffer_snapshot.remote_id())
 5650                                .map(|buffer| (buffer, range.start.row))
 5651                        })?;
 5652                    let (_, code_actions) = editor
 5653                        .available_code_actions
 5654                        .clone()
 5655                        .and_then(|(location, code_actions)| {
 5656                            let snapshot = location.buffer.read(cx).snapshot();
 5657                            let point_range = location.range.to_point(&snapshot);
 5658                            let point_range = point_range.start.row..=point_range.end.row;
 5659                            if point_range.contains(&buffer_row) {
 5660                                Some((location, code_actions))
 5661                            } else {
 5662                                None
 5663                            }
 5664                        })
 5665                        .unzip();
 5666                    let buffer_id = buffer.read(cx).remote_id();
 5667                    let tasks = editor
 5668                        .tasks
 5669                        .get(&(buffer_id, buffer_row))
 5670                        .map(|t| Arc::new(t.to_owned()));
 5671                    if tasks.is_none() && code_actions.is_none() {
 5672                        return None;
 5673                    }
 5674
 5675                    editor.completion_tasks.clear();
 5676                    editor.discard_inline_completion(false, cx);
 5677                    let task_context =
 5678                        tasks
 5679                            .as_ref()
 5680                            .zip(editor.project.clone())
 5681                            .map(|(tasks, project)| {
 5682                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5683                            });
 5684
 5685                    Some(cx.spawn_in(window, async move |editor, cx| {
 5686                        let task_context = match task_context {
 5687                            Some(task_context) => task_context.await,
 5688                            None => None,
 5689                        };
 5690                        let resolved_tasks =
 5691                            tasks
 5692                                .zip(task_context.clone())
 5693                                .map(|(tasks, task_context)| ResolvedTasks {
 5694                                    templates: tasks.resolve(&task_context).collect(),
 5695                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5696                                        multibuffer_point.row,
 5697                                        tasks.column,
 5698                                    )),
 5699                                });
 5700                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5701                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5702                                maybe!({
 5703                                    let project = editor.project.as_ref()?;
 5704                                    let dap_store = project.read(cx).dap_store();
 5705                                    let mut scenarios = vec![];
 5706                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5707                                    let buffer = buffer.read(cx);
 5708                                    let language = buffer.language()?;
 5709                                    let file = buffer.file();
 5710                                    let debug_adapter =
 5711                                        language_settings(language.name().into(), file, cx)
 5712                                            .debuggers
 5713                                            .first()
 5714                                            .map(SharedString::from)
 5715                                            .or_else(|| {
 5716                                                language
 5717                                                    .config()
 5718                                                    .debuggers
 5719                                                    .first()
 5720                                                    .map(SharedString::from)
 5721                                            })?;
 5722
 5723                                    dap_store.update(cx, |dap_store, cx| {
 5724                                        for (_, task) in &resolved_tasks.templates {
 5725                                            if let Some(scenario) = dap_store
 5726                                                .debug_scenario_for_build_task(
 5727                                                    task.original_task().clone(),
 5728                                                    debug_adapter.clone().into(),
 5729                                                    task.display_label().to_owned().into(),
 5730                                                    cx,
 5731                                                )
 5732                                            {
 5733                                                scenarios.push(scenario);
 5734                                            }
 5735                                        }
 5736                                    });
 5737                                    Some(scenarios)
 5738                                })
 5739                                .unwrap_or_default()
 5740                            } else {
 5741                                vec![]
 5742                            }
 5743                        })?;
 5744                        let spawn_straight_away = quick_launch
 5745                            && resolved_tasks
 5746                                .as_ref()
 5747                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5748                            && code_actions
 5749                                .as_ref()
 5750                                .map_or(true, |actions| actions.is_empty())
 5751                            && debug_scenarios.is_empty();
 5752                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5753                            crate::hover_popover::hide_hover(editor, cx);
 5754                            *editor.context_menu.borrow_mut() =
 5755                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5756                                    buffer,
 5757                                    actions: CodeActionContents::new(
 5758                                        resolved_tasks,
 5759                                        code_actions,
 5760                                        debug_scenarios,
 5761                                        task_context.unwrap_or_default(),
 5762                                    ),
 5763                                    selected_item: Default::default(),
 5764                                    scroll_handle: UniformListScrollHandle::default(),
 5765                                    deployed_from,
 5766                                }));
 5767                            if spawn_straight_away {
 5768                                if let Some(task) = editor.confirm_code_action(
 5769                                    &ConfirmCodeAction { item_ix: Some(0) },
 5770                                    window,
 5771                                    cx,
 5772                                ) {
 5773                                    cx.notify();
 5774                                    return task;
 5775                                }
 5776                            }
 5777                            cx.notify();
 5778                            Task::ready(Ok(()))
 5779                        }) {
 5780                            task.await
 5781                        } else {
 5782                            Ok(())
 5783                        }
 5784                    }))
 5785                } else {
 5786                    Some(Task::ready(Ok(())))
 5787                }
 5788            })?;
 5789            if let Some(task) = spawned_test_task {
 5790                task.await?;
 5791            }
 5792
 5793            anyhow::Ok(())
 5794        })
 5795        .detach_and_log_err(cx);
 5796    }
 5797
 5798    pub fn confirm_code_action(
 5799        &mut self,
 5800        action: &ConfirmCodeAction,
 5801        window: &mut Window,
 5802        cx: &mut Context<Self>,
 5803    ) -> Option<Task<Result<()>>> {
 5804        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5805
 5806        let actions_menu =
 5807            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5808                menu
 5809            } else {
 5810                return None;
 5811            };
 5812
 5813        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5814        let action = actions_menu.actions.get(action_ix)?;
 5815        let title = action.label();
 5816        let buffer = actions_menu.buffer;
 5817        let workspace = self.workspace()?;
 5818
 5819        match action {
 5820            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5821                workspace.update(cx, |workspace, cx| {
 5822                    workspace.schedule_resolved_task(
 5823                        task_source_kind,
 5824                        resolved_task,
 5825                        false,
 5826                        window,
 5827                        cx,
 5828                    );
 5829
 5830                    Some(Task::ready(Ok(())))
 5831                })
 5832            }
 5833            CodeActionsItem::CodeAction {
 5834                excerpt_id,
 5835                action,
 5836                provider,
 5837            } => {
 5838                let apply_code_action =
 5839                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5840                let workspace = workspace.downgrade();
 5841                Some(cx.spawn_in(window, async move |editor, cx| {
 5842                    let project_transaction = apply_code_action.await?;
 5843                    Self::open_project_transaction(
 5844                        &editor,
 5845                        workspace,
 5846                        project_transaction,
 5847                        title,
 5848                        cx,
 5849                    )
 5850                    .await
 5851                }))
 5852            }
 5853            CodeActionsItem::DebugScenario(scenario) => {
 5854                let context = actions_menu.actions.context.clone();
 5855
 5856                workspace.update(cx, |workspace, cx| {
 5857                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5858                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5859                });
 5860                Some(Task::ready(Ok(())))
 5861            }
 5862        }
 5863    }
 5864
 5865    pub async fn open_project_transaction(
 5866        this: &WeakEntity<Editor>,
 5867        workspace: WeakEntity<Workspace>,
 5868        transaction: ProjectTransaction,
 5869        title: String,
 5870        cx: &mut AsyncWindowContext,
 5871    ) -> Result<()> {
 5872        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5873        cx.update(|_, cx| {
 5874            entries.sort_unstable_by_key(|(buffer, _)| {
 5875                buffer.read(cx).file().map(|f| f.path().clone())
 5876            });
 5877        })?;
 5878
 5879        // If the project transaction's edits are all contained within this editor, then
 5880        // avoid opening a new editor to display them.
 5881
 5882        if let Some((buffer, transaction)) = entries.first() {
 5883            if entries.len() == 1 {
 5884                let excerpt = this.update(cx, |editor, cx| {
 5885                    editor
 5886                        .buffer()
 5887                        .read(cx)
 5888                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5889                })?;
 5890                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5891                    if excerpted_buffer == *buffer {
 5892                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5893                            let excerpt_range = excerpt_range.to_offset(buffer);
 5894                            buffer
 5895                                .edited_ranges_for_transaction::<usize>(transaction)
 5896                                .all(|range| {
 5897                                    excerpt_range.start <= range.start
 5898                                        && excerpt_range.end >= range.end
 5899                                })
 5900                        })?;
 5901
 5902                        if all_edits_within_excerpt {
 5903                            return Ok(());
 5904                        }
 5905                    }
 5906                }
 5907            }
 5908        } else {
 5909            return Ok(());
 5910        }
 5911
 5912        let mut ranges_to_highlight = Vec::new();
 5913        let excerpt_buffer = cx.new(|cx| {
 5914            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5915            for (buffer_handle, transaction) in &entries {
 5916                let edited_ranges = buffer_handle
 5917                    .read(cx)
 5918                    .edited_ranges_for_transaction::<Point>(transaction)
 5919                    .collect::<Vec<_>>();
 5920                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5921                    PathKey::for_buffer(buffer_handle, cx),
 5922                    buffer_handle.clone(),
 5923                    edited_ranges,
 5924                    DEFAULT_MULTIBUFFER_CONTEXT,
 5925                    cx,
 5926                );
 5927
 5928                ranges_to_highlight.extend(ranges);
 5929            }
 5930            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5931            multibuffer
 5932        })?;
 5933
 5934        workspace.update_in(cx, |workspace, window, cx| {
 5935            let project = workspace.project().clone();
 5936            let editor =
 5937                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5938            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5939            editor.update(cx, |editor, cx| {
 5940                editor.highlight_background::<Self>(
 5941                    &ranges_to_highlight,
 5942                    |theme| theme.editor_highlighted_line_background,
 5943                    cx,
 5944                );
 5945            });
 5946        })?;
 5947
 5948        Ok(())
 5949    }
 5950
 5951    pub fn clear_code_action_providers(&mut self) {
 5952        self.code_action_providers.clear();
 5953        self.available_code_actions.take();
 5954    }
 5955
 5956    pub fn add_code_action_provider(
 5957        &mut self,
 5958        provider: Rc<dyn CodeActionProvider>,
 5959        window: &mut Window,
 5960        cx: &mut Context<Self>,
 5961    ) {
 5962        if self
 5963            .code_action_providers
 5964            .iter()
 5965            .any(|existing_provider| existing_provider.id() == provider.id())
 5966        {
 5967            return;
 5968        }
 5969
 5970        self.code_action_providers.push(provider);
 5971        self.refresh_code_actions(window, cx);
 5972    }
 5973
 5974    pub fn remove_code_action_provider(
 5975        &mut self,
 5976        id: Arc<str>,
 5977        window: &mut Window,
 5978        cx: &mut Context<Self>,
 5979    ) {
 5980        self.code_action_providers
 5981            .retain(|provider| provider.id() != id);
 5982        self.refresh_code_actions(window, cx);
 5983    }
 5984
 5985    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 5986        !self.code_action_providers.is_empty()
 5987            && EditorSettings::get_global(cx).toolbar.code_actions
 5988    }
 5989
 5990    pub fn has_available_code_actions(&self) -> bool {
 5991        self.available_code_actions
 5992            .as_ref()
 5993            .is_some_and(|(_, actions)| !actions.is_empty())
 5994    }
 5995
 5996    fn render_inline_code_actions(
 5997        &self,
 5998        icon_size: ui::IconSize,
 5999        display_row: DisplayRow,
 6000        is_active: bool,
 6001        cx: &mut Context<Self>,
 6002    ) -> AnyElement {
 6003        let show_tooltip = !self.context_menu_visible();
 6004        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6005            .icon_size(icon_size)
 6006            .shape(ui::IconButtonShape::Square)
 6007            .style(ButtonStyle::Transparent)
 6008            .icon_color(ui::Color::Hidden)
 6009            .toggle_state(is_active)
 6010            .when(show_tooltip, |this| {
 6011                this.tooltip({
 6012                    let focus_handle = self.focus_handle.clone();
 6013                    move |window, cx| {
 6014                        Tooltip::for_action_in(
 6015                            "Toggle Code Actions",
 6016                            &ToggleCodeActions {
 6017                                deployed_from: None,
 6018                                quick_launch: false,
 6019                            },
 6020                            &focus_handle,
 6021                            window,
 6022                            cx,
 6023                        )
 6024                    }
 6025                })
 6026            })
 6027            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6028                window.focus(&editor.focus_handle(cx));
 6029                editor.toggle_code_actions(
 6030                    &crate::actions::ToggleCodeActions {
 6031                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6032                            display_row,
 6033                        )),
 6034                        quick_launch: false,
 6035                    },
 6036                    window,
 6037                    cx,
 6038                );
 6039            }))
 6040            .into_any_element()
 6041    }
 6042
 6043    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6044        &self.context_menu
 6045    }
 6046
 6047    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6048        let newest_selection = self.selections.newest_anchor().clone();
 6049        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6050        let buffer = self.buffer.read(cx);
 6051        if newest_selection.head().diff_base_anchor.is_some() {
 6052            return None;
 6053        }
 6054        let (start_buffer, start) =
 6055            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6056        let (end_buffer, end) =
 6057            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6058        if start_buffer != end_buffer {
 6059            return None;
 6060        }
 6061
 6062        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6063            cx.background_executor()
 6064                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6065                .await;
 6066
 6067            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6068                let providers = this.code_action_providers.clone();
 6069                let tasks = this
 6070                    .code_action_providers
 6071                    .iter()
 6072                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6073                    .collect::<Vec<_>>();
 6074                (providers, tasks)
 6075            })?;
 6076
 6077            let mut actions = Vec::new();
 6078            for (provider, provider_actions) in
 6079                providers.into_iter().zip(future::join_all(tasks).await)
 6080            {
 6081                if let Some(provider_actions) = provider_actions.log_err() {
 6082                    actions.extend(provider_actions.into_iter().map(|action| {
 6083                        AvailableCodeAction {
 6084                            excerpt_id: newest_selection.start.excerpt_id,
 6085                            action,
 6086                            provider: provider.clone(),
 6087                        }
 6088                    }));
 6089                }
 6090            }
 6091
 6092            this.update(cx, |this, cx| {
 6093                this.available_code_actions = if actions.is_empty() {
 6094                    None
 6095                } else {
 6096                    Some((
 6097                        Location {
 6098                            buffer: start_buffer,
 6099                            range: start..end,
 6100                        },
 6101                        actions.into(),
 6102                    ))
 6103                };
 6104                cx.notify();
 6105            })
 6106        }));
 6107        None
 6108    }
 6109
 6110    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6111        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6112            self.show_git_blame_inline = false;
 6113
 6114            self.show_git_blame_inline_delay_task =
 6115                Some(cx.spawn_in(window, async move |this, cx| {
 6116                    cx.background_executor().timer(delay).await;
 6117
 6118                    this.update(cx, |this, cx| {
 6119                        this.show_git_blame_inline = true;
 6120                        cx.notify();
 6121                    })
 6122                    .log_err();
 6123                }));
 6124        }
 6125    }
 6126
 6127    fn show_blame_popover(
 6128        &mut self,
 6129        blame_entry: &BlameEntry,
 6130        position: gpui::Point<Pixels>,
 6131        cx: &mut Context<Self>,
 6132    ) {
 6133        if let Some(state) = &mut self.inline_blame_popover {
 6134            state.hide_task.take();
 6135            cx.notify();
 6136        } else {
 6137            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6138            let show_task = cx.spawn(async move |editor, cx| {
 6139                cx.background_executor()
 6140                    .timer(std::time::Duration::from_millis(delay))
 6141                    .await;
 6142                editor
 6143                    .update(cx, |editor, cx| {
 6144                        if let Some(state) = &mut editor.inline_blame_popover {
 6145                            state.show_task = None;
 6146                            cx.notify();
 6147                        }
 6148                    })
 6149                    .ok();
 6150            });
 6151            let Some(blame) = self.blame.as_ref() else {
 6152                return;
 6153            };
 6154            let blame = blame.read(cx);
 6155            let details = blame.details_for_entry(&blame_entry);
 6156            let markdown = cx.new(|cx| {
 6157                Markdown::new(
 6158                    details
 6159                        .as_ref()
 6160                        .map(|message| message.message.clone())
 6161                        .unwrap_or_default(),
 6162                    None,
 6163                    None,
 6164                    cx,
 6165                )
 6166            });
 6167            self.inline_blame_popover = Some(InlineBlamePopover {
 6168                position,
 6169                show_task: Some(show_task),
 6170                hide_task: None,
 6171                popover_bounds: None,
 6172                popover_state: InlineBlamePopoverState {
 6173                    scroll_handle: ScrollHandle::new(),
 6174                    commit_message: details,
 6175                    markdown,
 6176                },
 6177            });
 6178        }
 6179    }
 6180
 6181    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6182        if let Some(state) = &mut self.inline_blame_popover {
 6183            if state.show_task.is_some() {
 6184                self.inline_blame_popover.take();
 6185                cx.notify();
 6186            } else {
 6187                let hide_task = cx.spawn(async move |editor, cx| {
 6188                    cx.background_executor()
 6189                        .timer(std::time::Duration::from_millis(100))
 6190                        .await;
 6191                    editor
 6192                        .update(cx, |editor, cx| {
 6193                            editor.inline_blame_popover.take();
 6194                            cx.notify();
 6195                        })
 6196                        .ok();
 6197                });
 6198                state.hide_task = Some(hide_task);
 6199            }
 6200        }
 6201    }
 6202
 6203    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6204        if self.pending_rename.is_some() {
 6205            return None;
 6206        }
 6207
 6208        let provider = self.semantics_provider.clone()?;
 6209        let buffer = self.buffer.read(cx);
 6210        let newest_selection = self.selections.newest_anchor().clone();
 6211        let cursor_position = newest_selection.head();
 6212        let (cursor_buffer, cursor_buffer_position) =
 6213            buffer.text_anchor_for_position(cursor_position, cx)?;
 6214        let (tail_buffer, tail_buffer_position) =
 6215            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6216        if cursor_buffer != tail_buffer {
 6217            return None;
 6218        }
 6219
 6220        let snapshot = cursor_buffer.read(cx).snapshot();
 6221        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6222        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6223        if start_word_range != end_word_range {
 6224            self.document_highlights_task.take();
 6225            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6226            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6227            return None;
 6228        }
 6229
 6230        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6231        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6232            cx.background_executor()
 6233                .timer(Duration::from_millis(debounce))
 6234                .await;
 6235
 6236            let highlights = if let Some(highlights) = cx
 6237                .update(|cx| {
 6238                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6239                })
 6240                .ok()
 6241                .flatten()
 6242            {
 6243                highlights.await.log_err()
 6244            } else {
 6245                None
 6246            };
 6247
 6248            if let Some(highlights) = highlights {
 6249                this.update(cx, |this, cx| {
 6250                    if this.pending_rename.is_some() {
 6251                        return;
 6252                    }
 6253
 6254                    let buffer_id = cursor_position.buffer_id;
 6255                    let buffer = this.buffer.read(cx);
 6256                    if !buffer
 6257                        .text_anchor_for_position(cursor_position, cx)
 6258                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6259                    {
 6260                        return;
 6261                    }
 6262
 6263                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6264                    let mut write_ranges = Vec::new();
 6265                    let mut read_ranges = Vec::new();
 6266                    for highlight in highlights {
 6267                        for (excerpt_id, excerpt_range) in
 6268                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6269                        {
 6270                            let start = highlight
 6271                                .range
 6272                                .start
 6273                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6274                            let end = highlight
 6275                                .range
 6276                                .end
 6277                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6278                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6279                                continue;
 6280                            }
 6281
 6282                            let range = Anchor {
 6283                                buffer_id,
 6284                                excerpt_id,
 6285                                text_anchor: start,
 6286                                diff_base_anchor: None,
 6287                            }..Anchor {
 6288                                buffer_id,
 6289                                excerpt_id,
 6290                                text_anchor: end,
 6291                                diff_base_anchor: None,
 6292                            };
 6293                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6294                                write_ranges.push(range);
 6295                            } else {
 6296                                read_ranges.push(range);
 6297                            }
 6298                        }
 6299                    }
 6300
 6301                    this.highlight_background::<DocumentHighlightRead>(
 6302                        &read_ranges,
 6303                        |theme| theme.editor_document_highlight_read_background,
 6304                        cx,
 6305                    );
 6306                    this.highlight_background::<DocumentHighlightWrite>(
 6307                        &write_ranges,
 6308                        |theme| theme.editor_document_highlight_write_background,
 6309                        cx,
 6310                    );
 6311                    cx.notify();
 6312                })
 6313                .log_err();
 6314            }
 6315        }));
 6316        None
 6317    }
 6318
 6319    fn prepare_highlight_query_from_selection(
 6320        &mut self,
 6321        cx: &mut Context<Editor>,
 6322    ) -> Option<(String, Range<Anchor>)> {
 6323        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6324            return None;
 6325        }
 6326        if !EditorSettings::get_global(cx).selection_highlight {
 6327            return None;
 6328        }
 6329        if self.selections.count() != 1 || self.selections.line_mode {
 6330            return None;
 6331        }
 6332        let selection = self.selections.newest::<Point>(cx);
 6333        if selection.is_empty() || selection.start.row != selection.end.row {
 6334            return None;
 6335        }
 6336        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6337        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6338        let query = multi_buffer_snapshot
 6339            .text_for_range(selection_anchor_range.clone())
 6340            .collect::<String>();
 6341        if query.trim().is_empty() {
 6342            return None;
 6343        }
 6344        Some((query, selection_anchor_range))
 6345    }
 6346
 6347    fn update_selection_occurrence_highlights(
 6348        &mut self,
 6349        query_text: String,
 6350        query_range: Range<Anchor>,
 6351        multi_buffer_range_to_query: Range<Point>,
 6352        use_debounce: bool,
 6353        window: &mut Window,
 6354        cx: &mut Context<Editor>,
 6355    ) -> Task<()> {
 6356        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6357        cx.spawn_in(window, async move |editor, cx| {
 6358            if use_debounce {
 6359                cx.background_executor()
 6360                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6361                    .await;
 6362            }
 6363            let match_task = cx.background_spawn(async move {
 6364                let buffer_ranges = multi_buffer_snapshot
 6365                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6366                    .into_iter()
 6367                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6368                let mut match_ranges = Vec::new();
 6369                let Ok(regex) = project::search::SearchQuery::text(
 6370                    query_text.clone(),
 6371                    false,
 6372                    false,
 6373                    false,
 6374                    Default::default(),
 6375                    Default::default(),
 6376                    false,
 6377                    None,
 6378                ) else {
 6379                    return Vec::default();
 6380                };
 6381                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6382                    match_ranges.extend(
 6383                        regex
 6384                            .search(&buffer_snapshot, Some(search_range.clone()))
 6385                            .await
 6386                            .into_iter()
 6387                            .filter_map(|match_range| {
 6388                                let match_start = buffer_snapshot
 6389                                    .anchor_after(search_range.start + match_range.start);
 6390                                let match_end = buffer_snapshot
 6391                                    .anchor_before(search_range.start + match_range.end);
 6392                                let match_anchor_range = Anchor::range_in_buffer(
 6393                                    excerpt_id,
 6394                                    buffer_snapshot.remote_id(),
 6395                                    match_start..match_end,
 6396                                );
 6397                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6398                            }),
 6399                    );
 6400                }
 6401                match_ranges
 6402            });
 6403            let match_ranges = match_task.await;
 6404            editor
 6405                .update_in(cx, |editor, _, cx| {
 6406                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6407                    if !match_ranges.is_empty() {
 6408                        editor.highlight_background::<SelectedTextHighlight>(
 6409                            &match_ranges,
 6410                            |theme| theme.editor_document_highlight_bracket_background,
 6411                            cx,
 6412                        )
 6413                    }
 6414                })
 6415                .log_err();
 6416        })
 6417    }
 6418
 6419    fn refresh_selected_text_highlights(
 6420        &mut self,
 6421        on_buffer_edit: bool,
 6422        window: &mut Window,
 6423        cx: &mut Context<Editor>,
 6424    ) {
 6425        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6426        else {
 6427            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6428            self.quick_selection_highlight_task.take();
 6429            self.debounced_selection_highlight_task.take();
 6430            return;
 6431        };
 6432        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6433        if on_buffer_edit
 6434            || self
 6435                .quick_selection_highlight_task
 6436                .as_ref()
 6437                .map_or(true, |(prev_anchor_range, _)| {
 6438                    prev_anchor_range != &query_range
 6439                })
 6440        {
 6441            let multi_buffer_visible_start = self
 6442                .scroll_manager
 6443                .anchor()
 6444                .anchor
 6445                .to_point(&multi_buffer_snapshot);
 6446            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6447                multi_buffer_visible_start
 6448                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6449                Bias::Left,
 6450            );
 6451            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6452            self.quick_selection_highlight_task = Some((
 6453                query_range.clone(),
 6454                self.update_selection_occurrence_highlights(
 6455                    query_text.clone(),
 6456                    query_range.clone(),
 6457                    multi_buffer_visible_range,
 6458                    false,
 6459                    window,
 6460                    cx,
 6461                ),
 6462            ));
 6463        }
 6464        if on_buffer_edit
 6465            || self
 6466                .debounced_selection_highlight_task
 6467                .as_ref()
 6468                .map_or(true, |(prev_anchor_range, _)| {
 6469                    prev_anchor_range != &query_range
 6470                })
 6471        {
 6472            let multi_buffer_start = multi_buffer_snapshot
 6473                .anchor_before(0)
 6474                .to_point(&multi_buffer_snapshot);
 6475            let multi_buffer_end = multi_buffer_snapshot
 6476                .anchor_after(multi_buffer_snapshot.len())
 6477                .to_point(&multi_buffer_snapshot);
 6478            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6479            self.debounced_selection_highlight_task = Some((
 6480                query_range.clone(),
 6481                self.update_selection_occurrence_highlights(
 6482                    query_text,
 6483                    query_range,
 6484                    multi_buffer_full_range,
 6485                    true,
 6486                    window,
 6487                    cx,
 6488                ),
 6489            ));
 6490        }
 6491    }
 6492
 6493    pub fn refresh_inline_completion(
 6494        &mut self,
 6495        debounce: bool,
 6496        user_requested: bool,
 6497        window: &mut Window,
 6498        cx: &mut Context<Self>,
 6499    ) -> Option<()> {
 6500        let provider = self.edit_prediction_provider()?;
 6501        let cursor = self.selections.newest_anchor().head();
 6502        let (buffer, cursor_buffer_position) =
 6503            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6504
 6505        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6506            self.discard_inline_completion(false, cx);
 6507            return None;
 6508        }
 6509
 6510        if !user_requested
 6511            && (!self.should_show_edit_predictions()
 6512                || !self.is_focused(window)
 6513                || buffer.read(cx).is_empty())
 6514        {
 6515            self.discard_inline_completion(false, cx);
 6516            return None;
 6517        }
 6518
 6519        self.update_visible_inline_completion(window, cx);
 6520        provider.refresh(
 6521            self.project.clone(),
 6522            buffer,
 6523            cursor_buffer_position,
 6524            debounce,
 6525            cx,
 6526        );
 6527        Some(())
 6528    }
 6529
 6530    fn show_edit_predictions_in_menu(&self) -> bool {
 6531        match self.edit_prediction_settings {
 6532            EditPredictionSettings::Disabled => false,
 6533            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6534        }
 6535    }
 6536
 6537    pub fn edit_predictions_enabled(&self) -> bool {
 6538        match self.edit_prediction_settings {
 6539            EditPredictionSettings::Disabled => false,
 6540            EditPredictionSettings::Enabled { .. } => true,
 6541        }
 6542    }
 6543
 6544    fn edit_prediction_requires_modifier(&self) -> bool {
 6545        match self.edit_prediction_settings {
 6546            EditPredictionSettings::Disabled => false,
 6547            EditPredictionSettings::Enabled {
 6548                preview_requires_modifier,
 6549                ..
 6550            } => preview_requires_modifier,
 6551        }
 6552    }
 6553
 6554    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6555        if self.edit_prediction_provider.is_none() {
 6556            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6557        } else {
 6558            let selection = self.selections.newest_anchor();
 6559            let cursor = selection.head();
 6560
 6561            if let Some((buffer, cursor_buffer_position)) =
 6562                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6563            {
 6564                self.edit_prediction_settings =
 6565                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6566            }
 6567        }
 6568    }
 6569
 6570    fn edit_prediction_settings_at_position(
 6571        &self,
 6572        buffer: &Entity<Buffer>,
 6573        buffer_position: language::Anchor,
 6574        cx: &App,
 6575    ) -> EditPredictionSettings {
 6576        if !self.mode.is_full()
 6577            || !self.show_inline_completions_override.unwrap_or(true)
 6578            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6579        {
 6580            return EditPredictionSettings::Disabled;
 6581        }
 6582
 6583        let buffer = buffer.read(cx);
 6584
 6585        let file = buffer.file();
 6586
 6587        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6588            return EditPredictionSettings::Disabled;
 6589        };
 6590
 6591        let by_provider = matches!(
 6592            self.menu_inline_completions_policy,
 6593            MenuInlineCompletionsPolicy::ByProvider
 6594        );
 6595
 6596        let show_in_menu = by_provider
 6597            && self
 6598                .edit_prediction_provider
 6599                .as_ref()
 6600                .map_or(false, |provider| {
 6601                    provider.provider.show_completions_in_menu()
 6602                });
 6603
 6604        let preview_requires_modifier =
 6605            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6606
 6607        EditPredictionSettings::Enabled {
 6608            show_in_menu,
 6609            preview_requires_modifier,
 6610        }
 6611    }
 6612
 6613    fn should_show_edit_predictions(&self) -> bool {
 6614        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6615    }
 6616
 6617    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6618        matches!(
 6619            self.edit_prediction_preview,
 6620            EditPredictionPreview::Active { .. }
 6621        )
 6622    }
 6623
 6624    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6625        let cursor = self.selections.newest_anchor().head();
 6626        if let Some((buffer, cursor_position)) =
 6627            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6628        {
 6629            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6630        } else {
 6631            false
 6632        }
 6633    }
 6634
 6635    pub fn supports_minimap(&self, cx: &App) -> bool {
 6636        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6637    }
 6638
 6639    fn edit_predictions_enabled_in_buffer(
 6640        &self,
 6641        buffer: &Entity<Buffer>,
 6642        buffer_position: language::Anchor,
 6643        cx: &App,
 6644    ) -> bool {
 6645        maybe!({
 6646            if self.read_only(cx) {
 6647                return Some(false);
 6648            }
 6649            let provider = self.edit_prediction_provider()?;
 6650            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6651                return Some(false);
 6652            }
 6653            let buffer = buffer.read(cx);
 6654            let Some(file) = buffer.file() else {
 6655                return Some(true);
 6656            };
 6657            let settings = all_language_settings(Some(file), cx);
 6658            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6659        })
 6660        .unwrap_or(false)
 6661    }
 6662
 6663    fn cycle_inline_completion(
 6664        &mut self,
 6665        direction: Direction,
 6666        window: &mut Window,
 6667        cx: &mut Context<Self>,
 6668    ) -> Option<()> {
 6669        let provider = self.edit_prediction_provider()?;
 6670        let cursor = self.selections.newest_anchor().head();
 6671        let (buffer, cursor_buffer_position) =
 6672            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6673        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6674            return None;
 6675        }
 6676
 6677        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6678        self.update_visible_inline_completion(window, cx);
 6679
 6680        Some(())
 6681    }
 6682
 6683    pub fn show_inline_completion(
 6684        &mut self,
 6685        _: &ShowEditPrediction,
 6686        window: &mut Window,
 6687        cx: &mut Context<Self>,
 6688    ) {
 6689        if !self.has_active_inline_completion() {
 6690            self.refresh_inline_completion(false, true, window, cx);
 6691            return;
 6692        }
 6693
 6694        self.update_visible_inline_completion(window, cx);
 6695    }
 6696
 6697    pub fn display_cursor_names(
 6698        &mut self,
 6699        _: &DisplayCursorNames,
 6700        window: &mut Window,
 6701        cx: &mut Context<Self>,
 6702    ) {
 6703        self.show_cursor_names(window, cx);
 6704    }
 6705
 6706    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6707        self.show_cursor_names = true;
 6708        cx.notify();
 6709        cx.spawn_in(window, async move |this, cx| {
 6710            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6711            this.update(cx, |this, cx| {
 6712                this.show_cursor_names = false;
 6713                cx.notify()
 6714            })
 6715            .ok()
 6716        })
 6717        .detach();
 6718    }
 6719
 6720    pub fn next_edit_prediction(
 6721        &mut self,
 6722        _: &NextEditPrediction,
 6723        window: &mut Window,
 6724        cx: &mut Context<Self>,
 6725    ) {
 6726        if self.has_active_inline_completion() {
 6727            self.cycle_inline_completion(Direction::Next, window, cx);
 6728        } else {
 6729            let is_copilot_disabled = self
 6730                .refresh_inline_completion(false, true, window, cx)
 6731                .is_none();
 6732            if is_copilot_disabled {
 6733                cx.propagate();
 6734            }
 6735        }
 6736    }
 6737
 6738    pub fn previous_edit_prediction(
 6739        &mut self,
 6740        _: &PreviousEditPrediction,
 6741        window: &mut Window,
 6742        cx: &mut Context<Self>,
 6743    ) {
 6744        if self.has_active_inline_completion() {
 6745            self.cycle_inline_completion(Direction::Prev, window, cx);
 6746        } else {
 6747            let is_copilot_disabled = self
 6748                .refresh_inline_completion(false, true, window, cx)
 6749                .is_none();
 6750            if is_copilot_disabled {
 6751                cx.propagate();
 6752            }
 6753        }
 6754    }
 6755
 6756    pub fn accept_edit_prediction(
 6757        &mut self,
 6758        _: &AcceptEditPrediction,
 6759        window: &mut Window,
 6760        cx: &mut Context<Self>,
 6761    ) {
 6762        if self.show_edit_predictions_in_menu() {
 6763            self.hide_context_menu(window, cx);
 6764        }
 6765
 6766        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6767            return;
 6768        };
 6769
 6770        self.report_inline_completion_event(
 6771            active_inline_completion.completion_id.clone(),
 6772            true,
 6773            cx,
 6774        );
 6775
 6776        match &active_inline_completion.completion {
 6777            InlineCompletion::Move { target, .. } => {
 6778                let target = *target;
 6779
 6780                if let Some(position_map) = &self.last_position_map {
 6781                    if position_map
 6782                        .visible_row_range
 6783                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6784                        || !self.edit_prediction_requires_modifier()
 6785                    {
 6786                        self.unfold_ranges(&[target..target], true, false, cx);
 6787                        // Note that this is also done in vim's handler of the Tab action.
 6788                        self.change_selections(
 6789                            Some(Autoscroll::newest()),
 6790                            window,
 6791                            cx,
 6792                            |selections| {
 6793                                selections.select_anchor_ranges([target..target]);
 6794                            },
 6795                        );
 6796                        self.clear_row_highlights::<EditPredictionPreview>();
 6797
 6798                        self.edit_prediction_preview
 6799                            .set_previous_scroll_position(None);
 6800                    } else {
 6801                        self.edit_prediction_preview
 6802                            .set_previous_scroll_position(Some(
 6803                                position_map.snapshot.scroll_anchor,
 6804                            ));
 6805
 6806                        self.highlight_rows::<EditPredictionPreview>(
 6807                            target..target,
 6808                            cx.theme().colors().editor_highlighted_line_background,
 6809                            RowHighlightOptions {
 6810                                autoscroll: true,
 6811                                ..Default::default()
 6812                            },
 6813                            cx,
 6814                        );
 6815                        self.request_autoscroll(Autoscroll::fit(), cx);
 6816                    }
 6817                }
 6818            }
 6819            InlineCompletion::Edit { edits, .. } => {
 6820                if let Some(provider) = self.edit_prediction_provider() {
 6821                    provider.accept(cx);
 6822                }
 6823
 6824                // Store the transaction ID and selections before applying the edit
 6825                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6826
 6827                let snapshot = self.buffer.read(cx).snapshot(cx);
 6828                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6829
 6830                self.buffer.update(cx, |buffer, cx| {
 6831                    buffer.edit(edits.iter().cloned(), None, cx)
 6832                });
 6833
 6834                self.change_selections(None, window, cx, |s| {
 6835                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6836                });
 6837
 6838                let selections = self.selections.disjoint_anchors();
 6839                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6840                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6841                    if has_new_transaction {
 6842                        self.selection_history
 6843                            .insert_transaction(transaction_id_now, selections);
 6844                    }
 6845                }
 6846
 6847                self.update_visible_inline_completion(window, cx);
 6848                if self.active_inline_completion.is_none() {
 6849                    self.refresh_inline_completion(true, true, window, cx);
 6850                }
 6851
 6852                cx.notify();
 6853            }
 6854        }
 6855
 6856        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6857    }
 6858
 6859    pub fn accept_partial_inline_completion(
 6860        &mut self,
 6861        _: &AcceptPartialEditPrediction,
 6862        window: &mut Window,
 6863        cx: &mut Context<Self>,
 6864    ) {
 6865        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6866            return;
 6867        };
 6868        if self.selections.count() != 1 {
 6869            return;
 6870        }
 6871
 6872        self.report_inline_completion_event(
 6873            active_inline_completion.completion_id.clone(),
 6874            true,
 6875            cx,
 6876        );
 6877
 6878        match &active_inline_completion.completion {
 6879            InlineCompletion::Move { target, .. } => {
 6880                let target = *target;
 6881                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6882                    selections.select_anchor_ranges([target..target]);
 6883                });
 6884            }
 6885            InlineCompletion::Edit { edits, .. } => {
 6886                // Find an insertion that starts at the cursor position.
 6887                let snapshot = self.buffer.read(cx).snapshot(cx);
 6888                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6889                let insertion = edits.iter().find_map(|(range, text)| {
 6890                    let range = range.to_offset(&snapshot);
 6891                    if range.is_empty() && range.start == cursor_offset {
 6892                        Some(text)
 6893                    } else {
 6894                        None
 6895                    }
 6896                });
 6897
 6898                if let Some(text) = insertion {
 6899                    let mut partial_completion = text
 6900                        .chars()
 6901                        .by_ref()
 6902                        .take_while(|c| c.is_alphabetic())
 6903                        .collect::<String>();
 6904                    if partial_completion.is_empty() {
 6905                        partial_completion = text
 6906                            .chars()
 6907                            .by_ref()
 6908                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6909                            .collect::<String>();
 6910                    }
 6911
 6912                    cx.emit(EditorEvent::InputHandled {
 6913                        utf16_range_to_replace: None,
 6914                        text: partial_completion.clone().into(),
 6915                    });
 6916
 6917                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6918
 6919                    self.refresh_inline_completion(true, true, window, cx);
 6920                    cx.notify();
 6921                } else {
 6922                    self.accept_edit_prediction(&Default::default(), window, cx);
 6923                }
 6924            }
 6925        }
 6926    }
 6927
 6928    fn discard_inline_completion(
 6929        &mut self,
 6930        should_report_inline_completion_event: bool,
 6931        cx: &mut Context<Self>,
 6932    ) -> bool {
 6933        if should_report_inline_completion_event {
 6934            let completion_id = self
 6935                .active_inline_completion
 6936                .as_ref()
 6937                .and_then(|active_completion| active_completion.completion_id.clone());
 6938
 6939            self.report_inline_completion_event(completion_id, false, cx);
 6940        }
 6941
 6942        if let Some(provider) = self.edit_prediction_provider() {
 6943            provider.discard(cx);
 6944        }
 6945
 6946        self.take_active_inline_completion(cx)
 6947    }
 6948
 6949    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6950        let Some(provider) = self.edit_prediction_provider() else {
 6951            return;
 6952        };
 6953
 6954        let Some((_, buffer, _)) = self
 6955            .buffer
 6956            .read(cx)
 6957            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6958        else {
 6959            return;
 6960        };
 6961
 6962        let extension = buffer
 6963            .read(cx)
 6964            .file()
 6965            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6966
 6967        let event_type = match accepted {
 6968            true => "Edit Prediction Accepted",
 6969            false => "Edit Prediction Discarded",
 6970        };
 6971        telemetry::event!(
 6972            event_type,
 6973            provider = provider.name(),
 6974            prediction_id = id,
 6975            suggestion_accepted = accepted,
 6976            file_extension = extension,
 6977        );
 6978    }
 6979
 6980    pub fn has_active_inline_completion(&self) -> bool {
 6981        self.active_inline_completion.is_some()
 6982    }
 6983
 6984    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6985        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6986            return false;
 6987        };
 6988
 6989        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6990        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6991        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6992        true
 6993    }
 6994
 6995    /// Returns true when we're displaying the edit prediction popover below the cursor
 6996    /// like we are not previewing and the LSP autocomplete menu is visible
 6997    /// or we are in `when_holding_modifier` mode.
 6998    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6999        if self.edit_prediction_preview_is_active()
 7000            || !self.show_edit_predictions_in_menu()
 7001            || !self.edit_predictions_enabled()
 7002        {
 7003            return false;
 7004        }
 7005
 7006        if self.has_visible_completions_menu() {
 7007            return true;
 7008        }
 7009
 7010        has_completion && self.edit_prediction_requires_modifier()
 7011    }
 7012
 7013    fn handle_modifiers_changed(
 7014        &mut self,
 7015        modifiers: Modifiers,
 7016        position_map: &PositionMap,
 7017        window: &mut Window,
 7018        cx: &mut Context<Self>,
 7019    ) {
 7020        if self.show_edit_predictions_in_menu() {
 7021            self.update_edit_prediction_preview(&modifiers, window, cx);
 7022        }
 7023
 7024        self.update_selection_mode(&modifiers, position_map, window, cx);
 7025
 7026        let mouse_position = window.mouse_position();
 7027        if !position_map.text_hitbox.is_hovered(window) {
 7028            return;
 7029        }
 7030
 7031        self.update_hovered_link(
 7032            position_map.point_for_position(mouse_position),
 7033            &position_map.snapshot,
 7034            modifiers,
 7035            window,
 7036            cx,
 7037        )
 7038    }
 7039
 7040    fn update_selection_mode(
 7041        &mut self,
 7042        modifiers: &Modifiers,
 7043        position_map: &PositionMap,
 7044        window: &mut Window,
 7045        cx: &mut Context<Self>,
 7046    ) {
 7047        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 7048            return;
 7049        }
 7050
 7051        let mouse_position = window.mouse_position();
 7052        let point_for_position = position_map.point_for_position(mouse_position);
 7053        let position = point_for_position.previous_valid;
 7054
 7055        self.select(
 7056            SelectPhase::BeginColumnar {
 7057                position,
 7058                reset: false,
 7059                goal_column: point_for_position.exact_unclipped.column(),
 7060            },
 7061            window,
 7062            cx,
 7063        );
 7064    }
 7065
 7066    fn update_edit_prediction_preview(
 7067        &mut self,
 7068        modifiers: &Modifiers,
 7069        window: &mut Window,
 7070        cx: &mut Context<Self>,
 7071    ) {
 7072        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 7073        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 7074            return;
 7075        };
 7076
 7077        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 7078            if matches!(
 7079                self.edit_prediction_preview,
 7080                EditPredictionPreview::Inactive { .. }
 7081            ) {
 7082                self.edit_prediction_preview = EditPredictionPreview::Active {
 7083                    previous_scroll_position: None,
 7084                    since: Instant::now(),
 7085                };
 7086
 7087                self.update_visible_inline_completion(window, cx);
 7088                cx.notify();
 7089            }
 7090        } else if let EditPredictionPreview::Active {
 7091            previous_scroll_position,
 7092            since,
 7093        } = self.edit_prediction_preview
 7094        {
 7095            if let (Some(previous_scroll_position), Some(position_map)) =
 7096                (previous_scroll_position, self.last_position_map.as_ref())
 7097            {
 7098                self.set_scroll_position(
 7099                    previous_scroll_position
 7100                        .scroll_position(&position_map.snapshot.display_snapshot),
 7101                    window,
 7102                    cx,
 7103                );
 7104            }
 7105
 7106            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7107                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7108            };
 7109            self.clear_row_highlights::<EditPredictionPreview>();
 7110            self.update_visible_inline_completion(window, cx);
 7111            cx.notify();
 7112        }
 7113    }
 7114
 7115    fn update_visible_inline_completion(
 7116        &mut self,
 7117        _window: &mut Window,
 7118        cx: &mut Context<Self>,
 7119    ) -> Option<()> {
 7120        let selection = self.selections.newest_anchor();
 7121        let cursor = selection.head();
 7122        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7123        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7124        let excerpt_id = cursor.excerpt_id;
 7125
 7126        let show_in_menu = self.show_edit_predictions_in_menu();
 7127        let completions_menu_has_precedence = !show_in_menu
 7128            && (self.context_menu.borrow().is_some()
 7129                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7130
 7131        if completions_menu_has_precedence
 7132            || !offset_selection.is_empty()
 7133            || self
 7134                .active_inline_completion
 7135                .as_ref()
 7136                .map_or(false, |completion| {
 7137                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7138                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7139                    !invalidation_range.contains(&offset_selection.head())
 7140                })
 7141        {
 7142            self.discard_inline_completion(false, cx);
 7143            return None;
 7144        }
 7145
 7146        self.take_active_inline_completion(cx);
 7147        let Some(provider) = self.edit_prediction_provider() else {
 7148            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7149            return None;
 7150        };
 7151
 7152        let (buffer, cursor_buffer_position) =
 7153            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7154
 7155        self.edit_prediction_settings =
 7156            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7157
 7158        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7159
 7160        if self.edit_prediction_indent_conflict {
 7161            let cursor_point = cursor.to_point(&multibuffer);
 7162
 7163            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7164
 7165            if let Some((_, indent)) = indents.iter().next() {
 7166                if indent.len == cursor_point.column {
 7167                    self.edit_prediction_indent_conflict = false;
 7168                }
 7169            }
 7170        }
 7171
 7172        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7173        let edits = inline_completion
 7174            .edits
 7175            .into_iter()
 7176            .flat_map(|(range, new_text)| {
 7177                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7178                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7179                Some((start..end, new_text))
 7180            })
 7181            .collect::<Vec<_>>();
 7182        if edits.is_empty() {
 7183            return None;
 7184        }
 7185
 7186        let first_edit_start = edits.first().unwrap().0.start;
 7187        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7188        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7189
 7190        let last_edit_end = edits.last().unwrap().0.end;
 7191        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7192        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7193
 7194        let cursor_row = cursor.to_point(&multibuffer).row;
 7195
 7196        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7197
 7198        let mut inlay_ids = Vec::new();
 7199        let invalidation_row_range;
 7200        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7201            Some(cursor_row..edit_end_row)
 7202        } else if cursor_row > edit_end_row {
 7203            Some(edit_start_row..cursor_row)
 7204        } else {
 7205            None
 7206        };
 7207        let is_move =
 7208            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7209        let completion = if is_move {
 7210            invalidation_row_range =
 7211                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7212            let target = first_edit_start;
 7213            InlineCompletion::Move { target, snapshot }
 7214        } else {
 7215            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7216                && !self.inline_completions_hidden_for_vim_mode;
 7217
 7218            if show_completions_in_buffer {
 7219                if edits
 7220                    .iter()
 7221                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7222                {
 7223                    let mut inlays = Vec::new();
 7224                    for (range, new_text) in &edits {
 7225                        let inlay = Inlay::inline_completion(
 7226                            post_inc(&mut self.next_inlay_id),
 7227                            range.start,
 7228                            new_text.as_str(),
 7229                        );
 7230                        inlay_ids.push(inlay.id);
 7231                        inlays.push(inlay);
 7232                    }
 7233
 7234                    self.splice_inlays(&[], inlays, cx);
 7235                } else {
 7236                    let background_color = cx.theme().status().deleted_background;
 7237                    self.highlight_text::<InlineCompletionHighlight>(
 7238                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7239                        HighlightStyle {
 7240                            background_color: Some(background_color),
 7241                            ..Default::default()
 7242                        },
 7243                        cx,
 7244                    );
 7245                }
 7246            }
 7247
 7248            invalidation_row_range = edit_start_row..edit_end_row;
 7249
 7250            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7251                if provider.show_tab_accept_marker() {
 7252                    EditDisplayMode::TabAccept
 7253                } else {
 7254                    EditDisplayMode::Inline
 7255                }
 7256            } else {
 7257                EditDisplayMode::DiffPopover
 7258            };
 7259
 7260            InlineCompletion::Edit {
 7261                edits,
 7262                edit_preview: inline_completion.edit_preview,
 7263                display_mode,
 7264                snapshot,
 7265            }
 7266        };
 7267
 7268        let invalidation_range = multibuffer
 7269            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7270            ..multibuffer.anchor_after(Point::new(
 7271                invalidation_row_range.end,
 7272                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7273            ));
 7274
 7275        self.stale_inline_completion_in_menu = None;
 7276        self.active_inline_completion = Some(InlineCompletionState {
 7277            inlay_ids,
 7278            completion,
 7279            completion_id: inline_completion.id,
 7280            invalidation_range,
 7281        });
 7282
 7283        cx.notify();
 7284
 7285        Some(())
 7286    }
 7287
 7288    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7289        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7290    }
 7291
 7292    fn clear_tasks(&mut self) {
 7293        self.tasks.clear()
 7294    }
 7295
 7296    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7297        if self.tasks.insert(key, value).is_some() {
 7298            // This case should hopefully be rare, but just in case...
 7299            log::error!(
 7300                "multiple different run targets found on a single line, only the last target will be rendered"
 7301            )
 7302        }
 7303    }
 7304
 7305    /// Get all display points of breakpoints that will be rendered within editor
 7306    ///
 7307    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7308    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7309    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7310    fn active_breakpoints(
 7311        &self,
 7312        range: Range<DisplayRow>,
 7313        window: &mut Window,
 7314        cx: &mut Context<Self>,
 7315    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7316        let mut breakpoint_display_points = HashMap::default();
 7317
 7318        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7319            return breakpoint_display_points;
 7320        };
 7321
 7322        let snapshot = self.snapshot(window, cx);
 7323
 7324        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7325        let Some(project) = self.project.as_ref() else {
 7326            return breakpoint_display_points;
 7327        };
 7328
 7329        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7330            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7331
 7332        for (buffer_snapshot, range, excerpt_id) in
 7333            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7334        {
 7335            let Some(buffer) = project
 7336                .read(cx)
 7337                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7338            else {
 7339                continue;
 7340            };
 7341            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7342                &buffer,
 7343                Some(
 7344                    buffer_snapshot.anchor_before(range.start)
 7345                        ..buffer_snapshot.anchor_after(range.end),
 7346                ),
 7347                buffer_snapshot,
 7348                cx,
 7349            );
 7350            for (breakpoint, state) in breakpoints {
 7351                let multi_buffer_anchor =
 7352                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7353                let position = multi_buffer_anchor
 7354                    .to_point(&multi_buffer_snapshot)
 7355                    .to_display_point(&snapshot);
 7356
 7357                breakpoint_display_points.insert(
 7358                    position.row(),
 7359                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7360                );
 7361            }
 7362        }
 7363
 7364        breakpoint_display_points
 7365    }
 7366
 7367    fn breakpoint_context_menu(
 7368        &self,
 7369        anchor: Anchor,
 7370        window: &mut Window,
 7371        cx: &mut Context<Self>,
 7372    ) -> Entity<ui::ContextMenu> {
 7373        let weak_editor = cx.weak_entity();
 7374        let focus_handle = self.focus_handle(cx);
 7375
 7376        let row = self
 7377            .buffer
 7378            .read(cx)
 7379            .snapshot(cx)
 7380            .summary_for_anchor::<Point>(&anchor)
 7381            .row;
 7382
 7383        let breakpoint = self
 7384            .breakpoint_at_row(row, window, cx)
 7385            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7386
 7387        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7388            "Edit Log Breakpoint"
 7389        } else {
 7390            "Set Log Breakpoint"
 7391        };
 7392
 7393        let condition_breakpoint_msg = if breakpoint
 7394            .as_ref()
 7395            .is_some_and(|bp| bp.1.condition.is_some())
 7396        {
 7397            "Edit Condition Breakpoint"
 7398        } else {
 7399            "Set Condition Breakpoint"
 7400        };
 7401
 7402        let hit_condition_breakpoint_msg = if breakpoint
 7403            .as_ref()
 7404            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7405        {
 7406            "Edit Hit Condition Breakpoint"
 7407        } else {
 7408            "Set Hit Condition Breakpoint"
 7409        };
 7410
 7411        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7412            "Unset Breakpoint"
 7413        } else {
 7414            "Set Breakpoint"
 7415        };
 7416
 7417        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7418            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7419
 7420        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7421            BreakpointState::Enabled => Some("Disable"),
 7422            BreakpointState::Disabled => Some("Enable"),
 7423        });
 7424
 7425        let (anchor, breakpoint) =
 7426            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7427
 7428        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7429            menu.on_blur_subscription(Subscription::new(|| {}))
 7430                .context(focus_handle)
 7431                .when(run_to_cursor, |this| {
 7432                    let weak_editor = weak_editor.clone();
 7433                    this.entry("Run to cursor", None, move |window, cx| {
 7434                        weak_editor
 7435                            .update(cx, |editor, cx| {
 7436                                editor.change_selections(None, window, cx, |s| {
 7437                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7438                                });
 7439                            })
 7440                            .ok();
 7441
 7442                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7443                    })
 7444                    .separator()
 7445                })
 7446                .when_some(toggle_state_msg, |this, msg| {
 7447                    this.entry(msg, None, {
 7448                        let weak_editor = weak_editor.clone();
 7449                        let breakpoint = breakpoint.clone();
 7450                        move |_window, cx| {
 7451                            weak_editor
 7452                                .update(cx, |this, cx| {
 7453                                    this.edit_breakpoint_at_anchor(
 7454                                        anchor,
 7455                                        breakpoint.as_ref().clone(),
 7456                                        BreakpointEditAction::InvertState,
 7457                                        cx,
 7458                                    );
 7459                                })
 7460                                .log_err();
 7461                        }
 7462                    })
 7463                })
 7464                .entry(set_breakpoint_msg, None, {
 7465                    let weak_editor = weak_editor.clone();
 7466                    let breakpoint = breakpoint.clone();
 7467                    move |_window, cx| {
 7468                        weak_editor
 7469                            .update(cx, |this, cx| {
 7470                                this.edit_breakpoint_at_anchor(
 7471                                    anchor,
 7472                                    breakpoint.as_ref().clone(),
 7473                                    BreakpointEditAction::Toggle,
 7474                                    cx,
 7475                                );
 7476                            })
 7477                            .log_err();
 7478                    }
 7479                })
 7480                .entry(log_breakpoint_msg, None, {
 7481                    let breakpoint = breakpoint.clone();
 7482                    let weak_editor = weak_editor.clone();
 7483                    move |window, cx| {
 7484                        weak_editor
 7485                            .update(cx, |this, cx| {
 7486                                this.add_edit_breakpoint_block(
 7487                                    anchor,
 7488                                    breakpoint.as_ref(),
 7489                                    BreakpointPromptEditAction::Log,
 7490                                    window,
 7491                                    cx,
 7492                                );
 7493                            })
 7494                            .log_err();
 7495                    }
 7496                })
 7497                .entry(condition_breakpoint_msg, None, {
 7498                    let breakpoint = breakpoint.clone();
 7499                    let weak_editor = weak_editor.clone();
 7500                    move |window, cx| {
 7501                        weak_editor
 7502                            .update(cx, |this, cx| {
 7503                                this.add_edit_breakpoint_block(
 7504                                    anchor,
 7505                                    breakpoint.as_ref(),
 7506                                    BreakpointPromptEditAction::Condition,
 7507                                    window,
 7508                                    cx,
 7509                                );
 7510                            })
 7511                            .log_err();
 7512                    }
 7513                })
 7514                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7515                    weak_editor
 7516                        .update(cx, |this, cx| {
 7517                            this.add_edit_breakpoint_block(
 7518                                anchor,
 7519                                breakpoint.as_ref(),
 7520                                BreakpointPromptEditAction::HitCondition,
 7521                                window,
 7522                                cx,
 7523                            );
 7524                        })
 7525                        .log_err();
 7526                })
 7527        })
 7528    }
 7529
 7530    fn render_breakpoint(
 7531        &self,
 7532        position: Anchor,
 7533        row: DisplayRow,
 7534        breakpoint: &Breakpoint,
 7535        state: Option<BreakpointSessionState>,
 7536        cx: &mut Context<Self>,
 7537    ) -> IconButton {
 7538        let is_rejected = state.is_some_and(|s| !s.verified);
 7539        // Is it a breakpoint that shows up when hovering over gutter?
 7540        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7541            (false, false),
 7542            |PhantomBreakpointIndicator {
 7543                 is_active,
 7544                 display_row,
 7545                 collides_with_existing_breakpoint,
 7546             }| {
 7547                (
 7548                    is_active && display_row == row,
 7549                    collides_with_existing_breakpoint,
 7550                )
 7551            },
 7552        );
 7553
 7554        let (color, icon) = {
 7555            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7556                (false, false) => ui::IconName::DebugBreakpoint,
 7557                (true, false) => ui::IconName::DebugLogBreakpoint,
 7558                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7559                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7560            };
 7561
 7562            let color = if is_phantom {
 7563                Color::Hint
 7564            } else if is_rejected {
 7565                Color::Disabled
 7566            } else {
 7567                Color::Debugger
 7568            };
 7569
 7570            (color, icon)
 7571        };
 7572
 7573        let breakpoint = Arc::from(breakpoint.clone());
 7574
 7575        let alt_as_text = gpui::Keystroke {
 7576            modifiers: Modifiers::secondary_key(),
 7577            ..Default::default()
 7578        };
 7579        let primary_action_text = if breakpoint.is_disabled() {
 7580            "Enable breakpoint"
 7581        } else if is_phantom && !collides_with_existing {
 7582            "Set breakpoint"
 7583        } else {
 7584            "Unset breakpoint"
 7585        };
 7586        let focus_handle = self.focus_handle.clone();
 7587
 7588        let meta = if is_rejected {
 7589            SharedString::from("No executable code is associated with this line.")
 7590        } else if collides_with_existing && !breakpoint.is_disabled() {
 7591            SharedString::from(format!(
 7592                "{alt_as_text}-click to disable,\nright-click for more options."
 7593            ))
 7594        } else {
 7595            SharedString::from("Right-click for more options.")
 7596        };
 7597        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7598            .icon_size(IconSize::XSmall)
 7599            .size(ui::ButtonSize::None)
 7600            .when(is_rejected, |this| {
 7601                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7602            })
 7603            .icon_color(color)
 7604            .style(ButtonStyle::Transparent)
 7605            .on_click(cx.listener({
 7606                let breakpoint = breakpoint.clone();
 7607
 7608                move |editor, event: &ClickEvent, window, cx| {
 7609                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7610                        BreakpointEditAction::InvertState
 7611                    } else {
 7612                        BreakpointEditAction::Toggle
 7613                    };
 7614
 7615                    window.focus(&editor.focus_handle(cx));
 7616                    editor.edit_breakpoint_at_anchor(
 7617                        position,
 7618                        breakpoint.as_ref().clone(),
 7619                        edit_action,
 7620                        cx,
 7621                    );
 7622                }
 7623            }))
 7624            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7625                editor.set_breakpoint_context_menu(
 7626                    row,
 7627                    Some(position),
 7628                    event.down.position,
 7629                    window,
 7630                    cx,
 7631                );
 7632            }))
 7633            .tooltip(move |window, cx| {
 7634                Tooltip::with_meta_in(
 7635                    primary_action_text,
 7636                    Some(&ToggleBreakpoint),
 7637                    meta.clone(),
 7638                    &focus_handle,
 7639                    window,
 7640                    cx,
 7641                )
 7642            })
 7643    }
 7644
 7645    fn build_tasks_context(
 7646        project: &Entity<Project>,
 7647        buffer: &Entity<Buffer>,
 7648        buffer_row: u32,
 7649        tasks: &Arc<RunnableTasks>,
 7650        cx: &mut Context<Self>,
 7651    ) -> Task<Option<task::TaskContext>> {
 7652        let position = Point::new(buffer_row, tasks.column);
 7653        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7654        let location = Location {
 7655            buffer: buffer.clone(),
 7656            range: range_start..range_start,
 7657        };
 7658        // Fill in the environmental variables from the tree-sitter captures
 7659        let mut captured_task_variables = TaskVariables::default();
 7660        for (capture_name, value) in tasks.extra_variables.clone() {
 7661            captured_task_variables.insert(
 7662                task::VariableName::Custom(capture_name.into()),
 7663                value.clone(),
 7664            );
 7665        }
 7666        project.update(cx, |project, cx| {
 7667            project.task_store().update(cx, |task_store, cx| {
 7668                task_store.task_context_for_location(captured_task_variables, location, cx)
 7669            })
 7670        })
 7671    }
 7672
 7673    pub fn spawn_nearest_task(
 7674        &mut self,
 7675        action: &SpawnNearestTask,
 7676        window: &mut Window,
 7677        cx: &mut Context<Self>,
 7678    ) {
 7679        let Some((workspace, _)) = self.workspace.clone() else {
 7680            return;
 7681        };
 7682        let Some(project) = self.project.clone() else {
 7683            return;
 7684        };
 7685
 7686        // Try to find a closest, enclosing node using tree-sitter that has a
 7687        // task
 7688        let Some((buffer, buffer_row, tasks)) = self
 7689            .find_enclosing_node_task(cx)
 7690            // Or find the task that's closest in row-distance.
 7691            .or_else(|| self.find_closest_task(cx))
 7692        else {
 7693            return;
 7694        };
 7695
 7696        let reveal_strategy = action.reveal;
 7697        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7698        cx.spawn_in(window, async move |_, cx| {
 7699            let context = task_context.await?;
 7700            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7701
 7702            let resolved = &mut resolved_task.resolved;
 7703            resolved.reveal = reveal_strategy;
 7704
 7705            workspace
 7706                .update_in(cx, |workspace, window, cx| {
 7707                    workspace.schedule_resolved_task(
 7708                        task_source_kind,
 7709                        resolved_task,
 7710                        false,
 7711                        window,
 7712                        cx,
 7713                    );
 7714                })
 7715                .ok()
 7716        })
 7717        .detach();
 7718    }
 7719
 7720    fn find_closest_task(
 7721        &mut self,
 7722        cx: &mut Context<Self>,
 7723    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7724        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7725
 7726        let ((buffer_id, row), tasks) = self
 7727            .tasks
 7728            .iter()
 7729            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7730
 7731        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7732        let tasks = Arc::new(tasks.to_owned());
 7733        Some((buffer, *row, tasks))
 7734    }
 7735
 7736    fn find_enclosing_node_task(
 7737        &mut self,
 7738        cx: &mut Context<Self>,
 7739    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7740        let snapshot = self.buffer.read(cx).snapshot(cx);
 7741        let offset = self.selections.newest::<usize>(cx).head();
 7742        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7743        let buffer_id = excerpt.buffer().remote_id();
 7744
 7745        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7746        let mut cursor = layer.node().walk();
 7747
 7748        while cursor.goto_first_child_for_byte(offset).is_some() {
 7749            if cursor.node().end_byte() == offset {
 7750                cursor.goto_next_sibling();
 7751            }
 7752        }
 7753
 7754        // Ascend to the smallest ancestor that contains the range and has a task.
 7755        loop {
 7756            let node = cursor.node();
 7757            let node_range = node.byte_range();
 7758            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7759
 7760            // Check if this node contains our offset
 7761            if node_range.start <= offset && node_range.end >= offset {
 7762                // If it contains offset, check for task
 7763                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7764                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7765                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7766                }
 7767            }
 7768
 7769            if !cursor.goto_parent() {
 7770                break;
 7771            }
 7772        }
 7773        None
 7774    }
 7775
 7776    fn render_run_indicator(
 7777        &self,
 7778        _style: &EditorStyle,
 7779        is_active: bool,
 7780        row: DisplayRow,
 7781        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7782        cx: &mut Context<Self>,
 7783    ) -> IconButton {
 7784        let color = Color::Muted;
 7785        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7786
 7787        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7788            .shape(ui::IconButtonShape::Square)
 7789            .icon_size(IconSize::XSmall)
 7790            .icon_color(color)
 7791            .toggle_state(is_active)
 7792            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7793                let quick_launch = e.down.button == MouseButton::Left;
 7794                window.focus(&editor.focus_handle(cx));
 7795                editor.toggle_code_actions(
 7796                    &ToggleCodeActions {
 7797                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7798                        quick_launch,
 7799                    },
 7800                    window,
 7801                    cx,
 7802                );
 7803            }))
 7804            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7805                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7806            }))
 7807    }
 7808
 7809    pub fn context_menu_visible(&self) -> bool {
 7810        !self.edit_prediction_preview_is_active()
 7811            && self
 7812                .context_menu
 7813                .borrow()
 7814                .as_ref()
 7815                .map_or(false, |menu| menu.visible())
 7816    }
 7817
 7818    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7819        self.context_menu
 7820            .borrow()
 7821            .as_ref()
 7822            .map(|menu| menu.origin())
 7823    }
 7824
 7825    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7826        self.context_menu_options = Some(options);
 7827    }
 7828
 7829    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7830    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7831
 7832    fn render_edit_prediction_popover(
 7833        &mut self,
 7834        text_bounds: &Bounds<Pixels>,
 7835        content_origin: gpui::Point<Pixels>,
 7836        right_margin: Pixels,
 7837        editor_snapshot: &EditorSnapshot,
 7838        visible_row_range: Range<DisplayRow>,
 7839        scroll_top: f32,
 7840        scroll_bottom: f32,
 7841        line_layouts: &[LineWithInvisibles],
 7842        line_height: Pixels,
 7843        scroll_pixel_position: gpui::Point<Pixels>,
 7844        newest_selection_head: Option<DisplayPoint>,
 7845        editor_width: Pixels,
 7846        style: &EditorStyle,
 7847        window: &mut Window,
 7848        cx: &mut App,
 7849    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7850        if self.mode().is_minimap() {
 7851            return None;
 7852        }
 7853        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7854
 7855        if self.edit_prediction_visible_in_cursor_popover(true) {
 7856            return None;
 7857        }
 7858
 7859        match &active_inline_completion.completion {
 7860            InlineCompletion::Move { target, .. } => {
 7861                let target_display_point = target.to_display_point(editor_snapshot);
 7862
 7863                if self.edit_prediction_requires_modifier() {
 7864                    if !self.edit_prediction_preview_is_active() {
 7865                        return None;
 7866                    }
 7867
 7868                    self.render_edit_prediction_modifier_jump_popover(
 7869                        text_bounds,
 7870                        content_origin,
 7871                        visible_row_range,
 7872                        line_layouts,
 7873                        line_height,
 7874                        scroll_pixel_position,
 7875                        newest_selection_head,
 7876                        target_display_point,
 7877                        window,
 7878                        cx,
 7879                    )
 7880                } else {
 7881                    self.render_edit_prediction_eager_jump_popover(
 7882                        text_bounds,
 7883                        content_origin,
 7884                        editor_snapshot,
 7885                        visible_row_range,
 7886                        scroll_top,
 7887                        scroll_bottom,
 7888                        line_height,
 7889                        scroll_pixel_position,
 7890                        target_display_point,
 7891                        editor_width,
 7892                        window,
 7893                        cx,
 7894                    )
 7895                }
 7896            }
 7897            InlineCompletion::Edit {
 7898                display_mode: EditDisplayMode::Inline,
 7899                ..
 7900            } => None,
 7901            InlineCompletion::Edit {
 7902                display_mode: EditDisplayMode::TabAccept,
 7903                edits,
 7904                ..
 7905            } => {
 7906                let range = &edits.first()?.0;
 7907                let target_display_point = range.end.to_display_point(editor_snapshot);
 7908
 7909                self.render_edit_prediction_end_of_line_popover(
 7910                    "Accept",
 7911                    editor_snapshot,
 7912                    visible_row_range,
 7913                    target_display_point,
 7914                    line_height,
 7915                    scroll_pixel_position,
 7916                    content_origin,
 7917                    editor_width,
 7918                    window,
 7919                    cx,
 7920                )
 7921            }
 7922            InlineCompletion::Edit {
 7923                edits,
 7924                edit_preview,
 7925                display_mode: EditDisplayMode::DiffPopover,
 7926                snapshot,
 7927            } => self.render_edit_prediction_diff_popover(
 7928                text_bounds,
 7929                content_origin,
 7930                right_margin,
 7931                editor_snapshot,
 7932                visible_row_range,
 7933                line_layouts,
 7934                line_height,
 7935                scroll_pixel_position,
 7936                newest_selection_head,
 7937                editor_width,
 7938                style,
 7939                edits,
 7940                edit_preview,
 7941                snapshot,
 7942                window,
 7943                cx,
 7944            ),
 7945        }
 7946    }
 7947
 7948    fn render_edit_prediction_modifier_jump_popover(
 7949        &mut self,
 7950        text_bounds: &Bounds<Pixels>,
 7951        content_origin: gpui::Point<Pixels>,
 7952        visible_row_range: Range<DisplayRow>,
 7953        line_layouts: &[LineWithInvisibles],
 7954        line_height: Pixels,
 7955        scroll_pixel_position: gpui::Point<Pixels>,
 7956        newest_selection_head: Option<DisplayPoint>,
 7957        target_display_point: DisplayPoint,
 7958        window: &mut Window,
 7959        cx: &mut App,
 7960    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7961        let scrolled_content_origin =
 7962            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7963
 7964        const SCROLL_PADDING_Y: Pixels = px(12.);
 7965
 7966        if target_display_point.row() < visible_row_range.start {
 7967            return self.render_edit_prediction_scroll_popover(
 7968                |_| SCROLL_PADDING_Y,
 7969                IconName::ArrowUp,
 7970                visible_row_range,
 7971                line_layouts,
 7972                newest_selection_head,
 7973                scrolled_content_origin,
 7974                window,
 7975                cx,
 7976            );
 7977        } else if target_display_point.row() >= visible_row_range.end {
 7978            return self.render_edit_prediction_scroll_popover(
 7979                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7980                IconName::ArrowDown,
 7981                visible_row_range,
 7982                line_layouts,
 7983                newest_selection_head,
 7984                scrolled_content_origin,
 7985                window,
 7986                cx,
 7987            );
 7988        }
 7989
 7990        const POLE_WIDTH: Pixels = px(2.);
 7991
 7992        let line_layout =
 7993            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7994        let target_column = target_display_point.column() as usize;
 7995
 7996        let target_x = line_layout.x_for_index(target_column);
 7997        let target_y =
 7998            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7999
 8000        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8001
 8002        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8003        border_color.l += 0.001;
 8004
 8005        let mut element = v_flex()
 8006            .items_end()
 8007            .when(flag_on_right, |el| el.items_start())
 8008            .child(if flag_on_right {
 8009                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8010                    .rounded_bl(px(0.))
 8011                    .rounded_tl(px(0.))
 8012                    .border_l_2()
 8013                    .border_color(border_color)
 8014            } else {
 8015                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8016                    .rounded_br(px(0.))
 8017                    .rounded_tr(px(0.))
 8018                    .border_r_2()
 8019                    .border_color(border_color)
 8020            })
 8021            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8022            .into_any();
 8023
 8024        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8025
 8026        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8027            - point(
 8028                if flag_on_right {
 8029                    POLE_WIDTH
 8030                } else {
 8031                    size.width - POLE_WIDTH
 8032                },
 8033                size.height - line_height,
 8034            );
 8035
 8036        origin.x = origin.x.max(content_origin.x);
 8037
 8038        element.prepaint_at(origin, window, cx);
 8039
 8040        Some((element, origin))
 8041    }
 8042
 8043    fn render_edit_prediction_scroll_popover(
 8044        &mut self,
 8045        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8046        scroll_icon: IconName,
 8047        visible_row_range: Range<DisplayRow>,
 8048        line_layouts: &[LineWithInvisibles],
 8049        newest_selection_head: Option<DisplayPoint>,
 8050        scrolled_content_origin: gpui::Point<Pixels>,
 8051        window: &mut Window,
 8052        cx: &mut App,
 8053    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8054        let mut element = self
 8055            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8056            .into_any();
 8057
 8058        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8059
 8060        let cursor = newest_selection_head?;
 8061        let cursor_row_layout =
 8062            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8063        let cursor_column = cursor.column() as usize;
 8064
 8065        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8066
 8067        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8068
 8069        element.prepaint_at(origin, window, cx);
 8070        Some((element, origin))
 8071    }
 8072
 8073    fn render_edit_prediction_eager_jump_popover(
 8074        &mut self,
 8075        text_bounds: &Bounds<Pixels>,
 8076        content_origin: gpui::Point<Pixels>,
 8077        editor_snapshot: &EditorSnapshot,
 8078        visible_row_range: Range<DisplayRow>,
 8079        scroll_top: f32,
 8080        scroll_bottom: f32,
 8081        line_height: Pixels,
 8082        scroll_pixel_position: gpui::Point<Pixels>,
 8083        target_display_point: DisplayPoint,
 8084        editor_width: Pixels,
 8085        window: &mut Window,
 8086        cx: &mut App,
 8087    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8088        if target_display_point.row().as_f32() < scroll_top {
 8089            let mut element = self
 8090                .render_edit_prediction_line_popover(
 8091                    "Jump to Edit",
 8092                    Some(IconName::ArrowUp),
 8093                    window,
 8094                    cx,
 8095                )?
 8096                .into_any();
 8097
 8098            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8099            let offset = point(
 8100                (text_bounds.size.width - size.width) / 2.,
 8101                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8102            );
 8103
 8104            let origin = text_bounds.origin + offset;
 8105            element.prepaint_at(origin, window, cx);
 8106            Some((element, origin))
 8107        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8108            let mut element = self
 8109                .render_edit_prediction_line_popover(
 8110                    "Jump to Edit",
 8111                    Some(IconName::ArrowDown),
 8112                    window,
 8113                    cx,
 8114                )?
 8115                .into_any();
 8116
 8117            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8118            let offset = point(
 8119                (text_bounds.size.width - size.width) / 2.,
 8120                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8121            );
 8122
 8123            let origin = text_bounds.origin + offset;
 8124            element.prepaint_at(origin, window, cx);
 8125            Some((element, origin))
 8126        } else {
 8127            self.render_edit_prediction_end_of_line_popover(
 8128                "Jump to Edit",
 8129                editor_snapshot,
 8130                visible_row_range,
 8131                target_display_point,
 8132                line_height,
 8133                scroll_pixel_position,
 8134                content_origin,
 8135                editor_width,
 8136                window,
 8137                cx,
 8138            )
 8139        }
 8140    }
 8141
 8142    fn render_edit_prediction_end_of_line_popover(
 8143        self: &mut Editor,
 8144        label: &'static str,
 8145        editor_snapshot: &EditorSnapshot,
 8146        visible_row_range: Range<DisplayRow>,
 8147        target_display_point: DisplayPoint,
 8148        line_height: Pixels,
 8149        scroll_pixel_position: gpui::Point<Pixels>,
 8150        content_origin: gpui::Point<Pixels>,
 8151        editor_width: Pixels,
 8152        window: &mut Window,
 8153        cx: &mut App,
 8154    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8155        let target_line_end = DisplayPoint::new(
 8156            target_display_point.row(),
 8157            editor_snapshot.line_len(target_display_point.row()),
 8158        );
 8159
 8160        let mut element = self
 8161            .render_edit_prediction_line_popover(label, None, window, cx)?
 8162            .into_any();
 8163
 8164        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8165
 8166        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8167
 8168        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8169        let mut origin = start_point
 8170            + line_origin
 8171            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8172        origin.x = origin.x.max(content_origin.x);
 8173
 8174        let max_x = content_origin.x + editor_width - size.width;
 8175
 8176        if origin.x > max_x {
 8177            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8178
 8179            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8180                origin.y += offset;
 8181                IconName::ArrowUp
 8182            } else {
 8183                origin.y -= offset;
 8184                IconName::ArrowDown
 8185            };
 8186
 8187            element = self
 8188                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8189                .into_any();
 8190
 8191            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8192
 8193            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8194        }
 8195
 8196        element.prepaint_at(origin, window, cx);
 8197        Some((element, origin))
 8198    }
 8199
 8200    fn render_edit_prediction_diff_popover(
 8201        self: &Editor,
 8202        text_bounds: &Bounds<Pixels>,
 8203        content_origin: gpui::Point<Pixels>,
 8204        right_margin: Pixels,
 8205        editor_snapshot: &EditorSnapshot,
 8206        visible_row_range: Range<DisplayRow>,
 8207        line_layouts: &[LineWithInvisibles],
 8208        line_height: Pixels,
 8209        scroll_pixel_position: gpui::Point<Pixels>,
 8210        newest_selection_head: Option<DisplayPoint>,
 8211        editor_width: Pixels,
 8212        style: &EditorStyle,
 8213        edits: &Vec<(Range<Anchor>, String)>,
 8214        edit_preview: &Option<language::EditPreview>,
 8215        snapshot: &language::BufferSnapshot,
 8216        window: &mut Window,
 8217        cx: &mut App,
 8218    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8219        let edit_start = edits
 8220            .first()
 8221            .unwrap()
 8222            .0
 8223            .start
 8224            .to_display_point(editor_snapshot);
 8225        let edit_end = edits
 8226            .last()
 8227            .unwrap()
 8228            .0
 8229            .end
 8230            .to_display_point(editor_snapshot);
 8231
 8232        let is_visible = visible_row_range.contains(&edit_start.row())
 8233            || visible_row_range.contains(&edit_end.row());
 8234        if !is_visible {
 8235            return None;
 8236        }
 8237
 8238        let highlighted_edits =
 8239            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8240
 8241        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8242        let line_count = highlighted_edits.text.lines().count();
 8243
 8244        const BORDER_WIDTH: Pixels = px(1.);
 8245
 8246        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8247        let has_keybind = keybind.is_some();
 8248
 8249        let mut element = h_flex()
 8250            .items_start()
 8251            .child(
 8252                h_flex()
 8253                    .bg(cx.theme().colors().editor_background)
 8254                    .border(BORDER_WIDTH)
 8255                    .shadow_sm()
 8256                    .border_color(cx.theme().colors().border)
 8257                    .rounded_l_lg()
 8258                    .when(line_count > 1, |el| el.rounded_br_lg())
 8259                    .pr_1()
 8260                    .child(styled_text),
 8261            )
 8262            .child(
 8263                h_flex()
 8264                    .h(line_height + BORDER_WIDTH * 2.)
 8265                    .px_1p5()
 8266                    .gap_1()
 8267                    // Workaround: For some reason, there's a gap if we don't do this
 8268                    .ml(-BORDER_WIDTH)
 8269                    .shadow(vec![gpui::BoxShadow {
 8270                        color: gpui::black().opacity(0.05),
 8271                        offset: point(px(1.), px(1.)),
 8272                        blur_radius: px(2.),
 8273                        spread_radius: px(0.),
 8274                    }])
 8275                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8276                    .border(BORDER_WIDTH)
 8277                    .border_color(cx.theme().colors().border)
 8278                    .rounded_r_lg()
 8279                    .id("edit_prediction_diff_popover_keybind")
 8280                    .when(!has_keybind, |el| {
 8281                        let status_colors = cx.theme().status();
 8282
 8283                        el.bg(status_colors.error_background)
 8284                            .border_color(status_colors.error.opacity(0.6))
 8285                            .child(Icon::new(IconName::Info).color(Color::Error))
 8286                            .cursor_default()
 8287                            .hoverable_tooltip(move |_window, cx| {
 8288                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8289                            })
 8290                    })
 8291                    .children(keybind),
 8292            )
 8293            .into_any();
 8294
 8295        let longest_row =
 8296            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8297        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8298            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8299        } else {
 8300            layout_line(
 8301                longest_row,
 8302                editor_snapshot,
 8303                style,
 8304                editor_width,
 8305                |_| false,
 8306                window,
 8307                cx,
 8308            )
 8309            .width
 8310        };
 8311
 8312        let viewport_bounds =
 8313            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8314                right: -right_margin,
 8315                ..Default::default()
 8316            });
 8317
 8318        let x_after_longest =
 8319            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8320                - scroll_pixel_position.x;
 8321
 8322        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8323
 8324        // Fully visible if it can be displayed within the window (allow overlapping other
 8325        // panes). However, this is only allowed if the popover starts within text_bounds.
 8326        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8327            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8328
 8329        let mut origin = if can_position_to_the_right {
 8330            point(
 8331                x_after_longest,
 8332                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8333                    - scroll_pixel_position.y,
 8334            )
 8335        } else {
 8336            let cursor_row = newest_selection_head.map(|head| head.row());
 8337            let above_edit = edit_start
 8338                .row()
 8339                .0
 8340                .checked_sub(line_count as u32)
 8341                .map(DisplayRow);
 8342            let below_edit = Some(edit_end.row() + 1);
 8343            let above_cursor =
 8344                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8345            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8346
 8347            // Place the edit popover adjacent to the edit if there is a location
 8348            // available that is onscreen and does not obscure the cursor. Otherwise,
 8349            // place it adjacent to the cursor.
 8350            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8351                .into_iter()
 8352                .flatten()
 8353                .find(|&start_row| {
 8354                    let end_row = start_row + line_count as u32;
 8355                    visible_row_range.contains(&start_row)
 8356                        && visible_row_range.contains(&end_row)
 8357                        && cursor_row.map_or(true, |cursor_row| {
 8358                            !((start_row..end_row).contains(&cursor_row))
 8359                        })
 8360                })?;
 8361
 8362            content_origin
 8363                + point(
 8364                    -scroll_pixel_position.x,
 8365                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8366                )
 8367        };
 8368
 8369        origin.x -= BORDER_WIDTH;
 8370
 8371        window.defer_draw(element, origin, 1);
 8372
 8373        // Do not return an element, since it will already be drawn due to defer_draw.
 8374        None
 8375    }
 8376
 8377    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8378        px(30.)
 8379    }
 8380
 8381    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8382        if self.read_only(cx) {
 8383            cx.theme().players().read_only()
 8384        } else {
 8385            self.style.as_ref().unwrap().local_player
 8386        }
 8387    }
 8388
 8389    fn render_edit_prediction_accept_keybind(
 8390        &self,
 8391        window: &mut Window,
 8392        cx: &App,
 8393    ) -> Option<AnyElement> {
 8394        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8395        let accept_keystroke = accept_binding.keystroke()?;
 8396
 8397        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8398
 8399        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8400            Color::Accent
 8401        } else {
 8402            Color::Muted
 8403        };
 8404
 8405        h_flex()
 8406            .px_0p5()
 8407            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8408            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8409            .text_size(TextSize::XSmall.rems(cx))
 8410            .child(h_flex().children(ui::render_modifiers(
 8411                &accept_keystroke.modifiers,
 8412                PlatformStyle::platform(),
 8413                Some(modifiers_color),
 8414                Some(IconSize::XSmall.rems().into()),
 8415                true,
 8416            )))
 8417            .when(is_platform_style_mac, |parent| {
 8418                parent.child(accept_keystroke.key.clone())
 8419            })
 8420            .when(!is_platform_style_mac, |parent| {
 8421                parent.child(
 8422                    Key::new(
 8423                        util::capitalize(&accept_keystroke.key),
 8424                        Some(Color::Default),
 8425                    )
 8426                    .size(Some(IconSize::XSmall.rems().into())),
 8427                )
 8428            })
 8429            .into_any()
 8430            .into()
 8431    }
 8432
 8433    fn render_edit_prediction_line_popover(
 8434        &self,
 8435        label: impl Into<SharedString>,
 8436        icon: Option<IconName>,
 8437        window: &mut Window,
 8438        cx: &App,
 8439    ) -> Option<Stateful<Div>> {
 8440        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8441
 8442        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8443        let has_keybind = keybind.is_some();
 8444
 8445        let result = h_flex()
 8446            .id("ep-line-popover")
 8447            .py_0p5()
 8448            .pl_1()
 8449            .pr(padding_right)
 8450            .gap_1()
 8451            .rounded_md()
 8452            .border_1()
 8453            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8454            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8455            .shadow_sm()
 8456            .when(!has_keybind, |el| {
 8457                let status_colors = cx.theme().status();
 8458
 8459                el.bg(status_colors.error_background)
 8460                    .border_color(status_colors.error.opacity(0.6))
 8461                    .pl_2()
 8462                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8463                    .cursor_default()
 8464                    .hoverable_tooltip(move |_window, cx| {
 8465                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8466                    })
 8467            })
 8468            .children(keybind)
 8469            .child(
 8470                Label::new(label)
 8471                    .size(LabelSize::Small)
 8472                    .when(!has_keybind, |el| {
 8473                        el.color(cx.theme().status().error.into()).strikethrough()
 8474                    }),
 8475            )
 8476            .when(!has_keybind, |el| {
 8477                el.child(
 8478                    h_flex().ml_1().child(
 8479                        Icon::new(IconName::Info)
 8480                            .size(IconSize::Small)
 8481                            .color(cx.theme().status().error.into()),
 8482                    ),
 8483                )
 8484            })
 8485            .when_some(icon, |element, icon| {
 8486                element.child(
 8487                    div()
 8488                        .mt(px(1.5))
 8489                        .child(Icon::new(icon).size(IconSize::Small)),
 8490                )
 8491            });
 8492
 8493        Some(result)
 8494    }
 8495
 8496    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8497        let accent_color = cx.theme().colors().text_accent;
 8498        let editor_bg_color = cx.theme().colors().editor_background;
 8499        editor_bg_color.blend(accent_color.opacity(0.1))
 8500    }
 8501
 8502    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8503        let accent_color = cx.theme().colors().text_accent;
 8504        let editor_bg_color = cx.theme().colors().editor_background;
 8505        editor_bg_color.blend(accent_color.opacity(0.6))
 8506    }
 8507
 8508    fn render_edit_prediction_cursor_popover(
 8509        &self,
 8510        min_width: Pixels,
 8511        max_width: Pixels,
 8512        cursor_point: Point,
 8513        style: &EditorStyle,
 8514        accept_keystroke: Option<&gpui::Keystroke>,
 8515        _window: &Window,
 8516        cx: &mut Context<Editor>,
 8517    ) -> Option<AnyElement> {
 8518        let provider = self.edit_prediction_provider.as_ref()?;
 8519
 8520        if provider.provider.needs_terms_acceptance(cx) {
 8521            return Some(
 8522                h_flex()
 8523                    .min_w(min_width)
 8524                    .flex_1()
 8525                    .px_2()
 8526                    .py_1()
 8527                    .gap_3()
 8528                    .elevation_2(cx)
 8529                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8530                    .id("accept-terms")
 8531                    .cursor_pointer()
 8532                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8533                    .on_click(cx.listener(|this, _event, window, cx| {
 8534                        cx.stop_propagation();
 8535                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8536                        window.dispatch_action(
 8537                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8538                            cx,
 8539                        );
 8540                    }))
 8541                    .child(
 8542                        h_flex()
 8543                            .flex_1()
 8544                            .gap_2()
 8545                            .child(Icon::new(IconName::ZedPredict))
 8546                            .child(Label::new("Accept Terms of Service"))
 8547                            .child(div().w_full())
 8548                            .child(
 8549                                Icon::new(IconName::ArrowUpRight)
 8550                                    .color(Color::Muted)
 8551                                    .size(IconSize::Small),
 8552                            )
 8553                            .into_any_element(),
 8554                    )
 8555                    .into_any(),
 8556            );
 8557        }
 8558
 8559        let is_refreshing = provider.provider.is_refreshing(cx);
 8560
 8561        fn pending_completion_container() -> Div {
 8562            h_flex()
 8563                .h_full()
 8564                .flex_1()
 8565                .gap_2()
 8566                .child(Icon::new(IconName::ZedPredict))
 8567        }
 8568
 8569        let completion = match &self.active_inline_completion {
 8570            Some(prediction) => {
 8571                if !self.has_visible_completions_menu() {
 8572                    const RADIUS: Pixels = px(6.);
 8573                    const BORDER_WIDTH: Pixels = px(1.);
 8574
 8575                    return Some(
 8576                        h_flex()
 8577                            .elevation_2(cx)
 8578                            .border(BORDER_WIDTH)
 8579                            .border_color(cx.theme().colors().border)
 8580                            .when(accept_keystroke.is_none(), |el| {
 8581                                el.border_color(cx.theme().status().error)
 8582                            })
 8583                            .rounded(RADIUS)
 8584                            .rounded_tl(px(0.))
 8585                            .overflow_hidden()
 8586                            .child(div().px_1p5().child(match &prediction.completion {
 8587                                InlineCompletion::Move { target, snapshot } => {
 8588                                    use text::ToPoint as _;
 8589                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8590                                    {
 8591                                        Icon::new(IconName::ZedPredictDown)
 8592                                    } else {
 8593                                        Icon::new(IconName::ZedPredictUp)
 8594                                    }
 8595                                }
 8596                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8597                            }))
 8598                            .child(
 8599                                h_flex()
 8600                                    .gap_1()
 8601                                    .py_1()
 8602                                    .px_2()
 8603                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8604                                    .border_l_1()
 8605                                    .border_color(cx.theme().colors().border)
 8606                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8607                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8608                                        el.child(
 8609                                            Label::new("Hold")
 8610                                                .size(LabelSize::Small)
 8611                                                .when(accept_keystroke.is_none(), |el| {
 8612                                                    el.strikethrough()
 8613                                                })
 8614                                                .line_height_style(LineHeightStyle::UiLabel),
 8615                                        )
 8616                                    })
 8617                                    .id("edit_prediction_cursor_popover_keybind")
 8618                                    .when(accept_keystroke.is_none(), |el| {
 8619                                        let status_colors = cx.theme().status();
 8620
 8621                                        el.bg(status_colors.error_background)
 8622                                            .border_color(status_colors.error.opacity(0.6))
 8623                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8624                                            .cursor_default()
 8625                                            .hoverable_tooltip(move |_window, cx| {
 8626                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8627                                                    .into()
 8628                                            })
 8629                                    })
 8630                                    .when_some(
 8631                                        accept_keystroke.as_ref(),
 8632                                        |el, accept_keystroke| {
 8633                                            el.child(h_flex().children(ui::render_modifiers(
 8634                                                &accept_keystroke.modifiers,
 8635                                                PlatformStyle::platform(),
 8636                                                Some(Color::Default),
 8637                                                Some(IconSize::XSmall.rems().into()),
 8638                                                false,
 8639                                            )))
 8640                                        },
 8641                                    ),
 8642                            )
 8643                            .into_any(),
 8644                    );
 8645                }
 8646
 8647                self.render_edit_prediction_cursor_popover_preview(
 8648                    prediction,
 8649                    cursor_point,
 8650                    style,
 8651                    cx,
 8652                )?
 8653            }
 8654
 8655            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8656                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8657                    stale_completion,
 8658                    cursor_point,
 8659                    style,
 8660                    cx,
 8661                )?,
 8662
 8663                None => {
 8664                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8665                }
 8666            },
 8667
 8668            None => pending_completion_container().child(Label::new("No Prediction")),
 8669        };
 8670
 8671        let completion = if is_refreshing {
 8672            completion
 8673                .with_animation(
 8674                    "loading-completion",
 8675                    Animation::new(Duration::from_secs(2))
 8676                        .repeat()
 8677                        .with_easing(pulsating_between(0.4, 0.8)),
 8678                    |label, delta| label.opacity(delta),
 8679                )
 8680                .into_any_element()
 8681        } else {
 8682            completion.into_any_element()
 8683        };
 8684
 8685        let has_completion = self.active_inline_completion.is_some();
 8686
 8687        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8688        Some(
 8689            h_flex()
 8690                .min_w(min_width)
 8691                .max_w(max_width)
 8692                .flex_1()
 8693                .elevation_2(cx)
 8694                .border_color(cx.theme().colors().border)
 8695                .child(
 8696                    div()
 8697                        .flex_1()
 8698                        .py_1()
 8699                        .px_2()
 8700                        .overflow_hidden()
 8701                        .child(completion),
 8702                )
 8703                .when_some(accept_keystroke, |el, accept_keystroke| {
 8704                    if !accept_keystroke.modifiers.modified() {
 8705                        return el;
 8706                    }
 8707
 8708                    el.child(
 8709                        h_flex()
 8710                            .h_full()
 8711                            .border_l_1()
 8712                            .rounded_r_lg()
 8713                            .border_color(cx.theme().colors().border)
 8714                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8715                            .gap_1()
 8716                            .py_1()
 8717                            .px_2()
 8718                            .child(
 8719                                h_flex()
 8720                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8721                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8722                                    .child(h_flex().children(ui::render_modifiers(
 8723                                        &accept_keystroke.modifiers,
 8724                                        PlatformStyle::platform(),
 8725                                        Some(if !has_completion {
 8726                                            Color::Muted
 8727                                        } else {
 8728                                            Color::Default
 8729                                        }),
 8730                                        None,
 8731                                        false,
 8732                                    ))),
 8733                            )
 8734                            .child(Label::new("Preview").into_any_element())
 8735                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8736                    )
 8737                })
 8738                .into_any(),
 8739        )
 8740    }
 8741
 8742    fn render_edit_prediction_cursor_popover_preview(
 8743        &self,
 8744        completion: &InlineCompletionState,
 8745        cursor_point: Point,
 8746        style: &EditorStyle,
 8747        cx: &mut Context<Editor>,
 8748    ) -> Option<Div> {
 8749        use text::ToPoint as _;
 8750
 8751        fn render_relative_row_jump(
 8752            prefix: impl Into<String>,
 8753            current_row: u32,
 8754            target_row: u32,
 8755        ) -> Div {
 8756            let (row_diff, arrow) = if target_row < current_row {
 8757                (current_row - target_row, IconName::ArrowUp)
 8758            } else {
 8759                (target_row - current_row, IconName::ArrowDown)
 8760            };
 8761
 8762            h_flex()
 8763                .child(
 8764                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8765                        .color(Color::Muted)
 8766                        .size(LabelSize::Small),
 8767                )
 8768                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8769        }
 8770
 8771        match &completion.completion {
 8772            InlineCompletion::Move {
 8773                target, snapshot, ..
 8774            } => Some(
 8775                h_flex()
 8776                    .px_2()
 8777                    .gap_2()
 8778                    .flex_1()
 8779                    .child(
 8780                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8781                            Icon::new(IconName::ZedPredictDown)
 8782                        } else {
 8783                            Icon::new(IconName::ZedPredictUp)
 8784                        },
 8785                    )
 8786                    .child(Label::new("Jump to Edit")),
 8787            ),
 8788
 8789            InlineCompletion::Edit {
 8790                edits,
 8791                edit_preview,
 8792                snapshot,
 8793                display_mode: _,
 8794            } => {
 8795                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8796
 8797                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8798                    &snapshot,
 8799                    &edits,
 8800                    edit_preview.as_ref()?,
 8801                    true,
 8802                    cx,
 8803                )
 8804                .first_line_preview();
 8805
 8806                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8807                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8808
 8809                let preview = h_flex()
 8810                    .gap_1()
 8811                    .min_w_16()
 8812                    .child(styled_text)
 8813                    .when(has_more_lines, |parent| parent.child(""));
 8814
 8815                let left = if first_edit_row != cursor_point.row {
 8816                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8817                        .into_any_element()
 8818                } else {
 8819                    Icon::new(IconName::ZedPredict).into_any_element()
 8820                };
 8821
 8822                Some(
 8823                    h_flex()
 8824                        .h_full()
 8825                        .flex_1()
 8826                        .gap_2()
 8827                        .pr_1()
 8828                        .overflow_x_hidden()
 8829                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8830                        .child(left)
 8831                        .child(preview),
 8832                )
 8833            }
 8834        }
 8835    }
 8836
 8837    pub fn render_context_menu(
 8838        &self,
 8839        style: &EditorStyle,
 8840        max_height_in_lines: u32,
 8841        window: &mut Window,
 8842        cx: &mut Context<Editor>,
 8843    ) -> Option<AnyElement> {
 8844        let menu = self.context_menu.borrow();
 8845        let menu = menu.as_ref()?;
 8846        if !menu.visible() {
 8847            return None;
 8848        };
 8849        Some(menu.render(style, max_height_in_lines, window, cx))
 8850    }
 8851
 8852    fn render_context_menu_aside(
 8853        &mut self,
 8854        max_size: Size<Pixels>,
 8855        window: &mut Window,
 8856        cx: &mut Context<Editor>,
 8857    ) -> Option<AnyElement> {
 8858        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8859            if menu.visible() {
 8860                menu.render_aside(max_size, window, cx)
 8861            } else {
 8862                None
 8863            }
 8864        })
 8865    }
 8866
 8867    fn hide_context_menu(
 8868        &mut self,
 8869        window: &mut Window,
 8870        cx: &mut Context<Self>,
 8871    ) -> Option<CodeContextMenu> {
 8872        cx.notify();
 8873        self.completion_tasks.clear();
 8874        let context_menu = self.context_menu.borrow_mut().take();
 8875        self.stale_inline_completion_in_menu.take();
 8876        self.update_visible_inline_completion(window, cx);
 8877        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8878            if let Some(completion_provider) = &self.completion_provider {
 8879                completion_provider.selection_changed(None, window, cx);
 8880            }
 8881        }
 8882        context_menu
 8883    }
 8884
 8885    fn show_snippet_choices(
 8886        &mut self,
 8887        choices: &Vec<String>,
 8888        selection: Range<Anchor>,
 8889        cx: &mut Context<Self>,
 8890    ) {
 8891        if selection.start.buffer_id.is_none() {
 8892            return;
 8893        }
 8894        let buffer_id = selection.start.buffer_id.unwrap();
 8895        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8896        let id = post_inc(&mut self.next_completion_id);
 8897        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8898
 8899        if let Some(buffer) = buffer {
 8900            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8901                CompletionsMenu::new_snippet_choices(
 8902                    id,
 8903                    true,
 8904                    choices,
 8905                    selection,
 8906                    buffer,
 8907                    snippet_sort_order,
 8908                ),
 8909            ));
 8910        }
 8911    }
 8912
 8913    pub fn insert_snippet(
 8914        &mut self,
 8915        insertion_ranges: &[Range<usize>],
 8916        snippet: Snippet,
 8917        window: &mut Window,
 8918        cx: &mut Context<Self>,
 8919    ) -> Result<()> {
 8920        struct Tabstop<T> {
 8921            is_end_tabstop: bool,
 8922            ranges: Vec<Range<T>>,
 8923            choices: Option<Vec<String>>,
 8924        }
 8925
 8926        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8927            let snippet_text: Arc<str> = snippet.text.clone().into();
 8928            let edits = insertion_ranges
 8929                .iter()
 8930                .cloned()
 8931                .map(|range| (range, snippet_text.clone()));
 8932            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8933
 8934            let snapshot = &*buffer.read(cx);
 8935            let snippet = &snippet;
 8936            snippet
 8937                .tabstops
 8938                .iter()
 8939                .map(|tabstop| {
 8940                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8941                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8942                    });
 8943                    let mut tabstop_ranges = tabstop
 8944                        .ranges
 8945                        .iter()
 8946                        .flat_map(|tabstop_range| {
 8947                            let mut delta = 0_isize;
 8948                            insertion_ranges.iter().map(move |insertion_range| {
 8949                                let insertion_start = insertion_range.start as isize + delta;
 8950                                delta +=
 8951                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8952
 8953                                let start = ((insertion_start + tabstop_range.start) as usize)
 8954                                    .min(snapshot.len());
 8955                                let end = ((insertion_start + tabstop_range.end) as usize)
 8956                                    .min(snapshot.len());
 8957                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8958                            })
 8959                        })
 8960                        .collect::<Vec<_>>();
 8961                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8962
 8963                    Tabstop {
 8964                        is_end_tabstop,
 8965                        ranges: tabstop_ranges,
 8966                        choices: tabstop.choices.clone(),
 8967                    }
 8968                })
 8969                .collect::<Vec<_>>()
 8970        });
 8971        if let Some(tabstop) = tabstops.first() {
 8972            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8973                s.select_ranges(tabstop.ranges.iter().cloned());
 8974            });
 8975
 8976            if let Some(choices) = &tabstop.choices {
 8977                if let Some(selection) = tabstop.ranges.first() {
 8978                    self.show_snippet_choices(choices, selection.clone(), cx)
 8979                }
 8980            }
 8981
 8982            // If we're already at the last tabstop and it's at the end of the snippet,
 8983            // we're done, we don't need to keep the state around.
 8984            if !tabstop.is_end_tabstop {
 8985                let choices = tabstops
 8986                    .iter()
 8987                    .map(|tabstop| tabstop.choices.clone())
 8988                    .collect();
 8989
 8990                let ranges = tabstops
 8991                    .into_iter()
 8992                    .map(|tabstop| tabstop.ranges)
 8993                    .collect::<Vec<_>>();
 8994
 8995                self.snippet_stack.push(SnippetState {
 8996                    active_index: 0,
 8997                    ranges,
 8998                    choices,
 8999                });
 9000            }
 9001
 9002            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9003            if self.autoclose_regions.is_empty() {
 9004                let snapshot = self.buffer.read(cx).snapshot(cx);
 9005                for selection in &mut self.selections.all::<Point>(cx) {
 9006                    let selection_head = selection.head();
 9007                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9008                        continue;
 9009                    };
 9010
 9011                    let mut bracket_pair = None;
 9012                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9013                    let prev_chars = snapshot
 9014                        .reversed_chars_at(selection_head)
 9015                        .collect::<String>();
 9016                    for (pair, enabled) in scope.brackets() {
 9017                        if enabled
 9018                            && pair.close
 9019                            && prev_chars.starts_with(pair.start.as_str())
 9020                            && next_chars.starts_with(pair.end.as_str())
 9021                        {
 9022                            bracket_pair = Some(pair.clone());
 9023                            break;
 9024                        }
 9025                    }
 9026                    if let Some(pair) = bracket_pair {
 9027                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9028                        let autoclose_enabled =
 9029                            self.use_autoclose && snapshot_settings.use_autoclose;
 9030                        if autoclose_enabled {
 9031                            let start = snapshot.anchor_after(selection_head);
 9032                            let end = snapshot.anchor_after(selection_head);
 9033                            self.autoclose_regions.push(AutocloseRegion {
 9034                                selection_id: selection.id,
 9035                                range: start..end,
 9036                                pair,
 9037                            });
 9038                        }
 9039                    }
 9040                }
 9041            }
 9042        }
 9043        Ok(())
 9044    }
 9045
 9046    pub fn move_to_next_snippet_tabstop(
 9047        &mut self,
 9048        window: &mut Window,
 9049        cx: &mut Context<Self>,
 9050    ) -> bool {
 9051        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9052    }
 9053
 9054    pub fn move_to_prev_snippet_tabstop(
 9055        &mut self,
 9056        window: &mut Window,
 9057        cx: &mut Context<Self>,
 9058    ) -> bool {
 9059        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9060    }
 9061
 9062    pub fn move_to_snippet_tabstop(
 9063        &mut self,
 9064        bias: Bias,
 9065        window: &mut Window,
 9066        cx: &mut Context<Self>,
 9067    ) -> bool {
 9068        if let Some(mut snippet) = self.snippet_stack.pop() {
 9069            match bias {
 9070                Bias::Left => {
 9071                    if snippet.active_index > 0 {
 9072                        snippet.active_index -= 1;
 9073                    } else {
 9074                        self.snippet_stack.push(snippet);
 9075                        return false;
 9076                    }
 9077                }
 9078                Bias::Right => {
 9079                    if snippet.active_index + 1 < snippet.ranges.len() {
 9080                        snippet.active_index += 1;
 9081                    } else {
 9082                        self.snippet_stack.push(snippet);
 9083                        return false;
 9084                    }
 9085                }
 9086            }
 9087            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9088                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9089                    s.select_anchor_ranges(current_ranges.iter().cloned())
 9090                });
 9091
 9092                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9093                    if let Some(selection) = current_ranges.first() {
 9094                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9095                    }
 9096                }
 9097
 9098                // If snippet state is not at the last tabstop, push it back on the stack
 9099                if snippet.active_index + 1 < snippet.ranges.len() {
 9100                    self.snippet_stack.push(snippet);
 9101                }
 9102                return true;
 9103            }
 9104        }
 9105
 9106        false
 9107    }
 9108
 9109    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9110        self.transact(window, cx, |this, window, cx| {
 9111            this.select_all(&SelectAll, window, cx);
 9112            this.insert("", window, cx);
 9113        });
 9114    }
 9115
 9116    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9117        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9118        self.transact(window, cx, |this, window, cx| {
 9119            this.select_autoclose_pair(window, cx);
 9120            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9121            if !this.linked_edit_ranges.is_empty() {
 9122                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9123                let snapshot = this.buffer.read(cx).snapshot(cx);
 9124
 9125                for selection in selections.iter() {
 9126                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9127                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9128                    if selection_start.buffer_id != selection_end.buffer_id {
 9129                        continue;
 9130                    }
 9131                    if let Some(ranges) =
 9132                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9133                    {
 9134                        for (buffer, entries) in ranges {
 9135                            linked_ranges.entry(buffer).or_default().extend(entries);
 9136                        }
 9137                    }
 9138                }
 9139            }
 9140
 9141            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9142            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9143            for selection in &mut selections {
 9144                if selection.is_empty() {
 9145                    let old_head = selection.head();
 9146                    let mut new_head =
 9147                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9148                            .to_point(&display_map);
 9149                    if let Some((buffer, line_buffer_range)) = display_map
 9150                        .buffer_snapshot
 9151                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9152                    {
 9153                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9154                        let indent_len = match indent_size.kind {
 9155                            IndentKind::Space => {
 9156                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9157                            }
 9158                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9159                        };
 9160                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9161                            let indent_len = indent_len.get();
 9162                            new_head = cmp::min(
 9163                                new_head,
 9164                                MultiBufferPoint::new(
 9165                                    old_head.row,
 9166                                    ((old_head.column - 1) / indent_len) * indent_len,
 9167                                ),
 9168                            );
 9169                        }
 9170                    }
 9171
 9172                    selection.set_head(new_head, SelectionGoal::None);
 9173                }
 9174            }
 9175
 9176            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9177                s.select(selections)
 9178            });
 9179            this.insert("", window, cx);
 9180            let empty_str: Arc<str> = Arc::from("");
 9181            for (buffer, edits) in linked_ranges {
 9182                let snapshot = buffer.read(cx).snapshot();
 9183                use text::ToPoint as TP;
 9184
 9185                let edits = edits
 9186                    .into_iter()
 9187                    .map(|range| {
 9188                        let end_point = TP::to_point(&range.end, &snapshot);
 9189                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9190
 9191                        if end_point == start_point {
 9192                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9193                                .saturating_sub(1);
 9194                            start_point =
 9195                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9196                        };
 9197
 9198                        (start_point..end_point, empty_str.clone())
 9199                    })
 9200                    .sorted_by_key(|(range, _)| range.start)
 9201                    .collect::<Vec<_>>();
 9202                buffer.update(cx, |this, cx| {
 9203                    this.edit(edits, None, cx);
 9204                })
 9205            }
 9206            this.refresh_inline_completion(true, false, window, cx);
 9207            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9208        });
 9209    }
 9210
 9211    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9212        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9213        self.transact(window, cx, |this, window, cx| {
 9214            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9215                s.move_with(|map, selection| {
 9216                    if selection.is_empty() {
 9217                        let cursor = movement::right(map, selection.head());
 9218                        selection.end = cursor;
 9219                        selection.reversed = true;
 9220                        selection.goal = SelectionGoal::None;
 9221                    }
 9222                })
 9223            });
 9224            this.insert("", window, cx);
 9225            this.refresh_inline_completion(true, false, window, cx);
 9226        });
 9227    }
 9228
 9229    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9230        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9231        if self.move_to_prev_snippet_tabstop(window, cx) {
 9232            return;
 9233        }
 9234        self.outdent(&Outdent, window, cx);
 9235    }
 9236
 9237    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9238        if self.move_to_next_snippet_tabstop(window, cx) {
 9239            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9240            return;
 9241        }
 9242        if self.read_only(cx) {
 9243            return;
 9244        }
 9245        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9246        let mut selections = self.selections.all_adjusted(cx);
 9247        let buffer = self.buffer.read(cx);
 9248        let snapshot = buffer.snapshot(cx);
 9249        let rows_iter = selections.iter().map(|s| s.head().row);
 9250        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9251
 9252        let has_some_cursor_in_whitespace = selections
 9253            .iter()
 9254            .filter(|selection| selection.is_empty())
 9255            .any(|selection| {
 9256                let cursor = selection.head();
 9257                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9258                cursor.column < current_indent.len
 9259            });
 9260
 9261        let mut edits = Vec::new();
 9262        let mut prev_edited_row = 0;
 9263        let mut row_delta = 0;
 9264        for selection in &mut selections {
 9265            if selection.start.row != prev_edited_row {
 9266                row_delta = 0;
 9267            }
 9268            prev_edited_row = selection.end.row;
 9269
 9270            // If the selection is non-empty, then increase the indentation of the selected lines.
 9271            if !selection.is_empty() {
 9272                row_delta =
 9273                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9274                continue;
 9275            }
 9276
 9277            let cursor = selection.head();
 9278            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9279            if let Some(suggested_indent) =
 9280                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9281            {
 9282                // Don't do anything if already at suggested indent
 9283                // and there is any other cursor which is not
 9284                if has_some_cursor_in_whitespace
 9285                    && cursor.column == current_indent.len
 9286                    && current_indent.len == suggested_indent.len
 9287                {
 9288                    continue;
 9289                }
 9290
 9291                // Adjust line and move cursor to suggested indent
 9292                // if cursor is not at suggested indent
 9293                if cursor.column < suggested_indent.len
 9294                    && cursor.column <= current_indent.len
 9295                    && current_indent.len <= suggested_indent.len
 9296                {
 9297                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9298                    selection.end = selection.start;
 9299                    if row_delta == 0 {
 9300                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9301                            cursor.row,
 9302                            current_indent,
 9303                            suggested_indent,
 9304                        ));
 9305                        row_delta = suggested_indent.len - current_indent.len;
 9306                    }
 9307                    continue;
 9308                }
 9309
 9310                // If current indent is more than suggested indent
 9311                // only move cursor to current indent and skip indent
 9312                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9313                    selection.start = Point::new(cursor.row, current_indent.len);
 9314                    selection.end = selection.start;
 9315                    continue;
 9316                }
 9317            }
 9318
 9319            // Otherwise, insert a hard or soft tab.
 9320            let settings = buffer.language_settings_at(cursor, cx);
 9321            let tab_size = if settings.hard_tabs {
 9322                IndentSize::tab()
 9323            } else {
 9324                let tab_size = settings.tab_size.get();
 9325                let indent_remainder = snapshot
 9326                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9327                    .flat_map(str::chars)
 9328                    .fold(row_delta % tab_size, |counter: u32, c| {
 9329                        if c == '\t' {
 9330                            0
 9331                        } else {
 9332                            (counter + 1) % tab_size
 9333                        }
 9334                    });
 9335
 9336                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9337                IndentSize::spaces(chars_to_next_tab_stop)
 9338            };
 9339            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9340            selection.end = selection.start;
 9341            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9342            row_delta += tab_size.len;
 9343        }
 9344
 9345        self.transact(window, cx, |this, window, cx| {
 9346            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9347            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9348                s.select(selections)
 9349            });
 9350            this.refresh_inline_completion(true, false, window, cx);
 9351        });
 9352    }
 9353
 9354    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9355        if self.read_only(cx) {
 9356            return;
 9357        }
 9358        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9359        let mut selections = self.selections.all::<Point>(cx);
 9360        let mut prev_edited_row = 0;
 9361        let mut row_delta = 0;
 9362        let mut edits = Vec::new();
 9363        let buffer = self.buffer.read(cx);
 9364        let snapshot = buffer.snapshot(cx);
 9365        for selection in &mut selections {
 9366            if selection.start.row != prev_edited_row {
 9367                row_delta = 0;
 9368            }
 9369            prev_edited_row = selection.end.row;
 9370
 9371            row_delta =
 9372                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9373        }
 9374
 9375        self.transact(window, cx, |this, window, cx| {
 9376            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9377            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9378                s.select(selections)
 9379            });
 9380        });
 9381    }
 9382
 9383    fn indent_selection(
 9384        buffer: &MultiBuffer,
 9385        snapshot: &MultiBufferSnapshot,
 9386        selection: &mut Selection<Point>,
 9387        edits: &mut Vec<(Range<Point>, String)>,
 9388        delta_for_start_row: u32,
 9389        cx: &App,
 9390    ) -> u32 {
 9391        let settings = buffer.language_settings_at(selection.start, cx);
 9392        let tab_size = settings.tab_size.get();
 9393        let indent_kind = if settings.hard_tabs {
 9394            IndentKind::Tab
 9395        } else {
 9396            IndentKind::Space
 9397        };
 9398        let mut start_row = selection.start.row;
 9399        let mut end_row = selection.end.row + 1;
 9400
 9401        // If a selection ends at the beginning of a line, don't indent
 9402        // that last line.
 9403        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9404            end_row -= 1;
 9405        }
 9406
 9407        // Avoid re-indenting a row that has already been indented by a
 9408        // previous selection, but still update this selection's column
 9409        // to reflect that indentation.
 9410        if delta_for_start_row > 0 {
 9411            start_row += 1;
 9412            selection.start.column += delta_for_start_row;
 9413            if selection.end.row == selection.start.row {
 9414                selection.end.column += delta_for_start_row;
 9415            }
 9416        }
 9417
 9418        let mut delta_for_end_row = 0;
 9419        let has_multiple_rows = start_row + 1 != end_row;
 9420        for row in start_row..end_row {
 9421            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9422            let indent_delta = match (current_indent.kind, indent_kind) {
 9423                (IndentKind::Space, IndentKind::Space) => {
 9424                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9425                    IndentSize::spaces(columns_to_next_tab_stop)
 9426                }
 9427                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9428                (_, IndentKind::Tab) => IndentSize::tab(),
 9429            };
 9430
 9431            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9432                0
 9433            } else {
 9434                selection.start.column
 9435            };
 9436            let row_start = Point::new(row, start);
 9437            edits.push((
 9438                row_start..row_start,
 9439                indent_delta.chars().collect::<String>(),
 9440            ));
 9441
 9442            // Update this selection's endpoints to reflect the indentation.
 9443            if row == selection.start.row {
 9444                selection.start.column += indent_delta.len;
 9445            }
 9446            if row == selection.end.row {
 9447                selection.end.column += indent_delta.len;
 9448                delta_for_end_row = indent_delta.len;
 9449            }
 9450        }
 9451
 9452        if selection.start.row == selection.end.row {
 9453            delta_for_start_row + delta_for_end_row
 9454        } else {
 9455            delta_for_end_row
 9456        }
 9457    }
 9458
 9459    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9460        if self.read_only(cx) {
 9461            return;
 9462        }
 9463        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9464        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9465        let selections = self.selections.all::<Point>(cx);
 9466        let mut deletion_ranges = Vec::new();
 9467        let mut last_outdent = None;
 9468        {
 9469            let buffer = self.buffer.read(cx);
 9470            let snapshot = buffer.snapshot(cx);
 9471            for selection in &selections {
 9472                let settings = buffer.language_settings_at(selection.start, cx);
 9473                let tab_size = settings.tab_size.get();
 9474                let mut rows = selection.spanned_rows(false, &display_map);
 9475
 9476                // Avoid re-outdenting a row that has already been outdented by a
 9477                // previous selection.
 9478                if let Some(last_row) = last_outdent {
 9479                    if last_row == rows.start {
 9480                        rows.start = rows.start.next_row();
 9481                    }
 9482                }
 9483                let has_multiple_rows = rows.len() > 1;
 9484                for row in rows.iter_rows() {
 9485                    let indent_size = snapshot.indent_size_for_line(row);
 9486                    if indent_size.len > 0 {
 9487                        let deletion_len = match indent_size.kind {
 9488                            IndentKind::Space => {
 9489                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9490                                if columns_to_prev_tab_stop == 0 {
 9491                                    tab_size
 9492                                } else {
 9493                                    columns_to_prev_tab_stop
 9494                                }
 9495                            }
 9496                            IndentKind::Tab => 1,
 9497                        };
 9498                        let start = if has_multiple_rows
 9499                            || deletion_len > selection.start.column
 9500                            || indent_size.len < selection.start.column
 9501                        {
 9502                            0
 9503                        } else {
 9504                            selection.start.column - deletion_len
 9505                        };
 9506                        deletion_ranges.push(
 9507                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9508                        );
 9509                        last_outdent = Some(row);
 9510                    }
 9511                }
 9512            }
 9513        }
 9514
 9515        self.transact(window, cx, |this, window, cx| {
 9516            this.buffer.update(cx, |buffer, cx| {
 9517                let empty_str: Arc<str> = Arc::default();
 9518                buffer.edit(
 9519                    deletion_ranges
 9520                        .into_iter()
 9521                        .map(|range| (range, empty_str.clone())),
 9522                    None,
 9523                    cx,
 9524                );
 9525            });
 9526            let selections = this.selections.all::<usize>(cx);
 9527            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9528                s.select(selections)
 9529            });
 9530        });
 9531    }
 9532
 9533    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9534        if self.read_only(cx) {
 9535            return;
 9536        }
 9537        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9538        let selections = self
 9539            .selections
 9540            .all::<usize>(cx)
 9541            .into_iter()
 9542            .map(|s| s.range());
 9543
 9544        self.transact(window, cx, |this, window, cx| {
 9545            this.buffer.update(cx, |buffer, cx| {
 9546                buffer.autoindent_ranges(selections, cx);
 9547            });
 9548            let selections = this.selections.all::<usize>(cx);
 9549            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9550                s.select(selections)
 9551            });
 9552        });
 9553    }
 9554
 9555    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9556        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9557        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9558        let selections = self.selections.all::<Point>(cx);
 9559
 9560        let mut new_cursors = Vec::new();
 9561        let mut edit_ranges = Vec::new();
 9562        let mut selections = selections.iter().peekable();
 9563        while let Some(selection) = selections.next() {
 9564            let mut rows = selection.spanned_rows(false, &display_map);
 9565            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9566
 9567            // Accumulate contiguous regions of rows that we want to delete.
 9568            while let Some(next_selection) = selections.peek() {
 9569                let next_rows = next_selection.spanned_rows(false, &display_map);
 9570                if next_rows.start <= rows.end {
 9571                    rows.end = next_rows.end;
 9572                    selections.next().unwrap();
 9573                } else {
 9574                    break;
 9575                }
 9576            }
 9577
 9578            let buffer = &display_map.buffer_snapshot;
 9579            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9580            let edit_end;
 9581            let cursor_buffer_row;
 9582            if buffer.max_point().row >= rows.end.0 {
 9583                // If there's a line after the range, delete the \n from the end of the row range
 9584                // and position the cursor on the next line.
 9585                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9586                cursor_buffer_row = rows.end;
 9587            } else {
 9588                // If there isn't a line after the range, delete the \n from the line before the
 9589                // start of the row range and position the cursor there.
 9590                edit_start = edit_start.saturating_sub(1);
 9591                edit_end = buffer.len();
 9592                cursor_buffer_row = rows.start.previous_row();
 9593            }
 9594
 9595            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9596            *cursor.column_mut() =
 9597                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9598
 9599            new_cursors.push((
 9600                selection.id,
 9601                buffer.anchor_after(cursor.to_point(&display_map)),
 9602            ));
 9603            edit_ranges.push(edit_start..edit_end);
 9604        }
 9605
 9606        self.transact(window, cx, |this, window, cx| {
 9607            let buffer = this.buffer.update(cx, |buffer, cx| {
 9608                let empty_str: Arc<str> = Arc::default();
 9609                buffer.edit(
 9610                    edit_ranges
 9611                        .into_iter()
 9612                        .map(|range| (range, empty_str.clone())),
 9613                    None,
 9614                    cx,
 9615                );
 9616                buffer.snapshot(cx)
 9617            });
 9618            let new_selections = new_cursors
 9619                .into_iter()
 9620                .map(|(id, cursor)| {
 9621                    let cursor = cursor.to_point(&buffer);
 9622                    Selection {
 9623                        id,
 9624                        start: cursor,
 9625                        end: cursor,
 9626                        reversed: false,
 9627                        goal: SelectionGoal::None,
 9628                    }
 9629                })
 9630                .collect();
 9631
 9632            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9633                s.select(new_selections);
 9634            });
 9635        });
 9636    }
 9637
 9638    pub fn join_lines_impl(
 9639        &mut self,
 9640        insert_whitespace: bool,
 9641        window: &mut Window,
 9642        cx: &mut Context<Self>,
 9643    ) {
 9644        if self.read_only(cx) {
 9645            return;
 9646        }
 9647        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9648        for selection in self.selections.all::<Point>(cx) {
 9649            let start = MultiBufferRow(selection.start.row);
 9650            // Treat single line selections as if they include the next line. Otherwise this action
 9651            // would do nothing for single line selections individual cursors.
 9652            let end = if selection.start.row == selection.end.row {
 9653                MultiBufferRow(selection.start.row + 1)
 9654            } else {
 9655                MultiBufferRow(selection.end.row)
 9656            };
 9657
 9658            if let Some(last_row_range) = row_ranges.last_mut() {
 9659                if start <= last_row_range.end {
 9660                    last_row_range.end = end;
 9661                    continue;
 9662                }
 9663            }
 9664            row_ranges.push(start..end);
 9665        }
 9666
 9667        let snapshot = self.buffer.read(cx).snapshot(cx);
 9668        let mut cursor_positions = Vec::new();
 9669        for row_range in &row_ranges {
 9670            let anchor = snapshot.anchor_before(Point::new(
 9671                row_range.end.previous_row().0,
 9672                snapshot.line_len(row_range.end.previous_row()),
 9673            ));
 9674            cursor_positions.push(anchor..anchor);
 9675        }
 9676
 9677        self.transact(window, cx, |this, window, cx| {
 9678            for row_range in row_ranges.into_iter().rev() {
 9679                for row in row_range.iter_rows().rev() {
 9680                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9681                    let next_line_row = row.next_row();
 9682                    let indent = snapshot.indent_size_for_line(next_line_row);
 9683                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9684
 9685                    let replace =
 9686                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9687                            " "
 9688                        } else {
 9689                            ""
 9690                        };
 9691
 9692                    this.buffer.update(cx, |buffer, cx| {
 9693                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9694                    });
 9695                }
 9696            }
 9697
 9698            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9699                s.select_anchor_ranges(cursor_positions)
 9700            });
 9701        });
 9702    }
 9703
 9704    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9705        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9706        self.join_lines_impl(true, window, cx);
 9707    }
 9708
 9709    pub fn sort_lines_case_sensitive(
 9710        &mut self,
 9711        _: &SortLinesCaseSensitive,
 9712        window: &mut Window,
 9713        cx: &mut Context<Self>,
 9714    ) {
 9715        self.manipulate_lines(window, cx, |lines| lines.sort())
 9716    }
 9717
 9718    pub fn sort_lines_case_insensitive(
 9719        &mut self,
 9720        _: &SortLinesCaseInsensitive,
 9721        window: &mut Window,
 9722        cx: &mut Context<Self>,
 9723    ) {
 9724        self.manipulate_lines(window, cx, |lines| {
 9725            lines.sort_by_key(|line| line.to_lowercase())
 9726        })
 9727    }
 9728
 9729    pub fn unique_lines_case_insensitive(
 9730        &mut self,
 9731        _: &UniqueLinesCaseInsensitive,
 9732        window: &mut Window,
 9733        cx: &mut Context<Self>,
 9734    ) {
 9735        self.manipulate_lines(window, cx, |lines| {
 9736            let mut seen = HashSet::default();
 9737            lines.retain(|line| seen.insert(line.to_lowercase()));
 9738        })
 9739    }
 9740
 9741    pub fn unique_lines_case_sensitive(
 9742        &mut self,
 9743        _: &UniqueLinesCaseSensitive,
 9744        window: &mut Window,
 9745        cx: &mut Context<Self>,
 9746    ) {
 9747        self.manipulate_lines(window, cx, |lines| {
 9748            let mut seen = HashSet::default();
 9749            lines.retain(|line| seen.insert(*line));
 9750        })
 9751    }
 9752
 9753    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9754        let Some(project) = self.project.clone() else {
 9755            return;
 9756        };
 9757        self.reload(project, window, cx)
 9758            .detach_and_notify_err(window, cx);
 9759    }
 9760
 9761    pub fn restore_file(
 9762        &mut self,
 9763        _: &::git::RestoreFile,
 9764        window: &mut Window,
 9765        cx: &mut Context<Self>,
 9766    ) {
 9767        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9768        let mut buffer_ids = HashSet::default();
 9769        let snapshot = self.buffer().read(cx).snapshot(cx);
 9770        for selection in self.selections.all::<usize>(cx) {
 9771            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9772        }
 9773
 9774        let buffer = self.buffer().read(cx);
 9775        let ranges = buffer_ids
 9776            .into_iter()
 9777            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9778            .collect::<Vec<_>>();
 9779
 9780        self.restore_hunks_in_ranges(ranges, window, cx);
 9781    }
 9782
 9783    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9784        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9785        let selections = self
 9786            .selections
 9787            .all(cx)
 9788            .into_iter()
 9789            .map(|s| s.range())
 9790            .collect();
 9791        self.restore_hunks_in_ranges(selections, window, cx);
 9792    }
 9793
 9794    pub fn restore_hunks_in_ranges(
 9795        &mut self,
 9796        ranges: Vec<Range<Point>>,
 9797        window: &mut Window,
 9798        cx: &mut Context<Editor>,
 9799    ) {
 9800        let mut revert_changes = HashMap::default();
 9801        let chunk_by = self
 9802            .snapshot(window, cx)
 9803            .hunks_for_ranges(ranges)
 9804            .into_iter()
 9805            .chunk_by(|hunk| hunk.buffer_id);
 9806        for (buffer_id, hunks) in &chunk_by {
 9807            let hunks = hunks.collect::<Vec<_>>();
 9808            for hunk in &hunks {
 9809                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9810            }
 9811            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9812        }
 9813        drop(chunk_by);
 9814        if !revert_changes.is_empty() {
 9815            self.transact(window, cx, |editor, window, cx| {
 9816                editor.restore(revert_changes, window, cx);
 9817            });
 9818        }
 9819    }
 9820
 9821    pub fn open_active_item_in_terminal(
 9822        &mut self,
 9823        _: &OpenInTerminal,
 9824        window: &mut Window,
 9825        cx: &mut Context<Self>,
 9826    ) {
 9827        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9828            let project_path = buffer.read(cx).project_path(cx)?;
 9829            let project = self.project.as_ref()?.read(cx);
 9830            let entry = project.entry_for_path(&project_path, cx)?;
 9831            let parent = match &entry.canonical_path {
 9832                Some(canonical_path) => canonical_path.to_path_buf(),
 9833                None => project.absolute_path(&project_path, cx)?,
 9834            }
 9835            .parent()?
 9836            .to_path_buf();
 9837            Some(parent)
 9838        }) {
 9839            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9840        }
 9841    }
 9842
 9843    fn set_breakpoint_context_menu(
 9844        &mut self,
 9845        display_row: DisplayRow,
 9846        position: Option<Anchor>,
 9847        clicked_point: gpui::Point<Pixels>,
 9848        window: &mut Window,
 9849        cx: &mut Context<Self>,
 9850    ) {
 9851        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9852            return;
 9853        }
 9854        let source = self
 9855            .buffer
 9856            .read(cx)
 9857            .snapshot(cx)
 9858            .anchor_before(Point::new(display_row.0, 0u32));
 9859
 9860        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9861
 9862        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9863            self,
 9864            source,
 9865            clicked_point,
 9866            context_menu,
 9867            window,
 9868            cx,
 9869        );
 9870    }
 9871
 9872    fn add_edit_breakpoint_block(
 9873        &mut self,
 9874        anchor: Anchor,
 9875        breakpoint: &Breakpoint,
 9876        edit_action: BreakpointPromptEditAction,
 9877        window: &mut Window,
 9878        cx: &mut Context<Self>,
 9879    ) {
 9880        let weak_editor = cx.weak_entity();
 9881        let bp_prompt = cx.new(|cx| {
 9882            BreakpointPromptEditor::new(
 9883                weak_editor,
 9884                anchor,
 9885                breakpoint.clone(),
 9886                edit_action,
 9887                window,
 9888                cx,
 9889            )
 9890        });
 9891
 9892        let height = bp_prompt.update(cx, |this, cx| {
 9893            this.prompt
 9894                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9895        });
 9896        let cloned_prompt = bp_prompt.clone();
 9897        let blocks = vec![BlockProperties {
 9898            style: BlockStyle::Sticky,
 9899            placement: BlockPlacement::Above(anchor),
 9900            height: Some(height),
 9901            render: Arc::new(move |cx| {
 9902                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9903                cloned_prompt.clone().into_any_element()
 9904            }),
 9905            priority: 0,
 9906            render_in_minimap: true,
 9907        }];
 9908
 9909        let focus_handle = bp_prompt.focus_handle(cx);
 9910        window.focus(&focus_handle);
 9911
 9912        let block_ids = self.insert_blocks(blocks, None, cx);
 9913        bp_prompt.update(cx, |prompt, _| {
 9914            prompt.add_block_ids(block_ids);
 9915        });
 9916    }
 9917
 9918    pub(crate) fn breakpoint_at_row(
 9919        &self,
 9920        row: u32,
 9921        window: &mut Window,
 9922        cx: &mut Context<Self>,
 9923    ) -> Option<(Anchor, Breakpoint)> {
 9924        let snapshot = self.snapshot(window, cx);
 9925        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9926
 9927        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9928    }
 9929
 9930    pub(crate) fn breakpoint_at_anchor(
 9931        &self,
 9932        breakpoint_position: Anchor,
 9933        snapshot: &EditorSnapshot,
 9934        cx: &mut Context<Self>,
 9935    ) -> Option<(Anchor, Breakpoint)> {
 9936        let project = self.project.clone()?;
 9937
 9938        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9939            snapshot
 9940                .buffer_snapshot
 9941                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9942        })?;
 9943
 9944        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9945        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
 9946        let buffer_snapshot = buffer.read(cx).snapshot();
 9947
 9948        let row = buffer_snapshot
 9949            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9950            .row;
 9951
 9952        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9953        let anchor_end = snapshot
 9954            .buffer_snapshot
 9955            .anchor_after(Point::new(row, line_len));
 9956
 9957        let bp = self
 9958            .breakpoint_store
 9959            .as_ref()?
 9960            .read_with(cx, |breakpoint_store, cx| {
 9961                breakpoint_store
 9962                    .breakpoints(
 9963                        &buffer,
 9964                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9965                        &buffer_snapshot,
 9966                        cx,
 9967                    )
 9968                    .next()
 9969                    .and_then(|(bp, _)| {
 9970                        let breakpoint_row = buffer_snapshot
 9971                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9972                            .row;
 9973
 9974                        if breakpoint_row == row {
 9975                            snapshot
 9976                                .buffer_snapshot
 9977                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9978                                .map(|position| (position, bp.bp.clone()))
 9979                        } else {
 9980                            None
 9981                        }
 9982                    })
 9983            });
 9984        bp
 9985    }
 9986
 9987    pub fn edit_log_breakpoint(
 9988        &mut self,
 9989        _: &EditLogBreakpoint,
 9990        window: &mut Window,
 9991        cx: &mut Context<Self>,
 9992    ) {
 9993        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9994            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9995                message: None,
 9996                state: BreakpointState::Enabled,
 9997                condition: None,
 9998                hit_condition: None,
 9999            });
10000
10001            self.add_edit_breakpoint_block(
10002                anchor,
10003                &breakpoint,
10004                BreakpointPromptEditAction::Log,
10005                window,
10006                cx,
10007            );
10008        }
10009    }
10010
10011    fn breakpoints_at_cursors(
10012        &self,
10013        window: &mut Window,
10014        cx: &mut Context<Self>,
10015    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10016        let snapshot = self.snapshot(window, cx);
10017        let cursors = self
10018            .selections
10019            .disjoint_anchors()
10020            .into_iter()
10021            .map(|selection| {
10022                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10023
10024                let breakpoint_position = self
10025                    .breakpoint_at_row(cursor_position.row, window, cx)
10026                    .map(|bp| bp.0)
10027                    .unwrap_or_else(|| {
10028                        snapshot
10029                            .display_snapshot
10030                            .buffer_snapshot
10031                            .anchor_after(Point::new(cursor_position.row, 0))
10032                    });
10033
10034                let breakpoint = self
10035                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10036                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10037
10038                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10039            })
10040            // 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.
10041            .collect::<HashMap<Anchor, _>>();
10042
10043        cursors.into_iter().collect()
10044    }
10045
10046    pub fn enable_breakpoint(
10047        &mut self,
10048        _: &crate::actions::EnableBreakpoint,
10049        window: &mut Window,
10050        cx: &mut Context<Self>,
10051    ) {
10052        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10053            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10054                continue;
10055            };
10056            self.edit_breakpoint_at_anchor(
10057                anchor,
10058                breakpoint,
10059                BreakpointEditAction::InvertState,
10060                cx,
10061            );
10062        }
10063    }
10064
10065    pub fn disable_breakpoint(
10066        &mut self,
10067        _: &crate::actions::DisableBreakpoint,
10068        window: &mut Window,
10069        cx: &mut Context<Self>,
10070    ) {
10071        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10072            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10073                continue;
10074            };
10075            self.edit_breakpoint_at_anchor(
10076                anchor,
10077                breakpoint,
10078                BreakpointEditAction::InvertState,
10079                cx,
10080            );
10081        }
10082    }
10083
10084    pub fn toggle_breakpoint(
10085        &mut self,
10086        _: &crate::actions::ToggleBreakpoint,
10087        window: &mut Window,
10088        cx: &mut Context<Self>,
10089    ) {
10090        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10091            if let Some(breakpoint) = breakpoint {
10092                self.edit_breakpoint_at_anchor(
10093                    anchor,
10094                    breakpoint,
10095                    BreakpointEditAction::Toggle,
10096                    cx,
10097                );
10098            } else {
10099                self.edit_breakpoint_at_anchor(
10100                    anchor,
10101                    Breakpoint::new_standard(),
10102                    BreakpointEditAction::Toggle,
10103                    cx,
10104                );
10105            }
10106        }
10107    }
10108
10109    pub fn edit_breakpoint_at_anchor(
10110        &mut self,
10111        breakpoint_position: Anchor,
10112        breakpoint: Breakpoint,
10113        edit_action: BreakpointEditAction,
10114        cx: &mut Context<Self>,
10115    ) {
10116        let Some(breakpoint_store) = &self.breakpoint_store else {
10117            return;
10118        };
10119
10120        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10121            if breakpoint_position == Anchor::min() {
10122                self.buffer()
10123                    .read(cx)
10124                    .excerpt_buffer_ids()
10125                    .into_iter()
10126                    .next()
10127            } else {
10128                None
10129            }
10130        }) else {
10131            return;
10132        };
10133
10134        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10135            return;
10136        };
10137
10138        breakpoint_store.update(cx, |breakpoint_store, cx| {
10139            breakpoint_store.toggle_breakpoint(
10140                buffer,
10141                BreakpointWithPosition {
10142                    position: breakpoint_position.text_anchor,
10143                    bp: breakpoint,
10144                },
10145                edit_action,
10146                cx,
10147            );
10148        });
10149
10150        cx.notify();
10151    }
10152
10153    #[cfg(any(test, feature = "test-support"))]
10154    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10155        self.breakpoint_store.clone()
10156    }
10157
10158    pub fn prepare_restore_change(
10159        &self,
10160        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10161        hunk: &MultiBufferDiffHunk,
10162        cx: &mut App,
10163    ) -> Option<()> {
10164        if hunk.is_created_file() {
10165            return None;
10166        }
10167        let buffer = self.buffer.read(cx);
10168        let diff = buffer.diff_for(hunk.buffer_id)?;
10169        let buffer = buffer.buffer(hunk.buffer_id)?;
10170        let buffer = buffer.read(cx);
10171        let original_text = diff
10172            .read(cx)
10173            .base_text()
10174            .as_rope()
10175            .slice(hunk.diff_base_byte_range.clone());
10176        let buffer_snapshot = buffer.snapshot();
10177        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10178        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10179            probe
10180                .0
10181                .start
10182                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10183                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10184        }) {
10185            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10186            Some(())
10187        } else {
10188            None
10189        }
10190    }
10191
10192    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10193        self.manipulate_lines(window, cx, |lines| lines.reverse())
10194    }
10195
10196    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10197        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10198    }
10199
10200    fn manipulate_lines<Fn>(
10201        &mut self,
10202        window: &mut Window,
10203        cx: &mut Context<Self>,
10204        mut callback: Fn,
10205    ) where
10206        Fn: FnMut(&mut Vec<&str>),
10207    {
10208        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10209
10210        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10211        let buffer = self.buffer.read(cx).snapshot(cx);
10212
10213        let mut edits = Vec::new();
10214
10215        let selections = self.selections.all::<Point>(cx);
10216        let mut selections = selections.iter().peekable();
10217        let mut contiguous_row_selections = Vec::new();
10218        let mut new_selections = Vec::new();
10219        let mut added_lines = 0;
10220        let mut removed_lines = 0;
10221
10222        while let Some(selection) = selections.next() {
10223            let (start_row, end_row) = consume_contiguous_rows(
10224                &mut contiguous_row_selections,
10225                selection,
10226                &display_map,
10227                &mut selections,
10228            );
10229
10230            let start_point = Point::new(start_row.0, 0);
10231            let end_point = Point::new(
10232                end_row.previous_row().0,
10233                buffer.line_len(end_row.previous_row()),
10234            );
10235            let text = buffer
10236                .text_for_range(start_point..end_point)
10237                .collect::<String>();
10238
10239            let mut lines = text.split('\n').collect_vec();
10240
10241            let lines_before = lines.len();
10242            callback(&mut lines);
10243            let lines_after = lines.len();
10244
10245            edits.push((start_point..end_point, lines.join("\n")));
10246
10247            // Selections must change based on added and removed line count
10248            let start_row =
10249                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10250            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10251            new_selections.push(Selection {
10252                id: selection.id,
10253                start: start_row,
10254                end: end_row,
10255                goal: SelectionGoal::None,
10256                reversed: selection.reversed,
10257            });
10258
10259            if lines_after > lines_before {
10260                added_lines += lines_after - lines_before;
10261            } else if lines_before > lines_after {
10262                removed_lines += lines_before - lines_after;
10263            }
10264        }
10265
10266        self.transact(window, cx, |this, window, cx| {
10267            let buffer = this.buffer.update(cx, |buffer, cx| {
10268                buffer.edit(edits, None, cx);
10269                buffer.snapshot(cx)
10270            });
10271
10272            // Recalculate offsets on newly edited buffer
10273            let new_selections = new_selections
10274                .iter()
10275                .map(|s| {
10276                    let start_point = Point::new(s.start.0, 0);
10277                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10278                    Selection {
10279                        id: s.id,
10280                        start: buffer.point_to_offset(start_point),
10281                        end: buffer.point_to_offset(end_point),
10282                        goal: s.goal,
10283                        reversed: s.reversed,
10284                    }
10285                })
10286                .collect();
10287
10288            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10289                s.select(new_selections);
10290            });
10291
10292            this.request_autoscroll(Autoscroll::fit(), cx);
10293        });
10294    }
10295
10296    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10297        self.manipulate_text(window, cx, |text| {
10298            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10299            if has_upper_case_characters {
10300                text.to_lowercase()
10301            } else {
10302                text.to_uppercase()
10303            }
10304        })
10305    }
10306
10307    pub fn convert_to_upper_case(
10308        &mut self,
10309        _: &ConvertToUpperCase,
10310        window: &mut Window,
10311        cx: &mut Context<Self>,
10312    ) {
10313        self.manipulate_text(window, cx, |text| text.to_uppercase())
10314    }
10315
10316    pub fn convert_to_lower_case(
10317        &mut self,
10318        _: &ConvertToLowerCase,
10319        window: &mut Window,
10320        cx: &mut Context<Self>,
10321    ) {
10322        self.manipulate_text(window, cx, |text| text.to_lowercase())
10323    }
10324
10325    pub fn convert_to_title_case(
10326        &mut self,
10327        _: &ConvertToTitleCase,
10328        window: &mut Window,
10329        cx: &mut Context<Self>,
10330    ) {
10331        self.manipulate_text(window, cx, |text| {
10332            text.split('\n')
10333                .map(|line| line.to_case(Case::Title))
10334                .join("\n")
10335        })
10336    }
10337
10338    pub fn convert_to_snake_case(
10339        &mut self,
10340        _: &ConvertToSnakeCase,
10341        window: &mut Window,
10342        cx: &mut Context<Self>,
10343    ) {
10344        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10345    }
10346
10347    pub fn convert_to_kebab_case(
10348        &mut self,
10349        _: &ConvertToKebabCase,
10350        window: &mut Window,
10351        cx: &mut Context<Self>,
10352    ) {
10353        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10354    }
10355
10356    pub fn convert_to_upper_camel_case(
10357        &mut self,
10358        _: &ConvertToUpperCamelCase,
10359        window: &mut Window,
10360        cx: &mut Context<Self>,
10361    ) {
10362        self.manipulate_text(window, cx, |text| {
10363            text.split('\n')
10364                .map(|line| line.to_case(Case::UpperCamel))
10365                .join("\n")
10366        })
10367    }
10368
10369    pub fn convert_to_lower_camel_case(
10370        &mut self,
10371        _: &ConvertToLowerCamelCase,
10372        window: &mut Window,
10373        cx: &mut Context<Self>,
10374    ) {
10375        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10376    }
10377
10378    pub fn convert_to_opposite_case(
10379        &mut self,
10380        _: &ConvertToOppositeCase,
10381        window: &mut Window,
10382        cx: &mut Context<Self>,
10383    ) {
10384        self.manipulate_text(window, cx, |text| {
10385            text.chars()
10386                .fold(String::with_capacity(text.len()), |mut t, c| {
10387                    if c.is_uppercase() {
10388                        t.extend(c.to_lowercase());
10389                    } else {
10390                        t.extend(c.to_uppercase());
10391                    }
10392                    t
10393                })
10394        })
10395    }
10396
10397    pub fn convert_to_rot13(
10398        &mut self,
10399        _: &ConvertToRot13,
10400        window: &mut Window,
10401        cx: &mut Context<Self>,
10402    ) {
10403        self.manipulate_text(window, cx, |text| {
10404            text.chars()
10405                .map(|c| match c {
10406                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10407                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10408                    _ => c,
10409                })
10410                .collect()
10411        })
10412    }
10413
10414    pub fn convert_to_rot47(
10415        &mut self,
10416        _: &ConvertToRot47,
10417        window: &mut Window,
10418        cx: &mut Context<Self>,
10419    ) {
10420        self.manipulate_text(window, cx, |text| {
10421            text.chars()
10422                .map(|c| {
10423                    let code_point = c as u32;
10424                    if code_point >= 33 && code_point <= 126 {
10425                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10426                    }
10427                    c
10428                })
10429                .collect()
10430        })
10431    }
10432
10433    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10434    where
10435        Fn: FnMut(&str) -> String,
10436    {
10437        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10438        let buffer = self.buffer.read(cx).snapshot(cx);
10439
10440        let mut new_selections = Vec::new();
10441        let mut edits = Vec::new();
10442        let mut selection_adjustment = 0i32;
10443
10444        for selection in self.selections.all::<usize>(cx) {
10445            let selection_is_empty = selection.is_empty();
10446
10447            let (start, end) = if selection_is_empty {
10448                let word_range = movement::surrounding_word(
10449                    &display_map,
10450                    selection.start.to_display_point(&display_map),
10451                );
10452                let start = word_range.start.to_offset(&display_map, Bias::Left);
10453                let end = word_range.end.to_offset(&display_map, Bias::Left);
10454                (start, end)
10455            } else {
10456                (selection.start, selection.end)
10457            };
10458
10459            let text = buffer.text_for_range(start..end).collect::<String>();
10460            let old_length = text.len() as i32;
10461            let text = callback(&text);
10462
10463            new_selections.push(Selection {
10464                start: (start as i32 - selection_adjustment) as usize,
10465                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10466                goal: SelectionGoal::None,
10467                ..selection
10468            });
10469
10470            selection_adjustment += old_length - text.len() as i32;
10471
10472            edits.push((start..end, text));
10473        }
10474
10475        self.transact(window, cx, |this, window, cx| {
10476            this.buffer.update(cx, |buffer, cx| {
10477                buffer.edit(edits, None, cx);
10478            });
10479
10480            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10481                s.select(new_selections);
10482            });
10483
10484            this.request_autoscroll(Autoscroll::fit(), cx);
10485        });
10486    }
10487
10488    pub fn duplicate(
10489        &mut self,
10490        upwards: bool,
10491        whole_lines: bool,
10492        window: &mut Window,
10493        cx: &mut Context<Self>,
10494    ) {
10495        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10496
10497        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10498        let buffer = &display_map.buffer_snapshot;
10499        let selections = self.selections.all::<Point>(cx);
10500
10501        let mut edits = Vec::new();
10502        let mut selections_iter = selections.iter().peekable();
10503        while let Some(selection) = selections_iter.next() {
10504            let mut rows = selection.spanned_rows(false, &display_map);
10505            // duplicate line-wise
10506            if whole_lines || selection.start == selection.end {
10507                // Avoid duplicating the same lines twice.
10508                while let Some(next_selection) = selections_iter.peek() {
10509                    let next_rows = next_selection.spanned_rows(false, &display_map);
10510                    if next_rows.start < rows.end {
10511                        rows.end = next_rows.end;
10512                        selections_iter.next().unwrap();
10513                    } else {
10514                        break;
10515                    }
10516                }
10517
10518                // Copy the text from the selected row region and splice it either at the start
10519                // or end of the region.
10520                let start = Point::new(rows.start.0, 0);
10521                let end = Point::new(
10522                    rows.end.previous_row().0,
10523                    buffer.line_len(rows.end.previous_row()),
10524                );
10525                let text = buffer
10526                    .text_for_range(start..end)
10527                    .chain(Some("\n"))
10528                    .collect::<String>();
10529                let insert_location = if upwards {
10530                    Point::new(rows.end.0, 0)
10531                } else {
10532                    start
10533                };
10534                edits.push((insert_location..insert_location, text));
10535            } else {
10536                // duplicate character-wise
10537                let start = selection.start;
10538                let end = selection.end;
10539                let text = buffer.text_for_range(start..end).collect::<String>();
10540                edits.push((selection.end..selection.end, text));
10541            }
10542        }
10543
10544        self.transact(window, cx, |this, _, cx| {
10545            this.buffer.update(cx, |buffer, cx| {
10546                buffer.edit(edits, None, cx);
10547            });
10548
10549            this.request_autoscroll(Autoscroll::fit(), cx);
10550        });
10551    }
10552
10553    pub fn duplicate_line_up(
10554        &mut self,
10555        _: &DuplicateLineUp,
10556        window: &mut Window,
10557        cx: &mut Context<Self>,
10558    ) {
10559        self.duplicate(true, true, window, cx);
10560    }
10561
10562    pub fn duplicate_line_down(
10563        &mut self,
10564        _: &DuplicateLineDown,
10565        window: &mut Window,
10566        cx: &mut Context<Self>,
10567    ) {
10568        self.duplicate(false, true, window, cx);
10569    }
10570
10571    pub fn duplicate_selection(
10572        &mut self,
10573        _: &DuplicateSelection,
10574        window: &mut Window,
10575        cx: &mut Context<Self>,
10576    ) {
10577        self.duplicate(false, false, window, cx);
10578    }
10579
10580    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10581        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10582
10583        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10584        let buffer = self.buffer.read(cx).snapshot(cx);
10585
10586        let mut edits = Vec::new();
10587        let mut unfold_ranges = Vec::new();
10588        let mut refold_creases = Vec::new();
10589
10590        let selections = self.selections.all::<Point>(cx);
10591        let mut selections = selections.iter().peekable();
10592        let mut contiguous_row_selections = Vec::new();
10593        let mut new_selections = Vec::new();
10594
10595        while let Some(selection) = selections.next() {
10596            // Find all the selections that span a contiguous row range
10597            let (start_row, end_row) = consume_contiguous_rows(
10598                &mut contiguous_row_selections,
10599                selection,
10600                &display_map,
10601                &mut selections,
10602            );
10603
10604            // Move the text spanned by the row range to be before the line preceding the row range
10605            if start_row.0 > 0 {
10606                let range_to_move = Point::new(
10607                    start_row.previous_row().0,
10608                    buffer.line_len(start_row.previous_row()),
10609                )
10610                    ..Point::new(
10611                        end_row.previous_row().0,
10612                        buffer.line_len(end_row.previous_row()),
10613                    );
10614                let insertion_point = display_map
10615                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10616                    .0;
10617
10618                // Don't move lines across excerpts
10619                if buffer
10620                    .excerpt_containing(insertion_point..range_to_move.end)
10621                    .is_some()
10622                {
10623                    let text = buffer
10624                        .text_for_range(range_to_move.clone())
10625                        .flat_map(|s| s.chars())
10626                        .skip(1)
10627                        .chain(['\n'])
10628                        .collect::<String>();
10629
10630                    edits.push((
10631                        buffer.anchor_after(range_to_move.start)
10632                            ..buffer.anchor_before(range_to_move.end),
10633                        String::new(),
10634                    ));
10635                    let insertion_anchor = buffer.anchor_after(insertion_point);
10636                    edits.push((insertion_anchor..insertion_anchor, text));
10637
10638                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10639
10640                    // Move selections up
10641                    new_selections.extend(contiguous_row_selections.drain(..).map(
10642                        |mut selection| {
10643                            selection.start.row -= row_delta;
10644                            selection.end.row -= row_delta;
10645                            selection
10646                        },
10647                    ));
10648
10649                    // Move folds up
10650                    unfold_ranges.push(range_to_move.clone());
10651                    for fold in display_map.folds_in_range(
10652                        buffer.anchor_before(range_to_move.start)
10653                            ..buffer.anchor_after(range_to_move.end),
10654                    ) {
10655                        let mut start = fold.range.start.to_point(&buffer);
10656                        let mut end = fold.range.end.to_point(&buffer);
10657                        start.row -= row_delta;
10658                        end.row -= row_delta;
10659                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10660                    }
10661                }
10662            }
10663
10664            // If we didn't move line(s), preserve the existing selections
10665            new_selections.append(&mut contiguous_row_selections);
10666        }
10667
10668        self.transact(window, cx, |this, window, cx| {
10669            this.unfold_ranges(&unfold_ranges, true, true, cx);
10670            this.buffer.update(cx, |buffer, cx| {
10671                for (range, text) in edits {
10672                    buffer.edit([(range, text)], None, cx);
10673                }
10674            });
10675            this.fold_creases(refold_creases, true, window, cx);
10676            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10677                s.select(new_selections);
10678            })
10679        });
10680    }
10681
10682    pub fn move_line_down(
10683        &mut self,
10684        _: &MoveLineDown,
10685        window: &mut Window,
10686        cx: &mut Context<Self>,
10687    ) {
10688        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10689
10690        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10691        let buffer = self.buffer.read(cx).snapshot(cx);
10692
10693        let mut edits = Vec::new();
10694        let mut unfold_ranges = Vec::new();
10695        let mut refold_creases = Vec::new();
10696
10697        let selections = self.selections.all::<Point>(cx);
10698        let mut selections = selections.iter().peekable();
10699        let mut contiguous_row_selections = Vec::new();
10700        let mut new_selections = Vec::new();
10701
10702        while let Some(selection) = selections.next() {
10703            // Find all the selections that span a contiguous row range
10704            let (start_row, end_row) = consume_contiguous_rows(
10705                &mut contiguous_row_selections,
10706                selection,
10707                &display_map,
10708                &mut selections,
10709            );
10710
10711            // Move the text spanned by the row range to be after the last line of the row range
10712            if end_row.0 <= buffer.max_point().row {
10713                let range_to_move =
10714                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10715                let insertion_point = display_map
10716                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10717                    .0;
10718
10719                // Don't move lines across excerpt boundaries
10720                if buffer
10721                    .excerpt_containing(range_to_move.start..insertion_point)
10722                    .is_some()
10723                {
10724                    let mut text = String::from("\n");
10725                    text.extend(buffer.text_for_range(range_to_move.clone()));
10726                    text.pop(); // Drop trailing newline
10727                    edits.push((
10728                        buffer.anchor_after(range_to_move.start)
10729                            ..buffer.anchor_before(range_to_move.end),
10730                        String::new(),
10731                    ));
10732                    let insertion_anchor = buffer.anchor_after(insertion_point);
10733                    edits.push((insertion_anchor..insertion_anchor, text));
10734
10735                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10736
10737                    // Move selections down
10738                    new_selections.extend(contiguous_row_selections.drain(..).map(
10739                        |mut selection| {
10740                            selection.start.row += row_delta;
10741                            selection.end.row += row_delta;
10742                            selection
10743                        },
10744                    ));
10745
10746                    // Move folds down
10747                    unfold_ranges.push(range_to_move.clone());
10748                    for fold in display_map.folds_in_range(
10749                        buffer.anchor_before(range_to_move.start)
10750                            ..buffer.anchor_after(range_to_move.end),
10751                    ) {
10752                        let mut start = fold.range.start.to_point(&buffer);
10753                        let mut end = fold.range.end.to_point(&buffer);
10754                        start.row += row_delta;
10755                        end.row += row_delta;
10756                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10757                    }
10758                }
10759            }
10760
10761            // If we didn't move line(s), preserve the existing selections
10762            new_selections.append(&mut contiguous_row_selections);
10763        }
10764
10765        self.transact(window, cx, |this, window, cx| {
10766            this.unfold_ranges(&unfold_ranges, true, true, cx);
10767            this.buffer.update(cx, |buffer, cx| {
10768                for (range, text) in edits {
10769                    buffer.edit([(range, text)], None, cx);
10770                }
10771            });
10772            this.fold_creases(refold_creases, true, window, cx);
10773            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10774                s.select(new_selections)
10775            });
10776        });
10777    }
10778
10779    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10780        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10781        let text_layout_details = &self.text_layout_details(window);
10782        self.transact(window, cx, |this, window, cx| {
10783            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10784                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10785                s.move_with(|display_map, selection| {
10786                    if !selection.is_empty() {
10787                        return;
10788                    }
10789
10790                    let mut head = selection.head();
10791                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10792                    if head.column() == display_map.line_len(head.row()) {
10793                        transpose_offset = display_map
10794                            .buffer_snapshot
10795                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10796                    }
10797
10798                    if transpose_offset == 0 {
10799                        return;
10800                    }
10801
10802                    *head.column_mut() += 1;
10803                    head = display_map.clip_point(head, Bias::Right);
10804                    let goal = SelectionGoal::HorizontalPosition(
10805                        display_map
10806                            .x_for_display_point(head, text_layout_details)
10807                            .into(),
10808                    );
10809                    selection.collapse_to(head, goal);
10810
10811                    let transpose_start = display_map
10812                        .buffer_snapshot
10813                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10814                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10815                        let transpose_end = display_map
10816                            .buffer_snapshot
10817                            .clip_offset(transpose_offset + 1, Bias::Right);
10818                        if let Some(ch) =
10819                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10820                        {
10821                            edits.push((transpose_start..transpose_offset, String::new()));
10822                            edits.push((transpose_end..transpose_end, ch.to_string()));
10823                        }
10824                    }
10825                });
10826                edits
10827            });
10828            this.buffer
10829                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10830            let selections = this.selections.all::<usize>(cx);
10831            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10832                s.select(selections);
10833            });
10834        });
10835    }
10836
10837    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10838        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10839        self.rewrap_impl(RewrapOptions::default(), cx)
10840    }
10841
10842    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10843        let buffer = self.buffer.read(cx).snapshot(cx);
10844        let selections = self.selections.all::<Point>(cx);
10845        let mut selections = selections.iter().peekable();
10846
10847        let mut edits = Vec::new();
10848        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10849
10850        while let Some(selection) = selections.next() {
10851            let mut start_row = selection.start.row;
10852            let mut end_row = selection.end.row;
10853
10854            // Skip selections that overlap with a range that has already been rewrapped.
10855            let selection_range = start_row..end_row;
10856            if rewrapped_row_ranges
10857                .iter()
10858                .any(|range| range.overlaps(&selection_range))
10859            {
10860                continue;
10861            }
10862
10863            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10864
10865            // Since not all lines in the selection may be at the same indent
10866            // level, choose the indent size that is the most common between all
10867            // of the lines.
10868            //
10869            // If there is a tie, we use the deepest indent.
10870            let (indent_size, indent_end) = {
10871                let mut indent_size_occurrences = HashMap::default();
10872                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10873
10874                for row in start_row..=end_row {
10875                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10876                    rows_by_indent_size.entry(indent).or_default().push(row);
10877                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10878                }
10879
10880                let indent_size = indent_size_occurrences
10881                    .into_iter()
10882                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10883                    .map(|(indent, _)| indent)
10884                    .unwrap_or_default();
10885                let row = rows_by_indent_size[&indent_size][0];
10886                let indent_end = Point::new(row, indent_size.len);
10887
10888                (indent_size, indent_end)
10889            };
10890
10891            let mut line_prefix = indent_size.chars().collect::<String>();
10892
10893            let mut inside_comment = false;
10894            if let Some(comment_prefix) =
10895                buffer
10896                    .language_scope_at(selection.head())
10897                    .and_then(|language| {
10898                        language
10899                            .line_comment_prefixes()
10900                            .iter()
10901                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10902                            .cloned()
10903                    })
10904            {
10905                line_prefix.push_str(&comment_prefix);
10906                inside_comment = true;
10907            }
10908
10909            let language_settings = buffer.language_settings_at(selection.head(), cx);
10910            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10911                RewrapBehavior::InComments => inside_comment,
10912                RewrapBehavior::InSelections => !selection.is_empty(),
10913                RewrapBehavior::Anywhere => true,
10914            };
10915
10916            let should_rewrap = options.override_language_settings
10917                || allow_rewrap_based_on_language
10918                || self.hard_wrap.is_some();
10919            if !should_rewrap {
10920                continue;
10921            }
10922
10923            if selection.is_empty() {
10924                'expand_upwards: while start_row > 0 {
10925                    let prev_row = start_row - 1;
10926                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10927                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10928                    {
10929                        start_row = prev_row;
10930                    } else {
10931                        break 'expand_upwards;
10932                    }
10933                }
10934
10935                'expand_downwards: while end_row < buffer.max_point().row {
10936                    let next_row = end_row + 1;
10937                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10938                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10939                    {
10940                        end_row = next_row;
10941                    } else {
10942                        break 'expand_downwards;
10943                    }
10944                }
10945            }
10946
10947            let start = Point::new(start_row, 0);
10948            let start_offset = start.to_offset(&buffer);
10949            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10950            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10951            let Some(lines_without_prefixes) = selection_text
10952                .lines()
10953                .map(|line| {
10954                    line.strip_prefix(&line_prefix)
10955                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10956                        .with_context(|| {
10957                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10958                        })
10959                })
10960                .collect::<Result<Vec<_>, _>>()
10961                .log_err()
10962            else {
10963                continue;
10964            };
10965
10966            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10967                buffer
10968                    .language_settings_at(Point::new(start_row, 0), cx)
10969                    .preferred_line_length as usize
10970            });
10971            let wrapped_text = wrap_with_prefix(
10972                line_prefix,
10973                lines_without_prefixes.join("\n"),
10974                wrap_column,
10975                tab_size,
10976                options.preserve_existing_whitespace,
10977            );
10978
10979            // TODO: should always use char-based diff while still supporting cursor behavior that
10980            // matches vim.
10981            let mut diff_options = DiffOptions::default();
10982            if options.override_language_settings {
10983                diff_options.max_word_diff_len = 0;
10984                diff_options.max_word_diff_line_count = 0;
10985            } else {
10986                diff_options.max_word_diff_len = usize::MAX;
10987                diff_options.max_word_diff_line_count = usize::MAX;
10988            }
10989
10990            for (old_range, new_text) in
10991                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10992            {
10993                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10994                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10995                edits.push((edit_start..edit_end, new_text));
10996            }
10997
10998            rewrapped_row_ranges.push(start_row..=end_row);
10999        }
11000
11001        self.buffer
11002            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11003    }
11004
11005    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11006        let mut text = String::new();
11007        let buffer = self.buffer.read(cx).snapshot(cx);
11008        let mut selections = self.selections.all::<Point>(cx);
11009        let mut clipboard_selections = Vec::with_capacity(selections.len());
11010        {
11011            let max_point = buffer.max_point();
11012            let mut is_first = true;
11013            for selection in &mut selections {
11014                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11015                if is_entire_line {
11016                    selection.start = Point::new(selection.start.row, 0);
11017                    if !selection.is_empty() && selection.end.column == 0 {
11018                        selection.end = cmp::min(max_point, selection.end);
11019                    } else {
11020                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11021                    }
11022                    selection.goal = SelectionGoal::None;
11023                }
11024                if is_first {
11025                    is_first = false;
11026                } else {
11027                    text += "\n";
11028                }
11029                let mut len = 0;
11030                for chunk in buffer.text_for_range(selection.start..selection.end) {
11031                    text.push_str(chunk);
11032                    len += chunk.len();
11033                }
11034                clipboard_selections.push(ClipboardSelection {
11035                    len,
11036                    is_entire_line,
11037                    first_line_indent: buffer
11038                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11039                        .len,
11040                });
11041            }
11042        }
11043
11044        self.transact(window, cx, |this, window, cx| {
11045            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11046                s.select(selections);
11047            });
11048            this.insert("", window, cx);
11049        });
11050        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11051    }
11052
11053    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11054        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11055        let item = self.cut_common(window, cx);
11056        cx.write_to_clipboard(item);
11057    }
11058
11059    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11060        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11061        self.change_selections(None, window, cx, |s| {
11062            s.move_with(|snapshot, sel| {
11063                if sel.is_empty() {
11064                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11065                }
11066            });
11067        });
11068        let item = self.cut_common(window, cx);
11069        cx.set_global(KillRing(item))
11070    }
11071
11072    pub fn kill_ring_yank(
11073        &mut self,
11074        _: &KillRingYank,
11075        window: &mut Window,
11076        cx: &mut Context<Self>,
11077    ) {
11078        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11079        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11080            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11081                (kill_ring.text().to_string(), kill_ring.metadata_json())
11082            } else {
11083                return;
11084            }
11085        } else {
11086            return;
11087        };
11088        self.do_paste(&text, metadata, false, window, cx);
11089    }
11090
11091    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11092        self.do_copy(true, cx);
11093    }
11094
11095    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11096        self.do_copy(false, cx);
11097    }
11098
11099    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11100        let selections = self.selections.all::<Point>(cx);
11101        let buffer = self.buffer.read(cx).read(cx);
11102        let mut text = String::new();
11103
11104        let mut clipboard_selections = Vec::with_capacity(selections.len());
11105        {
11106            let max_point = buffer.max_point();
11107            let mut is_first = true;
11108            for selection in &selections {
11109                let mut start = selection.start;
11110                let mut end = selection.end;
11111                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11112                if is_entire_line {
11113                    start = Point::new(start.row, 0);
11114                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11115                }
11116
11117                let mut trimmed_selections = Vec::new();
11118                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11119                    let row = MultiBufferRow(start.row);
11120                    let first_indent = buffer.indent_size_for_line(row);
11121                    if first_indent.len == 0 || start.column > first_indent.len {
11122                        trimmed_selections.push(start..end);
11123                    } else {
11124                        trimmed_selections.push(
11125                            Point::new(row.0, first_indent.len)
11126                                ..Point::new(row.0, buffer.line_len(row)),
11127                        );
11128                        for row in start.row + 1..=end.row {
11129                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11130                            if row == end.row {
11131                                line_len = end.column;
11132                            }
11133                            if line_len == 0 {
11134                                trimmed_selections
11135                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11136                                continue;
11137                            }
11138                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11139                            if row_indent_size.len >= first_indent.len {
11140                                trimmed_selections.push(
11141                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11142                                );
11143                            } else {
11144                                trimmed_selections.clear();
11145                                trimmed_selections.push(start..end);
11146                                break;
11147                            }
11148                        }
11149                    }
11150                } else {
11151                    trimmed_selections.push(start..end);
11152                }
11153
11154                for trimmed_range in trimmed_selections {
11155                    if is_first {
11156                        is_first = false;
11157                    } else {
11158                        text += "\n";
11159                    }
11160                    let mut len = 0;
11161                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11162                        text.push_str(chunk);
11163                        len += chunk.len();
11164                    }
11165                    clipboard_selections.push(ClipboardSelection {
11166                        len,
11167                        is_entire_line,
11168                        first_line_indent: buffer
11169                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11170                            .len,
11171                    });
11172                }
11173            }
11174        }
11175
11176        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11177            text,
11178            clipboard_selections,
11179        ));
11180    }
11181
11182    pub fn do_paste(
11183        &mut self,
11184        text: &String,
11185        clipboard_selections: Option<Vec<ClipboardSelection>>,
11186        handle_entire_lines: bool,
11187        window: &mut Window,
11188        cx: &mut Context<Self>,
11189    ) {
11190        if self.read_only(cx) {
11191            return;
11192        }
11193
11194        let clipboard_text = Cow::Borrowed(text);
11195
11196        self.transact(window, cx, |this, window, cx| {
11197            if let Some(mut clipboard_selections) = clipboard_selections {
11198                let old_selections = this.selections.all::<usize>(cx);
11199                let all_selections_were_entire_line =
11200                    clipboard_selections.iter().all(|s| s.is_entire_line);
11201                let first_selection_indent_column =
11202                    clipboard_selections.first().map(|s| s.first_line_indent);
11203                if clipboard_selections.len() != old_selections.len() {
11204                    clipboard_selections.drain(..);
11205                }
11206                let cursor_offset = this.selections.last::<usize>(cx).head();
11207                let mut auto_indent_on_paste = true;
11208
11209                this.buffer.update(cx, |buffer, cx| {
11210                    let snapshot = buffer.read(cx);
11211                    auto_indent_on_paste = snapshot
11212                        .language_settings_at(cursor_offset, cx)
11213                        .auto_indent_on_paste;
11214
11215                    let mut start_offset = 0;
11216                    let mut edits = Vec::new();
11217                    let mut original_indent_columns = Vec::new();
11218                    for (ix, selection) in old_selections.iter().enumerate() {
11219                        let to_insert;
11220                        let entire_line;
11221                        let original_indent_column;
11222                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11223                            let end_offset = start_offset + clipboard_selection.len;
11224                            to_insert = &clipboard_text[start_offset..end_offset];
11225                            entire_line = clipboard_selection.is_entire_line;
11226                            start_offset = end_offset + 1;
11227                            original_indent_column = Some(clipboard_selection.first_line_indent);
11228                        } else {
11229                            to_insert = clipboard_text.as_str();
11230                            entire_line = all_selections_were_entire_line;
11231                            original_indent_column = first_selection_indent_column
11232                        }
11233
11234                        // If the corresponding selection was empty when this slice of the
11235                        // clipboard text was written, then the entire line containing the
11236                        // selection was copied. If this selection is also currently empty,
11237                        // then paste the line before the current line of the buffer.
11238                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11239                            let column = selection.start.to_point(&snapshot).column as usize;
11240                            let line_start = selection.start - column;
11241                            line_start..line_start
11242                        } else {
11243                            selection.range()
11244                        };
11245
11246                        edits.push((range, to_insert));
11247                        original_indent_columns.push(original_indent_column);
11248                    }
11249                    drop(snapshot);
11250
11251                    buffer.edit(
11252                        edits,
11253                        if auto_indent_on_paste {
11254                            Some(AutoindentMode::Block {
11255                                original_indent_columns,
11256                            })
11257                        } else {
11258                            None
11259                        },
11260                        cx,
11261                    );
11262                });
11263
11264                let selections = this.selections.all::<usize>(cx);
11265                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11266                    s.select(selections)
11267                });
11268            } else {
11269                this.insert(&clipboard_text, window, cx);
11270            }
11271        });
11272    }
11273
11274    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11275        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11276        if let Some(item) = cx.read_from_clipboard() {
11277            let entries = item.entries();
11278
11279            match entries.first() {
11280                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11281                // of all the pasted entries.
11282                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11283                    .do_paste(
11284                        clipboard_string.text(),
11285                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11286                        true,
11287                        window,
11288                        cx,
11289                    ),
11290                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11291            }
11292        }
11293    }
11294
11295    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11296        if self.read_only(cx) {
11297            return;
11298        }
11299
11300        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11301
11302        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11303            if let Some((selections, _)) =
11304                self.selection_history.transaction(transaction_id).cloned()
11305            {
11306                self.change_selections(None, window, cx, |s| {
11307                    s.select_anchors(selections.to_vec());
11308                });
11309            } else {
11310                log::error!(
11311                    "No entry in selection_history found for undo. \
11312                     This may correspond to a bug where undo does not update the selection. \
11313                     If this is occurring, please add details to \
11314                     https://github.com/zed-industries/zed/issues/22692"
11315                );
11316            }
11317            self.request_autoscroll(Autoscroll::fit(), cx);
11318            self.unmark_text(window, cx);
11319            self.refresh_inline_completion(true, false, window, cx);
11320            cx.emit(EditorEvent::Edited { transaction_id });
11321            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11322        }
11323    }
11324
11325    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11326        if self.read_only(cx) {
11327            return;
11328        }
11329
11330        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11331
11332        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11333            if let Some((_, Some(selections))) =
11334                self.selection_history.transaction(transaction_id).cloned()
11335            {
11336                self.change_selections(None, window, cx, |s| {
11337                    s.select_anchors(selections.to_vec());
11338                });
11339            } else {
11340                log::error!(
11341                    "No entry in selection_history found for redo. \
11342                     This may correspond to a bug where undo does not update the selection. \
11343                     If this is occurring, please add details to \
11344                     https://github.com/zed-industries/zed/issues/22692"
11345                );
11346            }
11347            self.request_autoscroll(Autoscroll::fit(), cx);
11348            self.unmark_text(window, cx);
11349            self.refresh_inline_completion(true, false, window, cx);
11350            cx.emit(EditorEvent::Edited { transaction_id });
11351        }
11352    }
11353
11354    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11355        self.buffer
11356            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11357    }
11358
11359    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11360        self.buffer
11361            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11362    }
11363
11364    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11365        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11366        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11367            s.move_with(|map, selection| {
11368                let cursor = if selection.is_empty() {
11369                    movement::left(map, selection.start)
11370                } else {
11371                    selection.start
11372                };
11373                selection.collapse_to(cursor, SelectionGoal::None);
11374            });
11375        })
11376    }
11377
11378    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11379        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11380        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11381            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11382        })
11383    }
11384
11385    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11386        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11387        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11388            s.move_with(|map, selection| {
11389                let cursor = if selection.is_empty() {
11390                    movement::right(map, selection.end)
11391                } else {
11392                    selection.end
11393                };
11394                selection.collapse_to(cursor, SelectionGoal::None)
11395            });
11396        })
11397    }
11398
11399    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11400        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11401        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11402            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11403        })
11404    }
11405
11406    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11407        if self.take_rename(true, window, cx).is_some() {
11408            return;
11409        }
11410
11411        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11412            cx.propagate();
11413            return;
11414        }
11415
11416        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11417
11418        let text_layout_details = &self.text_layout_details(window);
11419        let selection_count = self.selections.count();
11420        let first_selection = self.selections.first_anchor();
11421
11422        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11423            s.move_with(|map, selection| {
11424                if !selection.is_empty() {
11425                    selection.goal = SelectionGoal::None;
11426                }
11427                let (cursor, goal) = movement::up(
11428                    map,
11429                    selection.start,
11430                    selection.goal,
11431                    false,
11432                    text_layout_details,
11433                );
11434                selection.collapse_to(cursor, goal);
11435            });
11436        });
11437
11438        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11439        {
11440            cx.propagate();
11441        }
11442    }
11443
11444    pub fn move_up_by_lines(
11445        &mut self,
11446        action: &MoveUpByLines,
11447        window: &mut Window,
11448        cx: &mut Context<Self>,
11449    ) {
11450        if self.take_rename(true, window, cx).is_some() {
11451            return;
11452        }
11453
11454        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11455            cx.propagate();
11456            return;
11457        }
11458
11459        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11460
11461        let text_layout_details = &self.text_layout_details(window);
11462
11463        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11464            s.move_with(|map, selection| {
11465                if !selection.is_empty() {
11466                    selection.goal = SelectionGoal::None;
11467                }
11468                let (cursor, goal) = movement::up_by_rows(
11469                    map,
11470                    selection.start,
11471                    action.lines,
11472                    selection.goal,
11473                    false,
11474                    text_layout_details,
11475                );
11476                selection.collapse_to(cursor, goal);
11477            });
11478        })
11479    }
11480
11481    pub fn move_down_by_lines(
11482        &mut self,
11483        action: &MoveDownByLines,
11484        window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        if self.take_rename(true, window, cx).is_some() {
11488            return;
11489        }
11490
11491        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11492            cx.propagate();
11493            return;
11494        }
11495
11496        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11497
11498        let text_layout_details = &self.text_layout_details(window);
11499
11500        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11501            s.move_with(|map, selection| {
11502                if !selection.is_empty() {
11503                    selection.goal = SelectionGoal::None;
11504                }
11505                let (cursor, goal) = movement::down_by_rows(
11506                    map,
11507                    selection.start,
11508                    action.lines,
11509                    selection.goal,
11510                    false,
11511                    text_layout_details,
11512                );
11513                selection.collapse_to(cursor, goal);
11514            });
11515        })
11516    }
11517
11518    pub fn select_down_by_lines(
11519        &mut self,
11520        action: &SelectDownByLines,
11521        window: &mut Window,
11522        cx: &mut Context<Self>,
11523    ) {
11524        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11525        let text_layout_details = &self.text_layout_details(window);
11526        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11527            s.move_heads_with(|map, head, goal| {
11528                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11529            })
11530        })
11531    }
11532
11533    pub fn select_up_by_lines(
11534        &mut self,
11535        action: &SelectUpByLines,
11536        window: &mut Window,
11537        cx: &mut Context<Self>,
11538    ) {
11539        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11540        let text_layout_details = &self.text_layout_details(window);
11541        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11542            s.move_heads_with(|map, head, goal| {
11543                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11544            })
11545        })
11546    }
11547
11548    pub fn select_page_up(
11549        &mut self,
11550        _: &SelectPageUp,
11551        window: &mut Window,
11552        cx: &mut Context<Self>,
11553    ) {
11554        let Some(row_count) = self.visible_row_count() else {
11555            return;
11556        };
11557
11558        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11559
11560        let text_layout_details = &self.text_layout_details(window);
11561
11562        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11563            s.move_heads_with(|map, head, goal| {
11564                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11565            })
11566        })
11567    }
11568
11569    pub fn move_page_up(
11570        &mut self,
11571        action: &MovePageUp,
11572        window: &mut Window,
11573        cx: &mut Context<Self>,
11574    ) {
11575        if self.take_rename(true, window, cx).is_some() {
11576            return;
11577        }
11578
11579        if self
11580            .context_menu
11581            .borrow_mut()
11582            .as_mut()
11583            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11584            .unwrap_or(false)
11585        {
11586            return;
11587        }
11588
11589        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11590            cx.propagate();
11591            return;
11592        }
11593
11594        let Some(row_count) = self.visible_row_count() else {
11595            return;
11596        };
11597
11598        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11599
11600        let autoscroll = if action.center_cursor {
11601            Autoscroll::center()
11602        } else {
11603            Autoscroll::fit()
11604        };
11605
11606        let text_layout_details = &self.text_layout_details(window);
11607
11608        self.change_selections(Some(autoscroll), window, cx, |s| {
11609            s.move_with(|map, selection| {
11610                if !selection.is_empty() {
11611                    selection.goal = SelectionGoal::None;
11612                }
11613                let (cursor, goal) = movement::up_by_rows(
11614                    map,
11615                    selection.end,
11616                    row_count,
11617                    selection.goal,
11618                    false,
11619                    text_layout_details,
11620                );
11621                selection.collapse_to(cursor, goal);
11622            });
11623        });
11624    }
11625
11626    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11627        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11628        let text_layout_details = &self.text_layout_details(window);
11629        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11630            s.move_heads_with(|map, head, goal| {
11631                movement::up(map, head, goal, false, text_layout_details)
11632            })
11633        })
11634    }
11635
11636    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11637        self.take_rename(true, window, cx);
11638
11639        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11640            cx.propagate();
11641            return;
11642        }
11643
11644        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11645
11646        let text_layout_details = &self.text_layout_details(window);
11647        let selection_count = self.selections.count();
11648        let first_selection = self.selections.first_anchor();
11649
11650        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11651            s.move_with(|map, selection| {
11652                if !selection.is_empty() {
11653                    selection.goal = SelectionGoal::None;
11654                }
11655                let (cursor, goal) = movement::down(
11656                    map,
11657                    selection.end,
11658                    selection.goal,
11659                    false,
11660                    text_layout_details,
11661                );
11662                selection.collapse_to(cursor, goal);
11663            });
11664        });
11665
11666        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11667        {
11668            cx.propagate();
11669        }
11670    }
11671
11672    pub fn select_page_down(
11673        &mut self,
11674        _: &SelectPageDown,
11675        window: &mut Window,
11676        cx: &mut Context<Self>,
11677    ) {
11678        let Some(row_count) = self.visible_row_count() else {
11679            return;
11680        };
11681
11682        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11683
11684        let text_layout_details = &self.text_layout_details(window);
11685
11686        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11687            s.move_heads_with(|map, head, goal| {
11688                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11689            })
11690        })
11691    }
11692
11693    pub fn move_page_down(
11694        &mut self,
11695        action: &MovePageDown,
11696        window: &mut Window,
11697        cx: &mut Context<Self>,
11698    ) {
11699        if self.take_rename(true, window, cx).is_some() {
11700            return;
11701        }
11702
11703        if self
11704            .context_menu
11705            .borrow_mut()
11706            .as_mut()
11707            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11708            .unwrap_or(false)
11709        {
11710            return;
11711        }
11712
11713        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11714            cx.propagate();
11715            return;
11716        }
11717
11718        let Some(row_count) = self.visible_row_count() else {
11719            return;
11720        };
11721
11722        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11723
11724        let autoscroll = if action.center_cursor {
11725            Autoscroll::center()
11726        } else {
11727            Autoscroll::fit()
11728        };
11729
11730        let text_layout_details = &self.text_layout_details(window);
11731        self.change_selections(Some(autoscroll), window, cx, |s| {
11732            s.move_with(|map, selection| {
11733                if !selection.is_empty() {
11734                    selection.goal = SelectionGoal::None;
11735                }
11736                let (cursor, goal) = movement::down_by_rows(
11737                    map,
11738                    selection.end,
11739                    row_count,
11740                    selection.goal,
11741                    false,
11742                    text_layout_details,
11743                );
11744                selection.collapse_to(cursor, goal);
11745            });
11746        });
11747    }
11748
11749    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11750        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11751        let text_layout_details = &self.text_layout_details(window);
11752        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11753            s.move_heads_with(|map, head, goal| {
11754                movement::down(map, head, goal, false, text_layout_details)
11755            })
11756        });
11757    }
11758
11759    pub fn context_menu_first(
11760        &mut self,
11761        _: &ContextMenuFirst,
11762        window: &mut Window,
11763        cx: &mut Context<Self>,
11764    ) {
11765        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11766            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11767        }
11768    }
11769
11770    pub fn context_menu_prev(
11771        &mut self,
11772        _: &ContextMenuPrevious,
11773        window: &mut Window,
11774        cx: &mut Context<Self>,
11775    ) {
11776        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11777            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11778        }
11779    }
11780
11781    pub fn context_menu_next(
11782        &mut self,
11783        _: &ContextMenuNext,
11784        window: &mut Window,
11785        cx: &mut Context<Self>,
11786    ) {
11787        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11788            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11789        }
11790    }
11791
11792    pub fn context_menu_last(
11793        &mut self,
11794        _: &ContextMenuLast,
11795        window: &mut Window,
11796        cx: &mut Context<Self>,
11797    ) {
11798        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11799            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11800        }
11801    }
11802
11803    pub fn move_to_previous_word_start(
11804        &mut self,
11805        _: &MoveToPreviousWordStart,
11806        window: &mut Window,
11807        cx: &mut Context<Self>,
11808    ) {
11809        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11810        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11811            s.move_cursors_with(|map, head, _| {
11812                (
11813                    movement::previous_word_start(map, head),
11814                    SelectionGoal::None,
11815                )
11816            });
11817        })
11818    }
11819
11820    pub fn move_to_previous_subword_start(
11821        &mut self,
11822        _: &MoveToPreviousSubwordStart,
11823        window: &mut Window,
11824        cx: &mut Context<Self>,
11825    ) {
11826        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11827        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11828            s.move_cursors_with(|map, head, _| {
11829                (
11830                    movement::previous_subword_start(map, head),
11831                    SelectionGoal::None,
11832                )
11833            });
11834        })
11835    }
11836
11837    pub fn select_to_previous_word_start(
11838        &mut self,
11839        _: &SelectToPreviousWordStart,
11840        window: &mut Window,
11841        cx: &mut Context<Self>,
11842    ) {
11843        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11844        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11845            s.move_heads_with(|map, head, _| {
11846                (
11847                    movement::previous_word_start(map, head),
11848                    SelectionGoal::None,
11849                )
11850            });
11851        })
11852    }
11853
11854    pub fn select_to_previous_subword_start(
11855        &mut self,
11856        _: &SelectToPreviousSubwordStart,
11857        window: &mut Window,
11858        cx: &mut Context<Self>,
11859    ) {
11860        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11861        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11862            s.move_heads_with(|map, head, _| {
11863                (
11864                    movement::previous_subword_start(map, head),
11865                    SelectionGoal::None,
11866                )
11867            });
11868        })
11869    }
11870
11871    pub fn delete_to_previous_word_start(
11872        &mut self,
11873        action: &DeleteToPreviousWordStart,
11874        window: &mut Window,
11875        cx: &mut Context<Self>,
11876    ) {
11877        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11878        self.transact(window, cx, |this, window, cx| {
11879            this.select_autoclose_pair(window, cx);
11880            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11881                s.move_with(|map, selection| {
11882                    if selection.is_empty() {
11883                        let cursor = if action.ignore_newlines {
11884                            movement::previous_word_start(map, selection.head())
11885                        } else {
11886                            movement::previous_word_start_or_newline(map, selection.head())
11887                        };
11888                        selection.set_head(cursor, SelectionGoal::None);
11889                    }
11890                });
11891            });
11892            this.insert("", window, cx);
11893        });
11894    }
11895
11896    pub fn delete_to_previous_subword_start(
11897        &mut self,
11898        _: &DeleteToPreviousSubwordStart,
11899        window: &mut Window,
11900        cx: &mut Context<Self>,
11901    ) {
11902        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11903        self.transact(window, cx, |this, window, cx| {
11904            this.select_autoclose_pair(window, cx);
11905            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11906                s.move_with(|map, selection| {
11907                    if selection.is_empty() {
11908                        let cursor = movement::previous_subword_start(map, selection.head());
11909                        selection.set_head(cursor, SelectionGoal::None);
11910                    }
11911                });
11912            });
11913            this.insert("", window, cx);
11914        });
11915    }
11916
11917    pub fn move_to_next_word_end(
11918        &mut self,
11919        _: &MoveToNextWordEnd,
11920        window: &mut Window,
11921        cx: &mut Context<Self>,
11922    ) {
11923        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11924        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11925            s.move_cursors_with(|map, head, _| {
11926                (movement::next_word_end(map, head), SelectionGoal::None)
11927            });
11928        })
11929    }
11930
11931    pub fn move_to_next_subword_end(
11932        &mut self,
11933        _: &MoveToNextSubwordEnd,
11934        window: &mut Window,
11935        cx: &mut Context<Self>,
11936    ) {
11937        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11938        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11939            s.move_cursors_with(|map, head, _| {
11940                (movement::next_subword_end(map, head), SelectionGoal::None)
11941            });
11942        })
11943    }
11944
11945    pub fn select_to_next_word_end(
11946        &mut self,
11947        _: &SelectToNextWordEnd,
11948        window: &mut Window,
11949        cx: &mut Context<Self>,
11950    ) {
11951        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11952        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11953            s.move_heads_with(|map, head, _| {
11954                (movement::next_word_end(map, head), SelectionGoal::None)
11955            });
11956        })
11957    }
11958
11959    pub fn select_to_next_subword_end(
11960        &mut self,
11961        _: &SelectToNextSubwordEnd,
11962        window: &mut Window,
11963        cx: &mut Context<Self>,
11964    ) {
11965        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11966        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11967            s.move_heads_with(|map, head, _| {
11968                (movement::next_subword_end(map, head), SelectionGoal::None)
11969            });
11970        })
11971    }
11972
11973    pub fn delete_to_next_word_end(
11974        &mut self,
11975        action: &DeleteToNextWordEnd,
11976        window: &mut Window,
11977        cx: &mut Context<Self>,
11978    ) {
11979        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11980        self.transact(window, cx, |this, window, cx| {
11981            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11982                s.move_with(|map, selection| {
11983                    if selection.is_empty() {
11984                        let cursor = if action.ignore_newlines {
11985                            movement::next_word_end(map, selection.head())
11986                        } else {
11987                            movement::next_word_end_or_newline(map, selection.head())
11988                        };
11989                        selection.set_head(cursor, SelectionGoal::None);
11990                    }
11991                });
11992            });
11993            this.insert("", window, cx);
11994        });
11995    }
11996
11997    pub fn delete_to_next_subword_end(
11998        &mut self,
11999        _: &DeleteToNextSubwordEnd,
12000        window: &mut Window,
12001        cx: &mut Context<Self>,
12002    ) {
12003        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12004        self.transact(window, cx, |this, window, cx| {
12005            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12006                s.move_with(|map, selection| {
12007                    if selection.is_empty() {
12008                        let cursor = movement::next_subword_end(map, selection.head());
12009                        selection.set_head(cursor, SelectionGoal::None);
12010                    }
12011                });
12012            });
12013            this.insert("", window, cx);
12014        });
12015    }
12016
12017    pub fn move_to_beginning_of_line(
12018        &mut self,
12019        action: &MoveToBeginningOfLine,
12020        window: &mut Window,
12021        cx: &mut Context<Self>,
12022    ) {
12023        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12024        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12025            s.move_cursors_with(|map, head, _| {
12026                (
12027                    movement::indented_line_beginning(
12028                        map,
12029                        head,
12030                        action.stop_at_soft_wraps,
12031                        action.stop_at_indent,
12032                    ),
12033                    SelectionGoal::None,
12034                )
12035            });
12036        })
12037    }
12038
12039    pub fn select_to_beginning_of_line(
12040        &mut self,
12041        action: &SelectToBeginningOfLine,
12042        window: &mut Window,
12043        cx: &mut Context<Self>,
12044    ) {
12045        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12046        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12047            s.move_heads_with(|map, head, _| {
12048                (
12049                    movement::indented_line_beginning(
12050                        map,
12051                        head,
12052                        action.stop_at_soft_wraps,
12053                        action.stop_at_indent,
12054                    ),
12055                    SelectionGoal::None,
12056                )
12057            });
12058        });
12059    }
12060
12061    pub fn delete_to_beginning_of_line(
12062        &mut self,
12063        action: &DeleteToBeginningOfLine,
12064        window: &mut Window,
12065        cx: &mut Context<Self>,
12066    ) {
12067        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12068        self.transact(window, cx, |this, window, cx| {
12069            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12070                s.move_with(|_, selection| {
12071                    selection.reversed = true;
12072                });
12073            });
12074
12075            this.select_to_beginning_of_line(
12076                &SelectToBeginningOfLine {
12077                    stop_at_soft_wraps: false,
12078                    stop_at_indent: action.stop_at_indent,
12079                },
12080                window,
12081                cx,
12082            );
12083            this.backspace(&Backspace, window, cx);
12084        });
12085    }
12086
12087    pub fn move_to_end_of_line(
12088        &mut self,
12089        action: &MoveToEndOfLine,
12090        window: &mut Window,
12091        cx: &mut Context<Self>,
12092    ) {
12093        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12094        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12095            s.move_cursors_with(|map, head, _| {
12096                (
12097                    movement::line_end(map, head, action.stop_at_soft_wraps),
12098                    SelectionGoal::None,
12099                )
12100            });
12101        })
12102    }
12103
12104    pub fn select_to_end_of_line(
12105        &mut self,
12106        action: &SelectToEndOfLine,
12107        window: &mut Window,
12108        cx: &mut Context<Self>,
12109    ) {
12110        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12111        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12112            s.move_heads_with(|map, head, _| {
12113                (
12114                    movement::line_end(map, head, action.stop_at_soft_wraps),
12115                    SelectionGoal::None,
12116                )
12117            });
12118        })
12119    }
12120
12121    pub fn delete_to_end_of_line(
12122        &mut self,
12123        _: &DeleteToEndOfLine,
12124        window: &mut Window,
12125        cx: &mut Context<Self>,
12126    ) {
12127        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12128        self.transact(window, cx, |this, window, cx| {
12129            this.select_to_end_of_line(
12130                &SelectToEndOfLine {
12131                    stop_at_soft_wraps: false,
12132                },
12133                window,
12134                cx,
12135            );
12136            this.delete(&Delete, window, cx);
12137        });
12138    }
12139
12140    pub fn cut_to_end_of_line(
12141        &mut self,
12142        _: &CutToEndOfLine,
12143        window: &mut Window,
12144        cx: &mut Context<Self>,
12145    ) {
12146        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12147        self.transact(window, cx, |this, window, cx| {
12148            this.select_to_end_of_line(
12149                &SelectToEndOfLine {
12150                    stop_at_soft_wraps: false,
12151                },
12152                window,
12153                cx,
12154            );
12155            this.cut(&Cut, window, cx);
12156        });
12157    }
12158
12159    pub fn move_to_start_of_paragraph(
12160        &mut self,
12161        _: &MoveToStartOfParagraph,
12162        window: &mut Window,
12163        cx: &mut Context<Self>,
12164    ) {
12165        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12166            cx.propagate();
12167            return;
12168        }
12169        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12170        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12171            s.move_with(|map, selection| {
12172                selection.collapse_to(
12173                    movement::start_of_paragraph(map, selection.head(), 1),
12174                    SelectionGoal::None,
12175                )
12176            });
12177        })
12178    }
12179
12180    pub fn move_to_end_of_paragraph(
12181        &mut self,
12182        _: &MoveToEndOfParagraph,
12183        window: &mut Window,
12184        cx: &mut Context<Self>,
12185    ) {
12186        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12187            cx.propagate();
12188            return;
12189        }
12190        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12191        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12192            s.move_with(|map, selection| {
12193                selection.collapse_to(
12194                    movement::end_of_paragraph(map, selection.head(), 1),
12195                    SelectionGoal::None,
12196                )
12197            });
12198        })
12199    }
12200
12201    pub fn select_to_start_of_paragraph(
12202        &mut self,
12203        _: &SelectToStartOfParagraph,
12204        window: &mut Window,
12205        cx: &mut Context<Self>,
12206    ) {
12207        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12208            cx.propagate();
12209            return;
12210        }
12211        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12212        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12213            s.move_heads_with(|map, head, _| {
12214                (
12215                    movement::start_of_paragraph(map, head, 1),
12216                    SelectionGoal::None,
12217                )
12218            });
12219        })
12220    }
12221
12222    pub fn select_to_end_of_paragraph(
12223        &mut self,
12224        _: &SelectToEndOfParagraph,
12225        window: &mut Window,
12226        cx: &mut Context<Self>,
12227    ) {
12228        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12229            cx.propagate();
12230            return;
12231        }
12232        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12233        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12234            s.move_heads_with(|map, head, _| {
12235                (
12236                    movement::end_of_paragraph(map, head, 1),
12237                    SelectionGoal::None,
12238                )
12239            });
12240        })
12241    }
12242
12243    pub fn move_to_start_of_excerpt(
12244        &mut self,
12245        _: &MoveToStartOfExcerpt,
12246        window: &mut Window,
12247        cx: &mut Context<Self>,
12248    ) {
12249        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12250            cx.propagate();
12251            return;
12252        }
12253        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12254        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12255            s.move_with(|map, selection| {
12256                selection.collapse_to(
12257                    movement::start_of_excerpt(
12258                        map,
12259                        selection.head(),
12260                        workspace::searchable::Direction::Prev,
12261                    ),
12262                    SelectionGoal::None,
12263                )
12264            });
12265        })
12266    }
12267
12268    pub fn move_to_start_of_next_excerpt(
12269        &mut self,
12270        _: &MoveToStartOfNextExcerpt,
12271        window: &mut Window,
12272        cx: &mut Context<Self>,
12273    ) {
12274        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12275            cx.propagate();
12276            return;
12277        }
12278
12279        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12280            s.move_with(|map, selection| {
12281                selection.collapse_to(
12282                    movement::start_of_excerpt(
12283                        map,
12284                        selection.head(),
12285                        workspace::searchable::Direction::Next,
12286                    ),
12287                    SelectionGoal::None,
12288                )
12289            });
12290        })
12291    }
12292
12293    pub fn move_to_end_of_excerpt(
12294        &mut self,
12295        _: &MoveToEndOfExcerpt,
12296        window: &mut Window,
12297        cx: &mut Context<Self>,
12298    ) {
12299        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12300            cx.propagate();
12301            return;
12302        }
12303        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12304        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12305            s.move_with(|map, selection| {
12306                selection.collapse_to(
12307                    movement::end_of_excerpt(
12308                        map,
12309                        selection.head(),
12310                        workspace::searchable::Direction::Next,
12311                    ),
12312                    SelectionGoal::None,
12313                )
12314            });
12315        })
12316    }
12317
12318    pub fn move_to_end_of_previous_excerpt(
12319        &mut self,
12320        _: &MoveToEndOfPreviousExcerpt,
12321        window: &mut Window,
12322        cx: &mut Context<Self>,
12323    ) {
12324        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12325            cx.propagate();
12326            return;
12327        }
12328        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12329        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12330            s.move_with(|map, selection| {
12331                selection.collapse_to(
12332                    movement::end_of_excerpt(
12333                        map,
12334                        selection.head(),
12335                        workspace::searchable::Direction::Prev,
12336                    ),
12337                    SelectionGoal::None,
12338                )
12339            });
12340        })
12341    }
12342
12343    pub fn select_to_start_of_excerpt(
12344        &mut self,
12345        _: &SelectToStartOfExcerpt,
12346        window: &mut Window,
12347        cx: &mut Context<Self>,
12348    ) {
12349        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12350            cx.propagate();
12351            return;
12352        }
12353        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12354        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12355            s.move_heads_with(|map, head, _| {
12356                (
12357                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12358                    SelectionGoal::None,
12359                )
12360            });
12361        })
12362    }
12363
12364    pub fn select_to_start_of_next_excerpt(
12365        &mut self,
12366        _: &SelectToStartOfNextExcerpt,
12367        window: &mut Window,
12368        cx: &mut Context<Self>,
12369    ) {
12370        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12371            cx.propagate();
12372            return;
12373        }
12374        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12375        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12376            s.move_heads_with(|map, head, _| {
12377                (
12378                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12379                    SelectionGoal::None,
12380                )
12381            });
12382        })
12383    }
12384
12385    pub fn select_to_end_of_excerpt(
12386        &mut self,
12387        _: &SelectToEndOfExcerpt,
12388        window: &mut Window,
12389        cx: &mut Context<Self>,
12390    ) {
12391        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12392            cx.propagate();
12393            return;
12394        }
12395        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12396        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12397            s.move_heads_with(|map, head, _| {
12398                (
12399                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12400                    SelectionGoal::None,
12401                )
12402            });
12403        })
12404    }
12405
12406    pub fn select_to_end_of_previous_excerpt(
12407        &mut self,
12408        _: &SelectToEndOfPreviousExcerpt,
12409        window: &mut Window,
12410        cx: &mut Context<Self>,
12411    ) {
12412        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12413            cx.propagate();
12414            return;
12415        }
12416        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12417        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12418            s.move_heads_with(|map, head, _| {
12419                (
12420                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12421                    SelectionGoal::None,
12422                )
12423            });
12424        })
12425    }
12426
12427    pub fn move_to_beginning(
12428        &mut self,
12429        _: &MoveToBeginning,
12430        window: &mut Window,
12431        cx: &mut Context<Self>,
12432    ) {
12433        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12434            cx.propagate();
12435            return;
12436        }
12437        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12438        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12439            s.select_ranges(vec![0..0]);
12440        });
12441    }
12442
12443    pub fn select_to_beginning(
12444        &mut self,
12445        _: &SelectToBeginning,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) {
12449        let mut selection = self.selections.last::<Point>(cx);
12450        selection.set_head(Point::zero(), SelectionGoal::None);
12451        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12452        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12453            s.select(vec![selection]);
12454        });
12455    }
12456
12457    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12458        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12459            cx.propagate();
12460            return;
12461        }
12462        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12463        let cursor = self.buffer.read(cx).read(cx).len();
12464        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12465            s.select_ranges(vec![cursor..cursor])
12466        });
12467    }
12468
12469    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12470        self.nav_history = nav_history;
12471    }
12472
12473    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12474        self.nav_history.as_ref()
12475    }
12476
12477    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12478        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12479    }
12480
12481    fn push_to_nav_history(
12482        &mut self,
12483        cursor_anchor: Anchor,
12484        new_position: Option<Point>,
12485        is_deactivate: bool,
12486        cx: &mut Context<Self>,
12487    ) {
12488        if let Some(nav_history) = self.nav_history.as_mut() {
12489            let buffer = self.buffer.read(cx).read(cx);
12490            let cursor_position = cursor_anchor.to_point(&buffer);
12491            let scroll_state = self.scroll_manager.anchor();
12492            let scroll_top_row = scroll_state.top_row(&buffer);
12493            drop(buffer);
12494
12495            if let Some(new_position) = new_position {
12496                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12497                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12498                    return;
12499                }
12500            }
12501
12502            nav_history.push(
12503                Some(NavigationData {
12504                    cursor_anchor,
12505                    cursor_position,
12506                    scroll_anchor: scroll_state,
12507                    scroll_top_row,
12508                }),
12509                cx,
12510            );
12511            cx.emit(EditorEvent::PushedToNavHistory {
12512                anchor: cursor_anchor,
12513                is_deactivate,
12514            })
12515        }
12516    }
12517
12518    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12519        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12520        let buffer = self.buffer.read(cx).snapshot(cx);
12521        let mut selection = self.selections.first::<usize>(cx);
12522        selection.set_head(buffer.len(), SelectionGoal::None);
12523        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12524            s.select(vec![selection]);
12525        });
12526    }
12527
12528    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12529        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12530        let end = self.buffer.read(cx).read(cx).len();
12531        self.change_selections(None, window, cx, |s| {
12532            s.select_ranges(vec![0..end]);
12533        });
12534    }
12535
12536    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12537        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12538        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12539        let mut selections = self.selections.all::<Point>(cx);
12540        let max_point = display_map.buffer_snapshot.max_point();
12541        for selection in &mut selections {
12542            let rows = selection.spanned_rows(true, &display_map);
12543            selection.start = Point::new(rows.start.0, 0);
12544            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12545            selection.reversed = false;
12546        }
12547        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12548            s.select(selections);
12549        });
12550    }
12551
12552    pub fn split_selection_into_lines(
12553        &mut self,
12554        _: &SplitSelectionIntoLines,
12555        window: &mut Window,
12556        cx: &mut Context<Self>,
12557    ) {
12558        let selections = self
12559            .selections
12560            .all::<Point>(cx)
12561            .into_iter()
12562            .map(|selection| selection.start..selection.end)
12563            .collect::<Vec<_>>();
12564        self.unfold_ranges(&selections, true, true, cx);
12565
12566        let mut new_selection_ranges = Vec::new();
12567        {
12568            let buffer = self.buffer.read(cx).read(cx);
12569            for selection in selections {
12570                for row in selection.start.row..selection.end.row {
12571                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12572                    new_selection_ranges.push(cursor..cursor);
12573                }
12574
12575                let is_multiline_selection = selection.start.row != selection.end.row;
12576                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12577                // so this action feels more ergonomic when paired with other selection operations
12578                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12579                if !should_skip_last {
12580                    new_selection_ranges.push(selection.end..selection.end);
12581                }
12582            }
12583        }
12584        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12585            s.select_ranges(new_selection_ranges);
12586        });
12587    }
12588
12589    pub fn add_selection_above(
12590        &mut self,
12591        _: &AddSelectionAbove,
12592        window: &mut Window,
12593        cx: &mut Context<Self>,
12594    ) {
12595        self.add_selection(true, window, cx);
12596    }
12597
12598    pub fn add_selection_below(
12599        &mut self,
12600        _: &AddSelectionBelow,
12601        window: &mut Window,
12602        cx: &mut Context<Self>,
12603    ) {
12604        self.add_selection(false, window, cx);
12605    }
12606
12607    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12608        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12609
12610        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12611        let mut selections = self.selections.all::<Point>(cx);
12612        let text_layout_details = self.text_layout_details(window);
12613        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12614            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12615            let range = oldest_selection.display_range(&display_map).sorted();
12616
12617            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12618            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12619            let positions = start_x.min(end_x)..start_x.max(end_x);
12620
12621            selections.clear();
12622            let mut stack = Vec::new();
12623            for row in range.start.row().0..=range.end.row().0 {
12624                if let Some(selection) = self.selections.build_columnar_selection(
12625                    &display_map,
12626                    DisplayRow(row),
12627                    &positions,
12628                    oldest_selection.reversed,
12629                    &text_layout_details,
12630                ) {
12631                    stack.push(selection.id);
12632                    selections.push(selection);
12633                }
12634            }
12635
12636            if above {
12637                stack.reverse();
12638            }
12639
12640            AddSelectionsState { above, stack }
12641        });
12642
12643        let last_added_selection = *state.stack.last().unwrap();
12644        let mut new_selections = Vec::new();
12645        if above == state.above {
12646            let end_row = if above {
12647                DisplayRow(0)
12648            } else {
12649                display_map.max_point().row()
12650            };
12651
12652            'outer: for selection in selections {
12653                if selection.id == last_added_selection {
12654                    let range = selection.display_range(&display_map).sorted();
12655                    debug_assert_eq!(range.start.row(), range.end.row());
12656                    let mut row = range.start.row();
12657                    let positions =
12658                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12659                            px(start)..px(end)
12660                        } else {
12661                            let start_x =
12662                                display_map.x_for_display_point(range.start, &text_layout_details);
12663                            let end_x =
12664                                display_map.x_for_display_point(range.end, &text_layout_details);
12665                            start_x.min(end_x)..start_x.max(end_x)
12666                        };
12667
12668                    while row != end_row {
12669                        if above {
12670                            row.0 -= 1;
12671                        } else {
12672                            row.0 += 1;
12673                        }
12674
12675                        if let Some(new_selection) = self.selections.build_columnar_selection(
12676                            &display_map,
12677                            row,
12678                            &positions,
12679                            selection.reversed,
12680                            &text_layout_details,
12681                        ) {
12682                            state.stack.push(new_selection.id);
12683                            if above {
12684                                new_selections.push(new_selection);
12685                                new_selections.push(selection);
12686                            } else {
12687                                new_selections.push(selection);
12688                                new_selections.push(new_selection);
12689                            }
12690
12691                            continue 'outer;
12692                        }
12693                    }
12694                }
12695
12696                new_selections.push(selection);
12697            }
12698        } else {
12699            new_selections = selections;
12700            new_selections.retain(|s| s.id != last_added_selection);
12701            state.stack.pop();
12702        }
12703
12704        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12705            s.select(new_selections);
12706        });
12707        if state.stack.len() > 1 {
12708            self.add_selections_state = Some(state);
12709        }
12710    }
12711
12712    fn select_match_ranges(
12713        &mut self,
12714        range: Range<usize>,
12715        reversed: bool,
12716        replace_newest: bool,
12717        auto_scroll: Option<Autoscroll>,
12718        window: &mut Window,
12719        cx: &mut Context<Editor>,
12720    ) {
12721        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12722        self.change_selections(auto_scroll, window, cx, |s| {
12723            if replace_newest {
12724                s.delete(s.newest_anchor().id);
12725            }
12726            if reversed {
12727                s.insert_range(range.end..range.start);
12728            } else {
12729                s.insert_range(range);
12730            }
12731        });
12732    }
12733
12734    pub fn select_next_match_internal(
12735        &mut self,
12736        display_map: &DisplaySnapshot,
12737        replace_newest: bool,
12738        autoscroll: Option<Autoscroll>,
12739        window: &mut Window,
12740        cx: &mut Context<Self>,
12741    ) -> Result<()> {
12742        let buffer = &display_map.buffer_snapshot;
12743        let mut selections = self.selections.all::<usize>(cx);
12744        if let Some(mut select_next_state) = self.select_next_state.take() {
12745            let query = &select_next_state.query;
12746            if !select_next_state.done {
12747                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12748                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12749                let mut next_selected_range = None;
12750
12751                let bytes_after_last_selection =
12752                    buffer.bytes_in_range(last_selection.end..buffer.len());
12753                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12754                let query_matches = query
12755                    .stream_find_iter(bytes_after_last_selection)
12756                    .map(|result| (last_selection.end, result))
12757                    .chain(
12758                        query
12759                            .stream_find_iter(bytes_before_first_selection)
12760                            .map(|result| (0, result)),
12761                    );
12762
12763                for (start_offset, query_match) in query_matches {
12764                    let query_match = query_match.unwrap(); // can only fail due to I/O
12765                    let offset_range =
12766                        start_offset + query_match.start()..start_offset + query_match.end();
12767                    let display_range = offset_range.start.to_display_point(display_map)
12768                        ..offset_range.end.to_display_point(display_map);
12769
12770                    if !select_next_state.wordwise
12771                        || (!movement::is_inside_word(display_map, display_range.start)
12772                            && !movement::is_inside_word(display_map, display_range.end))
12773                    {
12774                        // TODO: This is n^2, because we might check all the selections
12775                        if !selections
12776                            .iter()
12777                            .any(|selection| selection.range().overlaps(&offset_range))
12778                        {
12779                            next_selected_range = Some(offset_range);
12780                            break;
12781                        }
12782                    }
12783                }
12784
12785                if let Some(next_selected_range) = next_selected_range {
12786                    self.select_match_ranges(
12787                        next_selected_range,
12788                        last_selection.reversed,
12789                        replace_newest,
12790                        autoscroll,
12791                        window,
12792                        cx,
12793                    );
12794                } else {
12795                    select_next_state.done = true;
12796                }
12797            }
12798
12799            self.select_next_state = Some(select_next_state);
12800        } else {
12801            let mut only_carets = true;
12802            let mut same_text_selected = true;
12803            let mut selected_text = None;
12804
12805            let mut selections_iter = selections.iter().peekable();
12806            while let Some(selection) = selections_iter.next() {
12807                if selection.start != selection.end {
12808                    only_carets = false;
12809                }
12810
12811                if same_text_selected {
12812                    if selected_text.is_none() {
12813                        selected_text =
12814                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12815                    }
12816
12817                    if let Some(next_selection) = selections_iter.peek() {
12818                        if next_selection.range().len() == selection.range().len() {
12819                            let next_selected_text = buffer
12820                                .text_for_range(next_selection.range())
12821                                .collect::<String>();
12822                            if Some(next_selected_text) != selected_text {
12823                                same_text_selected = false;
12824                                selected_text = None;
12825                            }
12826                        } else {
12827                            same_text_selected = false;
12828                            selected_text = None;
12829                        }
12830                    }
12831                }
12832            }
12833
12834            if only_carets {
12835                for selection in &mut selections {
12836                    let word_range = movement::surrounding_word(
12837                        display_map,
12838                        selection.start.to_display_point(display_map),
12839                    );
12840                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12841                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12842                    selection.goal = SelectionGoal::None;
12843                    selection.reversed = false;
12844                    self.select_match_ranges(
12845                        selection.start..selection.end,
12846                        selection.reversed,
12847                        replace_newest,
12848                        autoscroll,
12849                        window,
12850                        cx,
12851                    );
12852                }
12853
12854                if selections.len() == 1 {
12855                    let selection = selections
12856                        .last()
12857                        .expect("ensured that there's only one selection");
12858                    let query = buffer
12859                        .text_for_range(selection.start..selection.end)
12860                        .collect::<String>();
12861                    let is_empty = query.is_empty();
12862                    let select_state = SelectNextState {
12863                        query: AhoCorasick::new(&[query])?,
12864                        wordwise: true,
12865                        done: is_empty,
12866                    };
12867                    self.select_next_state = Some(select_state);
12868                } else {
12869                    self.select_next_state = None;
12870                }
12871            } else if let Some(selected_text) = selected_text {
12872                self.select_next_state = Some(SelectNextState {
12873                    query: AhoCorasick::new(&[selected_text])?,
12874                    wordwise: false,
12875                    done: false,
12876                });
12877                self.select_next_match_internal(
12878                    display_map,
12879                    replace_newest,
12880                    autoscroll,
12881                    window,
12882                    cx,
12883                )?;
12884            }
12885        }
12886        Ok(())
12887    }
12888
12889    pub fn select_all_matches(
12890        &mut self,
12891        _action: &SelectAllMatches,
12892        window: &mut Window,
12893        cx: &mut Context<Self>,
12894    ) -> Result<()> {
12895        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12896
12897        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12898
12899        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12900        let Some(select_next_state) = self.select_next_state.as_mut() else {
12901            return Ok(());
12902        };
12903        if select_next_state.done {
12904            return Ok(());
12905        }
12906
12907        let mut new_selections = Vec::new();
12908
12909        let reversed = self.selections.oldest::<usize>(cx).reversed;
12910        let buffer = &display_map.buffer_snapshot;
12911        let query_matches = select_next_state
12912            .query
12913            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12914
12915        for query_match in query_matches.into_iter() {
12916            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12917            let offset_range = if reversed {
12918                query_match.end()..query_match.start()
12919            } else {
12920                query_match.start()..query_match.end()
12921            };
12922            let display_range = offset_range.start.to_display_point(&display_map)
12923                ..offset_range.end.to_display_point(&display_map);
12924
12925            if !select_next_state.wordwise
12926                || (!movement::is_inside_word(&display_map, display_range.start)
12927                    && !movement::is_inside_word(&display_map, display_range.end))
12928            {
12929                new_selections.push(offset_range.start..offset_range.end);
12930            }
12931        }
12932
12933        select_next_state.done = true;
12934        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12935        self.change_selections(None, window, cx, |selections| {
12936            selections.select_ranges(new_selections)
12937        });
12938
12939        Ok(())
12940    }
12941
12942    pub fn select_next(
12943        &mut self,
12944        action: &SelectNext,
12945        window: &mut Window,
12946        cx: &mut Context<Self>,
12947    ) -> Result<()> {
12948        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12949        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12950        self.select_next_match_internal(
12951            &display_map,
12952            action.replace_newest,
12953            Some(Autoscroll::newest()),
12954            window,
12955            cx,
12956        )?;
12957        Ok(())
12958    }
12959
12960    pub fn select_previous(
12961        &mut self,
12962        action: &SelectPrevious,
12963        window: &mut Window,
12964        cx: &mut Context<Self>,
12965    ) -> Result<()> {
12966        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12967        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12968        let buffer = &display_map.buffer_snapshot;
12969        let mut selections = self.selections.all::<usize>(cx);
12970        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12971            let query = &select_prev_state.query;
12972            if !select_prev_state.done {
12973                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12974                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12975                let mut next_selected_range = None;
12976                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12977                let bytes_before_last_selection =
12978                    buffer.reversed_bytes_in_range(0..last_selection.start);
12979                let bytes_after_first_selection =
12980                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12981                let query_matches = query
12982                    .stream_find_iter(bytes_before_last_selection)
12983                    .map(|result| (last_selection.start, result))
12984                    .chain(
12985                        query
12986                            .stream_find_iter(bytes_after_first_selection)
12987                            .map(|result| (buffer.len(), result)),
12988                    );
12989                for (end_offset, query_match) in query_matches {
12990                    let query_match = query_match.unwrap(); // can only fail due to I/O
12991                    let offset_range =
12992                        end_offset - query_match.end()..end_offset - query_match.start();
12993                    let display_range = offset_range.start.to_display_point(&display_map)
12994                        ..offset_range.end.to_display_point(&display_map);
12995
12996                    if !select_prev_state.wordwise
12997                        || (!movement::is_inside_word(&display_map, display_range.start)
12998                            && !movement::is_inside_word(&display_map, display_range.end))
12999                    {
13000                        next_selected_range = Some(offset_range);
13001                        break;
13002                    }
13003                }
13004
13005                if let Some(next_selected_range) = next_selected_range {
13006                    self.select_match_ranges(
13007                        next_selected_range,
13008                        last_selection.reversed,
13009                        action.replace_newest,
13010                        Some(Autoscroll::newest()),
13011                        window,
13012                        cx,
13013                    );
13014                } else {
13015                    select_prev_state.done = true;
13016                }
13017            }
13018
13019            self.select_prev_state = Some(select_prev_state);
13020        } else {
13021            let mut only_carets = true;
13022            let mut same_text_selected = true;
13023            let mut selected_text = None;
13024
13025            let mut selections_iter = selections.iter().peekable();
13026            while let Some(selection) = selections_iter.next() {
13027                if selection.start != selection.end {
13028                    only_carets = false;
13029                }
13030
13031                if same_text_selected {
13032                    if selected_text.is_none() {
13033                        selected_text =
13034                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13035                    }
13036
13037                    if let Some(next_selection) = selections_iter.peek() {
13038                        if next_selection.range().len() == selection.range().len() {
13039                            let next_selected_text = buffer
13040                                .text_for_range(next_selection.range())
13041                                .collect::<String>();
13042                            if Some(next_selected_text) != selected_text {
13043                                same_text_selected = false;
13044                                selected_text = None;
13045                            }
13046                        } else {
13047                            same_text_selected = false;
13048                            selected_text = None;
13049                        }
13050                    }
13051                }
13052            }
13053
13054            if only_carets {
13055                for selection in &mut selections {
13056                    let word_range = movement::surrounding_word(
13057                        &display_map,
13058                        selection.start.to_display_point(&display_map),
13059                    );
13060                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13061                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13062                    selection.goal = SelectionGoal::None;
13063                    selection.reversed = false;
13064                    self.select_match_ranges(
13065                        selection.start..selection.end,
13066                        selection.reversed,
13067                        action.replace_newest,
13068                        Some(Autoscroll::newest()),
13069                        window,
13070                        cx,
13071                    );
13072                }
13073                if selections.len() == 1 {
13074                    let selection = selections
13075                        .last()
13076                        .expect("ensured that there's only one selection");
13077                    let query = buffer
13078                        .text_for_range(selection.start..selection.end)
13079                        .collect::<String>();
13080                    let is_empty = query.is_empty();
13081                    let select_state = SelectNextState {
13082                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13083                        wordwise: true,
13084                        done: is_empty,
13085                    };
13086                    self.select_prev_state = Some(select_state);
13087                } else {
13088                    self.select_prev_state = None;
13089                }
13090            } else if let Some(selected_text) = selected_text {
13091                self.select_prev_state = Some(SelectNextState {
13092                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13093                    wordwise: false,
13094                    done: false,
13095                });
13096                self.select_previous(action, window, cx)?;
13097            }
13098        }
13099        Ok(())
13100    }
13101
13102    pub fn find_next_match(
13103        &mut self,
13104        _: &FindNextMatch,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) -> Result<()> {
13108        let selections = self.selections.disjoint_anchors();
13109        match selections.first() {
13110            Some(first) if selections.len() >= 2 => {
13111                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13112                    s.select_ranges([first.range()]);
13113                });
13114            }
13115            _ => self.select_next(
13116                &SelectNext {
13117                    replace_newest: true,
13118                },
13119                window,
13120                cx,
13121            )?,
13122        }
13123        Ok(())
13124    }
13125
13126    pub fn find_previous_match(
13127        &mut self,
13128        _: &FindPreviousMatch,
13129        window: &mut Window,
13130        cx: &mut Context<Self>,
13131    ) -> Result<()> {
13132        let selections = self.selections.disjoint_anchors();
13133        match selections.last() {
13134            Some(last) if selections.len() >= 2 => {
13135                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13136                    s.select_ranges([last.range()]);
13137                });
13138            }
13139            _ => self.select_previous(
13140                &SelectPrevious {
13141                    replace_newest: true,
13142                },
13143                window,
13144                cx,
13145            )?,
13146        }
13147        Ok(())
13148    }
13149
13150    pub fn toggle_comments(
13151        &mut self,
13152        action: &ToggleComments,
13153        window: &mut Window,
13154        cx: &mut Context<Self>,
13155    ) {
13156        if self.read_only(cx) {
13157            return;
13158        }
13159        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13160        let text_layout_details = &self.text_layout_details(window);
13161        self.transact(window, cx, |this, window, cx| {
13162            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13163            let mut edits = Vec::new();
13164            let mut selection_edit_ranges = Vec::new();
13165            let mut last_toggled_row = None;
13166            let snapshot = this.buffer.read(cx).read(cx);
13167            let empty_str: Arc<str> = Arc::default();
13168            let mut suffixes_inserted = Vec::new();
13169            let ignore_indent = action.ignore_indent;
13170
13171            fn comment_prefix_range(
13172                snapshot: &MultiBufferSnapshot,
13173                row: MultiBufferRow,
13174                comment_prefix: &str,
13175                comment_prefix_whitespace: &str,
13176                ignore_indent: bool,
13177            ) -> Range<Point> {
13178                let indent_size = if ignore_indent {
13179                    0
13180                } else {
13181                    snapshot.indent_size_for_line(row).len
13182                };
13183
13184                let start = Point::new(row.0, indent_size);
13185
13186                let mut line_bytes = snapshot
13187                    .bytes_in_range(start..snapshot.max_point())
13188                    .flatten()
13189                    .copied();
13190
13191                // If this line currently begins with the line comment prefix, then record
13192                // the range containing the prefix.
13193                if line_bytes
13194                    .by_ref()
13195                    .take(comment_prefix.len())
13196                    .eq(comment_prefix.bytes())
13197                {
13198                    // Include any whitespace that matches the comment prefix.
13199                    let matching_whitespace_len = line_bytes
13200                        .zip(comment_prefix_whitespace.bytes())
13201                        .take_while(|(a, b)| a == b)
13202                        .count() as u32;
13203                    let end = Point::new(
13204                        start.row,
13205                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13206                    );
13207                    start..end
13208                } else {
13209                    start..start
13210                }
13211            }
13212
13213            fn comment_suffix_range(
13214                snapshot: &MultiBufferSnapshot,
13215                row: MultiBufferRow,
13216                comment_suffix: &str,
13217                comment_suffix_has_leading_space: bool,
13218            ) -> Range<Point> {
13219                let end = Point::new(row.0, snapshot.line_len(row));
13220                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13221
13222                let mut line_end_bytes = snapshot
13223                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13224                    .flatten()
13225                    .copied();
13226
13227                let leading_space_len = if suffix_start_column > 0
13228                    && line_end_bytes.next() == Some(b' ')
13229                    && comment_suffix_has_leading_space
13230                {
13231                    1
13232                } else {
13233                    0
13234                };
13235
13236                // If this line currently begins with the line comment prefix, then record
13237                // the range containing the prefix.
13238                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13239                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13240                    start..end
13241                } else {
13242                    end..end
13243                }
13244            }
13245
13246            // TODO: Handle selections that cross excerpts
13247            for selection in &mut selections {
13248                let start_column = snapshot
13249                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13250                    .len;
13251                let language = if let Some(language) =
13252                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13253                {
13254                    language
13255                } else {
13256                    continue;
13257                };
13258
13259                selection_edit_ranges.clear();
13260
13261                // If multiple selections contain a given row, avoid processing that
13262                // row more than once.
13263                let mut start_row = MultiBufferRow(selection.start.row);
13264                if last_toggled_row == Some(start_row) {
13265                    start_row = start_row.next_row();
13266                }
13267                let end_row =
13268                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13269                        MultiBufferRow(selection.end.row - 1)
13270                    } else {
13271                        MultiBufferRow(selection.end.row)
13272                    };
13273                last_toggled_row = Some(end_row);
13274
13275                if start_row > end_row {
13276                    continue;
13277                }
13278
13279                // If the language has line comments, toggle those.
13280                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13281
13282                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13283                if ignore_indent {
13284                    full_comment_prefixes = full_comment_prefixes
13285                        .into_iter()
13286                        .map(|s| Arc::from(s.trim_end()))
13287                        .collect();
13288                }
13289
13290                if !full_comment_prefixes.is_empty() {
13291                    let first_prefix = full_comment_prefixes
13292                        .first()
13293                        .expect("prefixes is non-empty");
13294                    let prefix_trimmed_lengths = full_comment_prefixes
13295                        .iter()
13296                        .map(|p| p.trim_end_matches(' ').len())
13297                        .collect::<SmallVec<[usize; 4]>>();
13298
13299                    let mut all_selection_lines_are_comments = true;
13300
13301                    for row in start_row.0..=end_row.0 {
13302                        let row = MultiBufferRow(row);
13303                        if start_row < end_row && snapshot.is_line_blank(row) {
13304                            continue;
13305                        }
13306
13307                        let prefix_range = full_comment_prefixes
13308                            .iter()
13309                            .zip(prefix_trimmed_lengths.iter().copied())
13310                            .map(|(prefix, trimmed_prefix_len)| {
13311                                comment_prefix_range(
13312                                    snapshot.deref(),
13313                                    row,
13314                                    &prefix[..trimmed_prefix_len],
13315                                    &prefix[trimmed_prefix_len..],
13316                                    ignore_indent,
13317                                )
13318                            })
13319                            .max_by_key(|range| range.end.column - range.start.column)
13320                            .expect("prefixes is non-empty");
13321
13322                        if prefix_range.is_empty() {
13323                            all_selection_lines_are_comments = false;
13324                        }
13325
13326                        selection_edit_ranges.push(prefix_range);
13327                    }
13328
13329                    if all_selection_lines_are_comments {
13330                        edits.extend(
13331                            selection_edit_ranges
13332                                .iter()
13333                                .cloned()
13334                                .map(|range| (range, empty_str.clone())),
13335                        );
13336                    } else {
13337                        let min_column = selection_edit_ranges
13338                            .iter()
13339                            .map(|range| range.start.column)
13340                            .min()
13341                            .unwrap_or(0);
13342                        edits.extend(selection_edit_ranges.iter().map(|range| {
13343                            let position = Point::new(range.start.row, min_column);
13344                            (position..position, first_prefix.clone())
13345                        }));
13346                    }
13347                } else if let Some((full_comment_prefix, comment_suffix)) =
13348                    language.block_comment_delimiters()
13349                {
13350                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13351                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13352                    let prefix_range = comment_prefix_range(
13353                        snapshot.deref(),
13354                        start_row,
13355                        comment_prefix,
13356                        comment_prefix_whitespace,
13357                        ignore_indent,
13358                    );
13359                    let suffix_range = comment_suffix_range(
13360                        snapshot.deref(),
13361                        end_row,
13362                        comment_suffix.trim_start_matches(' '),
13363                        comment_suffix.starts_with(' '),
13364                    );
13365
13366                    if prefix_range.is_empty() || suffix_range.is_empty() {
13367                        edits.push((
13368                            prefix_range.start..prefix_range.start,
13369                            full_comment_prefix.clone(),
13370                        ));
13371                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13372                        suffixes_inserted.push((end_row, comment_suffix.len()));
13373                    } else {
13374                        edits.push((prefix_range, empty_str.clone()));
13375                        edits.push((suffix_range, empty_str.clone()));
13376                    }
13377                } else {
13378                    continue;
13379                }
13380            }
13381
13382            drop(snapshot);
13383            this.buffer.update(cx, |buffer, cx| {
13384                buffer.edit(edits, None, cx);
13385            });
13386
13387            // Adjust selections so that they end before any comment suffixes that
13388            // were inserted.
13389            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13390            let mut selections = this.selections.all::<Point>(cx);
13391            let snapshot = this.buffer.read(cx).read(cx);
13392            for selection in &mut selections {
13393                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13394                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13395                        Ordering::Less => {
13396                            suffixes_inserted.next();
13397                            continue;
13398                        }
13399                        Ordering::Greater => break,
13400                        Ordering::Equal => {
13401                            if selection.end.column == snapshot.line_len(row) {
13402                                if selection.is_empty() {
13403                                    selection.start.column -= suffix_len as u32;
13404                                }
13405                                selection.end.column -= suffix_len as u32;
13406                            }
13407                            break;
13408                        }
13409                    }
13410                }
13411            }
13412
13413            drop(snapshot);
13414            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13415                s.select(selections)
13416            });
13417
13418            let selections = this.selections.all::<Point>(cx);
13419            let selections_on_single_row = selections.windows(2).all(|selections| {
13420                selections[0].start.row == selections[1].start.row
13421                    && selections[0].end.row == selections[1].end.row
13422                    && selections[0].start.row == selections[0].end.row
13423            });
13424            let selections_selecting = selections
13425                .iter()
13426                .any(|selection| selection.start != selection.end);
13427            let advance_downwards = action.advance_downwards
13428                && selections_on_single_row
13429                && !selections_selecting
13430                && !matches!(this.mode, EditorMode::SingleLine { .. });
13431
13432            if advance_downwards {
13433                let snapshot = this.buffer.read(cx).snapshot(cx);
13434
13435                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13436                    s.move_cursors_with(|display_snapshot, display_point, _| {
13437                        let mut point = display_point.to_point(display_snapshot);
13438                        point.row += 1;
13439                        point = snapshot.clip_point(point, Bias::Left);
13440                        let display_point = point.to_display_point(display_snapshot);
13441                        let goal = SelectionGoal::HorizontalPosition(
13442                            display_snapshot
13443                                .x_for_display_point(display_point, text_layout_details)
13444                                .into(),
13445                        );
13446                        (display_point, goal)
13447                    })
13448                });
13449            }
13450        });
13451    }
13452
13453    pub fn select_enclosing_symbol(
13454        &mut self,
13455        _: &SelectEnclosingSymbol,
13456        window: &mut Window,
13457        cx: &mut Context<Self>,
13458    ) {
13459        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13460
13461        let buffer = self.buffer.read(cx).snapshot(cx);
13462        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13463
13464        fn update_selection(
13465            selection: &Selection<usize>,
13466            buffer_snap: &MultiBufferSnapshot,
13467        ) -> Option<Selection<usize>> {
13468            let cursor = selection.head();
13469            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13470            for symbol in symbols.iter().rev() {
13471                let start = symbol.range.start.to_offset(buffer_snap);
13472                let end = symbol.range.end.to_offset(buffer_snap);
13473                let new_range = start..end;
13474                if start < selection.start || end > selection.end {
13475                    return Some(Selection {
13476                        id: selection.id,
13477                        start: new_range.start,
13478                        end: new_range.end,
13479                        goal: SelectionGoal::None,
13480                        reversed: selection.reversed,
13481                    });
13482                }
13483            }
13484            None
13485        }
13486
13487        let mut selected_larger_symbol = false;
13488        let new_selections = old_selections
13489            .iter()
13490            .map(|selection| match update_selection(selection, &buffer) {
13491                Some(new_selection) => {
13492                    if new_selection.range() != selection.range() {
13493                        selected_larger_symbol = true;
13494                    }
13495                    new_selection
13496                }
13497                None => selection.clone(),
13498            })
13499            .collect::<Vec<_>>();
13500
13501        if selected_larger_symbol {
13502            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13503                s.select(new_selections);
13504            });
13505        }
13506    }
13507
13508    pub fn select_larger_syntax_node(
13509        &mut self,
13510        _: &SelectLargerSyntaxNode,
13511        window: &mut Window,
13512        cx: &mut Context<Self>,
13513    ) {
13514        let Some(visible_row_count) = self.visible_row_count() else {
13515            return;
13516        };
13517        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13518        if old_selections.is_empty() {
13519            return;
13520        }
13521
13522        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13523
13524        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13525        let buffer = self.buffer.read(cx).snapshot(cx);
13526
13527        let mut selected_larger_node = false;
13528        let mut new_selections = old_selections
13529            .iter()
13530            .map(|selection| {
13531                let old_range = selection.start..selection.end;
13532
13533                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13534                    // manually select word at selection
13535                    if ["string_content", "inline"].contains(&node.kind()) {
13536                        let word_range = {
13537                            let display_point = buffer
13538                                .offset_to_point(old_range.start)
13539                                .to_display_point(&display_map);
13540                            let Range { start, end } =
13541                                movement::surrounding_word(&display_map, display_point);
13542                            start.to_point(&display_map).to_offset(&buffer)
13543                                ..end.to_point(&display_map).to_offset(&buffer)
13544                        };
13545                        // ignore if word is already selected
13546                        if !word_range.is_empty() && old_range != word_range {
13547                            let last_word_range = {
13548                                let display_point = buffer
13549                                    .offset_to_point(old_range.end)
13550                                    .to_display_point(&display_map);
13551                                let Range { start, end } =
13552                                    movement::surrounding_word(&display_map, display_point);
13553                                start.to_point(&display_map).to_offset(&buffer)
13554                                    ..end.to_point(&display_map).to_offset(&buffer)
13555                            };
13556                            // only select word if start and end point belongs to same word
13557                            if word_range == last_word_range {
13558                                selected_larger_node = true;
13559                                return Selection {
13560                                    id: selection.id,
13561                                    start: word_range.start,
13562                                    end: word_range.end,
13563                                    goal: SelectionGoal::None,
13564                                    reversed: selection.reversed,
13565                                };
13566                            }
13567                        }
13568                    }
13569                }
13570
13571                let mut new_range = old_range.clone();
13572                while let Some((_node, containing_range)) =
13573                    buffer.syntax_ancestor(new_range.clone())
13574                {
13575                    new_range = match containing_range {
13576                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13577                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13578                    };
13579                    if !display_map.intersects_fold(new_range.start)
13580                        && !display_map.intersects_fold(new_range.end)
13581                    {
13582                        break;
13583                    }
13584                }
13585
13586                selected_larger_node |= new_range != old_range;
13587                Selection {
13588                    id: selection.id,
13589                    start: new_range.start,
13590                    end: new_range.end,
13591                    goal: SelectionGoal::None,
13592                    reversed: selection.reversed,
13593                }
13594            })
13595            .collect::<Vec<_>>();
13596
13597        if !selected_larger_node {
13598            return; // don't put this call in the history
13599        }
13600
13601        // scroll based on transformation done to the last selection created by the user
13602        let (last_old, last_new) = old_selections
13603            .last()
13604            .zip(new_selections.last().cloned())
13605            .expect("old_selections isn't empty");
13606
13607        // revert selection
13608        let is_selection_reversed = {
13609            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13610            new_selections.last_mut().expect("checked above").reversed =
13611                should_newest_selection_be_reversed;
13612            should_newest_selection_be_reversed
13613        };
13614
13615        if selected_larger_node {
13616            self.select_syntax_node_history.disable_clearing = true;
13617            self.change_selections(None, window, cx, |s| {
13618                s.select(new_selections.clone());
13619            });
13620            self.select_syntax_node_history.disable_clearing = false;
13621        }
13622
13623        let start_row = last_new.start.to_display_point(&display_map).row().0;
13624        let end_row = last_new.end.to_display_point(&display_map).row().0;
13625        let selection_height = end_row - start_row + 1;
13626        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13627
13628        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13629        let scroll_behavior = if fits_on_the_screen {
13630            self.request_autoscroll(Autoscroll::fit(), cx);
13631            SelectSyntaxNodeScrollBehavior::FitSelection
13632        } else if is_selection_reversed {
13633            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13634            SelectSyntaxNodeScrollBehavior::CursorTop
13635        } else {
13636            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13637            SelectSyntaxNodeScrollBehavior::CursorBottom
13638        };
13639
13640        self.select_syntax_node_history.push((
13641            old_selections,
13642            scroll_behavior,
13643            is_selection_reversed,
13644        ));
13645    }
13646
13647    pub fn select_smaller_syntax_node(
13648        &mut self,
13649        _: &SelectSmallerSyntaxNode,
13650        window: &mut Window,
13651        cx: &mut Context<Self>,
13652    ) {
13653        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13654
13655        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13656            self.select_syntax_node_history.pop()
13657        {
13658            if let Some(selection) = selections.last_mut() {
13659                selection.reversed = is_selection_reversed;
13660            }
13661
13662            self.select_syntax_node_history.disable_clearing = true;
13663            self.change_selections(None, window, cx, |s| {
13664                s.select(selections.to_vec());
13665            });
13666            self.select_syntax_node_history.disable_clearing = false;
13667
13668            match scroll_behavior {
13669                SelectSyntaxNodeScrollBehavior::CursorTop => {
13670                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13671                }
13672                SelectSyntaxNodeScrollBehavior::FitSelection => {
13673                    self.request_autoscroll(Autoscroll::fit(), cx);
13674                }
13675                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13676                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13677                }
13678            }
13679        }
13680    }
13681
13682    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13683        if !EditorSettings::get_global(cx).gutter.runnables {
13684            self.clear_tasks();
13685            return Task::ready(());
13686        }
13687        let project = self.project.as_ref().map(Entity::downgrade);
13688        let task_sources = self.lsp_task_sources(cx);
13689        let multi_buffer = self.buffer.downgrade();
13690        cx.spawn_in(window, async move |editor, cx| {
13691            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13692            let Some(project) = project.and_then(|p| p.upgrade()) else {
13693                return;
13694            };
13695            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13696                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13697            }) else {
13698                return;
13699            };
13700
13701            let hide_runnables = project
13702                .update(cx, |project, cx| {
13703                    // Do not display any test indicators in non-dev server remote projects.
13704                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13705                })
13706                .unwrap_or(true);
13707            if hide_runnables {
13708                return;
13709            }
13710            let new_rows =
13711                cx.background_spawn({
13712                    let snapshot = display_snapshot.clone();
13713                    async move {
13714                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13715                    }
13716                })
13717                    .await;
13718            let Ok(lsp_tasks) =
13719                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13720            else {
13721                return;
13722            };
13723            let lsp_tasks = lsp_tasks.await;
13724
13725            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13726                lsp_tasks
13727                    .into_iter()
13728                    .flat_map(|(kind, tasks)| {
13729                        tasks.into_iter().filter_map(move |(location, task)| {
13730                            Some((kind.clone(), location?, task))
13731                        })
13732                    })
13733                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13734                        let buffer = location.target.buffer;
13735                        let buffer_snapshot = buffer.read(cx).snapshot();
13736                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13737                            |(excerpt_id, snapshot, _)| {
13738                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13739                                    display_snapshot
13740                                        .buffer_snapshot
13741                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13742                                } else {
13743                                    None
13744                                }
13745                            },
13746                        );
13747                        if let Some(offset) = offset {
13748                            let task_buffer_range =
13749                                location.target.range.to_point(&buffer_snapshot);
13750                            let context_buffer_range =
13751                                task_buffer_range.to_offset(&buffer_snapshot);
13752                            let context_range = BufferOffset(context_buffer_range.start)
13753                                ..BufferOffset(context_buffer_range.end);
13754
13755                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13756                                .or_insert_with(|| RunnableTasks {
13757                                    templates: Vec::new(),
13758                                    offset,
13759                                    column: task_buffer_range.start.column,
13760                                    extra_variables: HashMap::default(),
13761                                    context_range,
13762                                })
13763                                .templates
13764                                .push((kind, task.original_task().clone()));
13765                        }
13766
13767                        acc
13768                    })
13769            }) else {
13770                return;
13771            };
13772
13773            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
13774                buffer.language_settings(cx).tasks.prefer_lsp
13775            }) else {
13776                return;
13777            };
13778
13779            let rows = Self::runnable_rows(
13780                project,
13781                display_snapshot,
13782                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
13783                new_rows,
13784                cx.clone(),
13785            );
13786            editor
13787                .update(cx, |editor, _| {
13788                    editor.clear_tasks();
13789                    for (key, mut value) in rows {
13790                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13791                            value.templates.extend(lsp_tasks.templates);
13792                        }
13793
13794                        editor.insert_tasks(key, value);
13795                    }
13796                    for (key, value) in lsp_tasks_by_rows {
13797                        editor.insert_tasks(key, value);
13798                    }
13799                })
13800                .ok();
13801        })
13802    }
13803    fn fetch_runnable_ranges(
13804        snapshot: &DisplaySnapshot,
13805        range: Range<Anchor>,
13806    ) -> Vec<language::RunnableRange> {
13807        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13808    }
13809
13810    fn runnable_rows(
13811        project: Entity<Project>,
13812        snapshot: DisplaySnapshot,
13813        prefer_lsp: bool,
13814        runnable_ranges: Vec<RunnableRange>,
13815        mut cx: AsyncWindowContext,
13816    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13817        runnable_ranges
13818            .into_iter()
13819            .filter_map(|mut runnable| {
13820                let mut tasks = cx
13821                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13822                    .ok()?;
13823                if prefer_lsp {
13824                    tasks.retain(|(task_kind, _)| {
13825                        !matches!(task_kind, TaskSourceKind::Language { .. })
13826                    });
13827                }
13828                if tasks.is_empty() {
13829                    return None;
13830                }
13831
13832                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13833
13834                let row = snapshot
13835                    .buffer_snapshot
13836                    .buffer_line_for_row(MultiBufferRow(point.row))?
13837                    .1
13838                    .start
13839                    .row;
13840
13841                let context_range =
13842                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13843                Some((
13844                    (runnable.buffer_id, row),
13845                    RunnableTasks {
13846                        templates: tasks,
13847                        offset: snapshot
13848                            .buffer_snapshot
13849                            .anchor_before(runnable.run_range.start),
13850                        context_range,
13851                        column: point.column,
13852                        extra_variables: runnable.extra_captures,
13853                    },
13854                ))
13855            })
13856            .collect()
13857    }
13858
13859    fn templates_with_tags(
13860        project: &Entity<Project>,
13861        runnable: &mut Runnable,
13862        cx: &mut App,
13863    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13864        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13865            let (worktree_id, file) = project
13866                .buffer_for_id(runnable.buffer, cx)
13867                .and_then(|buffer| buffer.read(cx).file())
13868                .map(|file| (file.worktree_id(cx), file.clone()))
13869                .unzip();
13870
13871            (
13872                project.task_store().read(cx).task_inventory().cloned(),
13873                worktree_id,
13874                file,
13875            )
13876        });
13877
13878        let mut templates_with_tags = mem::take(&mut runnable.tags)
13879            .into_iter()
13880            .flat_map(|RunnableTag(tag)| {
13881                inventory
13882                    .as_ref()
13883                    .into_iter()
13884                    .flat_map(|inventory| {
13885                        inventory.read(cx).list_tasks(
13886                            file.clone(),
13887                            Some(runnable.language.clone()),
13888                            worktree_id,
13889                            cx,
13890                        )
13891                    })
13892                    .filter(move |(_, template)| {
13893                        template.tags.iter().any(|source_tag| source_tag == &tag)
13894                    })
13895            })
13896            .sorted_by_key(|(kind, _)| kind.to_owned())
13897            .collect::<Vec<_>>();
13898        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13899            // Strongest source wins; if we have worktree tag binding, prefer that to
13900            // global and language bindings;
13901            // if we have a global binding, prefer that to language binding.
13902            let first_mismatch = templates_with_tags
13903                .iter()
13904                .position(|(tag_source, _)| tag_source != leading_tag_source);
13905            if let Some(index) = first_mismatch {
13906                templates_with_tags.truncate(index);
13907            }
13908        }
13909
13910        templates_with_tags
13911    }
13912
13913    pub fn move_to_enclosing_bracket(
13914        &mut self,
13915        _: &MoveToEnclosingBracket,
13916        window: &mut Window,
13917        cx: &mut Context<Self>,
13918    ) {
13919        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13920        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13921            s.move_offsets_with(|snapshot, selection| {
13922                let Some(enclosing_bracket_ranges) =
13923                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13924                else {
13925                    return;
13926                };
13927
13928                let mut best_length = usize::MAX;
13929                let mut best_inside = false;
13930                let mut best_in_bracket_range = false;
13931                let mut best_destination = None;
13932                for (open, close) in enclosing_bracket_ranges {
13933                    let close = close.to_inclusive();
13934                    let length = close.end() - open.start;
13935                    let inside = selection.start >= open.end && selection.end <= *close.start();
13936                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13937                        || close.contains(&selection.head());
13938
13939                    // If best is next to a bracket and current isn't, skip
13940                    if !in_bracket_range && best_in_bracket_range {
13941                        continue;
13942                    }
13943
13944                    // Prefer smaller lengths unless best is inside and current isn't
13945                    if length > best_length && (best_inside || !inside) {
13946                        continue;
13947                    }
13948
13949                    best_length = length;
13950                    best_inside = inside;
13951                    best_in_bracket_range = in_bracket_range;
13952                    best_destination = Some(
13953                        if close.contains(&selection.start) && close.contains(&selection.end) {
13954                            if inside { open.end } else { open.start }
13955                        } else if inside {
13956                            *close.start()
13957                        } else {
13958                            *close.end()
13959                        },
13960                    );
13961                }
13962
13963                if let Some(destination) = best_destination {
13964                    selection.collapse_to(destination, SelectionGoal::None);
13965                }
13966            })
13967        });
13968    }
13969
13970    pub fn undo_selection(
13971        &mut self,
13972        _: &UndoSelection,
13973        window: &mut Window,
13974        cx: &mut Context<Self>,
13975    ) {
13976        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13977        self.end_selection(window, cx);
13978        self.selection_history.mode = SelectionHistoryMode::Undoing;
13979        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13980            self.change_selections(None, window, cx, |s| {
13981                s.select_anchors(entry.selections.to_vec())
13982            });
13983            self.select_next_state = entry.select_next_state;
13984            self.select_prev_state = entry.select_prev_state;
13985            self.add_selections_state = entry.add_selections_state;
13986            self.request_autoscroll(Autoscroll::newest(), cx);
13987        }
13988        self.selection_history.mode = SelectionHistoryMode::Normal;
13989    }
13990
13991    pub fn redo_selection(
13992        &mut self,
13993        _: &RedoSelection,
13994        window: &mut Window,
13995        cx: &mut Context<Self>,
13996    ) {
13997        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13998        self.end_selection(window, cx);
13999        self.selection_history.mode = SelectionHistoryMode::Redoing;
14000        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14001            self.change_selections(None, window, cx, |s| {
14002                s.select_anchors(entry.selections.to_vec())
14003            });
14004            self.select_next_state = entry.select_next_state;
14005            self.select_prev_state = entry.select_prev_state;
14006            self.add_selections_state = entry.add_selections_state;
14007            self.request_autoscroll(Autoscroll::newest(), cx);
14008        }
14009        self.selection_history.mode = SelectionHistoryMode::Normal;
14010    }
14011
14012    pub fn expand_excerpts(
14013        &mut self,
14014        action: &ExpandExcerpts,
14015        _: &mut Window,
14016        cx: &mut Context<Self>,
14017    ) {
14018        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14019    }
14020
14021    pub fn expand_excerpts_down(
14022        &mut self,
14023        action: &ExpandExcerptsDown,
14024        _: &mut Window,
14025        cx: &mut Context<Self>,
14026    ) {
14027        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14028    }
14029
14030    pub fn expand_excerpts_up(
14031        &mut self,
14032        action: &ExpandExcerptsUp,
14033        _: &mut Window,
14034        cx: &mut Context<Self>,
14035    ) {
14036        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14037    }
14038
14039    pub fn expand_excerpts_for_direction(
14040        &mut self,
14041        lines: u32,
14042        direction: ExpandExcerptDirection,
14043
14044        cx: &mut Context<Self>,
14045    ) {
14046        let selections = self.selections.disjoint_anchors();
14047
14048        let lines = if lines == 0 {
14049            EditorSettings::get_global(cx).expand_excerpt_lines
14050        } else {
14051            lines
14052        };
14053
14054        self.buffer.update(cx, |buffer, cx| {
14055            let snapshot = buffer.snapshot(cx);
14056            let mut excerpt_ids = selections
14057                .iter()
14058                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14059                .collect::<Vec<_>>();
14060            excerpt_ids.sort();
14061            excerpt_ids.dedup();
14062            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14063        })
14064    }
14065
14066    pub fn expand_excerpt(
14067        &mut self,
14068        excerpt: ExcerptId,
14069        direction: ExpandExcerptDirection,
14070        window: &mut Window,
14071        cx: &mut Context<Self>,
14072    ) {
14073        let current_scroll_position = self.scroll_position(cx);
14074        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14075        let mut should_scroll_up = false;
14076
14077        if direction == ExpandExcerptDirection::Down {
14078            let multi_buffer = self.buffer.read(cx);
14079            let snapshot = multi_buffer.snapshot(cx);
14080            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14081                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14082                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14083                        let buffer_snapshot = buffer.read(cx).snapshot();
14084                        let excerpt_end_row =
14085                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14086                        let last_row = buffer_snapshot.max_point().row;
14087                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14088                        should_scroll_up = lines_below >= lines_to_expand;
14089                    }
14090                }
14091            }
14092        }
14093
14094        self.buffer.update(cx, |buffer, cx| {
14095            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14096        });
14097
14098        if should_scroll_up {
14099            let new_scroll_position =
14100                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14101            self.set_scroll_position(new_scroll_position, window, cx);
14102        }
14103    }
14104
14105    pub fn go_to_singleton_buffer_point(
14106        &mut self,
14107        point: Point,
14108        window: &mut Window,
14109        cx: &mut Context<Self>,
14110    ) {
14111        self.go_to_singleton_buffer_range(point..point, window, cx);
14112    }
14113
14114    pub fn go_to_singleton_buffer_range(
14115        &mut self,
14116        range: Range<Point>,
14117        window: &mut Window,
14118        cx: &mut Context<Self>,
14119    ) {
14120        let multibuffer = self.buffer().read(cx);
14121        let Some(buffer) = multibuffer.as_singleton() else {
14122            return;
14123        };
14124        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14125            return;
14126        };
14127        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14128            return;
14129        };
14130        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14131            s.select_anchor_ranges([start..end])
14132        });
14133    }
14134
14135    pub fn go_to_diagnostic(
14136        &mut self,
14137        _: &GoToDiagnostic,
14138        window: &mut Window,
14139        cx: &mut Context<Self>,
14140    ) {
14141        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14142        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14143    }
14144
14145    pub fn go_to_prev_diagnostic(
14146        &mut self,
14147        _: &GoToPreviousDiagnostic,
14148        window: &mut Window,
14149        cx: &mut Context<Self>,
14150    ) {
14151        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14152        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14153    }
14154
14155    pub fn go_to_diagnostic_impl(
14156        &mut self,
14157        direction: Direction,
14158        window: &mut Window,
14159        cx: &mut Context<Self>,
14160    ) {
14161        let buffer = self.buffer.read(cx).snapshot(cx);
14162        let selection = self.selections.newest::<usize>(cx);
14163
14164        let mut active_group_id = None;
14165        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14166            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14167                active_group_id = Some(active_group.group_id);
14168            }
14169        }
14170
14171        fn filtered(
14172            snapshot: EditorSnapshot,
14173            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14174        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14175            diagnostics
14176                .filter(|entry| entry.range.start != entry.range.end)
14177                .filter(|entry| !entry.diagnostic.is_unnecessary)
14178                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14179        }
14180
14181        let snapshot = self.snapshot(window, cx);
14182        let before = filtered(
14183            snapshot.clone(),
14184            buffer
14185                .diagnostics_in_range(0..selection.start)
14186                .filter(|entry| entry.range.start <= selection.start),
14187        );
14188        let after = filtered(
14189            snapshot,
14190            buffer
14191                .diagnostics_in_range(selection.start..buffer.len())
14192                .filter(|entry| entry.range.start >= selection.start),
14193        );
14194
14195        let mut found: Option<DiagnosticEntry<usize>> = None;
14196        if direction == Direction::Prev {
14197            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14198            {
14199                for diagnostic in prev_diagnostics.into_iter().rev() {
14200                    if diagnostic.range.start != selection.start
14201                        || active_group_id
14202                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14203                    {
14204                        found = Some(diagnostic);
14205                        break 'outer;
14206                    }
14207                }
14208            }
14209        } else {
14210            for diagnostic in after.chain(before) {
14211                if diagnostic.range.start != selection.start
14212                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14213                {
14214                    found = Some(diagnostic);
14215                    break;
14216                }
14217            }
14218        }
14219        let Some(next_diagnostic) = found else {
14220            return;
14221        };
14222
14223        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14224            return;
14225        };
14226        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14227            s.select_ranges(vec![
14228                next_diagnostic.range.start..next_diagnostic.range.start,
14229            ])
14230        });
14231        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14232        self.refresh_inline_completion(false, true, window, cx);
14233    }
14234
14235    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14236        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14237        let snapshot = self.snapshot(window, cx);
14238        let selection = self.selections.newest::<Point>(cx);
14239        self.go_to_hunk_before_or_after_position(
14240            &snapshot,
14241            selection.head(),
14242            Direction::Next,
14243            window,
14244            cx,
14245        );
14246    }
14247
14248    pub fn go_to_hunk_before_or_after_position(
14249        &mut self,
14250        snapshot: &EditorSnapshot,
14251        position: Point,
14252        direction: Direction,
14253        window: &mut Window,
14254        cx: &mut Context<Editor>,
14255    ) {
14256        let row = if direction == Direction::Next {
14257            self.hunk_after_position(snapshot, position)
14258                .map(|hunk| hunk.row_range.start)
14259        } else {
14260            self.hunk_before_position(snapshot, position)
14261        };
14262
14263        if let Some(row) = row {
14264            let destination = Point::new(row.0, 0);
14265            let autoscroll = Autoscroll::center();
14266
14267            self.unfold_ranges(&[destination..destination], false, false, cx);
14268            self.change_selections(Some(autoscroll), window, cx, |s| {
14269                s.select_ranges([destination..destination]);
14270            });
14271        }
14272    }
14273
14274    fn hunk_after_position(
14275        &mut self,
14276        snapshot: &EditorSnapshot,
14277        position: Point,
14278    ) -> Option<MultiBufferDiffHunk> {
14279        snapshot
14280            .buffer_snapshot
14281            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14282            .find(|hunk| hunk.row_range.start.0 > position.row)
14283            .or_else(|| {
14284                snapshot
14285                    .buffer_snapshot
14286                    .diff_hunks_in_range(Point::zero()..position)
14287                    .find(|hunk| hunk.row_range.end.0 < position.row)
14288            })
14289    }
14290
14291    fn go_to_prev_hunk(
14292        &mut self,
14293        _: &GoToPreviousHunk,
14294        window: &mut Window,
14295        cx: &mut Context<Self>,
14296    ) {
14297        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14298        let snapshot = self.snapshot(window, cx);
14299        let selection = self.selections.newest::<Point>(cx);
14300        self.go_to_hunk_before_or_after_position(
14301            &snapshot,
14302            selection.head(),
14303            Direction::Prev,
14304            window,
14305            cx,
14306        );
14307    }
14308
14309    fn hunk_before_position(
14310        &mut self,
14311        snapshot: &EditorSnapshot,
14312        position: Point,
14313    ) -> Option<MultiBufferRow> {
14314        snapshot
14315            .buffer_snapshot
14316            .diff_hunk_before(position)
14317            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14318    }
14319
14320    fn go_to_next_change(
14321        &mut self,
14322        _: &GoToNextChange,
14323        window: &mut Window,
14324        cx: &mut Context<Self>,
14325    ) {
14326        if let Some(selections) = self
14327            .change_list
14328            .next_change(1, Direction::Next)
14329            .map(|s| s.to_vec())
14330        {
14331            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14332                let map = s.display_map();
14333                s.select_display_ranges(selections.iter().map(|a| {
14334                    let point = a.to_display_point(&map);
14335                    point..point
14336                }))
14337            })
14338        }
14339    }
14340
14341    fn go_to_previous_change(
14342        &mut self,
14343        _: &GoToPreviousChange,
14344        window: &mut Window,
14345        cx: &mut Context<Self>,
14346    ) {
14347        if let Some(selections) = self
14348            .change_list
14349            .next_change(1, Direction::Prev)
14350            .map(|s| s.to_vec())
14351        {
14352            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14353                let map = s.display_map();
14354                s.select_display_ranges(selections.iter().map(|a| {
14355                    let point = a.to_display_point(&map);
14356                    point..point
14357                }))
14358            })
14359        }
14360    }
14361
14362    fn go_to_line<T: 'static>(
14363        &mut self,
14364        position: Anchor,
14365        highlight_color: Option<Hsla>,
14366        window: &mut Window,
14367        cx: &mut Context<Self>,
14368    ) {
14369        let snapshot = self.snapshot(window, cx).display_snapshot;
14370        let position = position.to_point(&snapshot.buffer_snapshot);
14371        let start = snapshot
14372            .buffer_snapshot
14373            .clip_point(Point::new(position.row, 0), Bias::Left);
14374        let end = start + Point::new(1, 0);
14375        let start = snapshot.buffer_snapshot.anchor_before(start);
14376        let end = snapshot.buffer_snapshot.anchor_before(end);
14377
14378        self.highlight_rows::<T>(
14379            start..end,
14380            highlight_color
14381                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14382            Default::default(),
14383            cx,
14384        );
14385
14386        if self.buffer.read(cx).is_singleton() {
14387            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14388        }
14389    }
14390
14391    pub fn go_to_definition(
14392        &mut self,
14393        _: &GoToDefinition,
14394        window: &mut Window,
14395        cx: &mut Context<Self>,
14396    ) -> Task<Result<Navigated>> {
14397        let definition =
14398            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14399        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14400        cx.spawn_in(window, async move |editor, cx| {
14401            if definition.await? == Navigated::Yes {
14402                return Ok(Navigated::Yes);
14403            }
14404            match fallback_strategy {
14405                GoToDefinitionFallback::None => Ok(Navigated::No),
14406                GoToDefinitionFallback::FindAllReferences => {
14407                    match editor.update_in(cx, |editor, window, cx| {
14408                        editor.find_all_references(&FindAllReferences, window, cx)
14409                    })? {
14410                        Some(references) => references.await,
14411                        None => Ok(Navigated::No),
14412                    }
14413                }
14414            }
14415        })
14416    }
14417
14418    pub fn go_to_declaration(
14419        &mut self,
14420        _: &GoToDeclaration,
14421        window: &mut Window,
14422        cx: &mut Context<Self>,
14423    ) -> Task<Result<Navigated>> {
14424        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14425    }
14426
14427    pub fn go_to_declaration_split(
14428        &mut self,
14429        _: &GoToDeclaration,
14430        window: &mut Window,
14431        cx: &mut Context<Self>,
14432    ) -> Task<Result<Navigated>> {
14433        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14434    }
14435
14436    pub fn go_to_implementation(
14437        &mut self,
14438        _: &GoToImplementation,
14439        window: &mut Window,
14440        cx: &mut Context<Self>,
14441    ) -> Task<Result<Navigated>> {
14442        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14443    }
14444
14445    pub fn go_to_implementation_split(
14446        &mut self,
14447        _: &GoToImplementationSplit,
14448        window: &mut Window,
14449        cx: &mut Context<Self>,
14450    ) -> Task<Result<Navigated>> {
14451        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14452    }
14453
14454    pub fn go_to_type_definition(
14455        &mut self,
14456        _: &GoToTypeDefinition,
14457        window: &mut Window,
14458        cx: &mut Context<Self>,
14459    ) -> Task<Result<Navigated>> {
14460        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14461    }
14462
14463    pub fn go_to_definition_split(
14464        &mut self,
14465        _: &GoToDefinitionSplit,
14466        window: &mut Window,
14467        cx: &mut Context<Self>,
14468    ) -> Task<Result<Navigated>> {
14469        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14470    }
14471
14472    pub fn go_to_type_definition_split(
14473        &mut self,
14474        _: &GoToTypeDefinitionSplit,
14475        window: &mut Window,
14476        cx: &mut Context<Self>,
14477    ) -> Task<Result<Navigated>> {
14478        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14479    }
14480
14481    fn go_to_definition_of_kind(
14482        &mut self,
14483        kind: GotoDefinitionKind,
14484        split: bool,
14485        window: &mut Window,
14486        cx: &mut Context<Self>,
14487    ) -> Task<Result<Navigated>> {
14488        let Some(provider) = self.semantics_provider.clone() else {
14489            return Task::ready(Ok(Navigated::No));
14490        };
14491        let head = self.selections.newest::<usize>(cx).head();
14492        let buffer = self.buffer.read(cx);
14493        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14494            text_anchor
14495        } else {
14496            return Task::ready(Ok(Navigated::No));
14497        };
14498
14499        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14500            return Task::ready(Ok(Navigated::No));
14501        };
14502
14503        cx.spawn_in(window, async move |editor, cx| {
14504            let definitions = definitions.await?;
14505            let navigated = editor
14506                .update_in(cx, |editor, window, cx| {
14507                    editor.navigate_to_hover_links(
14508                        Some(kind),
14509                        definitions
14510                            .into_iter()
14511                            .filter(|location| {
14512                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14513                            })
14514                            .map(HoverLink::Text)
14515                            .collect::<Vec<_>>(),
14516                        split,
14517                        window,
14518                        cx,
14519                    )
14520                })?
14521                .await?;
14522            anyhow::Ok(navigated)
14523        })
14524    }
14525
14526    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14527        let selection = self.selections.newest_anchor();
14528        let head = selection.head();
14529        let tail = selection.tail();
14530
14531        let Some((buffer, start_position)) =
14532            self.buffer.read(cx).text_anchor_for_position(head, cx)
14533        else {
14534            return;
14535        };
14536
14537        let end_position = if head != tail {
14538            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14539                return;
14540            };
14541            Some(pos)
14542        } else {
14543            None
14544        };
14545
14546        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14547            let url = if let Some(end_pos) = end_position {
14548                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14549            } else {
14550                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14551            };
14552
14553            if let Some(url) = url {
14554                editor.update(cx, |_, cx| {
14555                    cx.open_url(&url);
14556                })
14557            } else {
14558                Ok(())
14559            }
14560        });
14561
14562        url_finder.detach();
14563    }
14564
14565    pub fn open_selected_filename(
14566        &mut self,
14567        _: &OpenSelectedFilename,
14568        window: &mut Window,
14569        cx: &mut Context<Self>,
14570    ) {
14571        let Some(workspace) = self.workspace() else {
14572            return;
14573        };
14574
14575        let position = self.selections.newest_anchor().head();
14576
14577        let Some((buffer, buffer_position)) =
14578            self.buffer.read(cx).text_anchor_for_position(position, cx)
14579        else {
14580            return;
14581        };
14582
14583        let project = self.project.clone();
14584
14585        cx.spawn_in(window, async move |_, cx| {
14586            let result = find_file(&buffer, project, buffer_position, cx).await;
14587
14588            if let Some((_, path)) = result {
14589                workspace
14590                    .update_in(cx, |workspace, window, cx| {
14591                        workspace.open_resolved_path(path, window, cx)
14592                    })?
14593                    .await?;
14594            }
14595            anyhow::Ok(())
14596        })
14597        .detach();
14598    }
14599
14600    pub(crate) fn navigate_to_hover_links(
14601        &mut self,
14602        kind: Option<GotoDefinitionKind>,
14603        mut definitions: Vec<HoverLink>,
14604        split: bool,
14605        window: &mut Window,
14606        cx: &mut Context<Editor>,
14607    ) -> Task<Result<Navigated>> {
14608        // If there is one definition, just open it directly
14609        if definitions.len() == 1 {
14610            let definition = definitions.pop().unwrap();
14611
14612            enum TargetTaskResult {
14613                Location(Option<Location>),
14614                AlreadyNavigated,
14615            }
14616
14617            let target_task = match definition {
14618                HoverLink::Text(link) => {
14619                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14620                }
14621                HoverLink::InlayHint(lsp_location, server_id) => {
14622                    let computation =
14623                        self.compute_target_location(lsp_location, server_id, window, cx);
14624                    cx.background_spawn(async move {
14625                        let location = computation.await?;
14626                        Ok(TargetTaskResult::Location(location))
14627                    })
14628                }
14629                HoverLink::Url(url) => {
14630                    cx.open_url(&url);
14631                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14632                }
14633                HoverLink::File(path) => {
14634                    if let Some(workspace) = self.workspace() {
14635                        cx.spawn_in(window, async move |_, cx| {
14636                            workspace
14637                                .update_in(cx, |workspace, window, cx| {
14638                                    workspace.open_resolved_path(path, window, cx)
14639                                })?
14640                                .await
14641                                .map(|_| TargetTaskResult::AlreadyNavigated)
14642                        })
14643                    } else {
14644                        Task::ready(Ok(TargetTaskResult::Location(None)))
14645                    }
14646                }
14647            };
14648            cx.spawn_in(window, async move |editor, cx| {
14649                let target = match target_task.await.context("target resolution task")? {
14650                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14651                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14652                    TargetTaskResult::Location(Some(target)) => target,
14653                };
14654
14655                editor.update_in(cx, |editor, window, cx| {
14656                    let Some(workspace) = editor.workspace() else {
14657                        return Navigated::No;
14658                    };
14659                    let pane = workspace.read(cx).active_pane().clone();
14660
14661                    let range = target.range.to_point(target.buffer.read(cx));
14662                    let range = editor.range_for_match(&range);
14663                    let range = collapse_multiline_range(range);
14664
14665                    if !split
14666                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14667                    {
14668                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14669                    } else {
14670                        window.defer(cx, move |window, cx| {
14671                            let target_editor: Entity<Self> =
14672                                workspace.update(cx, |workspace, cx| {
14673                                    let pane = if split {
14674                                        workspace.adjacent_pane(window, cx)
14675                                    } else {
14676                                        workspace.active_pane().clone()
14677                                    };
14678
14679                                    workspace.open_project_item(
14680                                        pane,
14681                                        target.buffer.clone(),
14682                                        true,
14683                                        true,
14684                                        window,
14685                                        cx,
14686                                    )
14687                                });
14688                            target_editor.update(cx, |target_editor, cx| {
14689                                // When selecting a definition in a different buffer, disable the nav history
14690                                // to avoid creating a history entry at the previous cursor location.
14691                                pane.update(cx, |pane, _| pane.disable_history());
14692                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14693                                pane.update(cx, |pane, _| pane.enable_history());
14694                            });
14695                        });
14696                    }
14697                    Navigated::Yes
14698                })
14699            })
14700        } else if !definitions.is_empty() {
14701            cx.spawn_in(window, async move |editor, cx| {
14702                let (title, location_tasks, workspace) = editor
14703                    .update_in(cx, |editor, window, cx| {
14704                        let tab_kind = match kind {
14705                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14706                            _ => "Definitions",
14707                        };
14708                        let title = definitions
14709                            .iter()
14710                            .find_map(|definition| match definition {
14711                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14712                                    let buffer = origin.buffer.read(cx);
14713                                    format!(
14714                                        "{} for {}",
14715                                        tab_kind,
14716                                        buffer
14717                                            .text_for_range(origin.range.clone())
14718                                            .collect::<String>()
14719                                    )
14720                                }),
14721                                HoverLink::InlayHint(_, _) => None,
14722                                HoverLink::Url(_) => None,
14723                                HoverLink::File(_) => None,
14724                            })
14725                            .unwrap_or(tab_kind.to_string());
14726                        let location_tasks = definitions
14727                            .into_iter()
14728                            .map(|definition| match definition {
14729                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14730                                HoverLink::InlayHint(lsp_location, server_id) => editor
14731                                    .compute_target_location(lsp_location, server_id, window, cx),
14732                                HoverLink::Url(_) => Task::ready(Ok(None)),
14733                                HoverLink::File(_) => Task::ready(Ok(None)),
14734                            })
14735                            .collect::<Vec<_>>();
14736                        (title, location_tasks, editor.workspace().clone())
14737                    })
14738                    .context("location tasks preparation")?;
14739
14740                let locations = future::join_all(location_tasks)
14741                    .await
14742                    .into_iter()
14743                    .filter_map(|location| location.transpose())
14744                    .collect::<Result<_>>()
14745                    .context("location tasks")?;
14746
14747                let Some(workspace) = workspace else {
14748                    return Ok(Navigated::No);
14749                };
14750                let opened = workspace
14751                    .update_in(cx, |workspace, window, cx| {
14752                        Self::open_locations_in_multibuffer(
14753                            workspace,
14754                            locations,
14755                            title,
14756                            split,
14757                            MultibufferSelectionMode::First,
14758                            window,
14759                            cx,
14760                        )
14761                    })
14762                    .ok();
14763
14764                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14765            })
14766        } else {
14767            Task::ready(Ok(Navigated::No))
14768        }
14769    }
14770
14771    fn compute_target_location(
14772        &self,
14773        lsp_location: lsp::Location,
14774        server_id: LanguageServerId,
14775        window: &mut Window,
14776        cx: &mut Context<Self>,
14777    ) -> Task<anyhow::Result<Option<Location>>> {
14778        let Some(project) = self.project.clone() else {
14779            return Task::ready(Ok(None));
14780        };
14781
14782        cx.spawn_in(window, async move |editor, cx| {
14783            let location_task = editor.update(cx, |_, cx| {
14784                project.update(cx, |project, cx| {
14785                    let language_server_name = project
14786                        .language_server_statuses(cx)
14787                        .find(|(id, _)| server_id == *id)
14788                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14789                    language_server_name.map(|language_server_name| {
14790                        project.open_local_buffer_via_lsp(
14791                            lsp_location.uri.clone(),
14792                            server_id,
14793                            language_server_name,
14794                            cx,
14795                        )
14796                    })
14797                })
14798            })?;
14799            let location = match location_task {
14800                Some(task) => Some({
14801                    let target_buffer_handle = task.await.context("open local buffer")?;
14802                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14803                        let target_start = target_buffer
14804                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14805                        let target_end = target_buffer
14806                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14807                        target_buffer.anchor_after(target_start)
14808                            ..target_buffer.anchor_before(target_end)
14809                    })?;
14810                    Location {
14811                        buffer: target_buffer_handle,
14812                        range,
14813                    }
14814                }),
14815                None => None,
14816            };
14817            Ok(location)
14818        })
14819    }
14820
14821    pub fn find_all_references(
14822        &mut self,
14823        _: &FindAllReferences,
14824        window: &mut Window,
14825        cx: &mut Context<Self>,
14826    ) -> Option<Task<Result<Navigated>>> {
14827        let selection = self.selections.newest::<usize>(cx);
14828        let multi_buffer = self.buffer.read(cx);
14829        let head = selection.head();
14830
14831        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14832        let head_anchor = multi_buffer_snapshot.anchor_at(
14833            head,
14834            if head < selection.tail() {
14835                Bias::Right
14836            } else {
14837                Bias::Left
14838            },
14839        );
14840
14841        match self
14842            .find_all_references_task_sources
14843            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14844        {
14845            Ok(_) => {
14846                log::info!(
14847                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14848                );
14849                return None;
14850            }
14851            Err(i) => {
14852                self.find_all_references_task_sources.insert(i, head_anchor);
14853            }
14854        }
14855
14856        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14857        let workspace = self.workspace()?;
14858        let project = workspace.read(cx).project().clone();
14859        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14860        Some(cx.spawn_in(window, async move |editor, cx| {
14861            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14862                if let Ok(i) = editor
14863                    .find_all_references_task_sources
14864                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14865                {
14866                    editor.find_all_references_task_sources.remove(i);
14867                }
14868            });
14869
14870            let locations = references.await?;
14871            if locations.is_empty() {
14872                return anyhow::Ok(Navigated::No);
14873            }
14874
14875            workspace.update_in(cx, |workspace, window, cx| {
14876                let title = locations
14877                    .first()
14878                    .as_ref()
14879                    .map(|location| {
14880                        let buffer = location.buffer.read(cx);
14881                        format!(
14882                            "References to `{}`",
14883                            buffer
14884                                .text_for_range(location.range.clone())
14885                                .collect::<String>()
14886                        )
14887                    })
14888                    .unwrap();
14889                Self::open_locations_in_multibuffer(
14890                    workspace,
14891                    locations,
14892                    title,
14893                    false,
14894                    MultibufferSelectionMode::First,
14895                    window,
14896                    cx,
14897                );
14898                Navigated::Yes
14899            })
14900        }))
14901    }
14902
14903    /// Opens a multibuffer with the given project locations in it
14904    pub fn open_locations_in_multibuffer(
14905        workspace: &mut Workspace,
14906        mut locations: Vec<Location>,
14907        title: String,
14908        split: bool,
14909        multibuffer_selection_mode: MultibufferSelectionMode,
14910        window: &mut Window,
14911        cx: &mut Context<Workspace>,
14912    ) {
14913        // If there are multiple definitions, open them in a multibuffer
14914        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14915        let mut locations = locations.into_iter().peekable();
14916        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14917        let capability = workspace.project().read(cx).capability();
14918
14919        let excerpt_buffer = cx.new(|cx| {
14920            let mut multibuffer = MultiBuffer::new(capability);
14921            while let Some(location) = locations.next() {
14922                let buffer = location.buffer.read(cx);
14923                let mut ranges_for_buffer = Vec::new();
14924                let range = location.range.to_point(buffer);
14925                ranges_for_buffer.push(range.clone());
14926
14927                while let Some(next_location) = locations.peek() {
14928                    if next_location.buffer == location.buffer {
14929                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14930                        locations.next();
14931                    } else {
14932                        break;
14933                    }
14934                }
14935
14936                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14937                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14938                    PathKey::for_buffer(&location.buffer, cx),
14939                    location.buffer.clone(),
14940                    ranges_for_buffer,
14941                    DEFAULT_MULTIBUFFER_CONTEXT,
14942                    cx,
14943                );
14944                ranges.extend(new_ranges)
14945            }
14946
14947            multibuffer.with_title(title)
14948        });
14949
14950        let editor = cx.new(|cx| {
14951            Editor::for_multibuffer(
14952                excerpt_buffer,
14953                Some(workspace.project().clone()),
14954                window,
14955                cx,
14956            )
14957        });
14958        editor.update(cx, |editor, cx| {
14959            match multibuffer_selection_mode {
14960                MultibufferSelectionMode::First => {
14961                    if let Some(first_range) = ranges.first() {
14962                        editor.change_selections(None, window, cx, |selections| {
14963                            selections.clear_disjoint();
14964                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14965                        });
14966                    }
14967                    editor.highlight_background::<Self>(
14968                        &ranges,
14969                        |theme| theme.editor_highlighted_line_background,
14970                        cx,
14971                    );
14972                }
14973                MultibufferSelectionMode::All => {
14974                    editor.change_selections(None, window, cx, |selections| {
14975                        selections.clear_disjoint();
14976                        selections.select_anchor_ranges(ranges);
14977                    });
14978                }
14979            }
14980            editor.register_buffers_with_language_servers(cx);
14981        });
14982
14983        let item = Box::new(editor);
14984        let item_id = item.item_id();
14985
14986        if split {
14987            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14988        } else {
14989            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14990                let (preview_item_id, preview_item_idx) =
14991                    workspace.active_pane().read_with(cx, |pane, _| {
14992                        (pane.preview_item_id(), pane.preview_item_idx())
14993                    });
14994
14995                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14996
14997                if let Some(preview_item_id) = preview_item_id {
14998                    workspace.active_pane().update(cx, |pane, cx| {
14999                        pane.remove_item(preview_item_id, false, false, window, cx);
15000                    });
15001                }
15002            } else {
15003                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15004            }
15005        }
15006        workspace.active_pane().update(cx, |pane, cx| {
15007            pane.set_preview_item_id(Some(item_id), cx);
15008        });
15009    }
15010
15011    pub fn rename(
15012        &mut self,
15013        _: &Rename,
15014        window: &mut Window,
15015        cx: &mut Context<Self>,
15016    ) -> Option<Task<Result<()>>> {
15017        use language::ToOffset as _;
15018
15019        let provider = self.semantics_provider.clone()?;
15020        let selection = self.selections.newest_anchor().clone();
15021        let (cursor_buffer, cursor_buffer_position) = self
15022            .buffer
15023            .read(cx)
15024            .text_anchor_for_position(selection.head(), cx)?;
15025        let (tail_buffer, cursor_buffer_position_end) = self
15026            .buffer
15027            .read(cx)
15028            .text_anchor_for_position(selection.tail(), cx)?;
15029        if tail_buffer != cursor_buffer {
15030            return None;
15031        }
15032
15033        let snapshot = cursor_buffer.read(cx).snapshot();
15034        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15035        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15036        let prepare_rename = provider
15037            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15038            .unwrap_or_else(|| Task::ready(Ok(None)));
15039        drop(snapshot);
15040
15041        Some(cx.spawn_in(window, async move |this, cx| {
15042            let rename_range = if let Some(range) = prepare_rename.await? {
15043                Some(range)
15044            } else {
15045                this.update(cx, |this, cx| {
15046                    let buffer = this.buffer.read(cx).snapshot(cx);
15047                    let mut buffer_highlights = this
15048                        .document_highlights_for_position(selection.head(), &buffer)
15049                        .filter(|highlight| {
15050                            highlight.start.excerpt_id == selection.head().excerpt_id
15051                                && highlight.end.excerpt_id == selection.head().excerpt_id
15052                        });
15053                    buffer_highlights
15054                        .next()
15055                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15056                })?
15057            };
15058            if let Some(rename_range) = rename_range {
15059                this.update_in(cx, |this, window, cx| {
15060                    let snapshot = cursor_buffer.read(cx).snapshot();
15061                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15062                    let cursor_offset_in_rename_range =
15063                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15064                    let cursor_offset_in_rename_range_end =
15065                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15066
15067                    this.take_rename(false, window, cx);
15068                    let buffer = this.buffer.read(cx).read(cx);
15069                    let cursor_offset = selection.head().to_offset(&buffer);
15070                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15071                    let rename_end = rename_start + rename_buffer_range.len();
15072                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15073                    let mut old_highlight_id = None;
15074                    let old_name: Arc<str> = buffer
15075                        .chunks(rename_start..rename_end, true)
15076                        .map(|chunk| {
15077                            if old_highlight_id.is_none() {
15078                                old_highlight_id = chunk.syntax_highlight_id;
15079                            }
15080                            chunk.text
15081                        })
15082                        .collect::<String>()
15083                        .into();
15084
15085                    drop(buffer);
15086
15087                    // Position the selection in the rename editor so that it matches the current selection.
15088                    this.show_local_selections = false;
15089                    let rename_editor = cx.new(|cx| {
15090                        let mut editor = Editor::single_line(window, cx);
15091                        editor.buffer.update(cx, |buffer, cx| {
15092                            buffer.edit([(0..0, old_name.clone())], None, cx)
15093                        });
15094                        let rename_selection_range = match cursor_offset_in_rename_range
15095                            .cmp(&cursor_offset_in_rename_range_end)
15096                        {
15097                            Ordering::Equal => {
15098                                editor.select_all(&SelectAll, window, cx);
15099                                return editor;
15100                            }
15101                            Ordering::Less => {
15102                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15103                            }
15104                            Ordering::Greater => {
15105                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15106                            }
15107                        };
15108                        if rename_selection_range.end > old_name.len() {
15109                            editor.select_all(&SelectAll, window, cx);
15110                        } else {
15111                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15112                                s.select_ranges([rename_selection_range]);
15113                            });
15114                        }
15115                        editor
15116                    });
15117                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15118                        if e == &EditorEvent::Focused {
15119                            cx.emit(EditorEvent::FocusedIn)
15120                        }
15121                    })
15122                    .detach();
15123
15124                    let write_highlights =
15125                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15126                    let read_highlights =
15127                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15128                    let ranges = write_highlights
15129                        .iter()
15130                        .flat_map(|(_, ranges)| ranges.iter())
15131                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15132                        .cloned()
15133                        .collect();
15134
15135                    this.highlight_text::<Rename>(
15136                        ranges,
15137                        HighlightStyle {
15138                            fade_out: Some(0.6),
15139                            ..Default::default()
15140                        },
15141                        cx,
15142                    );
15143                    let rename_focus_handle = rename_editor.focus_handle(cx);
15144                    window.focus(&rename_focus_handle);
15145                    let block_id = this.insert_blocks(
15146                        [BlockProperties {
15147                            style: BlockStyle::Flex,
15148                            placement: BlockPlacement::Below(range.start),
15149                            height: Some(1),
15150                            render: Arc::new({
15151                                let rename_editor = rename_editor.clone();
15152                                move |cx: &mut BlockContext| {
15153                                    let mut text_style = cx.editor_style.text.clone();
15154                                    if let Some(highlight_style) = old_highlight_id
15155                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15156                                    {
15157                                        text_style = text_style.highlight(highlight_style);
15158                                    }
15159                                    div()
15160                                        .block_mouse_except_scroll()
15161                                        .pl(cx.anchor_x)
15162                                        .child(EditorElement::new(
15163                                            &rename_editor,
15164                                            EditorStyle {
15165                                                background: cx.theme().system().transparent,
15166                                                local_player: cx.editor_style.local_player,
15167                                                text: text_style,
15168                                                scrollbar_width: cx.editor_style.scrollbar_width,
15169                                                syntax: cx.editor_style.syntax.clone(),
15170                                                status: cx.editor_style.status.clone(),
15171                                                inlay_hints_style: HighlightStyle {
15172                                                    font_weight: Some(FontWeight::BOLD),
15173                                                    ..make_inlay_hints_style(cx.app)
15174                                                },
15175                                                inline_completion_styles: make_suggestion_styles(
15176                                                    cx.app,
15177                                                ),
15178                                                ..EditorStyle::default()
15179                                            },
15180                                        ))
15181                                        .into_any_element()
15182                                }
15183                            }),
15184                            priority: 0,
15185                            render_in_minimap: true,
15186                        }],
15187                        Some(Autoscroll::fit()),
15188                        cx,
15189                    )[0];
15190                    this.pending_rename = Some(RenameState {
15191                        range,
15192                        old_name,
15193                        editor: rename_editor,
15194                        block_id,
15195                    });
15196                })?;
15197            }
15198
15199            Ok(())
15200        }))
15201    }
15202
15203    pub fn confirm_rename(
15204        &mut self,
15205        _: &ConfirmRename,
15206        window: &mut Window,
15207        cx: &mut Context<Self>,
15208    ) -> Option<Task<Result<()>>> {
15209        let rename = self.take_rename(false, window, cx)?;
15210        let workspace = self.workspace()?.downgrade();
15211        let (buffer, start) = self
15212            .buffer
15213            .read(cx)
15214            .text_anchor_for_position(rename.range.start, cx)?;
15215        let (end_buffer, _) = self
15216            .buffer
15217            .read(cx)
15218            .text_anchor_for_position(rename.range.end, cx)?;
15219        if buffer != end_buffer {
15220            return None;
15221        }
15222
15223        let old_name = rename.old_name;
15224        let new_name = rename.editor.read(cx).text(cx);
15225
15226        let rename = self.semantics_provider.as_ref()?.perform_rename(
15227            &buffer,
15228            start,
15229            new_name.clone(),
15230            cx,
15231        )?;
15232
15233        Some(cx.spawn_in(window, async move |editor, cx| {
15234            let project_transaction = rename.await?;
15235            Self::open_project_transaction(
15236                &editor,
15237                workspace,
15238                project_transaction,
15239                format!("Rename: {}{}", old_name, new_name),
15240                cx,
15241            )
15242            .await?;
15243
15244            editor.update(cx, |editor, cx| {
15245                editor.refresh_document_highlights(cx);
15246            })?;
15247            Ok(())
15248        }))
15249    }
15250
15251    fn take_rename(
15252        &mut self,
15253        moving_cursor: bool,
15254        window: &mut Window,
15255        cx: &mut Context<Self>,
15256    ) -> Option<RenameState> {
15257        let rename = self.pending_rename.take()?;
15258        if rename.editor.focus_handle(cx).is_focused(window) {
15259            window.focus(&self.focus_handle);
15260        }
15261
15262        self.remove_blocks(
15263            [rename.block_id].into_iter().collect(),
15264            Some(Autoscroll::fit()),
15265            cx,
15266        );
15267        self.clear_highlights::<Rename>(cx);
15268        self.show_local_selections = true;
15269
15270        if moving_cursor {
15271            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15272                editor.selections.newest::<usize>(cx).head()
15273            });
15274
15275            // Update the selection to match the position of the selection inside
15276            // the rename editor.
15277            let snapshot = self.buffer.read(cx).read(cx);
15278            let rename_range = rename.range.to_offset(&snapshot);
15279            let cursor_in_editor = snapshot
15280                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15281                .min(rename_range.end);
15282            drop(snapshot);
15283
15284            self.change_selections(None, window, cx, |s| {
15285                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15286            });
15287        } else {
15288            self.refresh_document_highlights(cx);
15289        }
15290
15291        Some(rename)
15292    }
15293
15294    pub fn pending_rename(&self) -> Option<&RenameState> {
15295        self.pending_rename.as_ref()
15296    }
15297
15298    fn format(
15299        &mut self,
15300        _: &Format,
15301        window: &mut Window,
15302        cx: &mut Context<Self>,
15303    ) -> Option<Task<Result<()>>> {
15304        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15305
15306        let project = match &self.project {
15307            Some(project) => project.clone(),
15308            None => return None,
15309        };
15310
15311        Some(self.perform_format(
15312            project,
15313            FormatTrigger::Manual,
15314            FormatTarget::Buffers,
15315            window,
15316            cx,
15317        ))
15318    }
15319
15320    fn format_selections(
15321        &mut self,
15322        _: &FormatSelections,
15323        window: &mut Window,
15324        cx: &mut Context<Self>,
15325    ) -> Option<Task<Result<()>>> {
15326        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15327
15328        let project = match &self.project {
15329            Some(project) => project.clone(),
15330            None => return None,
15331        };
15332
15333        let ranges = self
15334            .selections
15335            .all_adjusted(cx)
15336            .into_iter()
15337            .map(|selection| selection.range())
15338            .collect_vec();
15339
15340        Some(self.perform_format(
15341            project,
15342            FormatTrigger::Manual,
15343            FormatTarget::Ranges(ranges),
15344            window,
15345            cx,
15346        ))
15347    }
15348
15349    fn perform_format(
15350        &mut self,
15351        project: Entity<Project>,
15352        trigger: FormatTrigger,
15353        target: FormatTarget,
15354        window: &mut Window,
15355        cx: &mut Context<Self>,
15356    ) -> Task<Result<()>> {
15357        let buffer = self.buffer.clone();
15358        let (buffers, target) = match target {
15359            FormatTarget::Buffers => {
15360                let mut buffers = buffer.read(cx).all_buffers();
15361                if trigger == FormatTrigger::Save {
15362                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15363                }
15364                (buffers, LspFormatTarget::Buffers)
15365            }
15366            FormatTarget::Ranges(selection_ranges) => {
15367                let multi_buffer = buffer.read(cx);
15368                let snapshot = multi_buffer.read(cx);
15369                let mut buffers = HashSet::default();
15370                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15371                    BTreeMap::new();
15372                for selection_range in selection_ranges {
15373                    for (buffer, buffer_range, _) in
15374                        snapshot.range_to_buffer_ranges(selection_range)
15375                    {
15376                        let buffer_id = buffer.remote_id();
15377                        let start = buffer.anchor_before(buffer_range.start);
15378                        let end = buffer.anchor_after(buffer_range.end);
15379                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15380                        buffer_id_to_ranges
15381                            .entry(buffer_id)
15382                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15383                            .or_insert_with(|| vec![start..end]);
15384                    }
15385                }
15386                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15387            }
15388        };
15389
15390        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15391        let selections_prev = transaction_id_prev
15392            .and_then(|transaction_id_prev| {
15393                // default to selections as they were after the last edit, if we have them,
15394                // instead of how they are now.
15395                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15396                // will take you back to where you made the last edit, instead of staying where you scrolled
15397                self.selection_history
15398                    .transaction(transaction_id_prev)
15399                    .map(|t| t.0.clone())
15400            })
15401            .unwrap_or_else(|| {
15402                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15403                self.selections.disjoint_anchors()
15404            });
15405
15406        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15407        let format = project.update(cx, |project, cx| {
15408            project.format(buffers, target, true, trigger, cx)
15409        });
15410
15411        cx.spawn_in(window, async move |editor, cx| {
15412            let transaction = futures::select_biased! {
15413                transaction = format.log_err().fuse() => transaction,
15414                () = timeout => {
15415                    log::warn!("timed out waiting for formatting");
15416                    None
15417                }
15418            };
15419
15420            buffer
15421                .update(cx, |buffer, cx| {
15422                    if let Some(transaction) = transaction {
15423                        if !buffer.is_singleton() {
15424                            buffer.push_transaction(&transaction.0, cx);
15425                        }
15426                    }
15427                    cx.notify();
15428                })
15429                .ok();
15430
15431            if let Some(transaction_id_now) =
15432                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15433            {
15434                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15435                if has_new_transaction {
15436                    _ = editor.update(cx, |editor, _| {
15437                        editor
15438                            .selection_history
15439                            .insert_transaction(transaction_id_now, selections_prev);
15440                    });
15441                }
15442            }
15443
15444            Ok(())
15445        })
15446    }
15447
15448    fn organize_imports(
15449        &mut self,
15450        _: &OrganizeImports,
15451        window: &mut Window,
15452        cx: &mut Context<Self>,
15453    ) -> Option<Task<Result<()>>> {
15454        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15455        let project = match &self.project {
15456            Some(project) => project.clone(),
15457            None => return None,
15458        };
15459        Some(self.perform_code_action_kind(
15460            project,
15461            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15462            window,
15463            cx,
15464        ))
15465    }
15466
15467    fn perform_code_action_kind(
15468        &mut self,
15469        project: Entity<Project>,
15470        kind: CodeActionKind,
15471        window: &mut Window,
15472        cx: &mut Context<Self>,
15473    ) -> Task<Result<()>> {
15474        let buffer = self.buffer.clone();
15475        let buffers = buffer.read(cx).all_buffers();
15476        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15477        let apply_action = project.update(cx, |project, cx| {
15478            project.apply_code_action_kind(buffers, kind, true, cx)
15479        });
15480        cx.spawn_in(window, async move |_, cx| {
15481            let transaction = futures::select_biased! {
15482                () = timeout => {
15483                    log::warn!("timed out waiting for executing code action");
15484                    None
15485                }
15486                transaction = apply_action.log_err().fuse() => transaction,
15487            };
15488            buffer
15489                .update(cx, |buffer, cx| {
15490                    // check if we need this
15491                    if let Some(transaction) = transaction {
15492                        if !buffer.is_singleton() {
15493                            buffer.push_transaction(&transaction.0, cx);
15494                        }
15495                    }
15496                    cx.notify();
15497                })
15498                .ok();
15499            Ok(())
15500        })
15501    }
15502
15503    fn restart_language_server(
15504        &mut self,
15505        _: &RestartLanguageServer,
15506        _: &mut Window,
15507        cx: &mut Context<Self>,
15508    ) {
15509        if let Some(project) = self.project.clone() {
15510            self.buffer.update(cx, |multi_buffer, cx| {
15511                project.update(cx, |project, cx| {
15512                    project.restart_language_servers_for_buffers(
15513                        multi_buffer.all_buffers().into_iter().collect(),
15514                        cx,
15515                    );
15516                });
15517            })
15518        }
15519    }
15520
15521    fn stop_language_server(
15522        &mut self,
15523        _: &StopLanguageServer,
15524        _: &mut Window,
15525        cx: &mut Context<Self>,
15526    ) {
15527        if let Some(project) = self.project.clone() {
15528            self.buffer.update(cx, |multi_buffer, cx| {
15529                project.update(cx, |project, cx| {
15530                    project.stop_language_servers_for_buffers(
15531                        multi_buffer.all_buffers().into_iter().collect(),
15532                        cx,
15533                    );
15534                    cx.emit(project::Event::RefreshInlayHints);
15535                });
15536            });
15537        }
15538    }
15539
15540    fn cancel_language_server_work(
15541        workspace: &mut Workspace,
15542        _: &actions::CancelLanguageServerWork,
15543        _: &mut Window,
15544        cx: &mut Context<Workspace>,
15545    ) {
15546        let project = workspace.project();
15547        let buffers = workspace
15548            .active_item(cx)
15549            .and_then(|item| item.act_as::<Editor>(cx))
15550            .map_or(HashSet::default(), |editor| {
15551                editor.read(cx).buffer.read(cx).all_buffers()
15552            });
15553        project.update(cx, |project, cx| {
15554            project.cancel_language_server_work_for_buffers(buffers, cx);
15555        });
15556    }
15557
15558    fn show_character_palette(
15559        &mut self,
15560        _: &ShowCharacterPalette,
15561        window: &mut Window,
15562        _: &mut Context<Self>,
15563    ) {
15564        window.show_character_palette();
15565    }
15566
15567    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15568        if self.mode.is_minimap() {
15569            return;
15570        }
15571
15572        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15573            let buffer = self.buffer.read(cx).snapshot(cx);
15574            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15575            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15576            let is_valid = buffer
15577                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15578                .any(|entry| {
15579                    entry.diagnostic.is_primary
15580                        && !entry.range.is_empty()
15581                        && entry.range.start == primary_range_start
15582                        && entry.diagnostic.message == active_diagnostics.active_message
15583                });
15584
15585            if !is_valid {
15586                self.dismiss_diagnostics(cx);
15587            }
15588        }
15589    }
15590
15591    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15592        match &self.active_diagnostics {
15593            ActiveDiagnostic::Group(group) => Some(group),
15594            _ => None,
15595        }
15596    }
15597
15598    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15599        self.dismiss_diagnostics(cx);
15600        self.active_diagnostics = ActiveDiagnostic::All;
15601    }
15602
15603    fn activate_diagnostics(
15604        &mut self,
15605        buffer_id: BufferId,
15606        diagnostic: DiagnosticEntry<usize>,
15607        window: &mut Window,
15608        cx: &mut Context<Self>,
15609    ) {
15610        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15611            return;
15612        }
15613        self.dismiss_diagnostics(cx);
15614        let snapshot = self.snapshot(window, cx);
15615        let buffer = self.buffer.read(cx).snapshot(cx);
15616        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15617            return;
15618        };
15619
15620        let diagnostic_group = buffer
15621            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15622            .collect::<Vec<_>>();
15623
15624        let blocks =
15625            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15626
15627        let blocks = self.display_map.update(cx, |display_map, cx| {
15628            display_map.insert_blocks(blocks, cx).into_iter().collect()
15629        });
15630        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15631            active_range: buffer.anchor_before(diagnostic.range.start)
15632                ..buffer.anchor_after(diagnostic.range.end),
15633            active_message: diagnostic.diagnostic.message.clone(),
15634            group_id: diagnostic.diagnostic.group_id,
15635            blocks,
15636        });
15637        cx.notify();
15638    }
15639
15640    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15641        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15642            return;
15643        };
15644
15645        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15646        if let ActiveDiagnostic::Group(group) = prev {
15647            self.display_map.update(cx, |display_map, cx| {
15648                display_map.remove_blocks(group.blocks, cx);
15649            });
15650            cx.notify();
15651        }
15652    }
15653
15654    /// Disable inline diagnostics rendering for this editor.
15655    pub fn disable_inline_diagnostics(&mut self) {
15656        self.inline_diagnostics_enabled = false;
15657        self.inline_diagnostics_update = Task::ready(());
15658        self.inline_diagnostics.clear();
15659    }
15660
15661    pub fn diagnostics_enabled(&self) -> bool {
15662        self.mode.is_full()
15663    }
15664
15665    pub fn inline_diagnostics_enabled(&self) -> bool {
15666        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15667    }
15668
15669    pub fn show_inline_diagnostics(&self) -> bool {
15670        self.show_inline_diagnostics
15671    }
15672
15673    pub fn toggle_inline_diagnostics(
15674        &mut self,
15675        _: &ToggleInlineDiagnostics,
15676        window: &mut Window,
15677        cx: &mut Context<Editor>,
15678    ) {
15679        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15680        self.refresh_inline_diagnostics(false, window, cx);
15681    }
15682
15683    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15684        self.diagnostics_max_severity = severity;
15685        self.display_map.update(cx, |display_map, _| {
15686            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15687        });
15688    }
15689
15690    pub fn toggle_diagnostics(
15691        &mut self,
15692        _: &ToggleDiagnostics,
15693        window: &mut Window,
15694        cx: &mut Context<Editor>,
15695    ) {
15696        if !self.diagnostics_enabled() {
15697            return;
15698        }
15699
15700        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15701            EditorSettings::get_global(cx)
15702                .diagnostics_max_severity
15703                .filter(|severity| severity != &DiagnosticSeverity::Off)
15704                .unwrap_or(DiagnosticSeverity::Hint)
15705        } else {
15706            DiagnosticSeverity::Off
15707        };
15708        self.set_max_diagnostics_severity(new_severity, cx);
15709        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15710            self.active_diagnostics = ActiveDiagnostic::None;
15711            self.inline_diagnostics_update = Task::ready(());
15712            self.inline_diagnostics.clear();
15713        } else {
15714            self.refresh_inline_diagnostics(false, window, cx);
15715        }
15716
15717        cx.notify();
15718    }
15719
15720    pub fn toggle_minimap(
15721        &mut self,
15722        _: &ToggleMinimap,
15723        window: &mut Window,
15724        cx: &mut Context<Editor>,
15725    ) {
15726        if self.supports_minimap(cx) {
15727            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15728        }
15729    }
15730
15731    fn refresh_inline_diagnostics(
15732        &mut self,
15733        debounce: bool,
15734        window: &mut Window,
15735        cx: &mut Context<Self>,
15736    ) {
15737        let max_severity = ProjectSettings::get_global(cx)
15738            .diagnostics
15739            .inline
15740            .max_severity
15741            .unwrap_or(self.diagnostics_max_severity);
15742
15743        if !self.inline_diagnostics_enabled()
15744            || !self.show_inline_diagnostics
15745            || max_severity == DiagnosticSeverity::Off
15746        {
15747            self.inline_diagnostics_update = Task::ready(());
15748            self.inline_diagnostics.clear();
15749            return;
15750        }
15751
15752        let debounce_ms = ProjectSettings::get_global(cx)
15753            .diagnostics
15754            .inline
15755            .update_debounce_ms;
15756        let debounce = if debounce && debounce_ms > 0 {
15757            Some(Duration::from_millis(debounce_ms))
15758        } else {
15759            None
15760        };
15761        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15762            if let Some(debounce) = debounce {
15763                cx.background_executor().timer(debounce).await;
15764            }
15765            let Some(snapshot) = editor.upgrade().and_then(|editor| {
15766                editor
15767                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15768                    .ok()
15769            }) else {
15770                return;
15771            };
15772
15773            let new_inline_diagnostics = cx
15774                .background_spawn(async move {
15775                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15776                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15777                        let message = diagnostic_entry
15778                            .diagnostic
15779                            .message
15780                            .split_once('\n')
15781                            .map(|(line, _)| line)
15782                            .map(SharedString::new)
15783                            .unwrap_or_else(|| {
15784                                SharedString::from(diagnostic_entry.diagnostic.message)
15785                            });
15786                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15787                        let (Ok(i) | Err(i)) = inline_diagnostics
15788                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15789                        inline_diagnostics.insert(
15790                            i,
15791                            (
15792                                start_anchor,
15793                                InlineDiagnostic {
15794                                    message,
15795                                    group_id: diagnostic_entry.diagnostic.group_id,
15796                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15797                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15798                                    severity: diagnostic_entry.diagnostic.severity,
15799                                },
15800                            ),
15801                        );
15802                    }
15803                    inline_diagnostics
15804                })
15805                .await;
15806
15807            editor
15808                .update(cx, |editor, cx| {
15809                    editor.inline_diagnostics = new_inline_diagnostics;
15810                    cx.notify();
15811                })
15812                .ok();
15813        });
15814    }
15815
15816    pub fn set_selections_from_remote(
15817        &mut self,
15818        selections: Vec<Selection<Anchor>>,
15819        pending_selection: Option<Selection<Anchor>>,
15820        window: &mut Window,
15821        cx: &mut Context<Self>,
15822    ) {
15823        let old_cursor_position = self.selections.newest_anchor().head();
15824        self.selections.change_with(cx, |s| {
15825            s.select_anchors(selections);
15826            if let Some(pending_selection) = pending_selection {
15827                s.set_pending(pending_selection, SelectMode::Character);
15828            } else {
15829                s.clear_pending();
15830            }
15831        });
15832        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15833    }
15834
15835    pub fn transact(
15836        &mut self,
15837        window: &mut Window,
15838        cx: &mut Context<Self>,
15839        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15840    ) -> Option<TransactionId> {
15841        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15842            this.start_transaction_at(Instant::now(), window, cx);
15843            update(this, window, cx);
15844            this.end_transaction_at(Instant::now(), cx)
15845        })
15846    }
15847
15848    pub fn start_transaction_at(
15849        &mut self,
15850        now: Instant,
15851        window: &mut Window,
15852        cx: &mut Context<Self>,
15853    ) {
15854        self.end_selection(window, cx);
15855        if let Some(tx_id) = self
15856            .buffer
15857            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15858        {
15859            self.selection_history
15860                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15861            cx.emit(EditorEvent::TransactionBegun {
15862                transaction_id: tx_id,
15863            })
15864        }
15865    }
15866
15867    pub fn end_transaction_at(
15868        &mut self,
15869        now: Instant,
15870        cx: &mut Context<Self>,
15871    ) -> Option<TransactionId> {
15872        if let Some(transaction_id) = self
15873            .buffer
15874            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15875        {
15876            if let Some((_, end_selections)) =
15877                self.selection_history.transaction_mut(transaction_id)
15878            {
15879                *end_selections = Some(self.selections.disjoint_anchors());
15880            } else {
15881                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15882            }
15883
15884            cx.emit(EditorEvent::Edited { transaction_id });
15885            Some(transaction_id)
15886        } else {
15887            None
15888        }
15889    }
15890
15891    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15892        if self.selection_mark_mode {
15893            self.change_selections(None, window, cx, |s| {
15894                s.move_with(|_, sel| {
15895                    sel.collapse_to(sel.head(), SelectionGoal::None);
15896                });
15897            })
15898        }
15899        self.selection_mark_mode = true;
15900        cx.notify();
15901    }
15902
15903    pub fn swap_selection_ends(
15904        &mut self,
15905        _: &actions::SwapSelectionEnds,
15906        window: &mut Window,
15907        cx: &mut Context<Self>,
15908    ) {
15909        self.change_selections(None, window, cx, |s| {
15910            s.move_with(|_, sel| {
15911                if sel.start != sel.end {
15912                    sel.reversed = !sel.reversed
15913                }
15914            });
15915        });
15916        self.request_autoscroll(Autoscroll::newest(), cx);
15917        cx.notify();
15918    }
15919
15920    pub fn toggle_fold(
15921        &mut self,
15922        _: &actions::ToggleFold,
15923        window: &mut Window,
15924        cx: &mut Context<Self>,
15925    ) {
15926        if self.is_singleton(cx) {
15927            let selection = self.selections.newest::<Point>(cx);
15928
15929            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15930            let range = if selection.is_empty() {
15931                let point = selection.head().to_display_point(&display_map);
15932                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15933                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15934                    .to_point(&display_map);
15935                start..end
15936            } else {
15937                selection.range()
15938            };
15939            if display_map.folds_in_range(range).next().is_some() {
15940                self.unfold_lines(&Default::default(), window, cx)
15941            } else {
15942                self.fold(&Default::default(), window, cx)
15943            }
15944        } else {
15945            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15946            let buffer_ids: HashSet<_> = self
15947                .selections
15948                .disjoint_anchor_ranges()
15949                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15950                .collect();
15951
15952            let should_unfold = buffer_ids
15953                .iter()
15954                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15955
15956            for buffer_id in buffer_ids {
15957                if should_unfold {
15958                    self.unfold_buffer(buffer_id, cx);
15959                } else {
15960                    self.fold_buffer(buffer_id, cx);
15961                }
15962            }
15963        }
15964    }
15965
15966    pub fn toggle_fold_recursive(
15967        &mut self,
15968        _: &actions::ToggleFoldRecursive,
15969        window: &mut Window,
15970        cx: &mut Context<Self>,
15971    ) {
15972        let selection = self.selections.newest::<Point>(cx);
15973
15974        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15975        let range = if selection.is_empty() {
15976            let point = selection.head().to_display_point(&display_map);
15977            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15978            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15979                .to_point(&display_map);
15980            start..end
15981        } else {
15982            selection.range()
15983        };
15984        if display_map.folds_in_range(range).next().is_some() {
15985            self.unfold_recursive(&Default::default(), window, cx)
15986        } else {
15987            self.fold_recursive(&Default::default(), window, cx)
15988        }
15989    }
15990
15991    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15992        if self.is_singleton(cx) {
15993            let mut to_fold = Vec::new();
15994            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15995            let selections = self.selections.all_adjusted(cx);
15996
15997            for selection in selections {
15998                let range = selection.range().sorted();
15999                let buffer_start_row = range.start.row;
16000
16001                if range.start.row != range.end.row {
16002                    let mut found = false;
16003                    let mut row = range.start.row;
16004                    while row <= range.end.row {
16005                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16006                        {
16007                            found = true;
16008                            row = crease.range().end.row + 1;
16009                            to_fold.push(crease);
16010                        } else {
16011                            row += 1
16012                        }
16013                    }
16014                    if found {
16015                        continue;
16016                    }
16017                }
16018
16019                for row in (0..=range.start.row).rev() {
16020                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16021                        if crease.range().end.row >= buffer_start_row {
16022                            to_fold.push(crease);
16023                            if row <= range.start.row {
16024                                break;
16025                            }
16026                        }
16027                    }
16028                }
16029            }
16030
16031            self.fold_creases(to_fold, true, window, cx);
16032        } else {
16033            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16034            let buffer_ids = self
16035                .selections
16036                .disjoint_anchor_ranges()
16037                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16038                .collect::<HashSet<_>>();
16039            for buffer_id in buffer_ids {
16040                self.fold_buffer(buffer_id, cx);
16041            }
16042        }
16043    }
16044
16045    fn fold_at_level(
16046        &mut self,
16047        fold_at: &FoldAtLevel,
16048        window: &mut Window,
16049        cx: &mut Context<Self>,
16050    ) {
16051        if !self.buffer.read(cx).is_singleton() {
16052            return;
16053        }
16054
16055        let fold_at_level = fold_at.0;
16056        let snapshot = self.buffer.read(cx).snapshot(cx);
16057        let mut to_fold = Vec::new();
16058        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16059
16060        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16061            while start_row < end_row {
16062                match self
16063                    .snapshot(window, cx)
16064                    .crease_for_buffer_row(MultiBufferRow(start_row))
16065                {
16066                    Some(crease) => {
16067                        let nested_start_row = crease.range().start.row + 1;
16068                        let nested_end_row = crease.range().end.row;
16069
16070                        if current_level < fold_at_level {
16071                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16072                        } else if current_level == fold_at_level {
16073                            to_fold.push(crease);
16074                        }
16075
16076                        start_row = nested_end_row + 1;
16077                    }
16078                    None => start_row += 1,
16079                }
16080            }
16081        }
16082
16083        self.fold_creases(to_fold, true, window, cx);
16084    }
16085
16086    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16087        if self.buffer.read(cx).is_singleton() {
16088            let mut fold_ranges = Vec::new();
16089            let snapshot = self.buffer.read(cx).snapshot(cx);
16090
16091            for row in 0..snapshot.max_row().0 {
16092                if let Some(foldable_range) = self
16093                    .snapshot(window, cx)
16094                    .crease_for_buffer_row(MultiBufferRow(row))
16095                {
16096                    fold_ranges.push(foldable_range);
16097                }
16098            }
16099
16100            self.fold_creases(fold_ranges, true, window, cx);
16101        } else {
16102            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16103                editor
16104                    .update_in(cx, |editor, _, cx| {
16105                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16106                            editor.fold_buffer(buffer_id, cx);
16107                        }
16108                    })
16109                    .ok();
16110            });
16111        }
16112    }
16113
16114    pub fn fold_function_bodies(
16115        &mut self,
16116        _: &actions::FoldFunctionBodies,
16117        window: &mut Window,
16118        cx: &mut Context<Self>,
16119    ) {
16120        let snapshot = self.buffer.read(cx).snapshot(cx);
16121
16122        let ranges = snapshot
16123            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16124            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16125            .collect::<Vec<_>>();
16126
16127        let creases = ranges
16128            .into_iter()
16129            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16130            .collect();
16131
16132        self.fold_creases(creases, true, window, cx);
16133    }
16134
16135    pub fn fold_recursive(
16136        &mut self,
16137        _: &actions::FoldRecursive,
16138        window: &mut Window,
16139        cx: &mut Context<Self>,
16140    ) {
16141        let mut to_fold = Vec::new();
16142        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16143        let selections = self.selections.all_adjusted(cx);
16144
16145        for selection in selections {
16146            let range = selection.range().sorted();
16147            let buffer_start_row = range.start.row;
16148
16149            if range.start.row != range.end.row {
16150                let mut found = false;
16151                for row in range.start.row..=range.end.row {
16152                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16153                        found = true;
16154                        to_fold.push(crease);
16155                    }
16156                }
16157                if found {
16158                    continue;
16159                }
16160            }
16161
16162            for row in (0..=range.start.row).rev() {
16163                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16164                    if crease.range().end.row >= buffer_start_row {
16165                        to_fold.push(crease);
16166                    } else {
16167                        break;
16168                    }
16169                }
16170            }
16171        }
16172
16173        self.fold_creases(to_fold, true, window, cx);
16174    }
16175
16176    pub fn fold_at(
16177        &mut self,
16178        buffer_row: MultiBufferRow,
16179        window: &mut Window,
16180        cx: &mut Context<Self>,
16181    ) {
16182        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16183
16184        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16185            let autoscroll = self
16186                .selections
16187                .all::<Point>(cx)
16188                .iter()
16189                .any(|selection| crease.range().overlaps(&selection.range()));
16190
16191            self.fold_creases(vec![crease], autoscroll, window, cx);
16192        }
16193    }
16194
16195    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16196        if self.is_singleton(cx) {
16197            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16198            let buffer = &display_map.buffer_snapshot;
16199            let selections = self.selections.all::<Point>(cx);
16200            let ranges = selections
16201                .iter()
16202                .map(|s| {
16203                    let range = s.display_range(&display_map).sorted();
16204                    let mut start = range.start.to_point(&display_map);
16205                    let mut end = range.end.to_point(&display_map);
16206                    start.column = 0;
16207                    end.column = buffer.line_len(MultiBufferRow(end.row));
16208                    start..end
16209                })
16210                .collect::<Vec<_>>();
16211
16212            self.unfold_ranges(&ranges, true, true, cx);
16213        } else {
16214            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16215            let buffer_ids = self
16216                .selections
16217                .disjoint_anchor_ranges()
16218                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16219                .collect::<HashSet<_>>();
16220            for buffer_id in buffer_ids {
16221                self.unfold_buffer(buffer_id, cx);
16222            }
16223        }
16224    }
16225
16226    pub fn unfold_recursive(
16227        &mut self,
16228        _: &UnfoldRecursive,
16229        _window: &mut Window,
16230        cx: &mut Context<Self>,
16231    ) {
16232        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16233        let selections = self.selections.all::<Point>(cx);
16234        let ranges = selections
16235            .iter()
16236            .map(|s| {
16237                let mut range = s.display_range(&display_map).sorted();
16238                *range.start.column_mut() = 0;
16239                *range.end.column_mut() = display_map.line_len(range.end.row());
16240                let start = range.start.to_point(&display_map);
16241                let end = range.end.to_point(&display_map);
16242                start..end
16243            })
16244            .collect::<Vec<_>>();
16245
16246        self.unfold_ranges(&ranges, true, true, cx);
16247    }
16248
16249    pub fn unfold_at(
16250        &mut self,
16251        buffer_row: MultiBufferRow,
16252        _window: &mut Window,
16253        cx: &mut Context<Self>,
16254    ) {
16255        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16256
16257        let intersection_range = Point::new(buffer_row.0, 0)
16258            ..Point::new(
16259                buffer_row.0,
16260                display_map.buffer_snapshot.line_len(buffer_row),
16261            );
16262
16263        let autoscroll = self
16264            .selections
16265            .all::<Point>(cx)
16266            .iter()
16267            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16268
16269        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16270    }
16271
16272    pub fn unfold_all(
16273        &mut self,
16274        _: &actions::UnfoldAll,
16275        _window: &mut Window,
16276        cx: &mut Context<Self>,
16277    ) {
16278        if self.buffer.read(cx).is_singleton() {
16279            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16280            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16281        } else {
16282            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16283                editor
16284                    .update(cx, |editor, cx| {
16285                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16286                            editor.unfold_buffer(buffer_id, cx);
16287                        }
16288                    })
16289                    .ok();
16290            });
16291        }
16292    }
16293
16294    pub fn fold_selected_ranges(
16295        &mut self,
16296        _: &FoldSelectedRanges,
16297        window: &mut Window,
16298        cx: &mut Context<Self>,
16299    ) {
16300        let selections = self.selections.all_adjusted(cx);
16301        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16302        let ranges = selections
16303            .into_iter()
16304            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16305            .collect::<Vec<_>>();
16306        self.fold_creases(ranges, true, window, cx);
16307    }
16308
16309    pub fn fold_ranges<T: ToOffset + Clone>(
16310        &mut self,
16311        ranges: Vec<Range<T>>,
16312        auto_scroll: bool,
16313        window: &mut Window,
16314        cx: &mut Context<Self>,
16315    ) {
16316        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16317        let ranges = ranges
16318            .into_iter()
16319            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16320            .collect::<Vec<_>>();
16321        self.fold_creases(ranges, auto_scroll, window, cx);
16322    }
16323
16324    pub fn fold_creases<T: ToOffset + Clone>(
16325        &mut self,
16326        creases: Vec<Crease<T>>,
16327        auto_scroll: bool,
16328        _window: &mut Window,
16329        cx: &mut Context<Self>,
16330    ) {
16331        if creases.is_empty() {
16332            return;
16333        }
16334
16335        let mut buffers_affected = HashSet::default();
16336        let multi_buffer = self.buffer().read(cx);
16337        for crease in &creases {
16338            if let Some((_, buffer, _)) =
16339                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16340            {
16341                buffers_affected.insert(buffer.read(cx).remote_id());
16342            };
16343        }
16344
16345        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16346
16347        if auto_scroll {
16348            self.request_autoscroll(Autoscroll::fit(), cx);
16349        }
16350
16351        cx.notify();
16352
16353        self.scrollbar_marker_state.dirty = true;
16354        self.folds_did_change(cx);
16355    }
16356
16357    /// Removes any folds whose ranges intersect any of the given ranges.
16358    pub fn unfold_ranges<T: ToOffset + Clone>(
16359        &mut self,
16360        ranges: &[Range<T>],
16361        inclusive: bool,
16362        auto_scroll: bool,
16363        cx: &mut Context<Self>,
16364    ) {
16365        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16366            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16367        });
16368        self.folds_did_change(cx);
16369    }
16370
16371    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16372        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16373            return;
16374        }
16375        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16376        self.display_map.update(cx, |display_map, cx| {
16377            display_map.fold_buffers([buffer_id], cx)
16378        });
16379        cx.emit(EditorEvent::BufferFoldToggled {
16380            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16381            folded: true,
16382        });
16383        cx.notify();
16384    }
16385
16386    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16387        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16388            return;
16389        }
16390        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16391        self.display_map.update(cx, |display_map, cx| {
16392            display_map.unfold_buffers([buffer_id], cx);
16393        });
16394        cx.emit(EditorEvent::BufferFoldToggled {
16395            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16396            folded: false,
16397        });
16398        cx.notify();
16399    }
16400
16401    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16402        self.display_map.read(cx).is_buffer_folded(buffer)
16403    }
16404
16405    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16406        self.display_map.read(cx).folded_buffers()
16407    }
16408
16409    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16410        self.display_map.update(cx, |display_map, cx| {
16411            display_map.disable_header_for_buffer(buffer_id, cx);
16412        });
16413        cx.notify();
16414    }
16415
16416    /// Removes any folds with the given ranges.
16417    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16418        &mut self,
16419        ranges: &[Range<T>],
16420        type_id: TypeId,
16421        auto_scroll: bool,
16422        cx: &mut Context<Self>,
16423    ) {
16424        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16425            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16426        });
16427        self.folds_did_change(cx);
16428    }
16429
16430    fn remove_folds_with<T: ToOffset + Clone>(
16431        &mut self,
16432        ranges: &[Range<T>],
16433        auto_scroll: bool,
16434        cx: &mut Context<Self>,
16435        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16436    ) {
16437        if ranges.is_empty() {
16438            return;
16439        }
16440
16441        let mut buffers_affected = HashSet::default();
16442        let multi_buffer = self.buffer().read(cx);
16443        for range in ranges {
16444            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16445                buffers_affected.insert(buffer.read(cx).remote_id());
16446            };
16447        }
16448
16449        self.display_map.update(cx, update);
16450
16451        if auto_scroll {
16452            self.request_autoscroll(Autoscroll::fit(), cx);
16453        }
16454
16455        cx.notify();
16456        self.scrollbar_marker_state.dirty = true;
16457        self.active_indent_guides_state.dirty = true;
16458    }
16459
16460    pub fn update_fold_widths(
16461        &mut self,
16462        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16463        cx: &mut Context<Self>,
16464    ) -> bool {
16465        self.display_map
16466            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16467    }
16468
16469    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16470        self.display_map.read(cx).fold_placeholder.clone()
16471    }
16472
16473    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16474        self.buffer.update(cx, |buffer, cx| {
16475            buffer.set_all_diff_hunks_expanded(cx);
16476        });
16477    }
16478
16479    pub fn expand_all_diff_hunks(
16480        &mut self,
16481        _: &ExpandAllDiffHunks,
16482        _window: &mut Window,
16483        cx: &mut Context<Self>,
16484    ) {
16485        self.buffer.update(cx, |buffer, cx| {
16486            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16487        });
16488    }
16489
16490    pub fn toggle_selected_diff_hunks(
16491        &mut self,
16492        _: &ToggleSelectedDiffHunks,
16493        _window: &mut Window,
16494        cx: &mut Context<Self>,
16495    ) {
16496        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16497        self.toggle_diff_hunks_in_ranges(ranges, cx);
16498    }
16499
16500    pub fn diff_hunks_in_ranges<'a>(
16501        &'a self,
16502        ranges: &'a [Range<Anchor>],
16503        buffer: &'a MultiBufferSnapshot,
16504    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16505        ranges.iter().flat_map(move |range| {
16506            let end_excerpt_id = range.end.excerpt_id;
16507            let range = range.to_point(buffer);
16508            let mut peek_end = range.end;
16509            if range.end.row < buffer.max_row().0 {
16510                peek_end = Point::new(range.end.row + 1, 0);
16511            }
16512            buffer
16513                .diff_hunks_in_range(range.start..peek_end)
16514                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16515        })
16516    }
16517
16518    pub fn has_stageable_diff_hunks_in_ranges(
16519        &self,
16520        ranges: &[Range<Anchor>],
16521        snapshot: &MultiBufferSnapshot,
16522    ) -> bool {
16523        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16524        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16525    }
16526
16527    pub fn toggle_staged_selected_diff_hunks(
16528        &mut self,
16529        _: &::git::ToggleStaged,
16530        _: &mut Window,
16531        cx: &mut Context<Self>,
16532    ) {
16533        let snapshot = self.buffer.read(cx).snapshot(cx);
16534        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16535        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16536        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16537    }
16538
16539    pub fn set_render_diff_hunk_controls(
16540        &mut self,
16541        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16542        cx: &mut Context<Self>,
16543    ) {
16544        self.render_diff_hunk_controls = render_diff_hunk_controls;
16545        cx.notify();
16546    }
16547
16548    pub fn stage_and_next(
16549        &mut self,
16550        _: &::git::StageAndNext,
16551        window: &mut Window,
16552        cx: &mut Context<Self>,
16553    ) {
16554        self.do_stage_or_unstage_and_next(true, window, cx);
16555    }
16556
16557    pub fn unstage_and_next(
16558        &mut self,
16559        _: &::git::UnstageAndNext,
16560        window: &mut Window,
16561        cx: &mut Context<Self>,
16562    ) {
16563        self.do_stage_or_unstage_and_next(false, window, cx);
16564    }
16565
16566    pub fn stage_or_unstage_diff_hunks(
16567        &mut self,
16568        stage: bool,
16569        ranges: Vec<Range<Anchor>>,
16570        cx: &mut Context<Self>,
16571    ) {
16572        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16573        cx.spawn(async move |this, cx| {
16574            task.await?;
16575            this.update(cx, |this, cx| {
16576                let snapshot = this.buffer.read(cx).snapshot(cx);
16577                let chunk_by = this
16578                    .diff_hunks_in_ranges(&ranges, &snapshot)
16579                    .chunk_by(|hunk| hunk.buffer_id);
16580                for (buffer_id, hunks) in &chunk_by {
16581                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16582                }
16583            })
16584        })
16585        .detach_and_log_err(cx);
16586    }
16587
16588    fn save_buffers_for_ranges_if_needed(
16589        &mut self,
16590        ranges: &[Range<Anchor>],
16591        cx: &mut Context<Editor>,
16592    ) -> Task<Result<()>> {
16593        let multibuffer = self.buffer.read(cx);
16594        let snapshot = multibuffer.read(cx);
16595        let buffer_ids: HashSet<_> = ranges
16596            .iter()
16597            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16598            .collect();
16599        drop(snapshot);
16600
16601        let mut buffers = HashSet::default();
16602        for buffer_id in buffer_ids {
16603            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16604                let buffer = buffer_entity.read(cx);
16605                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16606                {
16607                    buffers.insert(buffer_entity);
16608                }
16609            }
16610        }
16611
16612        if let Some(project) = &self.project {
16613            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16614        } else {
16615            Task::ready(Ok(()))
16616        }
16617    }
16618
16619    fn do_stage_or_unstage_and_next(
16620        &mut self,
16621        stage: bool,
16622        window: &mut Window,
16623        cx: &mut Context<Self>,
16624    ) {
16625        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16626
16627        if ranges.iter().any(|range| range.start != range.end) {
16628            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16629            return;
16630        }
16631
16632        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16633        let snapshot = self.snapshot(window, cx);
16634        let position = self.selections.newest::<Point>(cx).head();
16635        let mut row = snapshot
16636            .buffer_snapshot
16637            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16638            .find(|hunk| hunk.row_range.start.0 > position.row)
16639            .map(|hunk| hunk.row_range.start);
16640
16641        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16642        // Outside of the project diff editor, wrap around to the beginning.
16643        if !all_diff_hunks_expanded {
16644            row = row.or_else(|| {
16645                snapshot
16646                    .buffer_snapshot
16647                    .diff_hunks_in_range(Point::zero()..position)
16648                    .find(|hunk| hunk.row_range.end.0 < position.row)
16649                    .map(|hunk| hunk.row_range.start)
16650            });
16651        }
16652
16653        if let Some(row) = row {
16654            let destination = Point::new(row.0, 0);
16655            let autoscroll = Autoscroll::center();
16656
16657            self.unfold_ranges(&[destination..destination], false, false, cx);
16658            self.change_selections(Some(autoscroll), window, cx, |s| {
16659                s.select_ranges([destination..destination]);
16660            });
16661        }
16662    }
16663
16664    fn do_stage_or_unstage(
16665        &self,
16666        stage: bool,
16667        buffer_id: BufferId,
16668        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16669        cx: &mut App,
16670    ) -> Option<()> {
16671        let project = self.project.as_ref()?;
16672        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16673        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16674        let buffer_snapshot = buffer.read(cx).snapshot();
16675        let file_exists = buffer_snapshot
16676            .file()
16677            .is_some_and(|file| file.disk_state().exists());
16678        diff.update(cx, |diff, cx| {
16679            diff.stage_or_unstage_hunks(
16680                stage,
16681                &hunks
16682                    .map(|hunk| buffer_diff::DiffHunk {
16683                        buffer_range: hunk.buffer_range,
16684                        diff_base_byte_range: hunk.diff_base_byte_range,
16685                        secondary_status: hunk.secondary_status,
16686                        range: Point::zero()..Point::zero(), // unused
16687                    })
16688                    .collect::<Vec<_>>(),
16689                &buffer_snapshot,
16690                file_exists,
16691                cx,
16692            )
16693        });
16694        None
16695    }
16696
16697    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16698        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16699        self.buffer
16700            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16701    }
16702
16703    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16704        self.buffer.update(cx, |buffer, cx| {
16705            let ranges = vec![Anchor::min()..Anchor::max()];
16706            if !buffer.all_diff_hunks_expanded()
16707                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16708            {
16709                buffer.collapse_diff_hunks(ranges, cx);
16710                true
16711            } else {
16712                false
16713            }
16714        })
16715    }
16716
16717    fn toggle_diff_hunks_in_ranges(
16718        &mut self,
16719        ranges: Vec<Range<Anchor>>,
16720        cx: &mut Context<Editor>,
16721    ) {
16722        self.buffer.update(cx, |buffer, cx| {
16723            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16724            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16725        })
16726    }
16727
16728    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16729        self.buffer.update(cx, |buffer, cx| {
16730            let snapshot = buffer.snapshot(cx);
16731            let excerpt_id = range.end.excerpt_id;
16732            let point_range = range.to_point(&snapshot);
16733            let expand = !buffer.single_hunk_is_expanded(range, cx);
16734            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16735        })
16736    }
16737
16738    pub(crate) fn apply_all_diff_hunks(
16739        &mut self,
16740        _: &ApplyAllDiffHunks,
16741        window: &mut Window,
16742        cx: &mut Context<Self>,
16743    ) {
16744        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16745
16746        let buffers = self.buffer.read(cx).all_buffers();
16747        for branch_buffer in buffers {
16748            branch_buffer.update(cx, |branch_buffer, cx| {
16749                branch_buffer.merge_into_base(Vec::new(), cx);
16750            });
16751        }
16752
16753        if let Some(project) = self.project.clone() {
16754            self.save(true, project, window, cx).detach_and_log_err(cx);
16755        }
16756    }
16757
16758    pub(crate) fn apply_selected_diff_hunks(
16759        &mut self,
16760        _: &ApplyDiffHunk,
16761        window: &mut Window,
16762        cx: &mut Context<Self>,
16763    ) {
16764        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16765        let snapshot = self.snapshot(window, cx);
16766        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16767        let mut ranges_by_buffer = HashMap::default();
16768        self.transact(window, cx, |editor, _window, cx| {
16769            for hunk in hunks {
16770                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16771                    ranges_by_buffer
16772                        .entry(buffer.clone())
16773                        .or_insert_with(Vec::new)
16774                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16775                }
16776            }
16777
16778            for (buffer, ranges) in ranges_by_buffer {
16779                buffer.update(cx, |buffer, cx| {
16780                    buffer.merge_into_base(ranges, cx);
16781                });
16782            }
16783        });
16784
16785        if let Some(project) = self.project.clone() {
16786            self.save(true, project, window, cx).detach_and_log_err(cx);
16787        }
16788    }
16789
16790    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16791        if hovered != self.gutter_hovered {
16792            self.gutter_hovered = hovered;
16793            cx.notify();
16794        }
16795    }
16796
16797    pub fn insert_blocks(
16798        &mut self,
16799        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16800        autoscroll: Option<Autoscroll>,
16801        cx: &mut Context<Self>,
16802    ) -> Vec<CustomBlockId> {
16803        let blocks = self
16804            .display_map
16805            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16806        if let Some(autoscroll) = autoscroll {
16807            self.request_autoscroll(autoscroll, cx);
16808        }
16809        cx.notify();
16810        blocks
16811    }
16812
16813    pub fn resize_blocks(
16814        &mut self,
16815        heights: HashMap<CustomBlockId, u32>,
16816        autoscroll: Option<Autoscroll>,
16817        cx: &mut Context<Self>,
16818    ) {
16819        self.display_map
16820            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16821        if let Some(autoscroll) = autoscroll {
16822            self.request_autoscroll(autoscroll, cx);
16823        }
16824        cx.notify();
16825    }
16826
16827    pub fn replace_blocks(
16828        &mut self,
16829        renderers: HashMap<CustomBlockId, RenderBlock>,
16830        autoscroll: Option<Autoscroll>,
16831        cx: &mut Context<Self>,
16832    ) {
16833        self.display_map
16834            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16835        if let Some(autoscroll) = autoscroll {
16836            self.request_autoscroll(autoscroll, cx);
16837        }
16838        cx.notify();
16839    }
16840
16841    pub fn remove_blocks(
16842        &mut self,
16843        block_ids: HashSet<CustomBlockId>,
16844        autoscroll: Option<Autoscroll>,
16845        cx: &mut Context<Self>,
16846    ) {
16847        self.display_map.update(cx, |display_map, cx| {
16848            display_map.remove_blocks(block_ids, cx)
16849        });
16850        if let Some(autoscroll) = autoscroll {
16851            self.request_autoscroll(autoscroll, cx);
16852        }
16853        cx.notify();
16854    }
16855
16856    pub fn row_for_block(
16857        &self,
16858        block_id: CustomBlockId,
16859        cx: &mut Context<Self>,
16860    ) -> Option<DisplayRow> {
16861        self.display_map
16862            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16863    }
16864
16865    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16866        self.focused_block = Some(focused_block);
16867    }
16868
16869    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16870        self.focused_block.take()
16871    }
16872
16873    pub fn insert_creases(
16874        &mut self,
16875        creases: impl IntoIterator<Item = Crease<Anchor>>,
16876        cx: &mut Context<Self>,
16877    ) -> Vec<CreaseId> {
16878        self.display_map
16879            .update(cx, |map, cx| map.insert_creases(creases, cx))
16880    }
16881
16882    pub fn remove_creases(
16883        &mut self,
16884        ids: impl IntoIterator<Item = CreaseId>,
16885        cx: &mut Context<Self>,
16886    ) -> Vec<(CreaseId, Range<Anchor>)> {
16887        self.display_map
16888            .update(cx, |map, cx| map.remove_creases(ids, cx))
16889    }
16890
16891    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16892        self.display_map
16893            .update(cx, |map, cx| map.snapshot(cx))
16894            .longest_row()
16895    }
16896
16897    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16898        self.display_map
16899            .update(cx, |map, cx| map.snapshot(cx))
16900            .max_point()
16901    }
16902
16903    pub fn text(&self, cx: &App) -> String {
16904        self.buffer.read(cx).read(cx).text()
16905    }
16906
16907    pub fn is_empty(&self, cx: &App) -> bool {
16908        self.buffer.read(cx).read(cx).is_empty()
16909    }
16910
16911    pub fn text_option(&self, cx: &App) -> Option<String> {
16912        let text = self.text(cx);
16913        let text = text.trim();
16914
16915        if text.is_empty() {
16916            return None;
16917        }
16918
16919        Some(text.to_string())
16920    }
16921
16922    pub fn set_text(
16923        &mut self,
16924        text: impl Into<Arc<str>>,
16925        window: &mut Window,
16926        cx: &mut Context<Self>,
16927    ) {
16928        self.transact(window, cx, |this, _, cx| {
16929            this.buffer
16930                .read(cx)
16931                .as_singleton()
16932                .expect("you can only call set_text on editors for singleton buffers")
16933                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16934        });
16935    }
16936
16937    pub fn display_text(&self, cx: &mut App) -> String {
16938        self.display_map
16939            .update(cx, |map, cx| map.snapshot(cx))
16940            .text()
16941    }
16942
16943    fn create_minimap(
16944        &self,
16945        minimap_settings: MinimapSettings,
16946        window: &mut Window,
16947        cx: &mut Context<Self>,
16948    ) -> Option<Entity<Self>> {
16949        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16950            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16951    }
16952
16953    fn initialize_new_minimap(
16954        &self,
16955        minimap_settings: MinimapSettings,
16956        window: &mut Window,
16957        cx: &mut Context<Self>,
16958    ) -> Entity<Self> {
16959        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16960
16961        let mut minimap = Editor::new_internal(
16962            EditorMode::Minimap {
16963                parent: cx.weak_entity(),
16964            },
16965            self.buffer.clone(),
16966            self.project.clone(),
16967            Some(self.display_map.clone()),
16968            window,
16969            cx,
16970        );
16971        minimap.scroll_manager.clone_state(&self.scroll_manager);
16972        minimap.set_text_style_refinement(TextStyleRefinement {
16973            font_size: Some(MINIMAP_FONT_SIZE),
16974            font_weight: Some(MINIMAP_FONT_WEIGHT),
16975            ..Default::default()
16976        });
16977        minimap.update_minimap_configuration(minimap_settings, cx);
16978        cx.new(|_| minimap)
16979    }
16980
16981    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16982        let current_line_highlight = minimap_settings
16983            .current_line_highlight
16984            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16985        self.set_current_line_highlight(Some(current_line_highlight));
16986    }
16987
16988    pub fn minimap(&self) -> Option<&Entity<Self>> {
16989        self.minimap
16990            .as_ref()
16991            .filter(|_| self.minimap_visibility.visible())
16992    }
16993
16994    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16995        let mut wrap_guides = smallvec![];
16996
16997        if self.show_wrap_guides == Some(false) {
16998            return wrap_guides;
16999        }
17000
17001        let settings = self.buffer.read(cx).language_settings(cx);
17002        if settings.show_wrap_guides {
17003            match self.soft_wrap_mode(cx) {
17004                SoftWrap::Column(soft_wrap) => {
17005                    wrap_guides.push((soft_wrap as usize, true));
17006                }
17007                SoftWrap::Bounded(soft_wrap) => {
17008                    wrap_guides.push((soft_wrap as usize, true));
17009                }
17010                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17011            }
17012            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17013        }
17014
17015        wrap_guides
17016    }
17017
17018    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17019        let settings = self.buffer.read(cx).language_settings(cx);
17020        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17021        match mode {
17022            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17023                SoftWrap::None
17024            }
17025            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17026            language_settings::SoftWrap::PreferredLineLength => {
17027                SoftWrap::Column(settings.preferred_line_length)
17028            }
17029            language_settings::SoftWrap::Bounded => {
17030                SoftWrap::Bounded(settings.preferred_line_length)
17031            }
17032        }
17033    }
17034
17035    pub fn set_soft_wrap_mode(
17036        &mut self,
17037        mode: language_settings::SoftWrap,
17038
17039        cx: &mut Context<Self>,
17040    ) {
17041        self.soft_wrap_mode_override = Some(mode);
17042        cx.notify();
17043    }
17044
17045    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17046        self.hard_wrap = hard_wrap;
17047        cx.notify();
17048    }
17049
17050    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17051        self.text_style_refinement = Some(style);
17052    }
17053
17054    /// called by the Element so we know what style we were most recently rendered with.
17055    pub(crate) fn set_style(
17056        &mut self,
17057        style: EditorStyle,
17058        window: &mut Window,
17059        cx: &mut Context<Self>,
17060    ) {
17061        // We intentionally do not inform the display map about the minimap style
17062        // so that wrapping is not recalculated and stays consistent for the editor
17063        // and its linked minimap.
17064        if !self.mode.is_minimap() {
17065            let rem_size = window.rem_size();
17066            self.display_map.update(cx, |map, cx| {
17067                map.set_font(
17068                    style.text.font(),
17069                    style.text.font_size.to_pixels(rem_size),
17070                    cx,
17071                )
17072            });
17073        }
17074        self.style = Some(style);
17075    }
17076
17077    pub fn style(&self) -> Option<&EditorStyle> {
17078        self.style.as_ref()
17079    }
17080
17081    // Called by the element. This method is not designed to be called outside of the editor
17082    // element's layout code because it does not notify when rewrapping is computed synchronously.
17083    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17084        self.display_map
17085            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17086    }
17087
17088    pub fn set_soft_wrap(&mut self) {
17089        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17090    }
17091
17092    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17093        if self.soft_wrap_mode_override.is_some() {
17094            self.soft_wrap_mode_override.take();
17095        } else {
17096            let soft_wrap = match self.soft_wrap_mode(cx) {
17097                SoftWrap::GitDiff => return,
17098                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17099                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17100                    language_settings::SoftWrap::None
17101                }
17102            };
17103            self.soft_wrap_mode_override = Some(soft_wrap);
17104        }
17105        cx.notify();
17106    }
17107
17108    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17109        let Some(workspace) = self.workspace() else {
17110            return;
17111        };
17112        let fs = workspace.read(cx).app_state().fs.clone();
17113        let current_show = TabBarSettings::get_global(cx).show;
17114        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17115            setting.show = Some(!current_show);
17116        });
17117    }
17118
17119    pub fn toggle_indent_guides(
17120        &mut self,
17121        _: &ToggleIndentGuides,
17122        _: &mut Window,
17123        cx: &mut Context<Self>,
17124    ) {
17125        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17126            self.buffer
17127                .read(cx)
17128                .language_settings(cx)
17129                .indent_guides
17130                .enabled
17131        });
17132        self.show_indent_guides = Some(!currently_enabled);
17133        cx.notify();
17134    }
17135
17136    fn should_show_indent_guides(&self) -> Option<bool> {
17137        self.show_indent_guides
17138    }
17139
17140    pub fn toggle_line_numbers(
17141        &mut self,
17142        _: &ToggleLineNumbers,
17143        _: &mut Window,
17144        cx: &mut Context<Self>,
17145    ) {
17146        let mut editor_settings = EditorSettings::get_global(cx).clone();
17147        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17148        EditorSettings::override_global(editor_settings, cx);
17149    }
17150
17151    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17152        if let Some(show_line_numbers) = self.show_line_numbers {
17153            return show_line_numbers;
17154        }
17155        EditorSettings::get_global(cx).gutter.line_numbers
17156    }
17157
17158    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17159        self.use_relative_line_numbers
17160            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17161    }
17162
17163    pub fn toggle_relative_line_numbers(
17164        &mut self,
17165        _: &ToggleRelativeLineNumbers,
17166        _: &mut Window,
17167        cx: &mut Context<Self>,
17168    ) {
17169        let is_relative = self.should_use_relative_line_numbers(cx);
17170        self.set_relative_line_number(Some(!is_relative), cx)
17171    }
17172
17173    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17174        self.use_relative_line_numbers = is_relative;
17175        cx.notify();
17176    }
17177
17178    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17179        self.show_gutter = show_gutter;
17180        cx.notify();
17181    }
17182
17183    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17184        self.show_scrollbars = ScrollbarAxes {
17185            horizontal: show,
17186            vertical: show,
17187        };
17188        cx.notify();
17189    }
17190
17191    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17192        self.show_scrollbars.vertical = show;
17193        cx.notify();
17194    }
17195
17196    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17197        self.show_scrollbars.horizontal = show;
17198        cx.notify();
17199    }
17200
17201    pub fn set_minimap_visibility(
17202        &mut self,
17203        minimap_visibility: MinimapVisibility,
17204        window: &mut Window,
17205        cx: &mut Context<Self>,
17206    ) {
17207        if self.minimap_visibility != minimap_visibility {
17208            if minimap_visibility.visible() && self.minimap.is_none() {
17209                let minimap_settings = EditorSettings::get_global(cx).minimap;
17210                self.minimap =
17211                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17212            }
17213            self.minimap_visibility = minimap_visibility;
17214            cx.notify();
17215        }
17216    }
17217
17218    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17219        self.set_show_scrollbars(false, cx);
17220        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17221    }
17222
17223    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17224        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17225    }
17226
17227    /// Normally the text in full mode and auto height editors is padded on the
17228    /// left side by roughly half a character width for improved hit testing.
17229    ///
17230    /// Use this method to disable this for cases where this is not wanted (e.g.
17231    /// if you want to align the editor text with some other text above or below)
17232    /// or if you want to add this padding to single-line editors.
17233    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17234        self.offset_content = offset_content;
17235        cx.notify();
17236    }
17237
17238    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17239        self.show_line_numbers = Some(show_line_numbers);
17240        cx.notify();
17241    }
17242
17243    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17244        self.disable_expand_excerpt_buttons = true;
17245        cx.notify();
17246    }
17247
17248    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17249        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17250        cx.notify();
17251    }
17252
17253    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17254        self.show_code_actions = Some(show_code_actions);
17255        cx.notify();
17256    }
17257
17258    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17259        self.show_runnables = Some(show_runnables);
17260        cx.notify();
17261    }
17262
17263    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17264        self.show_breakpoints = Some(show_breakpoints);
17265        cx.notify();
17266    }
17267
17268    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17269        if self.display_map.read(cx).masked != masked {
17270            self.display_map.update(cx, |map, _| map.masked = masked);
17271        }
17272        cx.notify()
17273    }
17274
17275    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17276        self.show_wrap_guides = Some(show_wrap_guides);
17277        cx.notify();
17278    }
17279
17280    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17281        self.show_indent_guides = Some(show_indent_guides);
17282        cx.notify();
17283    }
17284
17285    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17286        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17287            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17288                if let Some(dir) = file.abs_path(cx).parent() {
17289                    return Some(dir.to_owned());
17290                }
17291            }
17292
17293            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17294                return Some(project_path.path.to_path_buf());
17295            }
17296        }
17297
17298        None
17299    }
17300
17301    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17302        self.active_excerpt(cx)?
17303            .1
17304            .read(cx)
17305            .file()
17306            .and_then(|f| f.as_local())
17307    }
17308
17309    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17310        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17311            let buffer = buffer.read(cx);
17312            if let Some(project_path) = buffer.project_path(cx) {
17313                let project = self.project.as_ref()?.read(cx);
17314                project.absolute_path(&project_path, cx)
17315            } else {
17316                buffer
17317                    .file()
17318                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17319            }
17320        })
17321    }
17322
17323    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17324        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17325            let project_path = buffer.read(cx).project_path(cx)?;
17326            let project = self.project.as_ref()?.read(cx);
17327            let entry = project.entry_for_path(&project_path, cx)?;
17328            let path = entry.path.to_path_buf();
17329            Some(path)
17330        })
17331    }
17332
17333    pub fn reveal_in_finder(
17334        &mut self,
17335        _: &RevealInFileManager,
17336        _window: &mut Window,
17337        cx: &mut Context<Self>,
17338    ) {
17339        if let Some(target) = self.target_file(cx) {
17340            cx.reveal_path(&target.abs_path(cx));
17341        }
17342    }
17343
17344    pub fn copy_path(
17345        &mut self,
17346        _: &zed_actions::workspace::CopyPath,
17347        _window: &mut Window,
17348        cx: &mut Context<Self>,
17349    ) {
17350        if let Some(path) = self.target_file_abs_path(cx) {
17351            if let Some(path) = path.to_str() {
17352                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17353            }
17354        }
17355    }
17356
17357    pub fn copy_relative_path(
17358        &mut self,
17359        _: &zed_actions::workspace::CopyRelativePath,
17360        _window: &mut Window,
17361        cx: &mut Context<Self>,
17362    ) {
17363        if let Some(path) = self.target_file_path(cx) {
17364            if let Some(path) = path.to_str() {
17365                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17366            }
17367        }
17368    }
17369
17370    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17371        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17372            buffer.read(cx).project_path(cx)
17373        } else {
17374            None
17375        }
17376    }
17377
17378    // Returns true if the editor handled a go-to-line request
17379    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17380        maybe!({
17381            let breakpoint_store = self.breakpoint_store.as_ref()?;
17382
17383            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17384            else {
17385                self.clear_row_highlights::<ActiveDebugLine>();
17386                return None;
17387            };
17388
17389            let position = active_stack_frame.position;
17390            let buffer_id = position.buffer_id?;
17391            let snapshot = self
17392                .project
17393                .as_ref()?
17394                .read(cx)
17395                .buffer_for_id(buffer_id, cx)?
17396                .read(cx)
17397                .snapshot();
17398
17399            let mut handled = false;
17400            for (id, ExcerptRange { context, .. }) in
17401                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17402            {
17403                if context.start.cmp(&position, &snapshot).is_ge()
17404                    || context.end.cmp(&position, &snapshot).is_lt()
17405                {
17406                    continue;
17407                }
17408                let snapshot = self.buffer.read(cx).snapshot(cx);
17409                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17410
17411                handled = true;
17412                self.clear_row_highlights::<ActiveDebugLine>();
17413
17414                self.go_to_line::<ActiveDebugLine>(
17415                    multibuffer_anchor,
17416                    Some(cx.theme().colors().editor_debugger_active_line_background),
17417                    window,
17418                    cx,
17419                );
17420
17421                cx.notify();
17422            }
17423
17424            handled.then_some(())
17425        })
17426        .is_some()
17427    }
17428
17429    pub fn copy_file_name_without_extension(
17430        &mut self,
17431        _: &CopyFileNameWithoutExtension,
17432        _: &mut Window,
17433        cx: &mut Context<Self>,
17434    ) {
17435        if let Some(file) = self.target_file(cx) {
17436            if let Some(file_stem) = file.path().file_stem() {
17437                if let Some(name) = file_stem.to_str() {
17438                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17439                }
17440            }
17441        }
17442    }
17443
17444    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17445        if let Some(file) = self.target_file(cx) {
17446            if let Some(file_name) = file.path().file_name() {
17447                if let Some(name) = file_name.to_str() {
17448                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17449                }
17450            }
17451        }
17452    }
17453
17454    pub fn toggle_git_blame(
17455        &mut self,
17456        _: &::git::Blame,
17457        window: &mut Window,
17458        cx: &mut Context<Self>,
17459    ) {
17460        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17461
17462        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17463            self.start_git_blame(true, window, cx);
17464        }
17465
17466        cx.notify();
17467    }
17468
17469    pub fn toggle_git_blame_inline(
17470        &mut self,
17471        _: &ToggleGitBlameInline,
17472        window: &mut Window,
17473        cx: &mut Context<Self>,
17474    ) {
17475        self.toggle_git_blame_inline_internal(true, window, cx);
17476        cx.notify();
17477    }
17478
17479    pub fn open_git_blame_commit(
17480        &mut self,
17481        _: &OpenGitBlameCommit,
17482        window: &mut Window,
17483        cx: &mut Context<Self>,
17484    ) {
17485        self.open_git_blame_commit_internal(window, cx);
17486    }
17487
17488    fn open_git_blame_commit_internal(
17489        &mut self,
17490        window: &mut Window,
17491        cx: &mut Context<Self>,
17492    ) -> Option<()> {
17493        let blame = self.blame.as_ref()?;
17494        let snapshot = self.snapshot(window, cx);
17495        let cursor = self.selections.newest::<Point>(cx).head();
17496        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17497        let blame_entry = blame
17498            .update(cx, |blame, cx| {
17499                blame
17500                    .blame_for_rows(
17501                        &[RowInfo {
17502                            buffer_id: Some(buffer.remote_id()),
17503                            buffer_row: Some(point.row),
17504                            ..Default::default()
17505                        }],
17506                        cx,
17507                    )
17508                    .next()
17509            })
17510            .flatten()?;
17511        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17512        let repo = blame.read(cx).repository(cx)?;
17513        let workspace = self.workspace()?.downgrade();
17514        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17515        None
17516    }
17517
17518    pub fn git_blame_inline_enabled(&self) -> bool {
17519        self.git_blame_inline_enabled
17520    }
17521
17522    pub fn toggle_selection_menu(
17523        &mut self,
17524        _: &ToggleSelectionMenu,
17525        _: &mut Window,
17526        cx: &mut Context<Self>,
17527    ) {
17528        self.show_selection_menu = self
17529            .show_selection_menu
17530            .map(|show_selections_menu| !show_selections_menu)
17531            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17532
17533        cx.notify();
17534    }
17535
17536    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17537        self.show_selection_menu
17538            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17539    }
17540
17541    fn start_git_blame(
17542        &mut self,
17543        user_triggered: bool,
17544        window: &mut Window,
17545        cx: &mut Context<Self>,
17546    ) {
17547        if let Some(project) = self.project.as_ref() {
17548            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17549                return;
17550            };
17551
17552            if buffer.read(cx).file().is_none() {
17553                return;
17554            }
17555
17556            let focused = self.focus_handle(cx).contains_focused(window, cx);
17557
17558            let project = project.clone();
17559            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17560            self.blame_subscription =
17561                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17562            self.blame = Some(blame);
17563        }
17564    }
17565
17566    fn toggle_git_blame_inline_internal(
17567        &mut self,
17568        user_triggered: bool,
17569        window: &mut Window,
17570        cx: &mut Context<Self>,
17571    ) {
17572        if self.git_blame_inline_enabled {
17573            self.git_blame_inline_enabled = false;
17574            self.show_git_blame_inline = false;
17575            self.show_git_blame_inline_delay_task.take();
17576        } else {
17577            self.git_blame_inline_enabled = true;
17578            self.start_git_blame_inline(user_triggered, window, cx);
17579        }
17580
17581        cx.notify();
17582    }
17583
17584    fn start_git_blame_inline(
17585        &mut self,
17586        user_triggered: bool,
17587        window: &mut Window,
17588        cx: &mut Context<Self>,
17589    ) {
17590        self.start_git_blame(user_triggered, window, cx);
17591
17592        if ProjectSettings::get_global(cx)
17593            .git
17594            .inline_blame_delay()
17595            .is_some()
17596        {
17597            self.start_inline_blame_timer(window, cx);
17598        } else {
17599            self.show_git_blame_inline = true
17600        }
17601    }
17602
17603    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17604        self.blame.as_ref()
17605    }
17606
17607    pub fn show_git_blame_gutter(&self) -> bool {
17608        self.show_git_blame_gutter
17609    }
17610
17611    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17612        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17613    }
17614
17615    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17616        self.show_git_blame_inline
17617            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17618            && !self.newest_selection_head_on_empty_line(cx)
17619            && self.has_blame_entries(cx)
17620    }
17621
17622    fn has_blame_entries(&self, cx: &App) -> bool {
17623        self.blame()
17624            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17625    }
17626
17627    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17628        let cursor_anchor = self.selections.newest_anchor().head();
17629
17630        let snapshot = self.buffer.read(cx).snapshot(cx);
17631        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17632
17633        snapshot.line_len(buffer_row) == 0
17634    }
17635
17636    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17637        let buffer_and_selection = maybe!({
17638            let selection = self.selections.newest::<Point>(cx);
17639            let selection_range = selection.range();
17640
17641            let multi_buffer = self.buffer().read(cx);
17642            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17643            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17644
17645            let (buffer, range, _) = if selection.reversed {
17646                buffer_ranges.first()
17647            } else {
17648                buffer_ranges.last()
17649            }?;
17650
17651            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17652                ..text::ToPoint::to_point(&range.end, &buffer).row;
17653            Some((
17654                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17655                selection,
17656            ))
17657        });
17658
17659        let Some((buffer, selection)) = buffer_and_selection else {
17660            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17661        };
17662
17663        let Some(project) = self.project.as_ref() else {
17664            return Task::ready(Err(anyhow!("editor does not have project")));
17665        };
17666
17667        project.update(cx, |project, cx| {
17668            project.get_permalink_to_line(&buffer, selection, cx)
17669        })
17670    }
17671
17672    pub fn copy_permalink_to_line(
17673        &mut self,
17674        _: &CopyPermalinkToLine,
17675        window: &mut Window,
17676        cx: &mut Context<Self>,
17677    ) {
17678        let permalink_task = self.get_permalink_to_line(cx);
17679        let workspace = self.workspace();
17680
17681        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17682            Ok(permalink) => {
17683                cx.update(|_, cx| {
17684                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17685                })
17686                .ok();
17687            }
17688            Err(err) => {
17689                let message = format!("Failed to copy permalink: {err}");
17690
17691                anyhow::Result::<()>::Err(err).log_err();
17692
17693                if let Some(workspace) = workspace {
17694                    workspace
17695                        .update_in(cx, |workspace, _, cx| {
17696                            struct CopyPermalinkToLine;
17697
17698                            workspace.show_toast(
17699                                Toast::new(
17700                                    NotificationId::unique::<CopyPermalinkToLine>(),
17701                                    message,
17702                                ),
17703                                cx,
17704                            )
17705                        })
17706                        .ok();
17707                }
17708            }
17709        })
17710        .detach();
17711    }
17712
17713    pub fn copy_file_location(
17714        &mut self,
17715        _: &CopyFileLocation,
17716        _: &mut Window,
17717        cx: &mut Context<Self>,
17718    ) {
17719        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17720        if let Some(file) = self.target_file(cx) {
17721            if let Some(path) = file.path().to_str() {
17722                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17723            }
17724        }
17725    }
17726
17727    pub fn open_permalink_to_line(
17728        &mut self,
17729        _: &OpenPermalinkToLine,
17730        window: &mut Window,
17731        cx: &mut Context<Self>,
17732    ) {
17733        let permalink_task = self.get_permalink_to_line(cx);
17734        let workspace = self.workspace();
17735
17736        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17737            Ok(permalink) => {
17738                cx.update(|_, cx| {
17739                    cx.open_url(permalink.as_ref());
17740                })
17741                .ok();
17742            }
17743            Err(err) => {
17744                let message = format!("Failed to open permalink: {err}");
17745
17746                anyhow::Result::<()>::Err(err).log_err();
17747
17748                if let Some(workspace) = workspace {
17749                    workspace
17750                        .update(cx, |workspace, cx| {
17751                            struct OpenPermalinkToLine;
17752
17753                            workspace.show_toast(
17754                                Toast::new(
17755                                    NotificationId::unique::<OpenPermalinkToLine>(),
17756                                    message,
17757                                ),
17758                                cx,
17759                            )
17760                        })
17761                        .ok();
17762                }
17763            }
17764        })
17765        .detach();
17766    }
17767
17768    pub fn insert_uuid_v4(
17769        &mut self,
17770        _: &InsertUuidV4,
17771        window: &mut Window,
17772        cx: &mut Context<Self>,
17773    ) {
17774        self.insert_uuid(UuidVersion::V4, window, cx);
17775    }
17776
17777    pub fn insert_uuid_v7(
17778        &mut self,
17779        _: &InsertUuidV7,
17780        window: &mut Window,
17781        cx: &mut Context<Self>,
17782    ) {
17783        self.insert_uuid(UuidVersion::V7, window, cx);
17784    }
17785
17786    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17787        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17788        self.transact(window, cx, |this, window, cx| {
17789            let edits = this
17790                .selections
17791                .all::<Point>(cx)
17792                .into_iter()
17793                .map(|selection| {
17794                    let uuid = match version {
17795                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17796                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17797                    };
17798
17799                    (selection.range(), uuid.to_string())
17800                });
17801            this.edit(edits, cx);
17802            this.refresh_inline_completion(true, false, window, cx);
17803        });
17804    }
17805
17806    pub fn open_selections_in_multibuffer(
17807        &mut self,
17808        _: &OpenSelectionsInMultibuffer,
17809        window: &mut Window,
17810        cx: &mut Context<Self>,
17811    ) {
17812        let multibuffer = self.buffer.read(cx);
17813
17814        let Some(buffer) = multibuffer.as_singleton() else {
17815            return;
17816        };
17817
17818        let Some(workspace) = self.workspace() else {
17819            return;
17820        };
17821
17822        let locations = self
17823            .selections
17824            .disjoint_anchors()
17825            .iter()
17826            .map(|selection| {
17827                let range = if selection.reversed {
17828                    selection.end.text_anchor..selection.start.text_anchor
17829                } else {
17830                    selection.start.text_anchor..selection.end.text_anchor
17831                };
17832                Location {
17833                    buffer: buffer.clone(),
17834                    range,
17835                }
17836            })
17837            .collect::<Vec<_>>();
17838
17839        let title = multibuffer.title(cx).to_string();
17840
17841        cx.spawn_in(window, async move |_, cx| {
17842            workspace.update_in(cx, |workspace, window, cx| {
17843                Self::open_locations_in_multibuffer(
17844                    workspace,
17845                    locations,
17846                    format!("Selections for '{title}'"),
17847                    false,
17848                    MultibufferSelectionMode::All,
17849                    window,
17850                    cx,
17851                );
17852            })
17853        })
17854        .detach();
17855    }
17856
17857    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17858    /// last highlight added will be used.
17859    ///
17860    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17861    pub fn highlight_rows<T: 'static>(
17862        &mut self,
17863        range: Range<Anchor>,
17864        color: Hsla,
17865        options: RowHighlightOptions,
17866        cx: &mut Context<Self>,
17867    ) {
17868        let snapshot = self.buffer().read(cx).snapshot(cx);
17869        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17870        let ix = row_highlights.binary_search_by(|highlight| {
17871            Ordering::Equal
17872                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17873                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17874        });
17875
17876        if let Err(mut ix) = ix {
17877            let index = post_inc(&mut self.highlight_order);
17878
17879            // If this range intersects with the preceding highlight, then merge it with
17880            // the preceding highlight. Otherwise insert a new highlight.
17881            let mut merged = false;
17882            if ix > 0 {
17883                let prev_highlight = &mut row_highlights[ix - 1];
17884                if prev_highlight
17885                    .range
17886                    .end
17887                    .cmp(&range.start, &snapshot)
17888                    .is_ge()
17889                {
17890                    ix -= 1;
17891                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17892                        prev_highlight.range.end = range.end;
17893                    }
17894                    merged = true;
17895                    prev_highlight.index = index;
17896                    prev_highlight.color = color;
17897                    prev_highlight.options = options;
17898                }
17899            }
17900
17901            if !merged {
17902                row_highlights.insert(
17903                    ix,
17904                    RowHighlight {
17905                        range: range.clone(),
17906                        index,
17907                        color,
17908                        options,
17909                        type_id: TypeId::of::<T>(),
17910                    },
17911                );
17912            }
17913
17914            // If any of the following highlights intersect with this one, merge them.
17915            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17916                let highlight = &row_highlights[ix];
17917                if next_highlight
17918                    .range
17919                    .start
17920                    .cmp(&highlight.range.end, &snapshot)
17921                    .is_le()
17922                {
17923                    if next_highlight
17924                        .range
17925                        .end
17926                        .cmp(&highlight.range.end, &snapshot)
17927                        .is_gt()
17928                    {
17929                        row_highlights[ix].range.end = next_highlight.range.end;
17930                    }
17931                    row_highlights.remove(ix + 1);
17932                } else {
17933                    break;
17934                }
17935            }
17936        }
17937    }
17938
17939    /// Remove any highlighted row ranges of the given type that intersect the
17940    /// given ranges.
17941    pub fn remove_highlighted_rows<T: 'static>(
17942        &mut self,
17943        ranges_to_remove: Vec<Range<Anchor>>,
17944        cx: &mut Context<Self>,
17945    ) {
17946        let snapshot = self.buffer().read(cx).snapshot(cx);
17947        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17948        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17949        row_highlights.retain(|highlight| {
17950            while let Some(range_to_remove) = ranges_to_remove.peek() {
17951                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17952                    Ordering::Less | Ordering::Equal => {
17953                        ranges_to_remove.next();
17954                    }
17955                    Ordering::Greater => {
17956                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17957                            Ordering::Less | Ordering::Equal => {
17958                                return false;
17959                            }
17960                            Ordering::Greater => break,
17961                        }
17962                    }
17963                }
17964            }
17965
17966            true
17967        })
17968    }
17969
17970    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17971    pub fn clear_row_highlights<T: 'static>(&mut self) {
17972        self.highlighted_rows.remove(&TypeId::of::<T>());
17973    }
17974
17975    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17976    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17977        self.highlighted_rows
17978            .get(&TypeId::of::<T>())
17979            .map_or(&[] as &[_], |vec| vec.as_slice())
17980            .iter()
17981            .map(|highlight| (highlight.range.clone(), highlight.color))
17982    }
17983
17984    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17985    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17986    /// Allows to ignore certain kinds of highlights.
17987    pub fn highlighted_display_rows(
17988        &self,
17989        window: &mut Window,
17990        cx: &mut App,
17991    ) -> BTreeMap<DisplayRow, LineHighlight> {
17992        let snapshot = self.snapshot(window, cx);
17993        let mut used_highlight_orders = HashMap::default();
17994        self.highlighted_rows
17995            .iter()
17996            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17997            .fold(
17998                BTreeMap::<DisplayRow, LineHighlight>::new(),
17999                |mut unique_rows, highlight| {
18000                    let start = highlight.range.start.to_display_point(&snapshot);
18001                    let end = highlight.range.end.to_display_point(&snapshot);
18002                    let start_row = start.row().0;
18003                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18004                        && end.column() == 0
18005                    {
18006                        end.row().0.saturating_sub(1)
18007                    } else {
18008                        end.row().0
18009                    };
18010                    for row in start_row..=end_row {
18011                        let used_index =
18012                            used_highlight_orders.entry(row).or_insert(highlight.index);
18013                        if highlight.index >= *used_index {
18014                            *used_index = highlight.index;
18015                            unique_rows.insert(
18016                                DisplayRow(row),
18017                                LineHighlight {
18018                                    include_gutter: highlight.options.include_gutter,
18019                                    border: None,
18020                                    background: highlight.color.into(),
18021                                    type_id: Some(highlight.type_id),
18022                                },
18023                            );
18024                        }
18025                    }
18026                    unique_rows
18027                },
18028            )
18029    }
18030
18031    pub fn highlighted_display_row_for_autoscroll(
18032        &self,
18033        snapshot: &DisplaySnapshot,
18034    ) -> Option<DisplayRow> {
18035        self.highlighted_rows
18036            .values()
18037            .flat_map(|highlighted_rows| highlighted_rows.iter())
18038            .filter_map(|highlight| {
18039                if highlight.options.autoscroll {
18040                    Some(highlight.range.start.to_display_point(snapshot).row())
18041                } else {
18042                    None
18043                }
18044            })
18045            .min()
18046    }
18047
18048    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18049        self.highlight_background::<SearchWithinRange>(
18050            ranges,
18051            |colors| colors.editor_document_highlight_read_background,
18052            cx,
18053        )
18054    }
18055
18056    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18057        self.breadcrumb_header = Some(new_header);
18058    }
18059
18060    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18061        self.clear_background_highlights::<SearchWithinRange>(cx);
18062    }
18063
18064    pub fn highlight_background<T: 'static>(
18065        &mut self,
18066        ranges: &[Range<Anchor>],
18067        color_fetcher: fn(&ThemeColors) -> Hsla,
18068        cx: &mut Context<Self>,
18069    ) {
18070        self.background_highlights
18071            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18072        self.scrollbar_marker_state.dirty = true;
18073        cx.notify();
18074    }
18075
18076    pub fn clear_background_highlights<T: 'static>(
18077        &mut self,
18078        cx: &mut Context<Self>,
18079    ) -> Option<BackgroundHighlight> {
18080        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18081        if !text_highlights.1.is_empty() {
18082            self.scrollbar_marker_state.dirty = true;
18083            cx.notify();
18084        }
18085        Some(text_highlights)
18086    }
18087
18088    pub fn highlight_gutter<T: 'static>(
18089        &mut self,
18090        ranges: &[Range<Anchor>],
18091        color_fetcher: fn(&App) -> Hsla,
18092        cx: &mut Context<Self>,
18093    ) {
18094        self.gutter_highlights
18095            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18096        cx.notify();
18097    }
18098
18099    pub fn clear_gutter_highlights<T: 'static>(
18100        &mut self,
18101        cx: &mut Context<Self>,
18102    ) -> Option<GutterHighlight> {
18103        cx.notify();
18104        self.gutter_highlights.remove(&TypeId::of::<T>())
18105    }
18106
18107    #[cfg(feature = "test-support")]
18108    pub fn all_text_background_highlights(
18109        &self,
18110        window: &mut Window,
18111        cx: &mut Context<Self>,
18112    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18113        let snapshot = self.snapshot(window, cx);
18114        let buffer = &snapshot.buffer_snapshot;
18115        let start = buffer.anchor_before(0);
18116        let end = buffer.anchor_after(buffer.len());
18117        let theme = cx.theme().colors();
18118        self.background_highlights_in_range(start..end, &snapshot, theme)
18119    }
18120
18121    #[cfg(feature = "test-support")]
18122    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18123        let snapshot = self.buffer().read(cx).snapshot(cx);
18124
18125        let highlights = self
18126            .background_highlights
18127            .get(&TypeId::of::<items::BufferSearchHighlights>());
18128
18129        if let Some((_color, ranges)) = highlights {
18130            ranges
18131                .iter()
18132                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18133                .collect_vec()
18134        } else {
18135            vec![]
18136        }
18137    }
18138
18139    fn document_highlights_for_position<'a>(
18140        &'a self,
18141        position: Anchor,
18142        buffer: &'a MultiBufferSnapshot,
18143    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18144        let read_highlights = self
18145            .background_highlights
18146            .get(&TypeId::of::<DocumentHighlightRead>())
18147            .map(|h| &h.1);
18148        let write_highlights = self
18149            .background_highlights
18150            .get(&TypeId::of::<DocumentHighlightWrite>())
18151            .map(|h| &h.1);
18152        let left_position = position.bias_left(buffer);
18153        let right_position = position.bias_right(buffer);
18154        read_highlights
18155            .into_iter()
18156            .chain(write_highlights)
18157            .flat_map(move |ranges| {
18158                let start_ix = match ranges.binary_search_by(|probe| {
18159                    let cmp = probe.end.cmp(&left_position, buffer);
18160                    if cmp.is_ge() {
18161                        Ordering::Greater
18162                    } else {
18163                        Ordering::Less
18164                    }
18165                }) {
18166                    Ok(i) | Err(i) => i,
18167                };
18168
18169                ranges[start_ix..]
18170                    .iter()
18171                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18172            })
18173    }
18174
18175    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18176        self.background_highlights
18177            .get(&TypeId::of::<T>())
18178            .map_or(false, |(_, highlights)| !highlights.is_empty())
18179    }
18180
18181    pub fn background_highlights_in_range(
18182        &self,
18183        search_range: Range<Anchor>,
18184        display_snapshot: &DisplaySnapshot,
18185        theme: &ThemeColors,
18186    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18187        let mut results = Vec::new();
18188        for (color_fetcher, ranges) in self.background_highlights.values() {
18189            let color = color_fetcher(theme);
18190            let start_ix = match ranges.binary_search_by(|probe| {
18191                let cmp = probe
18192                    .end
18193                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18194                if cmp.is_gt() {
18195                    Ordering::Greater
18196                } else {
18197                    Ordering::Less
18198                }
18199            }) {
18200                Ok(i) | Err(i) => i,
18201            };
18202            for range in &ranges[start_ix..] {
18203                if range
18204                    .start
18205                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18206                    .is_ge()
18207                {
18208                    break;
18209                }
18210
18211                let start = range.start.to_display_point(display_snapshot);
18212                let end = range.end.to_display_point(display_snapshot);
18213                results.push((start..end, color))
18214            }
18215        }
18216        results
18217    }
18218
18219    pub fn background_highlight_row_ranges<T: 'static>(
18220        &self,
18221        search_range: Range<Anchor>,
18222        display_snapshot: &DisplaySnapshot,
18223        count: usize,
18224    ) -> Vec<RangeInclusive<DisplayPoint>> {
18225        let mut results = Vec::new();
18226        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18227            return vec![];
18228        };
18229
18230        let start_ix = match ranges.binary_search_by(|probe| {
18231            let cmp = probe
18232                .end
18233                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18234            if cmp.is_gt() {
18235                Ordering::Greater
18236            } else {
18237                Ordering::Less
18238            }
18239        }) {
18240            Ok(i) | Err(i) => i,
18241        };
18242        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18243            if let (Some(start_display), Some(end_display)) = (start, end) {
18244                results.push(
18245                    start_display.to_display_point(display_snapshot)
18246                        ..=end_display.to_display_point(display_snapshot),
18247                );
18248            }
18249        };
18250        let mut start_row: Option<Point> = None;
18251        let mut end_row: Option<Point> = None;
18252        if ranges.len() > count {
18253            return Vec::new();
18254        }
18255        for range in &ranges[start_ix..] {
18256            if range
18257                .start
18258                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18259                .is_ge()
18260            {
18261                break;
18262            }
18263            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18264            if let Some(current_row) = &end_row {
18265                if end.row == current_row.row {
18266                    continue;
18267                }
18268            }
18269            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18270            if start_row.is_none() {
18271                assert_eq!(end_row, None);
18272                start_row = Some(start);
18273                end_row = Some(end);
18274                continue;
18275            }
18276            if let Some(current_end) = end_row.as_mut() {
18277                if start.row > current_end.row + 1 {
18278                    push_region(start_row, end_row);
18279                    start_row = Some(start);
18280                    end_row = Some(end);
18281                } else {
18282                    // Merge two hunks.
18283                    *current_end = end;
18284                }
18285            } else {
18286                unreachable!();
18287            }
18288        }
18289        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18290        push_region(start_row, end_row);
18291        results
18292    }
18293
18294    pub fn gutter_highlights_in_range(
18295        &self,
18296        search_range: Range<Anchor>,
18297        display_snapshot: &DisplaySnapshot,
18298        cx: &App,
18299    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18300        let mut results = Vec::new();
18301        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18302            let color = color_fetcher(cx);
18303            let start_ix = match ranges.binary_search_by(|probe| {
18304                let cmp = probe
18305                    .end
18306                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18307                if cmp.is_gt() {
18308                    Ordering::Greater
18309                } else {
18310                    Ordering::Less
18311                }
18312            }) {
18313                Ok(i) | Err(i) => i,
18314            };
18315            for range in &ranges[start_ix..] {
18316                if range
18317                    .start
18318                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18319                    .is_ge()
18320                {
18321                    break;
18322                }
18323
18324                let start = range.start.to_display_point(display_snapshot);
18325                let end = range.end.to_display_point(display_snapshot);
18326                results.push((start..end, color))
18327            }
18328        }
18329        results
18330    }
18331
18332    /// Get the text ranges corresponding to the redaction query
18333    pub fn redacted_ranges(
18334        &self,
18335        search_range: Range<Anchor>,
18336        display_snapshot: &DisplaySnapshot,
18337        cx: &App,
18338    ) -> Vec<Range<DisplayPoint>> {
18339        display_snapshot
18340            .buffer_snapshot
18341            .redacted_ranges(search_range, |file| {
18342                if let Some(file) = file {
18343                    file.is_private()
18344                        && EditorSettings::get(
18345                            Some(SettingsLocation {
18346                                worktree_id: file.worktree_id(cx),
18347                                path: file.path().as_ref(),
18348                            }),
18349                            cx,
18350                        )
18351                        .redact_private_values
18352                } else {
18353                    false
18354                }
18355            })
18356            .map(|range| {
18357                range.start.to_display_point(display_snapshot)
18358                    ..range.end.to_display_point(display_snapshot)
18359            })
18360            .collect()
18361    }
18362
18363    pub fn highlight_text<T: 'static>(
18364        &mut self,
18365        ranges: Vec<Range<Anchor>>,
18366        style: HighlightStyle,
18367        cx: &mut Context<Self>,
18368    ) {
18369        self.display_map.update(cx, |map, _| {
18370            map.highlight_text(TypeId::of::<T>(), ranges, style)
18371        });
18372        cx.notify();
18373    }
18374
18375    pub(crate) fn highlight_inlays<T: 'static>(
18376        &mut self,
18377        highlights: Vec<InlayHighlight>,
18378        style: HighlightStyle,
18379        cx: &mut Context<Self>,
18380    ) {
18381        self.display_map.update(cx, |map, _| {
18382            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18383        });
18384        cx.notify();
18385    }
18386
18387    pub fn text_highlights<'a, T: 'static>(
18388        &'a self,
18389        cx: &'a App,
18390    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18391        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18392    }
18393
18394    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18395        let cleared = self
18396            .display_map
18397            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18398        if cleared {
18399            cx.notify();
18400        }
18401    }
18402
18403    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18404        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18405            && self.focus_handle.is_focused(window)
18406    }
18407
18408    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18409        self.show_cursor_when_unfocused = is_enabled;
18410        cx.notify();
18411    }
18412
18413    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18414        cx.notify();
18415    }
18416
18417    fn on_debug_session_event(
18418        &mut self,
18419        _session: Entity<Session>,
18420        event: &SessionEvent,
18421        cx: &mut Context<Self>,
18422    ) {
18423        match event {
18424            SessionEvent::InvalidateInlineValue => {
18425                self.refresh_inline_values(cx);
18426            }
18427            _ => {}
18428        }
18429    }
18430
18431    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18432        let Some(project) = self.project.clone() else {
18433            return;
18434        };
18435
18436        if !self.inline_value_cache.enabled {
18437            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18438            self.splice_inlays(&inlays, Vec::new(), cx);
18439            return;
18440        }
18441
18442        let current_execution_position = self
18443            .highlighted_rows
18444            .get(&TypeId::of::<ActiveDebugLine>())
18445            .and_then(|lines| lines.last().map(|line| line.range.start));
18446
18447        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18448            let inline_values = editor
18449                .update(cx, |editor, cx| {
18450                    let Some(current_execution_position) = current_execution_position else {
18451                        return Some(Task::ready(Ok(Vec::new())));
18452                    };
18453
18454                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18455                        let snapshot = buffer.snapshot(cx);
18456
18457                        let excerpt = snapshot.excerpt_containing(
18458                            current_execution_position..current_execution_position,
18459                        )?;
18460
18461                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18462                    })?;
18463
18464                    let range =
18465                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18466
18467                    project.inline_values(buffer, range, cx)
18468                })
18469                .ok()
18470                .flatten()?
18471                .await
18472                .context("refreshing debugger inlays")
18473                .log_err()?;
18474
18475            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18476
18477            for (buffer_id, inline_value) in inline_values
18478                .into_iter()
18479                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18480            {
18481                buffer_inline_values
18482                    .entry(buffer_id)
18483                    .or_default()
18484                    .push(inline_value);
18485            }
18486
18487            editor
18488                .update(cx, |editor, cx| {
18489                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18490                    let mut new_inlays = Vec::default();
18491
18492                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18493                        let buffer_id = buffer_snapshot.remote_id();
18494                        buffer_inline_values
18495                            .get(&buffer_id)
18496                            .into_iter()
18497                            .flatten()
18498                            .for_each(|hint| {
18499                                let inlay = Inlay::debugger_hint(
18500                                    post_inc(&mut editor.next_inlay_id),
18501                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18502                                    hint.text(),
18503                                );
18504
18505                                new_inlays.push(inlay);
18506                            });
18507                    }
18508
18509                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18510                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18511
18512                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18513                })
18514                .ok()?;
18515            Some(())
18516        });
18517    }
18518
18519    fn on_buffer_event(
18520        &mut self,
18521        multibuffer: &Entity<MultiBuffer>,
18522        event: &multi_buffer::Event,
18523        window: &mut Window,
18524        cx: &mut Context<Self>,
18525    ) {
18526        match event {
18527            multi_buffer::Event::Edited {
18528                singleton_buffer_edited,
18529                edited_buffer: buffer_edited,
18530            } => {
18531                self.scrollbar_marker_state.dirty = true;
18532                self.active_indent_guides_state.dirty = true;
18533                self.refresh_active_diagnostics(cx);
18534                self.refresh_code_actions(window, cx);
18535                self.refresh_selected_text_highlights(true, window, cx);
18536                refresh_matching_bracket_highlights(self, window, cx);
18537                if self.has_active_inline_completion() {
18538                    self.update_visible_inline_completion(window, cx);
18539                }
18540                if let Some(buffer) = buffer_edited {
18541                    let buffer_id = buffer.read(cx).remote_id();
18542                    if !self.registered_buffers.contains_key(&buffer_id) {
18543                        if let Some(project) = self.project.as_ref() {
18544                            project.update(cx, |project, cx| {
18545                                self.registered_buffers.insert(
18546                                    buffer_id,
18547                                    project.register_buffer_with_language_servers(&buffer, cx),
18548                                );
18549                            })
18550                        }
18551                    }
18552                }
18553                cx.emit(EditorEvent::BufferEdited);
18554                cx.emit(SearchEvent::MatchesInvalidated);
18555                if *singleton_buffer_edited {
18556                    if let Some(project) = &self.project {
18557                        #[allow(clippy::mutable_key_type)]
18558                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18559                            multibuffer
18560                                .all_buffers()
18561                                .into_iter()
18562                                .filter_map(|buffer| {
18563                                    buffer.update(cx, |buffer, cx| {
18564                                        let language = buffer.language()?;
18565                                        let should_discard = project.update(cx, |project, cx| {
18566                                            project.is_local()
18567                                                && !project.has_language_servers_for(buffer, cx)
18568                                        });
18569                                        should_discard.not().then_some(language.clone())
18570                                    })
18571                                })
18572                                .collect::<HashSet<_>>()
18573                        });
18574                        if !languages_affected.is_empty() {
18575                            self.refresh_inlay_hints(
18576                                InlayHintRefreshReason::BufferEdited(languages_affected),
18577                                cx,
18578                            );
18579                        }
18580                    }
18581                }
18582
18583                let Some(project) = &self.project else { return };
18584                let (telemetry, is_via_ssh) = {
18585                    let project = project.read(cx);
18586                    let telemetry = project.client().telemetry().clone();
18587                    let is_via_ssh = project.is_via_ssh();
18588                    (telemetry, is_via_ssh)
18589                };
18590                refresh_linked_ranges(self, window, cx);
18591                telemetry.log_edit_event("editor", is_via_ssh);
18592            }
18593            multi_buffer::Event::ExcerptsAdded {
18594                buffer,
18595                predecessor,
18596                excerpts,
18597            } => {
18598                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18599                let buffer_id = buffer.read(cx).remote_id();
18600                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18601                    if let Some(project) = &self.project {
18602                        update_uncommitted_diff_for_buffer(
18603                            cx.entity(),
18604                            project,
18605                            [buffer.clone()],
18606                            self.buffer.clone(),
18607                            cx,
18608                        )
18609                        .detach();
18610                    }
18611                }
18612                cx.emit(EditorEvent::ExcerptsAdded {
18613                    buffer: buffer.clone(),
18614                    predecessor: *predecessor,
18615                    excerpts: excerpts.clone(),
18616                });
18617                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18618            }
18619            multi_buffer::Event::ExcerptsRemoved {
18620                ids,
18621                removed_buffer_ids,
18622            } => {
18623                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18624                let buffer = self.buffer.read(cx);
18625                self.registered_buffers
18626                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18627                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18628                cx.emit(EditorEvent::ExcerptsRemoved {
18629                    ids: ids.clone(),
18630                    removed_buffer_ids: removed_buffer_ids.clone(),
18631                })
18632            }
18633            multi_buffer::Event::ExcerptsEdited {
18634                excerpt_ids,
18635                buffer_ids,
18636            } => {
18637                self.display_map.update(cx, |map, cx| {
18638                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18639                });
18640                cx.emit(EditorEvent::ExcerptsEdited {
18641                    ids: excerpt_ids.clone(),
18642                })
18643            }
18644            multi_buffer::Event::ExcerptsExpanded { ids } => {
18645                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18646                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18647            }
18648            multi_buffer::Event::Reparsed(buffer_id) => {
18649                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18650                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18651
18652                cx.emit(EditorEvent::Reparsed(*buffer_id));
18653            }
18654            multi_buffer::Event::DiffHunksToggled => {
18655                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18656            }
18657            multi_buffer::Event::LanguageChanged(buffer_id) => {
18658                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18659                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18660                cx.emit(EditorEvent::Reparsed(*buffer_id));
18661                cx.notify();
18662            }
18663            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18664            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18665            multi_buffer::Event::FileHandleChanged
18666            | multi_buffer::Event::Reloaded
18667            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18668            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18669            multi_buffer::Event::DiagnosticsUpdated => {
18670                self.refresh_active_diagnostics(cx);
18671                self.refresh_inline_diagnostics(true, window, cx);
18672                self.scrollbar_marker_state.dirty = true;
18673                cx.notify();
18674            }
18675            _ => {}
18676        };
18677    }
18678
18679    pub fn start_temporary_diff_override(&mut self) {
18680        self.load_diff_task.take();
18681        self.temporary_diff_override = true;
18682    }
18683
18684    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18685        self.temporary_diff_override = false;
18686        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18687        self.buffer.update(cx, |buffer, cx| {
18688            buffer.set_all_diff_hunks_collapsed(cx);
18689        });
18690
18691        if let Some(project) = self.project.clone() {
18692            self.load_diff_task = Some(
18693                update_uncommitted_diff_for_buffer(
18694                    cx.entity(),
18695                    &project,
18696                    self.buffer.read(cx).all_buffers(),
18697                    self.buffer.clone(),
18698                    cx,
18699                )
18700                .shared(),
18701            );
18702        }
18703    }
18704
18705    fn on_display_map_changed(
18706        &mut self,
18707        _: Entity<DisplayMap>,
18708        _: &mut Window,
18709        cx: &mut Context<Self>,
18710    ) {
18711        cx.notify();
18712    }
18713
18714    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18715        let new_severity = if self.diagnostics_enabled() {
18716            EditorSettings::get_global(cx)
18717                .diagnostics_max_severity
18718                .unwrap_or(DiagnosticSeverity::Hint)
18719        } else {
18720            DiagnosticSeverity::Off
18721        };
18722        self.set_max_diagnostics_severity(new_severity, cx);
18723        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18724        self.update_edit_prediction_settings(cx);
18725        self.refresh_inline_completion(true, false, window, cx);
18726        self.refresh_inlay_hints(
18727            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18728                self.selections.newest_anchor().head(),
18729                &self.buffer.read(cx).snapshot(cx),
18730                cx,
18731            )),
18732            cx,
18733        );
18734
18735        let old_cursor_shape = self.cursor_shape;
18736
18737        {
18738            let editor_settings = EditorSettings::get_global(cx);
18739            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18740            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18741            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18742            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18743        }
18744
18745        if old_cursor_shape != self.cursor_shape {
18746            cx.emit(EditorEvent::CursorShapeChanged);
18747        }
18748
18749        let project_settings = ProjectSettings::get_global(cx);
18750        self.serialize_dirty_buffers =
18751            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18752
18753        if self.mode.is_full() {
18754            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18755            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18756            if self.show_inline_diagnostics != show_inline_diagnostics {
18757                self.show_inline_diagnostics = show_inline_diagnostics;
18758                self.refresh_inline_diagnostics(false, window, cx);
18759            }
18760
18761            if self.git_blame_inline_enabled != inline_blame_enabled {
18762                self.toggle_git_blame_inline_internal(false, window, cx);
18763            }
18764
18765            let minimap_settings = EditorSettings::get_global(cx).minimap;
18766            if self.minimap_visibility != MinimapVisibility::Disabled {
18767                if self.minimap_visibility.settings_visibility()
18768                    != minimap_settings.minimap_enabled()
18769                {
18770                    self.set_minimap_visibility(
18771                        MinimapVisibility::for_mode(self.mode(), cx),
18772                        window,
18773                        cx,
18774                    );
18775                } else if let Some(minimap_entity) = self.minimap.as_ref() {
18776                    minimap_entity.update(cx, |minimap_editor, cx| {
18777                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
18778                    })
18779                }
18780            }
18781        }
18782
18783        cx.notify();
18784    }
18785
18786    pub fn set_searchable(&mut self, searchable: bool) {
18787        self.searchable = searchable;
18788    }
18789
18790    pub fn searchable(&self) -> bool {
18791        self.searchable
18792    }
18793
18794    fn open_proposed_changes_editor(
18795        &mut self,
18796        _: &OpenProposedChangesEditor,
18797        window: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) {
18800        let Some(workspace) = self.workspace() else {
18801            cx.propagate();
18802            return;
18803        };
18804
18805        let selections = self.selections.all::<usize>(cx);
18806        let multi_buffer = self.buffer.read(cx);
18807        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18808        let mut new_selections_by_buffer = HashMap::default();
18809        for selection in selections {
18810            for (buffer, range, _) in
18811                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18812            {
18813                let mut range = range.to_point(buffer);
18814                range.start.column = 0;
18815                range.end.column = buffer.line_len(range.end.row);
18816                new_selections_by_buffer
18817                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18818                    .or_insert(Vec::new())
18819                    .push(range)
18820            }
18821        }
18822
18823        let proposed_changes_buffers = new_selections_by_buffer
18824            .into_iter()
18825            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18826            .collect::<Vec<_>>();
18827        let proposed_changes_editor = cx.new(|cx| {
18828            ProposedChangesEditor::new(
18829                "Proposed changes",
18830                proposed_changes_buffers,
18831                self.project.clone(),
18832                window,
18833                cx,
18834            )
18835        });
18836
18837        window.defer(cx, move |window, cx| {
18838            workspace.update(cx, |workspace, cx| {
18839                workspace.active_pane().update(cx, |pane, cx| {
18840                    pane.add_item(
18841                        Box::new(proposed_changes_editor),
18842                        true,
18843                        true,
18844                        None,
18845                        window,
18846                        cx,
18847                    );
18848                });
18849            });
18850        });
18851    }
18852
18853    pub fn open_excerpts_in_split(
18854        &mut self,
18855        _: &OpenExcerptsSplit,
18856        window: &mut Window,
18857        cx: &mut Context<Self>,
18858    ) {
18859        self.open_excerpts_common(None, true, window, cx)
18860    }
18861
18862    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18863        self.open_excerpts_common(None, false, window, cx)
18864    }
18865
18866    fn open_excerpts_common(
18867        &mut self,
18868        jump_data: Option<JumpData>,
18869        split: bool,
18870        window: &mut Window,
18871        cx: &mut Context<Self>,
18872    ) {
18873        let Some(workspace) = self.workspace() else {
18874            cx.propagate();
18875            return;
18876        };
18877
18878        if self.buffer.read(cx).is_singleton() {
18879            cx.propagate();
18880            return;
18881        }
18882
18883        let mut new_selections_by_buffer = HashMap::default();
18884        match &jump_data {
18885            Some(JumpData::MultiBufferPoint {
18886                excerpt_id,
18887                position,
18888                anchor,
18889                line_offset_from_top,
18890            }) => {
18891                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18892                if let Some(buffer) = multi_buffer_snapshot
18893                    .buffer_id_for_excerpt(*excerpt_id)
18894                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18895                {
18896                    let buffer_snapshot = buffer.read(cx).snapshot();
18897                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18898                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18899                    } else {
18900                        buffer_snapshot.clip_point(*position, Bias::Left)
18901                    };
18902                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18903                    new_selections_by_buffer.insert(
18904                        buffer,
18905                        (
18906                            vec![jump_to_offset..jump_to_offset],
18907                            Some(*line_offset_from_top),
18908                        ),
18909                    );
18910                }
18911            }
18912            Some(JumpData::MultiBufferRow {
18913                row,
18914                line_offset_from_top,
18915            }) => {
18916                let point = MultiBufferPoint::new(row.0, 0);
18917                if let Some((buffer, buffer_point, _)) =
18918                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18919                {
18920                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18921                    new_selections_by_buffer
18922                        .entry(buffer)
18923                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18924                        .0
18925                        .push(buffer_offset..buffer_offset)
18926                }
18927            }
18928            None => {
18929                let selections = self.selections.all::<usize>(cx);
18930                let multi_buffer = self.buffer.read(cx);
18931                for selection in selections {
18932                    for (snapshot, range, _, anchor) in multi_buffer
18933                        .snapshot(cx)
18934                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18935                    {
18936                        if let Some(anchor) = anchor {
18937                            // selection is in a deleted hunk
18938                            let Some(buffer_id) = anchor.buffer_id else {
18939                                continue;
18940                            };
18941                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18942                                continue;
18943                            };
18944                            let offset = text::ToOffset::to_offset(
18945                                &anchor.text_anchor,
18946                                &buffer_handle.read(cx).snapshot(),
18947                            );
18948                            let range = offset..offset;
18949                            new_selections_by_buffer
18950                                .entry(buffer_handle)
18951                                .or_insert((Vec::new(), None))
18952                                .0
18953                                .push(range)
18954                        } else {
18955                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18956                            else {
18957                                continue;
18958                            };
18959                            new_selections_by_buffer
18960                                .entry(buffer_handle)
18961                                .or_insert((Vec::new(), None))
18962                                .0
18963                                .push(range)
18964                        }
18965                    }
18966                }
18967            }
18968        }
18969
18970        new_selections_by_buffer
18971            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18972
18973        if new_selections_by_buffer.is_empty() {
18974            return;
18975        }
18976
18977        // We defer the pane interaction because we ourselves are a workspace item
18978        // and activating a new item causes the pane to call a method on us reentrantly,
18979        // which panics if we're on the stack.
18980        window.defer(cx, move |window, cx| {
18981            workspace.update(cx, |workspace, cx| {
18982                let pane = if split {
18983                    workspace.adjacent_pane(window, cx)
18984                } else {
18985                    workspace.active_pane().clone()
18986                };
18987
18988                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18989                    let editor = buffer
18990                        .read(cx)
18991                        .file()
18992                        .is_none()
18993                        .then(|| {
18994                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18995                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18996                            // Instead, we try to activate the existing editor in the pane first.
18997                            let (editor, pane_item_index) =
18998                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18999                                    let editor = item.downcast::<Editor>()?;
19000                                    let singleton_buffer =
19001                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19002                                    if singleton_buffer == buffer {
19003                                        Some((editor, i))
19004                                    } else {
19005                                        None
19006                                    }
19007                                })?;
19008                            pane.update(cx, |pane, cx| {
19009                                pane.activate_item(pane_item_index, true, true, window, cx)
19010                            });
19011                            Some(editor)
19012                        })
19013                        .flatten()
19014                        .unwrap_or_else(|| {
19015                            workspace.open_project_item::<Self>(
19016                                pane.clone(),
19017                                buffer,
19018                                true,
19019                                true,
19020                                window,
19021                                cx,
19022                            )
19023                        });
19024
19025                    editor.update(cx, |editor, cx| {
19026                        let autoscroll = match scroll_offset {
19027                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19028                            None => Autoscroll::newest(),
19029                        };
19030                        let nav_history = editor.nav_history.take();
19031                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19032                            s.select_ranges(ranges);
19033                        });
19034                        editor.nav_history = nav_history;
19035                    });
19036                }
19037            })
19038        });
19039    }
19040
19041    // For now, don't allow opening excerpts in buffers that aren't backed by
19042    // regular project files.
19043    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19044        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19045    }
19046
19047    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19048        let snapshot = self.buffer.read(cx).read(cx);
19049        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19050        Some(
19051            ranges
19052                .iter()
19053                .map(move |range| {
19054                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19055                })
19056                .collect(),
19057        )
19058    }
19059
19060    fn selection_replacement_ranges(
19061        &self,
19062        range: Range<OffsetUtf16>,
19063        cx: &mut App,
19064    ) -> Vec<Range<OffsetUtf16>> {
19065        let selections = self.selections.all::<OffsetUtf16>(cx);
19066        let newest_selection = selections
19067            .iter()
19068            .max_by_key(|selection| selection.id)
19069            .unwrap();
19070        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19071        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19072        let snapshot = self.buffer.read(cx).read(cx);
19073        selections
19074            .into_iter()
19075            .map(|mut selection| {
19076                selection.start.0 =
19077                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19078                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19079                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19080                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19081            })
19082            .collect()
19083    }
19084
19085    fn report_editor_event(
19086        &self,
19087        event_type: &'static str,
19088        file_extension: Option<String>,
19089        cx: &App,
19090    ) {
19091        if cfg!(any(test, feature = "test-support")) {
19092            return;
19093        }
19094
19095        let Some(project) = &self.project else { return };
19096
19097        // If None, we are in a file without an extension
19098        let file = self
19099            .buffer
19100            .read(cx)
19101            .as_singleton()
19102            .and_then(|b| b.read(cx).file());
19103        let file_extension = file_extension.or(file
19104            .as_ref()
19105            .and_then(|file| Path::new(file.file_name(cx)).extension())
19106            .and_then(|e| e.to_str())
19107            .map(|a| a.to_string()));
19108
19109        let vim_mode = vim_enabled(cx);
19110
19111        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19112        let copilot_enabled = edit_predictions_provider
19113            == language::language_settings::EditPredictionProvider::Copilot;
19114        let copilot_enabled_for_language = self
19115            .buffer
19116            .read(cx)
19117            .language_settings(cx)
19118            .show_edit_predictions;
19119
19120        let project = project.read(cx);
19121        telemetry::event!(
19122            event_type,
19123            file_extension,
19124            vim_mode,
19125            copilot_enabled,
19126            copilot_enabled_for_language,
19127            edit_predictions_provider,
19128            is_via_ssh = project.is_via_ssh(),
19129        );
19130    }
19131
19132    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19133    /// with each line being an array of {text, highlight} objects.
19134    fn copy_highlight_json(
19135        &mut self,
19136        _: &CopyHighlightJson,
19137        window: &mut Window,
19138        cx: &mut Context<Self>,
19139    ) {
19140        #[derive(Serialize)]
19141        struct Chunk<'a> {
19142            text: String,
19143            highlight: Option<&'a str>,
19144        }
19145
19146        let snapshot = self.buffer.read(cx).snapshot(cx);
19147        let range = self
19148            .selected_text_range(false, window, cx)
19149            .and_then(|selection| {
19150                if selection.range.is_empty() {
19151                    None
19152                } else {
19153                    Some(selection.range)
19154                }
19155            })
19156            .unwrap_or_else(|| 0..snapshot.len());
19157
19158        let chunks = snapshot.chunks(range, true);
19159        let mut lines = Vec::new();
19160        let mut line: VecDeque<Chunk> = VecDeque::new();
19161
19162        let Some(style) = self.style.as_ref() else {
19163            return;
19164        };
19165
19166        for chunk in chunks {
19167            let highlight = chunk
19168                .syntax_highlight_id
19169                .and_then(|id| id.name(&style.syntax));
19170            let mut chunk_lines = chunk.text.split('\n').peekable();
19171            while let Some(text) = chunk_lines.next() {
19172                let mut merged_with_last_token = false;
19173                if let Some(last_token) = line.back_mut() {
19174                    if last_token.highlight == highlight {
19175                        last_token.text.push_str(text);
19176                        merged_with_last_token = true;
19177                    }
19178                }
19179
19180                if !merged_with_last_token {
19181                    line.push_back(Chunk {
19182                        text: text.into(),
19183                        highlight,
19184                    });
19185                }
19186
19187                if chunk_lines.peek().is_some() {
19188                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19189                        line.pop_front();
19190                    }
19191                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19192                        line.pop_back();
19193                    }
19194
19195                    lines.push(mem::take(&mut line));
19196                }
19197            }
19198        }
19199
19200        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19201            return;
19202        };
19203        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19204    }
19205
19206    pub fn open_context_menu(
19207        &mut self,
19208        _: &OpenContextMenu,
19209        window: &mut Window,
19210        cx: &mut Context<Self>,
19211    ) {
19212        self.request_autoscroll(Autoscroll::newest(), cx);
19213        let position = self.selections.newest_display(cx).start;
19214        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19215    }
19216
19217    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19218        &self.inlay_hint_cache
19219    }
19220
19221    pub fn replay_insert_event(
19222        &mut self,
19223        text: &str,
19224        relative_utf16_range: Option<Range<isize>>,
19225        window: &mut Window,
19226        cx: &mut Context<Self>,
19227    ) {
19228        if !self.input_enabled {
19229            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19230            return;
19231        }
19232        if let Some(relative_utf16_range) = relative_utf16_range {
19233            let selections = self.selections.all::<OffsetUtf16>(cx);
19234            self.change_selections(None, window, cx, |s| {
19235                let new_ranges = selections.into_iter().map(|range| {
19236                    let start = OffsetUtf16(
19237                        range
19238                            .head()
19239                            .0
19240                            .saturating_add_signed(relative_utf16_range.start),
19241                    );
19242                    let end = OffsetUtf16(
19243                        range
19244                            .head()
19245                            .0
19246                            .saturating_add_signed(relative_utf16_range.end),
19247                    );
19248                    start..end
19249                });
19250                s.select_ranges(new_ranges);
19251            });
19252        }
19253
19254        self.handle_input(text, window, cx);
19255    }
19256
19257    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19258        let Some(provider) = self.semantics_provider.as_ref() else {
19259            return false;
19260        };
19261
19262        let mut supports = false;
19263        self.buffer().update(cx, |this, cx| {
19264            this.for_each_buffer(|buffer| {
19265                supports |= provider.supports_inlay_hints(buffer, cx);
19266            });
19267        });
19268
19269        supports
19270    }
19271
19272    pub fn is_focused(&self, window: &Window) -> bool {
19273        self.focus_handle.is_focused(window)
19274    }
19275
19276    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19277        cx.emit(EditorEvent::Focused);
19278
19279        if let Some(descendant) = self
19280            .last_focused_descendant
19281            .take()
19282            .and_then(|descendant| descendant.upgrade())
19283        {
19284            window.focus(&descendant);
19285        } else {
19286            if let Some(blame) = self.blame.as_ref() {
19287                blame.update(cx, GitBlame::focus)
19288            }
19289
19290            self.blink_manager.update(cx, BlinkManager::enable);
19291            self.show_cursor_names(window, cx);
19292            self.buffer.update(cx, |buffer, cx| {
19293                buffer.finalize_last_transaction(cx);
19294                if self.leader_id.is_none() {
19295                    buffer.set_active_selections(
19296                        &self.selections.disjoint_anchors(),
19297                        self.selections.line_mode,
19298                        self.cursor_shape,
19299                        cx,
19300                    );
19301                }
19302            });
19303        }
19304    }
19305
19306    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19307        cx.emit(EditorEvent::FocusedIn)
19308    }
19309
19310    fn handle_focus_out(
19311        &mut self,
19312        event: FocusOutEvent,
19313        _window: &mut Window,
19314        cx: &mut Context<Self>,
19315    ) {
19316        if event.blurred != self.focus_handle {
19317            self.last_focused_descendant = Some(event.blurred);
19318        }
19319        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19320    }
19321
19322    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19323        self.blink_manager.update(cx, BlinkManager::disable);
19324        self.buffer
19325            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19326
19327        if let Some(blame) = self.blame.as_ref() {
19328            blame.update(cx, GitBlame::blur)
19329        }
19330        if !self.hover_state.focused(window, cx) {
19331            hide_hover(self, cx);
19332        }
19333        if !self
19334            .context_menu
19335            .borrow()
19336            .as_ref()
19337            .is_some_and(|context_menu| context_menu.focused(window, cx))
19338        {
19339            self.hide_context_menu(window, cx);
19340        }
19341        self.discard_inline_completion(false, cx);
19342        cx.emit(EditorEvent::Blurred);
19343        cx.notify();
19344    }
19345
19346    pub fn register_action<A: Action>(
19347        &mut self,
19348        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19349    ) -> Subscription {
19350        let id = self.next_editor_action_id.post_inc();
19351        let listener = Arc::new(listener);
19352        self.editor_actions.borrow_mut().insert(
19353            id,
19354            Box::new(move |window, _| {
19355                let listener = listener.clone();
19356                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19357                    let action = action.downcast_ref().unwrap();
19358                    if phase == DispatchPhase::Bubble {
19359                        listener(action, window, cx)
19360                    }
19361                })
19362            }),
19363        );
19364
19365        let editor_actions = self.editor_actions.clone();
19366        Subscription::new(move || {
19367            editor_actions.borrow_mut().remove(&id);
19368        })
19369    }
19370
19371    pub fn file_header_size(&self) -> u32 {
19372        FILE_HEADER_HEIGHT
19373    }
19374
19375    pub fn restore(
19376        &mut self,
19377        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19378        window: &mut Window,
19379        cx: &mut Context<Self>,
19380    ) {
19381        let workspace = self.workspace();
19382        let project = self.project.as_ref();
19383        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19384            let mut tasks = Vec::new();
19385            for (buffer_id, changes) in revert_changes {
19386                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19387                    buffer.update(cx, |buffer, cx| {
19388                        buffer.edit(
19389                            changes
19390                                .into_iter()
19391                                .map(|(range, text)| (range, text.to_string())),
19392                            None,
19393                            cx,
19394                        );
19395                    });
19396
19397                    if let Some(project) =
19398                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19399                    {
19400                        project.update(cx, |project, cx| {
19401                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19402                        })
19403                    }
19404                }
19405            }
19406            tasks
19407        });
19408        cx.spawn_in(window, async move |_, cx| {
19409            for (buffer, task) in save_tasks {
19410                let result = task.await;
19411                if result.is_err() {
19412                    let Some(path) = buffer
19413                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19414                        .ok()
19415                    else {
19416                        continue;
19417                    };
19418                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19419                        let Some(task) = cx
19420                            .update_window_entity(&workspace, |workspace, window, cx| {
19421                                workspace
19422                                    .open_path_preview(path, None, false, false, false, window, cx)
19423                            })
19424                            .ok()
19425                        else {
19426                            continue;
19427                        };
19428                        task.await.log_err();
19429                    }
19430                }
19431            }
19432        })
19433        .detach();
19434        self.change_selections(None, window, cx, |selections| selections.refresh());
19435    }
19436
19437    pub fn to_pixel_point(
19438        &self,
19439        source: multi_buffer::Anchor,
19440        editor_snapshot: &EditorSnapshot,
19441        window: &mut Window,
19442    ) -> Option<gpui::Point<Pixels>> {
19443        let source_point = source.to_display_point(editor_snapshot);
19444        self.display_to_pixel_point(source_point, editor_snapshot, window)
19445    }
19446
19447    pub fn display_to_pixel_point(
19448        &self,
19449        source: DisplayPoint,
19450        editor_snapshot: &EditorSnapshot,
19451        window: &mut Window,
19452    ) -> Option<gpui::Point<Pixels>> {
19453        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19454        let text_layout_details = self.text_layout_details(window);
19455        let scroll_top = text_layout_details
19456            .scroll_anchor
19457            .scroll_position(editor_snapshot)
19458            .y;
19459
19460        if source.row().as_f32() < scroll_top.floor() {
19461            return None;
19462        }
19463        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19464        let source_y = line_height * (source.row().as_f32() - scroll_top);
19465        Some(gpui::Point::new(source_x, source_y))
19466    }
19467
19468    pub fn has_visible_completions_menu(&self) -> bool {
19469        !self.edit_prediction_preview_is_active()
19470            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19471                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19472            })
19473    }
19474
19475    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19476        if self.mode.is_minimap() {
19477            return;
19478        }
19479        self.addons
19480            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19481    }
19482
19483    pub fn unregister_addon<T: Addon>(&mut self) {
19484        self.addons.remove(&std::any::TypeId::of::<T>());
19485    }
19486
19487    pub fn addon<T: Addon>(&self) -> Option<&T> {
19488        let type_id = std::any::TypeId::of::<T>();
19489        self.addons
19490            .get(&type_id)
19491            .and_then(|item| item.to_any().downcast_ref::<T>())
19492    }
19493
19494    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19495        let type_id = std::any::TypeId::of::<T>();
19496        self.addons
19497            .get_mut(&type_id)
19498            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19499    }
19500
19501    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19502        let text_layout_details = self.text_layout_details(window);
19503        let style = &text_layout_details.editor_style;
19504        let font_id = window.text_system().resolve_font(&style.text.font());
19505        let font_size = style.text.font_size.to_pixels(window.rem_size());
19506        let line_height = style.text.line_height_in_pixels(window.rem_size());
19507        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19508
19509        gpui::Size::new(em_width, line_height)
19510    }
19511
19512    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19513        self.load_diff_task.clone()
19514    }
19515
19516    fn read_metadata_from_db(
19517        &mut self,
19518        item_id: u64,
19519        workspace_id: WorkspaceId,
19520        window: &mut Window,
19521        cx: &mut Context<Editor>,
19522    ) {
19523        if self.is_singleton(cx)
19524            && !self.mode.is_minimap()
19525            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19526        {
19527            let buffer_snapshot = OnceCell::new();
19528
19529            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19530                if !folds.is_empty() {
19531                    let snapshot =
19532                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19533                    self.fold_ranges(
19534                        folds
19535                            .into_iter()
19536                            .map(|(start, end)| {
19537                                snapshot.clip_offset(start, Bias::Left)
19538                                    ..snapshot.clip_offset(end, Bias::Right)
19539                            })
19540                            .collect(),
19541                        false,
19542                        window,
19543                        cx,
19544                    );
19545                }
19546            }
19547
19548            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19549                if !selections.is_empty() {
19550                    let snapshot =
19551                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19552                    self.change_selections(None, window, cx, |s| {
19553                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19554                            snapshot.clip_offset(start, Bias::Left)
19555                                ..snapshot.clip_offset(end, Bias::Right)
19556                        }));
19557                    });
19558                }
19559            };
19560        }
19561
19562        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19563    }
19564}
19565
19566fn vim_enabled(cx: &App) -> bool {
19567    cx.global::<SettingsStore>()
19568        .raw_user_settings()
19569        .get("vim_mode")
19570        == Some(&serde_json::Value::Bool(true))
19571}
19572
19573fn process_completion_for_edit(
19574    completion: &Completion,
19575    intent: CompletionIntent,
19576    buffer: &Entity<Buffer>,
19577    cursor_position: &text::Anchor,
19578    cx: &mut Context<Editor>,
19579) -> CompletionEdit {
19580    let buffer = buffer.read(cx);
19581    let buffer_snapshot = buffer.snapshot();
19582    let (snippet, new_text) = if completion.is_snippet() {
19583        let mut snippet_source = completion.new_text.clone();
19584        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
19585            if scope.prefers_label_for_snippet_in_completion() {
19586                if let Some(label) = completion.label() {
19587                    if matches!(
19588                        completion.kind(),
19589                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
19590                    ) {
19591                        snippet_source = label;
19592                    }
19593                }
19594            }
19595        }
19596        match Snippet::parse(&snippet_source).log_err() {
19597            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
19598            None => (None, completion.new_text.clone()),
19599        }
19600    } else {
19601        (None, completion.new_text.clone())
19602    };
19603
19604    let mut range_to_replace = {
19605        let replace_range = &completion.replace_range;
19606        if let CompletionSource::Lsp {
19607            insert_range: Some(insert_range),
19608            ..
19609        } = &completion.source
19610        {
19611            debug_assert_eq!(
19612                insert_range.start, replace_range.start,
19613                "insert_range and replace_range should start at the same position"
19614            );
19615            debug_assert!(
19616                insert_range
19617                    .start
19618                    .cmp(&cursor_position, &buffer_snapshot)
19619                    .is_le(),
19620                "insert_range should start before or at cursor position"
19621            );
19622            debug_assert!(
19623                replace_range
19624                    .start
19625                    .cmp(&cursor_position, &buffer_snapshot)
19626                    .is_le(),
19627                "replace_range should start before or at cursor position"
19628            );
19629            debug_assert!(
19630                insert_range
19631                    .end
19632                    .cmp(&cursor_position, &buffer_snapshot)
19633                    .is_le(),
19634                "insert_range should end before or at cursor position"
19635            );
19636
19637            let should_replace = match intent {
19638                CompletionIntent::CompleteWithInsert => false,
19639                CompletionIntent::CompleteWithReplace => true,
19640                CompletionIntent::Complete | CompletionIntent::Compose => {
19641                    let insert_mode =
19642                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19643                            .completions
19644                            .lsp_insert_mode;
19645                    match insert_mode {
19646                        LspInsertMode::Insert => false,
19647                        LspInsertMode::Replace => true,
19648                        LspInsertMode::ReplaceSubsequence => {
19649                            let mut text_to_replace = buffer.chars_for_range(
19650                                buffer.anchor_before(replace_range.start)
19651                                    ..buffer.anchor_after(replace_range.end),
19652                            );
19653                            let mut current_needle = text_to_replace.next();
19654                            for haystack_ch in completion.label.text.chars() {
19655                                if let Some(needle_ch) = current_needle {
19656                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
19657                                        current_needle = text_to_replace.next();
19658                                    }
19659                                }
19660                            }
19661                            current_needle.is_none()
19662                        }
19663                        LspInsertMode::ReplaceSuffix => {
19664                            if replace_range
19665                                .end
19666                                .cmp(&cursor_position, &buffer_snapshot)
19667                                .is_gt()
19668                            {
19669                                let range_after_cursor = *cursor_position..replace_range.end;
19670                                let text_after_cursor = buffer
19671                                    .text_for_range(
19672                                        buffer.anchor_before(range_after_cursor.start)
19673                                            ..buffer.anchor_after(range_after_cursor.end),
19674                                    )
19675                                    .collect::<String>()
19676                                    .to_ascii_lowercase();
19677                                completion
19678                                    .label
19679                                    .text
19680                                    .to_ascii_lowercase()
19681                                    .ends_with(&text_after_cursor)
19682                            } else {
19683                                true
19684                            }
19685                        }
19686                    }
19687                }
19688            };
19689
19690            if should_replace {
19691                replace_range.clone()
19692            } else {
19693                insert_range.clone()
19694            }
19695        } else {
19696            replace_range.clone()
19697        }
19698    };
19699
19700    if range_to_replace
19701        .end
19702        .cmp(&cursor_position, &buffer_snapshot)
19703        .is_lt()
19704    {
19705        range_to_replace.end = *cursor_position;
19706    }
19707
19708    CompletionEdit {
19709        new_text,
19710        replace_range: range_to_replace.to_offset(&buffer),
19711        snippet,
19712    }
19713}
19714
19715struct CompletionEdit {
19716    new_text: String,
19717    replace_range: Range<usize>,
19718    snippet: Option<Snippet>,
19719}
19720
19721fn insert_extra_newline_brackets(
19722    buffer: &MultiBufferSnapshot,
19723    range: Range<usize>,
19724    language: &language::LanguageScope,
19725) -> bool {
19726    let leading_whitespace_len = buffer
19727        .reversed_chars_at(range.start)
19728        .take_while(|c| c.is_whitespace() && *c != '\n')
19729        .map(|c| c.len_utf8())
19730        .sum::<usize>();
19731    let trailing_whitespace_len = buffer
19732        .chars_at(range.end)
19733        .take_while(|c| c.is_whitespace() && *c != '\n')
19734        .map(|c| c.len_utf8())
19735        .sum::<usize>();
19736    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19737
19738    language.brackets().any(|(pair, enabled)| {
19739        let pair_start = pair.start.trim_end();
19740        let pair_end = pair.end.trim_start();
19741
19742        enabled
19743            && pair.newline
19744            && buffer.contains_str_at(range.end, pair_end)
19745            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19746    })
19747}
19748
19749fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19750    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19751        [(buffer, range, _)] => (*buffer, range.clone()),
19752        _ => return false,
19753    };
19754    let pair = {
19755        let mut result: Option<BracketMatch> = None;
19756
19757        for pair in buffer
19758            .all_bracket_ranges(range.clone())
19759            .filter(move |pair| {
19760                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19761            })
19762        {
19763            let len = pair.close_range.end - pair.open_range.start;
19764
19765            if let Some(existing) = &result {
19766                let existing_len = existing.close_range.end - existing.open_range.start;
19767                if len > existing_len {
19768                    continue;
19769                }
19770            }
19771
19772            result = Some(pair);
19773        }
19774
19775        result
19776    };
19777    let Some(pair) = pair else {
19778        return false;
19779    };
19780    pair.newline_only
19781        && buffer
19782            .chars_for_range(pair.open_range.end..range.start)
19783            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19784            .all(|c| c.is_whitespace() && c != '\n')
19785}
19786
19787fn update_uncommitted_diff_for_buffer(
19788    editor: Entity<Editor>,
19789    project: &Entity<Project>,
19790    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19791    buffer: Entity<MultiBuffer>,
19792    cx: &mut App,
19793) -> Task<()> {
19794    let mut tasks = Vec::new();
19795    project.update(cx, |project, cx| {
19796        for buffer in buffers {
19797            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19798                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19799            }
19800        }
19801    });
19802    cx.spawn(async move |cx| {
19803        let diffs = future::join_all(tasks).await;
19804        if editor
19805            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19806            .unwrap_or(false)
19807        {
19808            return;
19809        }
19810
19811        buffer
19812            .update(cx, |buffer, cx| {
19813                for diff in diffs.into_iter().flatten() {
19814                    buffer.add_diff(diff, cx);
19815                }
19816            })
19817            .ok();
19818    })
19819}
19820
19821fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19822    let tab_size = tab_size.get() as usize;
19823    let mut width = offset;
19824
19825    for ch in text.chars() {
19826        width += if ch == '\t' {
19827            tab_size - (width % tab_size)
19828        } else {
19829            1
19830        };
19831    }
19832
19833    width - offset
19834}
19835
19836#[cfg(test)]
19837mod tests {
19838    use super::*;
19839
19840    #[test]
19841    fn test_string_size_with_expanded_tabs() {
19842        let nz = |val| NonZeroU32::new(val).unwrap();
19843        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19844        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19845        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19846        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19847        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19848        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19849        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19850        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19851    }
19852}
19853
19854/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19855struct WordBreakingTokenizer<'a> {
19856    input: &'a str,
19857}
19858
19859impl<'a> WordBreakingTokenizer<'a> {
19860    fn new(input: &'a str) -> Self {
19861        Self { input }
19862    }
19863}
19864
19865fn is_char_ideographic(ch: char) -> bool {
19866    use unicode_script::Script::*;
19867    use unicode_script::UnicodeScript;
19868    matches!(ch.script(), Han | Tangut | Yi)
19869}
19870
19871fn is_grapheme_ideographic(text: &str) -> bool {
19872    text.chars().any(is_char_ideographic)
19873}
19874
19875fn is_grapheme_whitespace(text: &str) -> bool {
19876    text.chars().any(|x| x.is_whitespace())
19877}
19878
19879fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19880    text.chars().next().map_or(false, |ch| {
19881        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19882    })
19883}
19884
19885#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19886enum WordBreakToken<'a> {
19887    Word { token: &'a str, grapheme_len: usize },
19888    InlineWhitespace { token: &'a str, grapheme_len: usize },
19889    Newline,
19890}
19891
19892impl<'a> Iterator for WordBreakingTokenizer<'a> {
19893    /// Yields a span, the count of graphemes in the token, and whether it was
19894    /// whitespace. Note that it also breaks at word boundaries.
19895    type Item = WordBreakToken<'a>;
19896
19897    fn next(&mut self) -> Option<Self::Item> {
19898        use unicode_segmentation::UnicodeSegmentation;
19899        if self.input.is_empty() {
19900            return None;
19901        }
19902
19903        let mut iter = self.input.graphemes(true).peekable();
19904        let mut offset = 0;
19905        let mut grapheme_len = 0;
19906        if let Some(first_grapheme) = iter.next() {
19907            let is_newline = first_grapheme == "\n";
19908            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19909            offset += first_grapheme.len();
19910            grapheme_len += 1;
19911            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19912                if let Some(grapheme) = iter.peek().copied() {
19913                    if should_stay_with_preceding_ideograph(grapheme) {
19914                        offset += grapheme.len();
19915                        grapheme_len += 1;
19916                    }
19917                }
19918            } else {
19919                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19920                let mut next_word_bound = words.peek().copied();
19921                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19922                    next_word_bound = words.next();
19923                }
19924                while let Some(grapheme) = iter.peek().copied() {
19925                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19926                        break;
19927                    };
19928                    if is_grapheme_whitespace(grapheme) != is_whitespace
19929                        || (grapheme == "\n") != is_newline
19930                    {
19931                        break;
19932                    };
19933                    offset += grapheme.len();
19934                    grapheme_len += 1;
19935                    iter.next();
19936                }
19937            }
19938            let token = &self.input[..offset];
19939            self.input = &self.input[offset..];
19940            if token == "\n" {
19941                Some(WordBreakToken::Newline)
19942            } else if is_whitespace {
19943                Some(WordBreakToken::InlineWhitespace {
19944                    token,
19945                    grapheme_len,
19946                })
19947            } else {
19948                Some(WordBreakToken::Word {
19949                    token,
19950                    grapheme_len,
19951                })
19952            }
19953        } else {
19954            None
19955        }
19956    }
19957}
19958
19959#[test]
19960fn test_word_breaking_tokenizer() {
19961    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19962        ("", &[]),
19963        ("  ", &[whitespace("  ", 2)]),
19964        ("Ʒ", &[word("Ʒ", 1)]),
19965        ("Ǽ", &[word("Ǽ", 1)]),
19966        ("", &[word("", 1)]),
19967        ("⋑⋑", &[word("⋑⋑", 2)]),
19968        (
19969            "原理,进而",
19970            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19971        ),
19972        (
19973            "hello world",
19974            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19975        ),
19976        (
19977            "hello, world",
19978            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19979        ),
19980        (
19981            "  hello world",
19982            &[
19983                whitespace("  ", 2),
19984                word("hello", 5),
19985                whitespace(" ", 1),
19986                word("world", 5),
19987            ],
19988        ),
19989        (
19990            "这是什么 \n 钢笔",
19991            &[
19992                word("", 1),
19993                word("", 1),
19994                word("", 1),
19995                word("", 1),
19996                whitespace(" ", 1),
19997                newline(),
19998                whitespace(" ", 1),
19999                word("", 1),
20000                word("", 1),
20001            ],
20002        ),
20003        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20004    ];
20005
20006    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20007        WordBreakToken::Word {
20008            token,
20009            grapheme_len,
20010        }
20011    }
20012
20013    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20014        WordBreakToken::InlineWhitespace {
20015            token,
20016            grapheme_len,
20017        }
20018    }
20019
20020    fn newline() -> WordBreakToken<'static> {
20021        WordBreakToken::Newline
20022    }
20023
20024    for (input, result) in tests {
20025        assert_eq!(
20026            WordBreakingTokenizer::new(input)
20027                .collect::<Vec<_>>()
20028                .as_slice(),
20029            *result,
20030        );
20031    }
20032}
20033
20034fn wrap_with_prefix(
20035    line_prefix: String,
20036    unwrapped_text: String,
20037    wrap_column: usize,
20038    tab_size: NonZeroU32,
20039    preserve_existing_whitespace: bool,
20040) -> String {
20041    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20042    let mut wrapped_text = String::new();
20043    let mut current_line = line_prefix.clone();
20044
20045    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20046    let mut current_line_len = line_prefix_len;
20047    let mut in_whitespace = false;
20048    for token in tokenizer {
20049        let have_preceding_whitespace = in_whitespace;
20050        match token {
20051            WordBreakToken::Word {
20052                token,
20053                grapheme_len,
20054            } => {
20055                in_whitespace = false;
20056                if current_line_len + grapheme_len > wrap_column
20057                    && current_line_len != line_prefix_len
20058                {
20059                    wrapped_text.push_str(current_line.trim_end());
20060                    wrapped_text.push('\n');
20061                    current_line.truncate(line_prefix.len());
20062                    current_line_len = line_prefix_len;
20063                }
20064                current_line.push_str(token);
20065                current_line_len += grapheme_len;
20066            }
20067            WordBreakToken::InlineWhitespace {
20068                mut token,
20069                mut grapheme_len,
20070            } => {
20071                in_whitespace = true;
20072                if have_preceding_whitespace && !preserve_existing_whitespace {
20073                    continue;
20074                }
20075                if !preserve_existing_whitespace {
20076                    token = " ";
20077                    grapheme_len = 1;
20078                }
20079                if current_line_len + grapheme_len > wrap_column {
20080                    wrapped_text.push_str(current_line.trim_end());
20081                    wrapped_text.push('\n');
20082                    current_line.truncate(line_prefix.len());
20083                    current_line_len = line_prefix_len;
20084                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20085                    current_line.push_str(token);
20086                    current_line_len += grapheme_len;
20087                }
20088            }
20089            WordBreakToken::Newline => {
20090                in_whitespace = true;
20091                if preserve_existing_whitespace {
20092                    wrapped_text.push_str(current_line.trim_end());
20093                    wrapped_text.push('\n');
20094                    current_line.truncate(line_prefix.len());
20095                    current_line_len = line_prefix_len;
20096                } else if have_preceding_whitespace {
20097                    continue;
20098                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20099                {
20100                    wrapped_text.push_str(current_line.trim_end());
20101                    wrapped_text.push('\n');
20102                    current_line.truncate(line_prefix.len());
20103                    current_line_len = line_prefix_len;
20104                } else if current_line_len != line_prefix_len {
20105                    current_line.push(' ');
20106                    current_line_len += 1;
20107                }
20108            }
20109        }
20110    }
20111
20112    if !current_line.is_empty() {
20113        wrapped_text.push_str(&current_line);
20114    }
20115    wrapped_text
20116}
20117
20118#[test]
20119fn test_wrap_with_prefix() {
20120    assert_eq!(
20121        wrap_with_prefix(
20122            "# ".to_string(),
20123            "abcdefg".to_string(),
20124            4,
20125            NonZeroU32::new(4).unwrap(),
20126            false,
20127        ),
20128        "# abcdefg"
20129    );
20130    assert_eq!(
20131        wrap_with_prefix(
20132            "".to_string(),
20133            "\thello world".to_string(),
20134            8,
20135            NonZeroU32::new(4).unwrap(),
20136            false,
20137        ),
20138        "hello\nworld"
20139    );
20140    assert_eq!(
20141        wrap_with_prefix(
20142            "// ".to_string(),
20143            "xx \nyy zz aa bb cc".to_string(),
20144            12,
20145            NonZeroU32::new(4).unwrap(),
20146            false,
20147        ),
20148        "// xx yy zz\n// aa bb cc"
20149    );
20150    assert_eq!(
20151        wrap_with_prefix(
20152            String::new(),
20153            "这是什么 \n 钢笔".to_string(),
20154            3,
20155            NonZeroU32::new(4).unwrap(),
20156            false,
20157        ),
20158        "这是什\n么 钢\n"
20159    );
20160}
20161
20162pub trait CollaborationHub {
20163    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20164    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20165    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20166}
20167
20168impl CollaborationHub for Entity<Project> {
20169    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20170        self.read(cx).collaborators()
20171    }
20172
20173    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20174        self.read(cx).user_store().read(cx).participant_indices()
20175    }
20176
20177    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20178        let this = self.read(cx);
20179        let user_ids = this.collaborators().values().map(|c| c.user_id);
20180        this.user_store().read(cx).participant_names(user_ids, cx)
20181    }
20182}
20183
20184pub trait SemanticsProvider {
20185    fn hover(
20186        &self,
20187        buffer: &Entity<Buffer>,
20188        position: text::Anchor,
20189        cx: &mut App,
20190    ) -> Option<Task<Vec<project::Hover>>>;
20191
20192    fn inline_values(
20193        &self,
20194        buffer_handle: Entity<Buffer>,
20195        range: Range<text::Anchor>,
20196        cx: &mut App,
20197    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20198
20199    fn inlay_hints(
20200        &self,
20201        buffer_handle: Entity<Buffer>,
20202        range: Range<text::Anchor>,
20203        cx: &mut App,
20204    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20205
20206    fn resolve_inlay_hint(
20207        &self,
20208        hint: InlayHint,
20209        buffer_handle: Entity<Buffer>,
20210        server_id: LanguageServerId,
20211        cx: &mut App,
20212    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20213
20214    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20215
20216    fn document_highlights(
20217        &self,
20218        buffer: &Entity<Buffer>,
20219        position: text::Anchor,
20220        cx: &mut App,
20221    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20222
20223    fn definitions(
20224        &self,
20225        buffer: &Entity<Buffer>,
20226        position: text::Anchor,
20227        kind: GotoDefinitionKind,
20228        cx: &mut App,
20229    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20230
20231    fn range_for_rename(
20232        &self,
20233        buffer: &Entity<Buffer>,
20234        position: text::Anchor,
20235        cx: &mut App,
20236    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20237
20238    fn perform_rename(
20239        &self,
20240        buffer: &Entity<Buffer>,
20241        position: text::Anchor,
20242        new_name: String,
20243        cx: &mut App,
20244    ) -> Option<Task<Result<ProjectTransaction>>>;
20245}
20246
20247pub trait CompletionProvider {
20248    fn completions(
20249        &self,
20250        excerpt_id: ExcerptId,
20251        buffer: &Entity<Buffer>,
20252        buffer_position: text::Anchor,
20253        trigger: CompletionContext,
20254        window: &mut Window,
20255        cx: &mut Context<Editor>,
20256    ) -> Task<Result<Vec<CompletionResponse>>>;
20257
20258    fn resolve_completions(
20259        &self,
20260        buffer: Entity<Buffer>,
20261        completion_indices: Vec<usize>,
20262        completions: Rc<RefCell<Box<[Completion]>>>,
20263        cx: &mut Context<Editor>,
20264    ) -> Task<Result<bool>>;
20265
20266    fn apply_additional_edits_for_completion(
20267        &self,
20268        _buffer: Entity<Buffer>,
20269        _completions: Rc<RefCell<Box<[Completion]>>>,
20270        _completion_index: usize,
20271        _push_to_history: bool,
20272        _cx: &mut Context<Editor>,
20273    ) -> Task<Result<Option<language::Transaction>>> {
20274        Task::ready(Ok(None))
20275    }
20276
20277    fn is_completion_trigger(
20278        &self,
20279        buffer: &Entity<Buffer>,
20280        position: language::Anchor,
20281        text: &str,
20282        trigger_in_words: bool,
20283        cx: &mut Context<Editor>,
20284    ) -> bool;
20285
20286    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20287
20288    fn sort_completions(&self) -> bool {
20289        true
20290    }
20291
20292    fn filter_completions(&self) -> bool {
20293        true
20294    }
20295}
20296
20297pub trait CodeActionProvider {
20298    fn id(&self) -> Arc<str>;
20299
20300    fn code_actions(
20301        &self,
20302        buffer: &Entity<Buffer>,
20303        range: Range<text::Anchor>,
20304        window: &mut Window,
20305        cx: &mut App,
20306    ) -> Task<Result<Vec<CodeAction>>>;
20307
20308    fn apply_code_action(
20309        &self,
20310        buffer_handle: Entity<Buffer>,
20311        action: CodeAction,
20312        excerpt_id: ExcerptId,
20313        push_to_history: bool,
20314        window: &mut Window,
20315        cx: &mut App,
20316    ) -> Task<Result<ProjectTransaction>>;
20317}
20318
20319impl CodeActionProvider for Entity<Project> {
20320    fn id(&self) -> Arc<str> {
20321        "project".into()
20322    }
20323
20324    fn code_actions(
20325        &self,
20326        buffer: &Entity<Buffer>,
20327        range: Range<text::Anchor>,
20328        _window: &mut Window,
20329        cx: &mut App,
20330    ) -> Task<Result<Vec<CodeAction>>> {
20331        self.update(cx, |project, cx| {
20332            let code_lens = project.code_lens(buffer, range.clone(), cx);
20333            let code_actions = project.code_actions(buffer, range, None, cx);
20334            cx.background_spawn(async move {
20335                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20336                Ok(code_lens
20337                    .context("code lens fetch")?
20338                    .into_iter()
20339                    .chain(code_actions.context("code action fetch")?)
20340                    .collect())
20341            })
20342        })
20343    }
20344
20345    fn apply_code_action(
20346        &self,
20347        buffer_handle: Entity<Buffer>,
20348        action: CodeAction,
20349        _excerpt_id: ExcerptId,
20350        push_to_history: bool,
20351        _window: &mut Window,
20352        cx: &mut App,
20353    ) -> Task<Result<ProjectTransaction>> {
20354        self.update(cx, |project, cx| {
20355            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20356        })
20357    }
20358}
20359
20360fn snippet_completions(
20361    project: &Project,
20362    buffer: &Entity<Buffer>,
20363    buffer_position: text::Anchor,
20364    cx: &mut App,
20365) -> Task<Result<CompletionResponse>> {
20366    let languages = buffer.read(cx).languages_at(buffer_position);
20367    let snippet_store = project.snippets().read(cx);
20368
20369    let scopes: Vec<_> = languages
20370        .iter()
20371        .filter_map(|language| {
20372            let language_name = language.lsp_id();
20373            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20374
20375            if snippets.is_empty() {
20376                None
20377            } else {
20378                Some((language.default_scope(), snippets))
20379            }
20380        })
20381        .collect();
20382
20383    if scopes.is_empty() {
20384        return Task::ready(Ok(CompletionResponse {
20385            completions: vec![],
20386            is_incomplete: false,
20387        }));
20388    }
20389
20390    let snapshot = buffer.read(cx).text_snapshot();
20391    let chars: String = snapshot
20392        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20393        .collect();
20394    let executor = cx.background_executor().clone();
20395
20396    cx.background_spawn(async move {
20397        let mut is_incomplete = false;
20398        let mut completions: Vec<Completion> = Vec::new();
20399        for (scope, snippets) in scopes.into_iter() {
20400            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20401            let mut last_word = chars
20402                .chars()
20403                .take_while(|c| classifier.is_word(*c))
20404                .collect::<String>();
20405            last_word = last_word.chars().rev().collect();
20406
20407            if last_word.is_empty() {
20408                return Ok(CompletionResponse {
20409                    completions: vec![],
20410                    is_incomplete: true,
20411                });
20412            }
20413
20414            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20415            let to_lsp = |point: &text::Anchor| {
20416                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20417                point_to_lsp(end)
20418            };
20419            let lsp_end = to_lsp(&buffer_position);
20420
20421            let candidates = snippets
20422                .iter()
20423                .enumerate()
20424                .flat_map(|(ix, snippet)| {
20425                    snippet
20426                        .prefix
20427                        .iter()
20428                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20429                })
20430                .collect::<Vec<StringMatchCandidate>>();
20431
20432            const MAX_RESULTS: usize = 100;
20433            let mut matches = fuzzy::match_strings(
20434                &candidates,
20435                &last_word,
20436                last_word.chars().any(|c| c.is_uppercase()),
20437                MAX_RESULTS,
20438                &Default::default(),
20439                executor.clone(),
20440            )
20441            .await;
20442
20443            if matches.len() >= MAX_RESULTS {
20444                is_incomplete = true;
20445            }
20446
20447            // Remove all candidates where the query's start does not match the start of any word in the candidate
20448            if let Some(query_start) = last_word.chars().next() {
20449                matches.retain(|string_match| {
20450                    split_words(&string_match.string).any(|word| {
20451                        // Check that the first codepoint of the word as lowercase matches the first
20452                        // codepoint of the query as lowercase
20453                        word.chars()
20454                            .flat_map(|codepoint| codepoint.to_lowercase())
20455                            .zip(query_start.to_lowercase())
20456                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20457                    })
20458                });
20459            }
20460
20461            let matched_strings = matches
20462                .into_iter()
20463                .map(|m| m.string)
20464                .collect::<HashSet<_>>();
20465
20466            completions.extend(snippets.iter().filter_map(|snippet| {
20467                let matching_prefix = snippet
20468                    .prefix
20469                    .iter()
20470                    .find(|prefix| matched_strings.contains(*prefix))?;
20471                let start = as_offset - last_word.len();
20472                let start = snapshot.anchor_before(start);
20473                let range = start..buffer_position;
20474                let lsp_start = to_lsp(&start);
20475                let lsp_range = lsp::Range {
20476                    start: lsp_start,
20477                    end: lsp_end,
20478                };
20479                Some(Completion {
20480                    replace_range: range,
20481                    new_text: snippet.body.clone(),
20482                    source: CompletionSource::Lsp {
20483                        insert_range: None,
20484                        server_id: LanguageServerId(usize::MAX),
20485                        resolved: true,
20486                        lsp_completion: Box::new(lsp::CompletionItem {
20487                            label: snippet.prefix.first().unwrap().clone(),
20488                            kind: Some(CompletionItemKind::SNIPPET),
20489                            label_details: snippet.description.as_ref().map(|description| {
20490                                lsp::CompletionItemLabelDetails {
20491                                    detail: Some(description.clone()),
20492                                    description: None,
20493                                }
20494                            }),
20495                            insert_text_format: Some(InsertTextFormat::SNIPPET),
20496                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20497                                lsp::InsertReplaceEdit {
20498                                    new_text: snippet.body.clone(),
20499                                    insert: lsp_range,
20500                                    replace: lsp_range,
20501                                },
20502                            )),
20503                            filter_text: Some(snippet.body.clone()),
20504                            sort_text: Some(char::MAX.to_string()),
20505                            ..lsp::CompletionItem::default()
20506                        }),
20507                        lsp_defaults: None,
20508                    },
20509                    label: CodeLabel {
20510                        text: matching_prefix.clone(),
20511                        runs: Vec::new(),
20512                        filter_range: 0..matching_prefix.len(),
20513                    },
20514                    icon_path: None,
20515                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
20516                        single_line: snippet.name.clone().into(),
20517                        plain_text: snippet
20518                            .description
20519                            .clone()
20520                            .map(|description| description.into()),
20521                    }),
20522                    insert_text_mode: None,
20523                    confirm: None,
20524                })
20525            }))
20526        }
20527
20528        Ok(CompletionResponse {
20529            completions,
20530            is_incomplete,
20531        })
20532    })
20533}
20534
20535impl CompletionProvider for Entity<Project> {
20536    fn completions(
20537        &self,
20538        _excerpt_id: ExcerptId,
20539        buffer: &Entity<Buffer>,
20540        buffer_position: text::Anchor,
20541        options: CompletionContext,
20542        _window: &mut Window,
20543        cx: &mut Context<Editor>,
20544    ) -> Task<Result<Vec<CompletionResponse>>> {
20545        self.update(cx, |project, cx| {
20546            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20547            let project_completions = project.completions(buffer, buffer_position, options, cx);
20548            cx.background_spawn(async move {
20549                let mut responses = project_completions.await?;
20550                let snippets = snippets.await?;
20551                if !snippets.completions.is_empty() {
20552                    responses.push(snippets);
20553                }
20554                Ok(responses)
20555            })
20556        })
20557    }
20558
20559    fn resolve_completions(
20560        &self,
20561        buffer: Entity<Buffer>,
20562        completion_indices: Vec<usize>,
20563        completions: Rc<RefCell<Box<[Completion]>>>,
20564        cx: &mut Context<Editor>,
20565    ) -> Task<Result<bool>> {
20566        self.update(cx, |project, cx| {
20567            project.lsp_store().update(cx, |lsp_store, cx| {
20568                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20569            })
20570        })
20571    }
20572
20573    fn apply_additional_edits_for_completion(
20574        &self,
20575        buffer: Entity<Buffer>,
20576        completions: Rc<RefCell<Box<[Completion]>>>,
20577        completion_index: usize,
20578        push_to_history: bool,
20579        cx: &mut Context<Editor>,
20580    ) -> Task<Result<Option<language::Transaction>>> {
20581        self.update(cx, |project, cx| {
20582            project.lsp_store().update(cx, |lsp_store, cx| {
20583                lsp_store.apply_additional_edits_for_completion(
20584                    buffer,
20585                    completions,
20586                    completion_index,
20587                    push_to_history,
20588                    cx,
20589                )
20590            })
20591        })
20592    }
20593
20594    fn is_completion_trigger(
20595        &self,
20596        buffer: &Entity<Buffer>,
20597        position: language::Anchor,
20598        text: &str,
20599        trigger_in_words: bool,
20600        cx: &mut Context<Editor>,
20601    ) -> bool {
20602        let mut chars = text.chars();
20603        let char = if let Some(char) = chars.next() {
20604            char
20605        } else {
20606            return false;
20607        };
20608        if chars.next().is_some() {
20609            return false;
20610        }
20611
20612        let buffer = buffer.read(cx);
20613        let snapshot = buffer.snapshot();
20614        if !snapshot.settings_at(position, cx).show_completions_on_input {
20615            return false;
20616        }
20617        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20618        if trigger_in_words && classifier.is_word(char) {
20619            return true;
20620        }
20621
20622        buffer.completion_triggers().contains(text)
20623    }
20624}
20625
20626impl SemanticsProvider for Entity<Project> {
20627    fn hover(
20628        &self,
20629        buffer: &Entity<Buffer>,
20630        position: text::Anchor,
20631        cx: &mut App,
20632    ) -> Option<Task<Vec<project::Hover>>> {
20633        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20634    }
20635
20636    fn document_highlights(
20637        &self,
20638        buffer: &Entity<Buffer>,
20639        position: text::Anchor,
20640        cx: &mut App,
20641    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20642        Some(self.update(cx, |project, cx| {
20643            project.document_highlights(buffer, position, cx)
20644        }))
20645    }
20646
20647    fn definitions(
20648        &self,
20649        buffer: &Entity<Buffer>,
20650        position: text::Anchor,
20651        kind: GotoDefinitionKind,
20652        cx: &mut App,
20653    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20654        Some(self.update(cx, |project, cx| match kind {
20655            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20656            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20657            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20658            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20659        }))
20660    }
20661
20662    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20663        // TODO: make this work for remote projects
20664        self.update(cx, |project, cx| {
20665            if project
20666                .active_debug_session(cx)
20667                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20668            {
20669                return true;
20670            }
20671
20672            buffer.update(cx, |buffer, cx| {
20673                project.any_language_server_supports_inlay_hints(buffer, cx)
20674            })
20675        })
20676    }
20677
20678    fn inline_values(
20679        &self,
20680        buffer_handle: Entity<Buffer>,
20681
20682        range: Range<text::Anchor>,
20683        cx: &mut App,
20684    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20685        self.update(cx, |project, cx| {
20686            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20687
20688            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20689        })
20690    }
20691
20692    fn inlay_hints(
20693        &self,
20694        buffer_handle: Entity<Buffer>,
20695        range: Range<text::Anchor>,
20696        cx: &mut App,
20697    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20698        Some(self.update(cx, |project, cx| {
20699            project.inlay_hints(buffer_handle, range, cx)
20700        }))
20701    }
20702
20703    fn resolve_inlay_hint(
20704        &self,
20705        hint: InlayHint,
20706        buffer_handle: Entity<Buffer>,
20707        server_id: LanguageServerId,
20708        cx: &mut App,
20709    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20710        Some(self.update(cx, |project, cx| {
20711            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20712        }))
20713    }
20714
20715    fn range_for_rename(
20716        &self,
20717        buffer: &Entity<Buffer>,
20718        position: text::Anchor,
20719        cx: &mut App,
20720    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20721        Some(self.update(cx, |project, cx| {
20722            let buffer = buffer.clone();
20723            let task = project.prepare_rename(buffer.clone(), position, cx);
20724            cx.spawn(async move |_, cx| {
20725                Ok(match task.await? {
20726                    PrepareRenameResponse::Success(range) => Some(range),
20727                    PrepareRenameResponse::InvalidPosition => None,
20728                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20729                        // Fallback on using TreeSitter info to determine identifier range
20730                        buffer.read_with(cx, |buffer, _| {
20731                            let snapshot = buffer.snapshot();
20732                            let (range, kind) = snapshot.surrounding_word(position);
20733                            if kind != Some(CharKind::Word) {
20734                                return None;
20735                            }
20736                            Some(
20737                                snapshot.anchor_before(range.start)
20738                                    ..snapshot.anchor_after(range.end),
20739                            )
20740                        })?
20741                    }
20742                })
20743            })
20744        }))
20745    }
20746
20747    fn perform_rename(
20748        &self,
20749        buffer: &Entity<Buffer>,
20750        position: text::Anchor,
20751        new_name: String,
20752        cx: &mut App,
20753    ) -> Option<Task<Result<ProjectTransaction>>> {
20754        Some(self.update(cx, |project, cx| {
20755            project.perform_rename(buffer.clone(), position, new_name, cx)
20756        }))
20757    }
20758}
20759
20760fn inlay_hint_settings(
20761    location: Anchor,
20762    snapshot: &MultiBufferSnapshot,
20763    cx: &mut Context<Editor>,
20764) -> InlayHintSettings {
20765    let file = snapshot.file_at(location);
20766    let language = snapshot.language_at(location).map(|l| l.name());
20767    language_settings(language, file, cx).inlay_hints
20768}
20769
20770fn consume_contiguous_rows(
20771    contiguous_row_selections: &mut Vec<Selection<Point>>,
20772    selection: &Selection<Point>,
20773    display_map: &DisplaySnapshot,
20774    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20775) -> (MultiBufferRow, MultiBufferRow) {
20776    contiguous_row_selections.push(selection.clone());
20777    let start_row = MultiBufferRow(selection.start.row);
20778    let mut end_row = ending_row(selection, display_map);
20779
20780    while let Some(next_selection) = selections.peek() {
20781        if next_selection.start.row <= end_row.0 {
20782            end_row = ending_row(next_selection, display_map);
20783            contiguous_row_selections.push(selections.next().unwrap().clone());
20784        } else {
20785            break;
20786        }
20787    }
20788    (start_row, end_row)
20789}
20790
20791fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20792    if next_selection.end.column > 0 || next_selection.is_empty() {
20793        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20794    } else {
20795        MultiBufferRow(next_selection.end.row)
20796    }
20797}
20798
20799impl EditorSnapshot {
20800    pub fn remote_selections_in_range<'a>(
20801        &'a self,
20802        range: &'a Range<Anchor>,
20803        collaboration_hub: &dyn CollaborationHub,
20804        cx: &'a App,
20805    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20806        let participant_names = collaboration_hub.user_names(cx);
20807        let participant_indices = collaboration_hub.user_participant_indices(cx);
20808        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20809        let collaborators_by_replica_id = collaborators_by_peer_id
20810            .values()
20811            .map(|collaborator| (collaborator.replica_id, collaborator))
20812            .collect::<HashMap<_, _>>();
20813        self.buffer_snapshot
20814            .selections_in_range(range, false)
20815            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20816                if replica_id == AGENT_REPLICA_ID {
20817                    Some(RemoteSelection {
20818                        replica_id,
20819                        selection,
20820                        cursor_shape,
20821                        line_mode,
20822                        collaborator_id: CollaboratorId::Agent,
20823                        user_name: Some("Agent".into()),
20824                        color: cx.theme().players().agent(),
20825                    })
20826                } else {
20827                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20828                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20829                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20830                    Some(RemoteSelection {
20831                        replica_id,
20832                        selection,
20833                        cursor_shape,
20834                        line_mode,
20835                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20836                        user_name,
20837                        color: if let Some(index) = participant_index {
20838                            cx.theme().players().color_for_participant(index.0)
20839                        } else {
20840                            cx.theme().players().absent()
20841                        },
20842                    })
20843                }
20844            })
20845    }
20846
20847    pub fn hunks_for_ranges(
20848        &self,
20849        ranges: impl IntoIterator<Item = Range<Point>>,
20850    ) -> Vec<MultiBufferDiffHunk> {
20851        let mut hunks = Vec::new();
20852        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20853            HashMap::default();
20854        for query_range in ranges {
20855            let query_rows =
20856                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20857            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20858                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20859            ) {
20860                // Include deleted hunks that are adjacent to the query range, because
20861                // otherwise they would be missed.
20862                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20863                if hunk.status().is_deleted() {
20864                    intersects_range |= hunk.row_range.start == query_rows.end;
20865                    intersects_range |= hunk.row_range.end == query_rows.start;
20866                }
20867                if intersects_range {
20868                    if !processed_buffer_rows
20869                        .entry(hunk.buffer_id)
20870                        .or_default()
20871                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20872                    {
20873                        continue;
20874                    }
20875                    hunks.push(hunk);
20876                }
20877            }
20878        }
20879
20880        hunks
20881    }
20882
20883    fn display_diff_hunks_for_rows<'a>(
20884        &'a self,
20885        display_rows: Range<DisplayRow>,
20886        folded_buffers: &'a HashSet<BufferId>,
20887    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20888        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20889        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20890
20891        self.buffer_snapshot
20892            .diff_hunks_in_range(buffer_start..buffer_end)
20893            .filter_map(|hunk| {
20894                if folded_buffers.contains(&hunk.buffer_id) {
20895                    return None;
20896                }
20897
20898                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20899                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20900
20901                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20902                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20903
20904                let display_hunk = if hunk_display_start.column() != 0 {
20905                    DisplayDiffHunk::Folded {
20906                        display_row: hunk_display_start.row(),
20907                    }
20908                } else {
20909                    let mut end_row = hunk_display_end.row();
20910                    if hunk_display_end.column() > 0 {
20911                        end_row.0 += 1;
20912                    }
20913                    let is_created_file = hunk.is_created_file();
20914                    DisplayDiffHunk::Unfolded {
20915                        status: hunk.status(),
20916                        diff_base_byte_range: hunk.diff_base_byte_range,
20917                        display_row_range: hunk_display_start.row()..end_row,
20918                        multi_buffer_range: Anchor::range_in_buffer(
20919                            hunk.excerpt_id,
20920                            hunk.buffer_id,
20921                            hunk.buffer_range,
20922                        ),
20923                        is_created_file,
20924                    }
20925                };
20926
20927                Some(display_hunk)
20928            })
20929    }
20930
20931    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20932        self.display_snapshot.buffer_snapshot.language_at(position)
20933    }
20934
20935    pub fn is_focused(&self) -> bool {
20936        self.is_focused
20937    }
20938
20939    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20940        self.placeholder_text.as_ref()
20941    }
20942
20943    pub fn scroll_position(&self) -> gpui::Point<f32> {
20944        self.scroll_anchor.scroll_position(&self.display_snapshot)
20945    }
20946
20947    fn gutter_dimensions(
20948        &self,
20949        font_id: FontId,
20950        font_size: Pixels,
20951        max_line_number_width: Pixels,
20952        cx: &App,
20953    ) -> Option<GutterDimensions> {
20954        if !self.show_gutter {
20955            return None;
20956        }
20957
20958        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20959        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20960
20961        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20962            matches!(
20963                ProjectSettings::get_global(cx).git.git_gutter,
20964                Some(GitGutterSetting::TrackedFiles)
20965            )
20966        });
20967        let gutter_settings = EditorSettings::get_global(cx).gutter;
20968        let show_line_numbers = self
20969            .show_line_numbers
20970            .unwrap_or(gutter_settings.line_numbers);
20971        let line_gutter_width = if show_line_numbers {
20972            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20973            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20974            max_line_number_width.max(min_width_for_number_on_gutter)
20975        } else {
20976            0.0.into()
20977        };
20978
20979        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20980        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20981
20982        let git_blame_entries_width =
20983            self.git_blame_gutter_max_author_length
20984                .map(|max_author_length| {
20985                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20986                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20987
20988                    /// The number of characters to dedicate to gaps and margins.
20989                    const SPACING_WIDTH: usize = 4;
20990
20991                    let max_char_count = max_author_length.min(renderer.max_author_length())
20992                        + ::git::SHORT_SHA_LENGTH
20993                        + MAX_RELATIVE_TIMESTAMP.len()
20994                        + SPACING_WIDTH;
20995
20996                    em_advance * max_char_count
20997                });
20998
20999        let is_singleton = self.buffer_snapshot.is_singleton();
21000
21001        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21002        left_padding += if !is_singleton {
21003            em_width * 4.0
21004        } else if show_runnables || show_breakpoints {
21005            em_width * 3.0
21006        } else if show_git_gutter && show_line_numbers {
21007            em_width * 2.0
21008        } else if show_git_gutter || show_line_numbers {
21009            em_width
21010        } else {
21011            px(0.)
21012        };
21013
21014        let shows_folds = is_singleton && gutter_settings.folds;
21015
21016        let right_padding = if shows_folds && show_line_numbers {
21017            em_width * 4.0
21018        } else if shows_folds || (!is_singleton && show_line_numbers) {
21019            em_width * 3.0
21020        } else if show_line_numbers {
21021            em_width
21022        } else {
21023            px(0.)
21024        };
21025
21026        Some(GutterDimensions {
21027            left_padding,
21028            right_padding,
21029            width: line_gutter_width + left_padding + right_padding,
21030            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21031            git_blame_entries_width,
21032        })
21033    }
21034
21035    pub fn render_crease_toggle(
21036        &self,
21037        buffer_row: MultiBufferRow,
21038        row_contains_cursor: bool,
21039        editor: Entity<Editor>,
21040        window: &mut Window,
21041        cx: &mut App,
21042    ) -> Option<AnyElement> {
21043        let folded = self.is_line_folded(buffer_row);
21044        let mut is_foldable = false;
21045
21046        if let Some(crease) = self
21047            .crease_snapshot
21048            .query_row(buffer_row, &self.buffer_snapshot)
21049        {
21050            is_foldable = true;
21051            match crease {
21052                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21053                    if let Some(render_toggle) = render_toggle {
21054                        let toggle_callback =
21055                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21056                                if folded {
21057                                    editor.update(cx, |editor, cx| {
21058                                        editor.fold_at(buffer_row, window, cx)
21059                                    });
21060                                } else {
21061                                    editor.update(cx, |editor, cx| {
21062                                        editor.unfold_at(buffer_row, window, cx)
21063                                    });
21064                                }
21065                            });
21066                        return Some((render_toggle)(
21067                            buffer_row,
21068                            folded,
21069                            toggle_callback,
21070                            window,
21071                            cx,
21072                        ));
21073                    }
21074                }
21075            }
21076        }
21077
21078        is_foldable |= self.starts_indent(buffer_row);
21079
21080        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21081            Some(
21082                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21083                    .toggle_state(folded)
21084                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21085                        if folded {
21086                            this.unfold_at(buffer_row, window, cx);
21087                        } else {
21088                            this.fold_at(buffer_row, window, cx);
21089                        }
21090                    }))
21091                    .into_any_element(),
21092            )
21093        } else {
21094            None
21095        }
21096    }
21097
21098    pub fn render_crease_trailer(
21099        &self,
21100        buffer_row: MultiBufferRow,
21101        window: &mut Window,
21102        cx: &mut App,
21103    ) -> Option<AnyElement> {
21104        let folded = self.is_line_folded(buffer_row);
21105        if let Crease::Inline { render_trailer, .. } = self
21106            .crease_snapshot
21107            .query_row(buffer_row, &self.buffer_snapshot)?
21108        {
21109            let render_trailer = render_trailer.as_ref()?;
21110            Some(render_trailer(buffer_row, folded, window, cx))
21111        } else {
21112            None
21113        }
21114    }
21115}
21116
21117impl Deref for EditorSnapshot {
21118    type Target = DisplaySnapshot;
21119
21120    fn deref(&self) -> &Self::Target {
21121        &self.display_snapshot
21122    }
21123}
21124
21125#[derive(Clone, Debug, PartialEq, Eq)]
21126pub enum EditorEvent {
21127    InputIgnored {
21128        text: Arc<str>,
21129    },
21130    InputHandled {
21131        utf16_range_to_replace: Option<Range<isize>>,
21132        text: Arc<str>,
21133    },
21134    ExcerptsAdded {
21135        buffer: Entity<Buffer>,
21136        predecessor: ExcerptId,
21137        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21138    },
21139    ExcerptsRemoved {
21140        ids: Vec<ExcerptId>,
21141        removed_buffer_ids: Vec<BufferId>,
21142    },
21143    BufferFoldToggled {
21144        ids: Vec<ExcerptId>,
21145        folded: bool,
21146    },
21147    ExcerptsEdited {
21148        ids: Vec<ExcerptId>,
21149    },
21150    ExcerptsExpanded {
21151        ids: Vec<ExcerptId>,
21152    },
21153    BufferEdited,
21154    Edited {
21155        transaction_id: clock::Lamport,
21156    },
21157    Reparsed(BufferId),
21158    Focused,
21159    FocusedIn,
21160    Blurred,
21161    DirtyChanged,
21162    Saved,
21163    TitleChanged,
21164    DiffBaseChanged,
21165    SelectionsChanged {
21166        local: bool,
21167    },
21168    ScrollPositionChanged {
21169        local: bool,
21170        autoscroll: bool,
21171    },
21172    Closed,
21173    TransactionUndone {
21174        transaction_id: clock::Lamport,
21175    },
21176    TransactionBegun {
21177        transaction_id: clock::Lamport,
21178    },
21179    Reloaded,
21180    CursorShapeChanged,
21181    PushedToNavHistory {
21182        anchor: Anchor,
21183        is_deactivate: bool,
21184    },
21185}
21186
21187impl EventEmitter<EditorEvent> for Editor {}
21188
21189impl Focusable for Editor {
21190    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21191        self.focus_handle.clone()
21192    }
21193}
21194
21195impl Render for Editor {
21196    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21197        let settings = ThemeSettings::get_global(cx);
21198
21199        let mut text_style = match self.mode {
21200            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21201                color: cx.theme().colors().editor_foreground,
21202                font_family: settings.ui_font.family.clone(),
21203                font_features: settings.ui_font.features.clone(),
21204                font_fallbacks: settings.ui_font.fallbacks.clone(),
21205                font_size: rems(0.875).into(),
21206                font_weight: settings.ui_font.weight,
21207                line_height: relative(settings.buffer_line_height.value()),
21208                ..Default::default()
21209            },
21210            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21211                color: cx.theme().colors().editor_foreground,
21212                font_family: settings.buffer_font.family.clone(),
21213                font_features: settings.buffer_font.features.clone(),
21214                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21215                font_size: settings.buffer_font_size(cx).into(),
21216                font_weight: settings.buffer_font.weight,
21217                line_height: relative(settings.buffer_line_height.value()),
21218                ..Default::default()
21219            },
21220        };
21221        if let Some(text_style_refinement) = &self.text_style_refinement {
21222            text_style.refine(text_style_refinement)
21223        }
21224
21225        let background = match self.mode {
21226            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21227            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21228            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21229            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21230        };
21231
21232        EditorElement::new(
21233            &cx.entity(),
21234            EditorStyle {
21235                background,
21236                local_player: cx.theme().players().local(),
21237                text: text_style,
21238                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21239                syntax: cx.theme().syntax().clone(),
21240                status: cx.theme().status().clone(),
21241                inlay_hints_style: make_inlay_hints_style(cx),
21242                inline_completion_styles: make_suggestion_styles(cx),
21243                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21244                show_underlines: !self.mode.is_minimap(),
21245            },
21246        )
21247    }
21248}
21249
21250impl EntityInputHandler for Editor {
21251    fn text_for_range(
21252        &mut self,
21253        range_utf16: Range<usize>,
21254        adjusted_range: &mut Option<Range<usize>>,
21255        _: &mut Window,
21256        cx: &mut Context<Self>,
21257    ) -> Option<String> {
21258        let snapshot = self.buffer.read(cx).read(cx);
21259        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21260        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21261        if (start.0..end.0) != range_utf16 {
21262            adjusted_range.replace(start.0..end.0);
21263        }
21264        Some(snapshot.text_for_range(start..end).collect())
21265    }
21266
21267    fn selected_text_range(
21268        &mut self,
21269        ignore_disabled_input: bool,
21270        _: &mut Window,
21271        cx: &mut Context<Self>,
21272    ) -> Option<UTF16Selection> {
21273        // Prevent the IME menu from appearing when holding down an alphabetic key
21274        // while input is disabled.
21275        if !ignore_disabled_input && !self.input_enabled {
21276            return None;
21277        }
21278
21279        let selection = self.selections.newest::<OffsetUtf16>(cx);
21280        let range = selection.range();
21281
21282        Some(UTF16Selection {
21283            range: range.start.0..range.end.0,
21284            reversed: selection.reversed,
21285        })
21286    }
21287
21288    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21289        let snapshot = self.buffer.read(cx).read(cx);
21290        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21291        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21292    }
21293
21294    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21295        self.clear_highlights::<InputComposition>(cx);
21296        self.ime_transaction.take();
21297    }
21298
21299    fn replace_text_in_range(
21300        &mut self,
21301        range_utf16: Option<Range<usize>>,
21302        text: &str,
21303        window: &mut Window,
21304        cx: &mut Context<Self>,
21305    ) {
21306        if !self.input_enabled {
21307            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21308            return;
21309        }
21310
21311        self.transact(window, cx, |this, window, cx| {
21312            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21313                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21314                Some(this.selection_replacement_ranges(range_utf16, cx))
21315            } else {
21316                this.marked_text_ranges(cx)
21317            };
21318
21319            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21320                let newest_selection_id = this.selections.newest_anchor().id;
21321                this.selections
21322                    .all::<OffsetUtf16>(cx)
21323                    .iter()
21324                    .zip(ranges_to_replace.iter())
21325                    .find_map(|(selection, range)| {
21326                        if selection.id == newest_selection_id {
21327                            Some(
21328                                (range.start.0 as isize - selection.head().0 as isize)
21329                                    ..(range.end.0 as isize - selection.head().0 as isize),
21330                            )
21331                        } else {
21332                            None
21333                        }
21334                    })
21335            });
21336
21337            cx.emit(EditorEvent::InputHandled {
21338                utf16_range_to_replace: range_to_replace,
21339                text: text.into(),
21340            });
21341
21342            if let Some(new_selected_ranges) = new_selected_ranges {
21343                this.change_selections(None, window, cx, |selections| {
21344                    selections.select_ranges(new_selected_ranges)
21345                });
21346                this.backspace(&Default::default(), window, cx);
21347            }
21348
21349            this.handle_input(text, window, cx);
21350        });
21351
21352        if let Some(transaction) = self.ime_transaction {
21353            self.buffer.update(cx, |buffer, cx| {
21354                buffer.group_until_transaction(transaction, cx);
21355            });
21356        }
21357
21358        self.unmark_text(window, cx);
21359    }
21360
21361    fn replace_and_mark_text_in_range(
21362        &mut self,
21363        range_utf16: Option<Range<usize>>,
21364        text: &str,
21365        new_selected_range_utf16: Option<Range<usize>>,
21366        window: &mut Window,
21367        cx: &mut Context<Self>,
21368    ) {
21369        if !self.input_enabled {
21370            return;
21371        }
21372
21373        let transaction = self.transact(window, cx, |this, window, cx| {
21374            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21375                let snapshot = this.buffer.read(cx).read(cx);
21376                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21377                    for marked_range in &mut marked_ranges {
21378                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21379                        marked_range.start.0 += relative_range_utf16.start;
21380                        marked_range.start =
21381                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21382                        marked_range.end =
21383                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21384                    }
21385                }
21386                Some(marked_ranges)
21387            } else if let Some(range_utf16) = range_utf16 {
21388                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21389                Some(this.selection_replacement_ranges(range_utf16, cx))
21390            } else {
21391                None
21392            };
21393
21394            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21395                let newest_selection_id = this.selections.newest_anchor().id;
21396                this.selections
21397                    .all::<OffsetUtf16>(cx)
21398                    .iter()
21399                    .zip(ranges_to_replace.iter())
21400                    .find_map(|(selection, range)| {
21401                        if selection.id == newest_selection_id {
21402                            Some(
21403                                (range.start.0 as isize - selection.head().0 as isize)
21404                                    ..(range.end.0 as isize - selection.head().0 as isize),
21405                            )
21406                        } else {
21407                            None
21408                        }
21409                    })
21410            });
21411
21412            cx.emit(EditorEvent::InputHandled {
21413                utf16_range_to_replace: range_to_replace,
21414                text: text.into(),
21415            });
21416
21417            if let Some(ranges) = ranges_to_replace {
21418                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21419            }
21420
21421            let marked_ranges = {
21422                let snapshot = this.buffer.read(cx).read(cx);
21423                this.selections
21424                    .disjoint_anchors()
21425                    .iter()
21426                    .map(|selection| {
21427                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21428                    })
21429                    .collect::<Vec<_>>()
21430            };
21431
21432            if text.is_empty() {
21433                this.unmark_text(window, cx);
21434            } else {
21435                this.highlight_text::<InputComposition>(
21436                    marked_ranges.clone(),
21437                    HighlightStyle {
21438                        underline: Some(UnderlineStyle {
21439                            thickness: px(1.),
21440                            color: None,
21441                            wavy: false,
21442                        }),
21443                        ..Default::default()
21444                    },
21445                    cx,
21446                );
21447            }
21448
21449            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21450            let use_autoclose = this.use_autoclose;
21451            let use_auto_surround = this.use_auto_surround;
21452            this.set_use_autoclose(false);
21453            this.set_use_auto_surround(false);
21454            this.handle_input(text, window, cx);
21455            this.set_use_autoclose(use_autoclose);
21456            this.set_use_auto_surround(use_auto_surround);
21457
21458            if let Some(new_selected_range) = new_selected_range_utf16 {
21459                let snapshot = this.buffer.read(cx).read(cx);
21460                let new_selected_ranges = marked_ranges
21461                    .into_iter()
21462                    .map(|marked_range| {
21463                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21464                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21465                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21466                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21467                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21468                    })
21469                    .collect::<Vec<_>>();
21470
21471                drop(snapshot);
21472                this.change_selections(None, window, cx, |selections| {
21473                    selections.select_ranges(new_selected_ranges)
21474                });
21475            }
21476        });
21477
21478        self.ime_transaction = self.ime_transaction.or(transaction);
21479        if let Some(transaction) = self.ime_transaction {
21480            self.buffer.update(cx, |buffer, cx| {
21481                buffer.group_until_transaction(transaction, cx);
21482            });
21483        }
21484
21485        if self.text_highlights::<InputComposition>(cx).is_none() {
21486            self.ime_transaction.take();
21487        }
21488    }
21489
21490    fn bounds_for_range(
21491        &mut self,
21492        range_utf16: Range<usize>,
21493        element_bounds: gpui::Bounds<Pixels>,
21494        window: &mut Window,
21495        cx: &mut Context<Self>,
21496    ) -> Option<gpui::Bounds<Pixels>> {
21497        let text_layout_details = self.text_layout_details(window);
21498        let gpui::Size {
21499            width: em_width,
21500            height: line_height,
21501        } = self.character_size(window);
21502
21503        let snapshot = self.snapshot(window, cx);
21504        let scroll_position = snapshot.scroll_position();
21505        let scroll_left = scroll_position.x * em_width;
21506
21507        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21508        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21509            + self.gutter_dimensions.width
21510            + self.gutter_dimensions.margin;
21511        let y = line_height * (start.row().as_f32() - scroll_position.y);
21512
21513        Some(Bounds {
21514            origin: element_bounds.origin + point(x, y),
21515            size: size(em_width, line_height),
21516        })
21517    }
21518
21519    fn character_index_for_point(
21520        &mut self,
21521        point: gpui::Point<Pixels>,
21522        _window: &mut Window,
21523        _cx: &mut Context<Self>,
21524    ) -> Option<usize> {
21525        let position_map = self.last_position_map.as_ref()?;
21526        if !position_map.text_hitbox.contains(&point) {
21527            return None;
21528        }
21529        let display_point = position_map.point_for_position(point).previous_valid;
21530        let anchor = position_map
21531            .snapshot
21532            .display_point_to_anchor(display_point, Bias::Left);
21533        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21534        Some(utf16_offset.0)
21535    }
21536}
21537
21538trait SelectionExt {
21539    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21540    fn spanned_rows(
21541        &self,
21542        include_end_if_at_line_start: bool,
21543        map: &DisplaySnapshot,
21544    ) -> Range<MultiBufferRow>;
21545}
21546
21547impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21548    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21549        let start = self
21550            .start
21551            .to_point(&map.buffer_snapshot)
21552            .to_display_point(map);
21553        let end = self
21554            .end
21555            .to_point(&map.buffer_snapshot)
21556            .to_display_point(map);
21557        if self.reversed {
21558            end..start
21559        } else {
21560            start..end
21561        }
21562    }
21563
21564    fn spanned_rows(
21565        &self,
21566        include_end_if_at_line_start: bool,
21567        map: &DisplaySnapshot,
21568    ) -> Range<MultiBufferRow> {
21569        let start = self.start.to_point(&map.buffer_snapshot);
21570        let mut end = self.end.to_point(&map.buffer_snapshot);
21571        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21572            end.row -= 1;
21573        }
21574
21575        let buffer_start = map.prev_line_boundary(start).0;
21576        let buffer_end = map.next_line_boundary(end).0;
21577        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21578    }
21579}
21580
21581impl<T: InvalidationRegion> InvalidationStack<T> {
21582    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21583    where
21584        S: Clone + ToOffset,
21585    {
21586        while let Some(region) = self.last() {
21587            let all_selections_inside_invalidation_ranges =
21588                if selections.len() == region.ranges().len() {
21589                    selections
21590                        .iter()
21591                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21592                        .all(|(selection, invalidation_range)| {
21593                            let head = selection.head().to_offset(buffer);
21594                            invalidation_range.start <= head && invalidation_range.end >= head
21595                        })
21596                } else {
21597                    false
21598                };
21599
21600            if all_selections_inside_invalidation_ranges {
21601                break;
21602            } else {
21603                self.pop();
21604            }
21605        }
21606    }
21607}
21608
21609impl<T> Default for InvalidationStack<T> {
21610    fn default() -> Self {
21611        Self(Default::default())
21612    }
21613}
21614
21615impl<T> Deref for InvalidationStack<T> {
21616    type Target = Vec<T>;
21617
21618    fn deref(&self) -> &Self::Target {
21619        &self.0
21620    }
21621}
21622
21623impl<T> DerefMut for InvalidationStack<T> {
21624    fn deref_mut(&mut self) -> &mut Self::Target {
21625        &mut self.0
21626    }
21627}
21628
21629impl InvalidationRegion for SnippetState {
21630    fn ranges(&self) -> &[Range<Anchor>] {
21631        &self.ranges[self.active_index]
21632    }
21633}
21634
21635fn inline_completion_edit_text(
21636    current_snapshot: &BufferSnapshot,
21637    edits: &[(Range<Anchor>, String)],
21638    edit_preview: &EditPreview,
21639    include_deletions: bool,
21640    cx: &App,
21641) -> HighlightedText {
21642    let edits = edits
21643        .iter()
21644        .map(|(anchor, text)| {
21645            (
21646                anchor.start.text_anchor..anchor.end.text_anchor,
21647                text.clone(),
21648            )
21649        })
21650        .collect::<Vec<_>>();
21651
21652    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21653}
21654
21655pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21656    match severity {
21657        lsp::DiagnosticSeverity::ERROR => colors.error,
21658        lsp::DiagnosticSeverity::WARNING => colors.warning,
21659        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21660        lsp::DiagnosticSeverity::HINT => colors.info,
21661        _ => colors.ignored,
21662    }
21663}
21664
21665pub fn styled_runs_for_code_label<'a>(
21666    label: &'a CodeLabel,
21667    syntax_theme: &'a theme::SyntaxTheme,
21668) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21669    let fade_out = HighlightStyle {
21670        fade_out: Some(0.35),
21671        ..Default::default()
21672    };
21673
21674    let mut prev_end = label.filter_range.end;
21675    label
21676        .runs
21677        .iter()
21678        .enumerate()
21679        .flat_map(move |(ix, (range, highlight_id))| {
21680            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21681                style
21682            } else {
21683                return Default::default();
21684            };
21685            let mut muted_style = style;
21686            muted_style.highlight(fade_out);
21687
21688            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21689            if range.start >= label.filter_range.end {
21690                if range.start > prev_end {
21691                    runs.push((prev_end..range.start, fade_out));
21692                }
21693                runs.push((range.clone(), muted_style));
21694            } else if range.end <= label.filter_range.end {
21695                runs.push((range.clone(), style));
21696            } else {
21697                runs.push((range.start..label.filter_range.end, style));
21698                runs.push((label.filter_range.end..range.end, muted_style));
21699            }
21700            prev_end = cmp::max(prev_end, range.end);
21701
21702            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21703                runs.push((prev_end..label.text.len(), fade_out));
21704            }
21705
21706            runs
21707        })
21708}
21709
21710pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21711    let mut prev_index = 0;
21712    let mut prev_codepoint: Option<char> = None;
21713    text.char_indices()
21714        .chain([(text.len(), '\0')])
21715        .filter_map(move |(index, codepoint)| {
21716            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21717            let is_boundary = index == text.len()
21718                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21719                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21720            if is_boundary {
21721                let chunk = &text[prev_index..index];
21722                prev_index = index;
21723                Some(chunk)
21724            } else {
21725                None
21726            }
21727        })
21728}
21729
21730pub trait RangeToAnchorExt: Sized {
21731    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21732
21733    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21734        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21735        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21736    }
21737}
21738
21739impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21740    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21741        let start_offset = self.start.to_offset(snapshot);
21742        let end_offset = self.end.to_offset(snapshot);
21743        if start_offset == end_offset {
21744            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21745        } else {
21746            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21747        }
21748    }
21749}
21750
21751pub trait RowExt {
21752    fn as_f32(&self) -> f32;
21753
21754    fn next_row(&self) -> Self;
21755
21756    fn previous_row(&self) -> Self;
21757
21758    fn minus(&self, other: Self) -> u32;
21759}
21760
21761impl RowExt for DisplayRow {
21762    fn as_f32(&self) -> f32 {
21763        self.0 as f32
21764    }
21765
21766    fn next_row(&self) -> Self {
21767        Self(self.0 + 1)
21768    }
21769
21770    fn previous_row(&self) -> Self {
21771        Self(self.0.saturating_sub(1))
21772    }
21773
21774    fn minus(&self, other: Self) -> u32 {
21775        self.0 - other.0
21776    }
21777}
21778
21779impl RowExt for MultiBufferRow {
21780    fn as_f32(&self) -> f32 {
21781        self.0 as f32
21782    }
21783
21784    fn next_row(&self) -> Self {
21785        Self(self.0 + 1)
21786    }
21787
21788    fn previous_row(&self) -> Self {
21789        Self(self.0.saturating_sub(1))
21790    }
21791
21792    fn minus(&self, other: Self) -> u32 {
21793        self.0 - other.0
21794    }
21795}
21796
21797trait RowRangeExt {
21798    type Row;
21799
21800    fn len(&self) -> usize;
21801
21802    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21803}
21804
21805impl RowRangeExt for Range<MultiBufferRow> {
21806    type Row = MultiBufferRow;
21807
21808    fn len(&self) -> usize {
21809        (self.end.0 - self.start.0) as usize
21810    }
21811
21812    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21813        (self.start.0..self.end.0).map(MultiBufferRow)
21814    }
21815}
21816
21817impl RowRangeExt for Range<DisplayRow> {
21818    type Row = DisplayRow;
21819
21820    fn len(&self) -> usize {
21821        (self.end.0 - self.start.0) as usize
21822    }
21823
21824    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21825        (self.start.0..self.end.0).map(DisplayRow)
21826    }
21827}
21828
21829/// If select range has more than one line, we
21830/// just point the cursor to range.start.
21831fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21832    if range.start.row == range.end.row {
21833        range
21834    } else {
21835        range.start..range.start
21836    }
21837}
21838pub struct KillRing(ClipboardItem);
21839impl Global for KillRing {}
21840
21841const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21842
21843enum BreakpointPromptEditAction {
21844    Log,
21845    Condition,
21846    HitCondition,
21847}
21848
21849struct BreakpointPromptEditor {
21850    pub(crate) prompt: Entity<Editor>,
21851    editor: WeakEntity<Editor>,
21852    breakpoint_anchor: Anchor,
21853    breakpoint: Breakpoint,
21854    edit_action: BreakpointPromptEditAction,
21855    block_ids: HashSet<CustomBlockId>,
21856    editor_margins: Arc<Mutex<EditorMargins>>,
21857    _subscriptions: Vec<Subscription>,
21858}
21859
21860impl BreakpointPromptEditor {
21861    const MAX_LINES: u8 = 4;
21862
21863    fn new(
21864        editor: WeakEntity<Editor>,
21865        breakpoint_anchor: Anchor,
21866        breakpoint: Breakpoint,
21867        edit_action: BreakpointPromptEditAction,
21868        window: &mut Window,
21869        cx: &mut Context<Self>,
21870    ) -> Self {
21871        let base_text = match edit_action {
21872            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21873            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21874            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21875        }
21876        .map(|msg| msg.to_string())
21877        .unwrap_or_default();
21878
21879        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21880        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21881
21882        let prompt = cx.new(|cx| {
21883            let mut prompt = Editor::new(
21884                EditorMode::AutoHeight {
21885                    max_lines: Self::MAX_LINES as usize,
21886                },
21887                buffer,
21888                None,
21889                window,
21890                cx,
21891            );
21892            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21893            prompt.set_show_cursor_when_unfocused(false, cx);
21894            prompt.set_placeholder_text(
21895                match edit_action {
21896                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21897                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21898                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21899                },
21900                cx,
21901            );
21902
21903            prompt
21904        });
21905
21906        Self {
21907            prompt,
21908            editor,
21909            breakpoint_anchor,
21910            breakpoint,
21911            edit_action,
21912            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21913            block_ids: Default::default(),
21914            _subscriptions: vec![],
21915        }
21916    }
21917
21918    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21919        self.block_ids.extend(block_ids)
21920    }
21921
21922    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21923        if let Some(editor) = self.editor.upgrade() {
21924            let message = self
21925                .prompt
21926                .read(cx)
21927                .buffer
21928                .read(cx)
21929                .as_singleton()
21930                .expect("A multi buffer in breakpoint prompt isn't possible")
21931                .read(cx)
21932                .as_rope()
21933                .to_string();
21934
21935            editor.update(cx, |editor, cx| {
21936                editor.edit_breakpoint_at_anchor(
21937                    self.breakpoint_anchor,
21938                    self.breakpoint.clone(),
21939                    match self.edit_action {
21940                        BreakpointPromptEditAction::Log => {
21941                            BreakpointEditAction::EditLogMessage(message.into())
21942                        }
21943                        BreakpointPromptEditAction::Condition => {
21944                            BreakpointEditAction::EditCondition(message.into())
21945                        }
21946                        BreakpointPromptEditAction::HitCondition => {
21947                            BreakpointEditAction::EditHitCondition(message.into())
21948                        }
21949                    },
21950                    cx,
21951                );
21952
21953                editor.remove_blocks(self.block_ids.clone(), None, cx);
21954                cx.focus_self(window);
21955            });
21956        }
21957    }
21958
21959    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21960        self.editor
21961            .update(cx, |editor, cx| {
21962                editor.remove_blocks(self.block_ids.clone(), None, cx);
21963                window.focus(&editor.focus_handle);
21964            })
21965            .log_err();
21966    }
21967
21968    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21969        let settings = ThemeSettings::get_global(cx);
21970        let text_style = TextStyle {
21971            color: if self.prompt.read(cx).read_only(cx) {
21972                cx.theme().colors().text_disabled
21973            } else {
21974                cx.theme().colors().text
21975            },
21976            font_family: settings.buffer_font.family.clone(),
21977            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21978            font_size: settings.buffer_font_size(cx).into(),
21979            font_weight: settings.buffer_font.weight,
21980            line_height: relative(settings.buffer_line_height.value()),
21981            ..Default::default()
21982        };
21983        EditorElement::new(
21984            &self.prompt,
21985            EditorStyle {
21986                background: cx.theme().colors().editor_background,
21987                local_player: cx.theme().players().local(),
21988                text: text_style,
21989                ..Default::default()
21990            },
21991        )
21992    }
21993}
21994
21995impl Render for BreakpointPromptEditor {
21996    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21997        let editor_margins = *self.editor_margins.lock();
21998        let gutter_dimensions = editor_margins.gutter;
21999        h_flex()
22000            .key_context("Editor")
22001            .bg(cx.theme().colors().editor_background)
22002            .border_y_1()
22003            .border_color(cx.theme().status().info_border)
22004            .size_full()
22005            .py(window.line_height() / 2.5)
22006            .on_action(cx.listener(Self::confirm))
22007            .on_action(cx.listener(Self::cancel))
22008            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22009            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22010    }
22011}
22012
22013impl Focusable for BreakpointPromptEditor {
22014    fn focus_handle(&self, cx: &App) -> FocusHandle {
22015        self.prompt.focus_handle(cx)
22016    }
22017}
22018
22019fn all_edits_insertions_or_deletions(
22020    edits: &Vec<(Range<Anchor>, String)>,
22021    snapshot: &MultiBufferSnapshot,
22022) -> bool {
22023    let mut all_insertions = true;
22024    let mut all_deletions = true;
22025
22026    for (range, new_text) in edits.iter() {
22027        let range_is_empty = range.to_offset(&snapshot).is_empty();
22028        let text_is_empty = new_text.is_empty();
22029
22030        if range_is_empty != text_is_empty {
22031            if range_is_empty {
22032                all_deletions = false;
22033            } else {
22034                all_insertions = false;
22035            }
22036        } else {
22037            return false;
22038        }
22039
22040        if !all_insertions && !all_deletions {
22041            return false;
22042        }
22043    }
22044    all_insertions || all_deletions
22045}
22046
22047struct MissingEditPredictionKeybindingTooltip;
22048
22049impl Render for MissingEditPredictionKeybindingTooltip {
22050    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22051        ui::tooltip_container(window, cx, |container, _, cx| {
22052            container
22053                .flex_shrink_0()
22054                .max_w_80()
22055                .min_h(rems_from_px(124.))
22056                .justify_between()
22057                .child(
22058                    v_flex()
22059                        .flex_1()
22060                        .text_ui_sm(cx)
22061                        .child(Label::new("Conflict with Accept Keybinding"))
22062                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22063                )
22064                .child(
22065                    h_flex()
22066                        .pb_1()
22067                        .gap_1()
22068                        .items_end()
22069                        .w_full()
22070                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22071                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22072                        }))
22073                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22074                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22075                        })),
22076                )
22077        })
22078    }
22079}
22080
22081#[derive(Debug, Clone, Copy, PartialEq)]
22082pub struct LineHighlight {
22083    pub background: Background,
22084    pub border: Option<gpui::Hsla>,
22085    pub include_gutter: bool,
22086    pub type_id: Option<TypeId>,
22087}
22088
22089fn render_diff_hunk_controls(
22090    row: u32,
22091    status: &DiffHunkStatus,
22092    hunk_range: Range<Anchor>,
22093    is_created_file: bool,
22094    line_height: Pixels,
22095    editor: &Entity<Editor>,
22096    _window: &mut Window,
22097    cx: &mut App,
22098) -> AnyElement {
22099    h_flex()
22100        .h(line_height)
22101        .mr_1()
22102        .gap_1()
22103        .px_0p5()
22104        .pb_1()
22105        .border_x_1()
22106        .border_b_1()
22107        .border_color(cx.theme().colors().border_variant)
22108        .rounded_b_lg()
22109        .bg(cx.theme().colors().editor_background)
22110        .gap_1()
22111        .block_mouse_except_scroll()
22112        .shadow_md()
22113        .child(if status.has_secondary_hunk() {
22114            Button::new(("stage", row as u64), "Stage")
22115                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22116                .tooltip({
22117                    let focus_handle = editor.focus_handle(cx);
22118                    move |window, cx| {
22119                        Tooltip::for_action_in(
22120                            "Stage Hunk",
22121                            &::git::ToggleStaged,
22122                            &focus_handle,
22123                            window,
22124                            cx,
22125                        )
22126                    }
22127                })
22128                .on_click({
22129                    let editor = editor.clone();
22130                    move |_event, _window, cx| {
22131                        editor.update(cx, |editor, cx| {
22132                            editor.stage_or_unstage_diff_hunks(
22133                                true,
22134                                vec![hunk_range.start..hunk_range.start],
22135                                cx,
22136                            );
22137                        });
22138                    }
22139                })
22140        } else {
22141            Button::new(("unstage", row as u64), "Unstage")
22142                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22143                .tooltip({
22144                    let focus_handle = editor.focus_handle(cx);
22145                    move |window, cx| {
22146                        Tooltip::for_action_in(
22147                            "Unstage Hunk",
22148                            &::git::ToggleStaged,
22149                            &focus_handle,
22150                            window,
22151                            cx,
22152                        )
22153                    }
22154                })
22155                .on_click({
22156                    let editor = editor.clone();
22157                    move |_event, _window, cx| {
22158                        editor.update(cx, |editor, cx| {
22159                            editor.stage_or_unstage_diff_hunks(
22160                                false,
22161                                vec![hunk_range.start..hunk_range.start],
22162                                cx,
22163                            );
22164                        });
22165                    }
22166                })
22167        })
22168        .child(
22169            Button::new(("restore", row as u64), "Restore")
22170                .tooltip({
22171                    let focus_handle = editor.focus_handle(cx);
22172                    move |window, cx| {
22173                        Tooltip::for_action_in(
22174                            "Restore Hunk",
22175                            &::git::Restore,
22176                            &focus_handle,
22177                            window,
22178                            cx,
22179                        )
22180                    }
22181                })
22182                .on_click({
22183                    let editor = editor.clone();
22184                    move |_event, window, cx| {
22185                        editor.update(cx, |editor, cx| {
22186                            let snapshot = editor.snapshot(window, cx);
22187                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22188                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22189                        });
22190                    }
22191                })
22192                .disabled(is_created_file),
22193        )
22194        .when(
22195            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22196            |el| {
22197                el.child(
22198                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22199                        .shape(IconButtonShape::Square)
22200                        .icon_size(IconSize::Small)
22201                        // .disabled(!has_multiple_hunks)
22202                        .tooltip({
22203                            let focus_handle = editor.focus_handle(cx);
22204                            move |window, cx| {
22205                                Tooltip::for_action_in(
22206                                    "Next Hunk",
22207                                    &GoToHunk,
22208                                    &focus_handle,
22209                                    window,
22210                                    cx,
22211                                )
22212                            }
22213                        })
22214                        .on_click({
22215                            let editor = editor.clone();
22216                            move |_event, window, cx| {
22217                                editor.update(cx, |editor, cx| {
22218                                    let snapshot = editor.snapshot(window, cx);
22219                                    let position =
22220                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22221                                    editor.go_to_hunk_before_or_after_position(
22222                                        &snapshot,
22223                                        position,
22224                                        Direction::Next,
22225                                        window,
22226                                        cx,
22227                                    );
22228                                    editor.expand_selected_diff_hunks(cx);
22229                                });
22230                            }
22231                        }),
22232                )
22233                .child(
22234                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22235                        .shape(IconButtonShape::Square)
22236                        .icon_size(IconSize::Small)
22237                        // .disabled(!has_multiple_hunks)
22238                        .tooltip({
22239                            let focus_handle = editor.focus_handle(cx);
22240                            move |window, cx| {
22241                                Tooltip::for_action_in(
22242                                    "Previous Hunk",
22243                                    &GoToPreviousHunk,
22244                                    &focus_handle,
22245                                    window,
22246                                    cx,
22247                                )
22248                            }
22249                        })
22250                        .on_click({
22251                            let editor = editor.clone();
22252                            move |_event, window, cx| {
22253                                editor.update(cx, |editor, cx| {
22254                                    let snapshot = editor.snapshot(window, cx);
22255                                    let point =
22256                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22257                                    editor.go_to_hunk_before_or_after_position(
22258                                        &snapshot,
22259                                        point,
22260                                        Direction::Prev,
22261                                        window,
22262                                        cx,
22263                                    );
22264                                    editor.expand_selected_diff_hunks(cx);
22265                                });
22266                            }
22267                        }),
22268                )
22269            },
22270        )
22271        .into_any_element()
22272}