editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   77use futures::{
   78    FutureExt, StreamExt as _,
   79    future::{self, Shared, join},
   80    stream::FuturesUnordered,
   81};
   82use fuzzy::{StringMatch, StringMatchCandidate};
   83use lsp_colors::LspColorData;
   84
   85use ::git::blame::BlameEntry;
   86use ::git::{Restore, blame::ParsedCommitMessage};
   87use code_context_menus::{
   88    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   89    CompletionsMenu, ContextMenuOrigin,
   90};
   91use git::blame::{GitBlame, GlobalBlameRenderer};
   92use gpui::{
   93    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   94    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   95    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   96    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   97    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   98    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   99    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  100    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
  101};
  102use highlight_matching_bracket::refresh_matching_bracket_highlights;
  103use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  104pub use hover_popover::hover_markdown_style;
  105use hover_popover::{HoverState, hide_hover};
  106use indent_guides::ActiveIndentGuidesState;
  107use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  108pub use inline_completion::Direction;
  109use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  110pub use items::MAX_TAB_TITLE_LEN;
  111use itertools::Itertools;
  112use language::{
  113    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  114    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  115    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  116    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  117    language_settings::{
  118        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  119        all_language_settings, language_settings,
  120    },
  121    point_from_lsp, text_diff_with_options,
  122};
  123use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  124use linked_editing_ranges::refresh_linked_ranges;
  125use markdown::Markdown;
  126use mouse_context_menu::MouseContextMenu;
  127use persistence::DB;
  128use project::{
  129    BreakpointWithPosition, CompletionResponse, ProjectPath,
  130    debugger::{
  131        breakpoint_store::{
  132            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  133            BreakpointStoreEvent,
  134        },
  135        session::{Session, SessionEvent},
  136    },
  137    project_settings::DiagnosticSeverity,
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    hover_links::{find_url, find_url_from_range},
  220};
  221use crate::{
  222    editor_settings::MultiCursorModifier,
  223    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  224};
  225
  226pub const FILE_HEADER_HEIGHT: u32 = 2;
  227pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  228pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241
  242pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  243pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  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    DebuggerValue(usize),
  279    // LSP
  280    Hint(usize),
  281    Color(usize),
  282}
  283
  284impl InlayId {
  285    fn id(&self) -> usize {
  286        match self {
  287            Self::InlineCompletion(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::Color(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300pub enum PendingInput {}
  301enum SelectedTextHighlight {}
  302
  303pub enum ConflictsOuter {}
  304pub enum ConflictsOurs {}
  305pub enum ConflictsTheirs {}
  306pub enum ConflictsOursMarker {}
  307pub enum ConflictsTheirsMarker {}
  308
  309#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  310pub enum Navigated {
  311    Yes,
  312    No,
  313}
  314
  315impl Navigated {
  316    pub fn from_bool(yes: bool) -> Navigated {
  317        if yes { Navigated::Yes } else { Navigated::No }
  318    }
  319}
  320
  321#[derive(Debug, Clone, PartialEq, Eq)]
  322enum DisplayDiffHunk {
  323    Folded {
  324        display_row: DisplayRow,
  325    },
  326    Unfolded {
  327        is_created_file: bool,
  328        diff_base_byte_range: Range<usize>,
  329        display_row_range: Range<DisplayRow>,
  330        multi_buffer_range: Range<Anchor>,
  331        status: DiffHunkStatus,
  332    },
  333}
  334
  335pub enum HideMouseCursorOrigin {
  336    TypingAction,
  337    MovementAction,
  338}
  339
  340pub fn init_settings(cx: &mut App) {
  341    EditorSettings::register(cx);
  342}
  343
  344pub fn init(cx: &mut App) {
  345    init_settings(cx);
  346
  347    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  348
  349    workspace::register_project_item::<Editor>(cx);
  350    workspace::FollowableViewRegistry::register::<Editor>(cx);
  351    workspace::register_serializable_item::<Editor>(cx);
  352
  353    cx.observe_new(
  354        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  355            workspace.register_action(Editor::new_file);
  356            workspace.register_action(Editor::new_file_vertical);
  357            workspace.register_action(Editor::new_file_horizontal);
  358            workspace.register_action(Editor::cancel_language_server_work);
  359        },
  360    )
  361    .detach();
  362
  363    cx.on_action(move |_: &workspace::NewFile, cx| {
  364        let app_state = workspace::AppState::global(cx);
  365        if let Some(app_state) = app_state.upgrade() {
  366            workspace::open_new(
  367                Default::default(),
  368                app_state,
  369                cx,
  370                |workspace, window, cx| {
  371                    Editor::new_file(workspace, &Default::default(), window, cx)
  372                },
  373            )
  374            .detach();
  375        }
  376    });
  377    cx.on_action(move |_: &workspace::NewWindow, cx| {
  378        let app_state = workspace::AppState::global(cx);
  379        if let Some(app_state) = app_state.upgrade() {
  380            workspace::open_new(
  381                Default::default(),
  382                app_state,
  383                cx,
  384                |workspace, window, cx| {
  385                    cx.activate(true);
  386                    Editor::new_file(workspace, &Default::default(), window, cx)
  387                },
  388            )
  389            .detach();
  390        }
  391    });
  392}
  393
  394pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  395    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  396}
  397
  398pub trait DiagnosticRenderer {
  399    fn render_group(
  400        &self,
  401        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  402        buffer_id: BufferId,
  403        snapshot: EditorSnapshot,
  404        editor: WeakEntity<Editor>,
  405        cx: &mut App,
  406    ) -> Vec<BlockProperties<Anchor>>;
  407
  408    fn render_hover(
  409        &self,
  410        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  411        range: Range<Point>,
  412        buffer_id: BufferId,
  413        cx: &mut App,
  414    ) -> Option<Entity<markdown::Markdown>>;
  415
  416    fn open_link(
  417        &self,
  418        editor: &mut Editor,
  419        link: SharedString,
  420        window: &mut Window,
  421        cx: &mut Context<Editor>,
  422    );
  423}
  424
  425pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  426
  427impl GlobalDiagnosticRenderer {
  428    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  429        cx.try_global::<Self>().map(|g| g.0.clone())
  430    }
  431}
  432
  433impl gpui::Global for GlobalDiagnosticRenderer {}
  434pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  435    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  436}
  437
  438pub struct SearchWithinRange;
  439
  440trait InvalidationRegion {
  441    fn ranges(&self) -> &[Range<Anchor>];
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum SelectPhase {
  446    Begin {
  447        position: DisplayPoint,
  448        add: bool,
  449        click_count: usize,
  450    },
  451    BeginColumnar {
  452        position: DisplayPoint,
  453        reset: bool,
  454        mode: ColumnarMode,
  455        goal_column: u32,
  456    },
  457    Extend {
  458        position: DisplayPoint,
  459        click_count: usize,
  460    },
  461    Update {
  462        position: DisplayPoint,
  463        goal_column: u32,
  464        scroll_delta: gpui::Point<f32>,
  465    },
  466    End,
  467}
  468
  469#[derive(Clone, Debug, PartialEq)]
  470pub enum ColumnarMode {
  471    FromMouse,
  472    FromSelection,
  473}
  474
  475#[derive(Clone, Debug)]
  476pub enum SelectMode {
  477    Character,
  478    Word(Range<Anchor>),
  479    Line(Range<Anchor>),
  480    All,
  481}
  482
  483#[derive(Clone, PartialEq, Eq, Debug)]
  484pub enum EditorMode {
  485    SingleLine {
  486        auto_width: bool,
  487    },
  488    AutoHeight {
  489        min_lines: usize,
  490        max_lines: usize,
  491    },
  492    Full {
  493        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  494        scale_ui_elements_with_buffer_font_size: bool,
  495        /// When set to `true`, the editor will render a background for the active line.
  496        show_active_line_background: bool,
  497        /// When set to `true`, the editor's height will be determined by its content.
  498        sized_by_content: bool,
  499    },
  500    Minimap {
  501        parent: WeakEntity<Editor>,
  502    },
  503}
  504
  505impl EditorMode {
  506    pub fn full() -> Self {
  507        Self::Full {
  508            scale_ui_elements_with_buffer_font_size: true,
  509            show_active_line_background: true,
  510            sized_by_content: false,
  511        }
  512    }
  513
  514    pub fn is_full(&self) -> bool {
  515        matches!(self, Self::Full { .. })
  516    }
  517
  518    fn is_minimap(&self) -> bool {
  519        matches!(self, Self::Minimap { .. })
  520    }
  521}
  522
  523#[derive(Copy, Clone, Debug)]
  524pub enum SoftWrap {
  525    /// Prefer not to wrap at all.
  526    ///
  527    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  528    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  529    GitDiff,
  530    /// Prefer a single line generally, unless an overly long line is encountered.
  531    None,
  532    /// Soft wrap lines that exceed the editor width.
  533    EditorWidth,
  534    /// Soft wrap lines at the preferred line length.
  535    Column(u32),
  536    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  537    Bounded(u32),
  538}
  539
  540#[derive(Clone)]
  541pub struct EditorStyle {
  542    pub background: Hsla,
  543    pub local_player: PlayerColor,
  544    pub text: TextStyle,
  545    pub scrollbar_width: Pixels,
  546    pub syntax: Arc<SyntaxTheme>,
  547    pub status: StatusColors,
  548    pub inlay_hints_style: HighlightStyle,
  549    pub inline_completion_styles: InlineCompletionStyles,
  550    pub unnecessary_code_fade: f32,
  551    pub show_underlines: bool,
  552}
  553
  554impl Default for EditorStyle {
  555    fn default() -> Self {
  556        Self {
  557            background: Hsla::default(),
  558            local_player: PlayerColor::default(),
  559            text: TextStyle::default(),
  560            scrollbar_width: Pixels::default(),
  561            syntax: Default::default(),
  562            // HACK: Status colors don't have a real default.
  563            // We should look into removing the status colors from the editor
  564            // style and retrieve them directly from the theme.
  565            status: StatusColors::dark(),
  566            inlay_hints_style: HighlightStyle::default(),
  567            inline_completion_styles: InlineCompletionStyles {
  568                insertion: HighlightStyle::default(),
  569                whitespace: HighlightStyle::default(),
  570            },
  571            unnecessary_code_fade: Default::default(),
  572            show_underlines: true,
  573        }
  574    }
  575}
  576
  577pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  578    let show_background = language_settings::language_settings(None, None, cx)
  579        .inlay_hints
  580        .show_background;
  581
  582    HighlightStyle {
  583        color: Some(cx.theme().status().hint),
  584        background_color: show_background.then(|| cx.theme().status().hint_background),
  585        ..HighlightStyle::default()
  586    }
  587}
  588
  589pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  590    InlineCompletionStyles {
  591        insertion: HighlightStyle {
  592            color: Some(cx.theme().status().predictive),
  593            ..HighlightStyle::default()
  594        },
  595        whitespace: HighlightStyle {
  596            background_color: Some(cx.theme().status().created_background),
  597            ..HighlightStyle::default()
  598        },
  599    }
  600}
  601
  602type CompletionId = usize;
  603
  604pub(crate) enum EditDisplayMode {
  605    TabAccept,
  606    DiffPopover,
  607    Inline,
  608}
  609
  610enum InlineCompletion {
  611    Edit {
  612        edits: Vec<(Range<Anchor>, String)>,
  613        edit_preview: Option<EditPreview>,
  614        display_mode: EditDisplayMode,
  615        snapshot: BufferSnapshot,
  616    },
  617    Move {
  618        target: Anchor,
  619        snapshot: BufferSnapshot,
  620    },
  621}
  622
  623struct InlineCompletionState {
  624    inlay_ids: Vec<InlayId>,
  625    completion: InlineCompletion,
  626    completion_id: Option<SharedString>,
  627    invalidation_range: Range<Anchor>,
  628}
  629
  630enum EditPredictionSettings {
  631    Disabled,
  632    Enabled {
  633        show_in_menu: bool,
  634        preview_requires_modifier: bool,
  635    },
  636}
  637
  638enum InlineCompletionHighlight {}
  639
  640#[derive(Debug, Clone)]
  641struct InlineDiagnostic {
  642    message: SharedString,
  643    group_id: usize,
  644    is_primary: bool,
  645    start: Point,
  646    severity: lsp::DiagnosticSeverity,
  647}
  648
  649pub enum MenuInlineCompletionsPolicy {
  650    Never,
  651    ByProvider,
  652}
  653
  654pub enum EditPredictionPreview {
  655    /// Modifier is not pressed
  656    Inactive { released_too_fast: bool },
  657    /// Modifier pressed
  658    Active {
  659        since: Instant,
  660        previous_scroll_position: Option<ScrollAnchor>,
  661    },
  662}
  663
  664impl EditPredictionPreview {
  665    pub fn released_too_fast(&self) -> bool {
  666        match self {
  667            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  668            EditPredictionPreview::Active { .. } => false,
  669        }
  670    }
  671
  672    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  673        if let EditPredictionPreview::Active {
  674            previous_scroll_position,
  675            ..
  676        } = self
  677        {
  678            *previous_scroll_position = scroll_position;
  679        }
  680    }
  681}
  682
  683pub struct ContextMenuOptions {
  684    pub min_entries_visible: usize,
  685    pub max_entries_visible: usize,
  686    pub placement: Option<ContextMenuPlacement>,
  687}
  688
  689#[derive(Debug, Clone, PartialEq, Eq)]
  690pub enum ContextMenuPlacement {
  691    Above,
  692    Below,
  693}
  694
  695#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  696struct EditorActionId(usize);
  697
  698impl EditorActionId {
  699    pub fn post_inc(&mut self) -> Self {
  700        let answer = self.0;
  701
  702        *self = Self(answer + 1);
  703
  704        Self(answer)
  705    }
  706}
  707
  708// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  709// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  710
  711#[derive(Clone)]
  712pub struct BackgroundHighlight {
  713    pub range: Range<Anchor>,
  714    pub color_fetcher: fn(&Theme) -> Hsla,
  715}
  716
  717type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  718
  719#[derive(Default)]
  720struct ScrollbarMarkerState {
  721    scrollbar_size: Size<Pixels>,
  722    dirty: bool,
  723    markers: Arc<[PaintQuad]>,
  724    pending_refresh: Option<Task<Result<()>>>,
  725}
  726
  727impl ScrollbarMarkerState {
  728    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  729        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  730    }
  731}
  732
  733#[derive(Clone, Copy, PartialEq, Eq)]
  734pub enum MinimapVisibility {
  735    Disabled,
  736    Enabled {
  737        /// The configuration currently present in the users settings.
  738        setting_configuration: bool,
  739        /// Whether to override the currently set visibility from the users setting.
  740        toggle_override: bool,
  741    },
  742}
  743
  744impl MinimapVisibility {
  745    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  746        if mode.is_full() {
  747            Self::Enabled {
  748                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  749                toggle_override: false,
  750            }
  751        } else {
  752            Self::Disabled
  753        }
  754    }
  755
  756    fn hidden(&self) -> Self {
  757        match *self {
  758            Self::Enabled {
  759                setting_configuration,
  760                ..
  761            } => Self::Enabled {
  762                setting_configuration,
  763                toggle_override: setting_configuration,
  764            },
  765            Self::Disabled => Self::Disabled,
  766        }
  767    }
  768
  769    fn disabled(&self) -> bool {
  770        match *self {
  771            Self::Disabled => true,
  772            _ => false,
  773        }
  774    }
  775
  776    fn settings_visibility(&self) -> bool {
  777        match *self {
  778            Self::Enabled {
  779                setting_configuration,
  780                ..
  781            } => setting_configuration,
  782            _ => false,
  783        }
  784    }
  785
  786    fn visible(&self) -> bool {
  787        match *self {
  788            Self::Enabled {
  789                setting_configuration,
  790                toggle_override,
  791            } => setting_configuration ^ toggle_override,
  792            _ => false,
  793        }
  794    }
  795
  796    fn toggle_visibility(&self) -> Self {
  797        match *self {
  798            Self::Enabled {
  799                toggle_override,
  800                setting_configuration,
  801            } => Self::Enabled {
  802                setting_configuration,
  803                toggle_override: !toggle_override,
  804            },
  805            Self::Disabled => Self::Disabled,
  806        }
  807    }
  808}
  809
  810#[derive(Clone, Debug)]
  811struct RunnableTasks {
  812    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  813    offset: multi_buffer::Anchor,
  814    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  815    column: u32,
  816    // Values of all named captures, including those starting with '_'
  817    extra_variables: HashMap<String, String>,
  818    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  819    context_range: Range<BufferOffset>,
  820}
  821
  822impl RunnableTasks {
  823    fn resolve<'a>(
  824        &'a self,
  825        cx: &'a task::TaskContext,
  826    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  827        self.templates.iter().filter_map(|(kind, template)| {
  828            template
  829                .resolve_task(&kind.to_id_base(), cx)
  830                .map(|task| (kind.clone(), task))
  831        })
  832    }
  833}
  834
  835#[derive(Clone)]
  836pub struct ResolvedTasks {
  837    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  838    position: Anchor,
  839}
  840
  841#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  842struct BufferOffset(usize);
  843
  844// Addons allow storing per-editor state in other crates (e.g. Vim)
  845pub trait Addon: 'static {
  846    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  847
  848    fn render_buffer_header_controls(
  849        &self,
  850        _: &ExcerptInfo,
  851        _: &Window,
  852        _: &App,
  853    ) -> Option<AnyElement> {
  854        None
  855    }
  856
  857    fn to_any(&self) -> &dyn std::any::Any;
  858
  859    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  860        None
  861    }
  862}
  863
  864/// A set of caret positions, registered when the editor was edited.
  865pub struct ChangeList {
  866    changes: Vec<Vec<Anchor>>,
  867    /// Currently "selected" change.
  868    position: Option<usize>,
  869}
  870
  871impl ChangeList {
  872    pub fn new() -> Self {
  873        Self {
  874            changes: Vec::new(),
  875            position: None,
  876        }
  877    }
  878
  879    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  880    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  881    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  882        if self.changes.is_empty() {
  883            return None;
  884        }
  885
  886        let prev = self.position.unwrap_or(self.changes.len());
  887        let next = if direction == Direction::Prev {
  888            prev.saturating_sub(count)
  889        } else {
  890            (prev + count).min(self.changes.len() - 1)
  891        };
  892        self.position = Some(next);
  893        self.changes.get(next).map(|anchors| anchors.as_slice())
  894    }
  895
  896    /// Adds a new change to the list, resetting the change list position.
  897    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  898        self.position.take();
  899        if pop_state {
  900            self.changes.pop();
  901        }
  902        self.changes.push(new_positions.clone());
  903    }
  904
  905    pub fn last(&self) -> Option<&[Anchor]> {
  906        self.changes.last().map(|anchors| anchors.as_slice())
  907    }
  908}
  909
  910#[derive(Clone)]
  911struct InlineBlamePopoverState {
  912    scroll_handle: ScrollHandle,
  913    commit_message: Option<ParsedCommitMessage>,
  914    markdown: Entity<Markdown>,
  915}
  916
  917struct InlineBlamePopover {
  918    position: gpui::Point<Pixels>,
  919    hide_task: Option<Task<()>>,
  920    popover_bounds: Option<Bounds<Pixels>>,
  921    popover_state: InlineBlamePopoverState,
  922}
  923
  924enum SelectionDragState {
  925    /// State when no drag related activity is detected.
  926    None,
  927    /// State when the mouse is down on a selection that is about to be dragged.
  928    ReadyToDrag {
  929        selection: Selection<Anchor>,
  930        click_position: gpui::Point<Pixels>,
  931        mouse_down_time: Instant,
  932    },
  933    /// State when the mouse is dragging the selection in the editor.
  934    Dragging {
  935        selection: Selection<Anchor>,
  936        drop_cursor: Selection<Anchor>,
  937        hide_drop_cursor: bool,
  938    },
  939}
  940
  941enum ColumnarSelectionState {
  942    FromMouse {
  943        selection_tail: Anchor,
  944        display_point: Option<DisplayPoint>,
  945    },
  946    FromSelection {
  947        selection_tail: Anchor,
  948    },
  949}
  950
  951/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  952/// a breakpoint on them.
  953#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  954struct PhantomBreakpointIndicator {
  955    display_row: DisplayRow,
  956    /// There's a small debounce between hovering over the line and showing the indicator.
  957    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  958    is_active: bool,
  959    collides_with_existing_breakpoint: bool,
  960}
  961
  962/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  963///
  964/// See the [module level documentation](self) for more information.
  965pub struct Editor {
  966    focus_handle: FocusHandle,
  967    last_focused_descendant: Option<WeakFocusHandle>,
  968    /// The text buffer being edited
  969    buffer: Entity<MultiBuffer>,
  970    /// Map of how text in the buffer should be displayed.
  971    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  972    pub display_map: Entity<DisplayMap>,
  973    pub selections: SelectionsCollection,
  974    pub scroll_manager: ScrollManager,
  975    /// When inline assist editors are linked, they all render cursors because
  976    /// typing enters text into each of them, even the ones that aren't focused.
  977    pub(crate) show_cursor_when_unfocused: bool,
  978    columnar_selection_state: Option<ColumnarSelectionState>,
  979    add_selections_state: Option<AddSelectionsState>,
  980    select_next_state: Option<SelectNextState>,
  981    select_prev_state: Option<SelectNextState>,
  982    selection_history: SelectionHistory,
  983    defer_selection_effects: bool,
  984    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  985    autoclose_regions: Vec<AutocloseRegion>,
  986    snippet_stack: InvalidationStack<SnippetState>,
  987    select_syntax_node_history: SelectSyntaxNodeHistory,
  988    ime_transaction: Option<TransactionId>,
  989    pub diagnostics_max_severity: DiagnosticSeverity,
  990    active_diagnostics: ActiveDiagnostic,
  991    show_inline_diagnostics: bool,
  992    inline_diagnostics_update: Task<()>,
  993    inline_diagnostics_enabled: bool,
  994    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  995    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  996    hard_wrap: Option<usize>,
  997
  998    // TODO: make this a access method
  999    pub project: Option<Entity<Project>>,
 1000    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1001    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1002    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1003    blink_manager: Entity<BlinkManager>,
 1004    show_cursor_names: bool,
 1005    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1006    pub show_local_selections: bool,
 1007    mode: EditorMode,
 1008    show_breadcrumbs: bool,
 1009    show_gutter: bool,
 1010    show_scrollbars: ScrollbarAxes,
 1011    minimap_visibility: MinimapVisibility,
 1012    offset_content: bool,
 1013    disable_expand_excerpt_buttons: bool,
 1014    show_line_numbers: Option<bool>,
 1015    use_relative_line_numbers: Option<bool>,
 1016    show_git_diff_gutter: Option<bool>,
 1017    show_code_actions: Option<bool>,
 1018    show_runnables: Option<bool>,
 1019    show_breakpoints: Option<bool>,
 1020    show_wrap_guides: Option<bool>,
 1021    show_indent_guides: Option<bool>,
 1022    placeholder_text: Option<Arc<str>>,
 1023    highlight_order: usize,
 1024    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1025    background_highlights: TreeMap<TypeId, Vec<BackgroundHighlight>>,
 1026    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1027    scrollbar_marker_state: ScrollbarMarkerState,
 1028    active_indent_guides_state: ActiveIndentGuidesState,
 1029    nav_history: Option<ItemNavHistory>,
 1030    context_menu: RefCell<Option<CodeContextMenu>>,
 1031    context_menu_options: Option<ContextMenuOptions>,
 1032    mouse_context_menu: Option<MouseContextMenu>,
 1033    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1034    inline_blame_popover: Option<InlineBlamePopover>,
 1035    inline_blame_popover_show_task: Option<Task<()>>,
 1036    signature_help_state: SignatureHelpState,
 1037    auto_signature_help: Option<bool>,
 1038    find_all_references_task_sources: Vec<Anchor>,
 1039    next_completion_id: CompletionId,
 1040    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1041    code_actions_task: Option<Task<Result<()>>>,
 1042    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1043    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1044    document_highlights_task: Option<Task<()>>,
 1045    linked_editing_range_task: Option<Task<Option<()>>>,
 1046    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1047    pending_rename: Option<RenameState>,
 1048    searchable: bool,
 1049    cursor_shape: CursorShape,
 1050    current_line_highlight: Option<CurrentLineHighlight>,
 1051    collapse_matches: bool,
 1052    autoindent_mode: Option<AutoindentMode>,
 1053    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1054    input_enabled: bool,
 1055    use_modal_editing: bool,
 1056    read_only: bool,
 1057    leader_id: Option<CollaboratorId>,
 1058    remote_id: Option<ViewId>,
 1059    pub hover_state: HoverState,
 1060    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1061    gutter_hovered: bool,
 1062    hovered_link_state: Option<HoveredLinkState>,
 1063    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1064    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1065    active_inline_completion: Option<InlineCompletionState>,
 1066    /// Used to prevent flickering as the user types while the menu is open
 1067    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1068    edit_prediction_settings: EditPredictionSettings,
 1069    inline_completions_hidden_for_vim_mode: bool,
 1070    show_inline_completions_override: Option<bool>,
 1071    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1072    edit_prediction_preview: EditPredictionPreview,
 1073    edit_prediction_indent_conflict: bool,
 1074    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1075    inlay_hint_cache: InlayHintCache,
 1076    next_inlay_id: usize,
 1077    _subscriptions: Vec<Subscription>,
 1078    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1079    gutter_dimensions: GutterDimensions,
 1080    style: Option<EditorStyle>,
 1081    text_style_refinement: Option<TextStyleRefinement>,
 1082    next_editor_action_id: EditorActionId,
 1083    editor_actions: Rc<
 1084        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1085    >,
 1086    use_autoclose: bool,
 1087    use_auto_surround: bool,
 1088    auto_replace_emoji_shortcode: bool,
 1089    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1090    show_git_blame_gutter: bool,
 1091    show_git_blame_inline: bool,
 1092    show_git_blame_inline_delay_task: Option<Task<()>>,
 1093    git_blame_inline_enabled: bool,
 1094    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1095    serialize_dirty_buffers: bool,
 1096    show_selection_menu: Option<bool>,
 1097    blame: Option<Entity<GitBlame>>,
 1098    blame_subscription: Option<Subscription>,
 1099    custom_context_menu: Option<
 1100        Box<
 1101            dyn 'static
 1102                + Fn(
 1103                    &mut Self,
 1104                    DisplayPoint,
 1105                    &mut Window,
 1106                    &mut Context<Self>,
 1107                ) -> Option<Entity<ui::ContextMenu>>,
 1108        >,
 1109    >,
 1110    last_bounds: Option<Bounds<Pixels>>,
 1111    last_position_map: Option<Rc<PositionMap>>,
 1112    expect_bounds_change: Option<Bounds<Pixels>>,
 1113    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1114    tasks_update_task: Option<Task<()>>,
 1115    breakpoint_store: Option<Entity<BreakpointStore>>,
 1116    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1117    hovered_diff_hunk_row: Option<DisplayRow>,
 1118    pull_diagnostics_task: Task<()>,
 1119    in_project_search: bool,
 1120    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1121    breadcrumb_header: Option<String>,
 1122    focused_block: Option<FocusedBlock>,
 1123    next_scroll_position: NextScrollCursorCenterTopBottom,
 1124    addons: HashMap<TypeId, Box<dyn Addon>>,
 1125    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1126    load_diff_task: Option<Shared<Task<()>>>,
 1127    /// Whether we are temporarily displaying a diff other than git's
 1128    temporary_diff_override: bool,
 1129    selection_mark_mode: bool,
 1130    toggle_fold_multiple_buffers: Task<()>,
 1131    _scroll_cursor_center_top_bottom_task: Task<()>,
 1132    serialize_selections: Task<()>,
 1133    serialize_folds: Task<()>,
 1134    mouse_cursor_hidden: bool,
 1135    minimap: Option<Entity<Self>>,
 1136    hide_mouse_mode: HideMouseMode,
 1137    pub change_list: ChangeList,
 1138    inline_value_cache: InlineValueCache,
 1139    selection_drag_state: SelectionDragState,
 1140    drag_and_drop_selection_enabled: bool,
 1141    next_color_inlay_id: usize,
 1142    colors: Option<LspColorData>,
 1143}
 1144
 1145#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1146enum NextScrollCursorCenterTopBottom {
 1147    #[default]
 1148    Center,
 1149    Top,
 1150    Bottom,
 1151}
 1152
 1153impl NextScrollCursorCenterTopBottom {
 1154    fn next(&self) -> Self {
 1155        match self {
 1156            Self::Center => Self::Top,
 1157            Self::Top => Self::Bottom,
 1158            Self::Bottom => Self::Center,
 1159        }
 1160    }
 1161}
 1162
 1163#[derive(Clone)]
 1164pub struct EditorSnapshot {
 1165    pub mode: EditorMode,
 1166    show_gutter: bool,
 1167    show_line_numbers: Option<bool>,
 1168    show_git_diff_gutter: Option<bool>,
 1169    show_code_actions: Option<bool>,
 1170    show_runnables: Option<bool>,
 1171    show_breakpoints: Option<bool>,
 1172    git_blame_gutter_max_author_length: Option<usize>,
 1173    pub display_snapshot: DisplaySnapshot,
 1174    pub placeholder_text: Option<Arc<str>>,
 1175    is_focused: bool,
 1176    scroll_anchor: ScrollAnchor,
 1177    ongoing_scroll: OngoingScroll,
 1178    current_line_highlight: CurrentLineHighlight,
 1179    gutter_hovered: bool,
 1180}
 1181
 1182#[derive(Default, Debug, Clone, Copy)]
 1183pub struct GutterDimensions {
 1184    pub left_padding: Pixels,
 1185    pub right_padding: Pixels,
 1186    pub width: Pixels,
 1187    pub margin: Pixels,
 1188    pub git_blame_entries_width: Option<Pixels>,
 1189}
 1190
 1191impl GutterDimensions {
 1192    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1193        Self {
 1194            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1195            ..Default::default()
 1196        }
 1197    }
 1198
 1199    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1200        -cx.text_system().descent(font_id, font_size)
 1201    }
 1202    /// The full width of the space taken up by the gutter.
 1203    pub fn full_width(&self) -> Pixels {
 1204        self.margin + self.width
 1205    }
 1206
 1207    /// The width of the space reserved for the fold indicators,
 1208    /// use alongside 'justify_end' and `gutter_width` to
 1209    /// right align content with the line numbers
 1210    pub fn fold_area_width(&self) -> Pixels {
 1211        self.margin + self.right_padding
 1212    }
 1213}
 1214
 1215#[derive(Debug)]
 1216pub struct RemoteSelection {
 1217    pub replica_id: ReplicaId,
 1218    pub selection: Selection<Anchor>,
 1219    pub cursor_shape: CursorShape,
 1220    pub collaborator_id: CollaboratorId,
 1221    pub line_mode: bool,
 1222    pub user_name: Option<SharedString>,
 1223    pub color: PlayerColor,
 1224}
 1225
 1226#[derive(Clone, Debug)]
 1227struct SelectionHistoryEntry {
 1228    selections: Arc<[Selection<Anchor>]>,
 1229    select_next_state: Option<SelectNextState>,
 1230    select_prev_state: Option<SelectNextState>,
 1231    add_selections_state: Option<AddSelectionsState>,
 1232}
 1233
 1234#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1235enum SelectionHistoryMode {
 1236    Normal,
 1237    Undoing,
 1238    Redoing,
 1239    Skipping,
 1240}
 1241
 1242#[derive(Clone, PartialEq, Eq, Hash)]
 1243struct HoveredCursor {
 1244    replica_id: u16,
 1245    selection_id: usize,
 1246}
 1247
 1248impl Default for SelectionHistoryMode {
 1249    fn default() -> Self {
 1250        Self::Normal
 1251    }
 1252}
 1253
 1254#[derive(Debug)]
 1255pub struct SelectionEffects {
 1256    nav_history: bool,
 1257    completions: bool,
 1258    scroll: Option<Autoscroll>,
 1259}
 1260
 1261impl Default for SelectionEffects {
 1262    fn default() -> Self {
 1263        Self {
 1264            nav_history: true,
 1265            completions: true,
 1266            scroll: Some(Autoscroll::fit()),
 1267        }
 1268    }
 1269}
 1270impl SelectionEffects {
 1271    pub fn scroll(scroll: Autoscroll) -> Self {
 1272        Self {
 1273            scroll: Some(scroll),
 1274            ..Default::default()
 1275        }
 1276    }
 1277
 1278    pub fn no_scroll() -> Self {
 1279        Self {
 1280            scroll: None,
 1281            ..Default::default()
 1282        }
 1283    }
 1284
 1285    pub fn completions(self, completions: bool) -> Self {
 1286        Self {
 1287            completions,
 1288            ..self
 1289        }
 1290    }
 1291
 1292    pub fn nav_history(self, nav_history: bool) -> Self {
 1293        Self {
 1294            nav_history,
 1295            ..self
 1296        }
 1297    }
 1298}
 1299
 1300struct DeferredSelectionEffectsState {
 1301    changed: bool,
 1302    effects: SelectionEffects,
 1303    old_cursor_position: Anchor,
 1304    history_entry: SelectionHistoryEntry,
 1305}
 1306
 1307#[derive(Default)]
 1308struct SelectionHistory {
 1309    #[allow(clippy::type_complexity)]
 1310    selections_by_transaction:
 1311        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1312    mode: SelectionHistoryMode,
 1313    undo_stack: VecDeque<SelectionHistoryEntry>,
 1314    redo_stack: VecDeque<SelectionHistoryEntry>,
 1315}
 1316
 1317impl SelectionHistory {
 1318    #[track_caller]
 1319    fn insert_transaction(
 1320        &mut self,
 1321        transaction_id: TransactionId,
 1322        selections: Arc<[Selection<Anchor>]>,
 1323    ) {
 1324        if selections.is_empty() {
 1325            log::error!(
 1326                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1327                std::panic::Location::caller()
 1328            );
 1329            return;
 1330        }
 1331        self.selections_by_transaction
 1332            .insert(transaction_id, (selections, None));
 1333    }
 1334
 1335    #[allow(clippy::type_complexity)]
 1336    fn transaction(
 1337        &self,
 1338        transaction_id: TransactionId,
 1339    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1340        self.selections_by_transaction.get(&transaction_id)
 1341    }
 1342
 1343    #[allow(clippy::type_complexity)]
 1344    fn transaction_mut(
 1345        &mut self,
 1346        transaction_id: TransactionId,
 1347    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1348        self.selections_by_transaction.get_mut(&transaction_id)
 1349    }
 1350
 1351    fn push(&mut self, entry: SelectionHistoryEntry) {
 1352        if !entry.selections.is_empty() {
 1353            match self.mode {
 1354                SelectionHistoryMode::Normal => {
 1355                    self.push_undo(entry);
 1356                    self.redo_stack.clear();
 1357                }
 1358                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1359                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1360                SelectionHistoryMode::Skipping => {}
 1361            }
 1362        }
 1363    }
 1364
 1365    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1366        if self
 1367            .undo_stack
 1368            .back()
 1369            .map_or(true, |e| e.selections != entry.selections)
 1370        {
 1371            self.undo_stack.push_back(entry);
 1372            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1373                self.undo_stack.pop_front();
 1374            }
 1375        }
 1376    }
 1377
 1378    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1379        if self
 1380            .redo_stack
 1381            .back()
 1382            .map_or(true, |e| e.selections != entry.selections)
 1383        {
 1384            self.redo_stack.push_back(entry);
 1385            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1386                self.redo_stack.pop_front();
 1387            }
 1388        }
 1389    }
 1390}
 1391
 1392#[derive(Clone, Copy)]
 1393pub struct RowHighlightOptions {
 1394    pub autoscroll: bool,
 1395    pub include_gutter: bool,
 1396}
 1397
 1398impl Default for RowHighlightOptions {
 1399    fn default() -> Self {
 1400        Self {
 1401            autoscroll: Default::default(),
 1402            include_gutter: true,
 1403        }
 1404    }
 1405}
 1406
 1407struct RowHighlight {
 1408    index: usize,
 1409    range: Range<Anchor>,
 1410    color: Hsla,
 1411    options: RowHighlightOptions,
 1412    type_id: TypeId,
 1413}
 1414
 1415#[derive(Clone, Debug)]
 1416struct AddSelectionsState {
 1417    groups: Vec<AddSelectionsGroup>,
 1418}
 1419
 1420#[derive(Clone, Debug)]
 1421struct AddSelectionsGroup {
 1422    above: bool,
 1423    stack: Vec<usize>,
 1424}
 1425
 1426#[derive(Clone)]
 1427struct SelectNextState {
 1428    query: AhoCorasick,
 1429    wordwise: bool,
 1430    done: bool,
 1431}
 1432
 1433impl std::fmt::Debug for SelectNextState {
 1434    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1435        f.debug_struct(std::any::type_name::<Self>())
 1436            .field("wordwise", &self.wordwise)
 1437            .field("done", &self.done)
 1438            .finish()
 1439    }
 1440}
 1441
 1442#[derive(Debug)]
 1443struct AutocloseRegion {
 1444    selection_id: usize,
 1445    range: Range<Anchor>,
 1446    pair: BracketPair,
 1447}
 1448
 1449#[derive(Debug)]
 1450struct SnippetState {
 1451    ranges: Vec<Vec<Range<Anchor>>>,
 1452    active_index: usize,
 1453    choices: Vec<Option<Vec<String>>>,
 1454}
 1455
 1456#[doc(hidden)]
 1457pub struct RenameState {
 1458    pub range: Range<Anchor>,
 1459    pub old_name: Arc<str>,
 1460    pub editor: Entity<Editor>,
 1461    block_id: CustomBlockId,
 1462}
 1463
 1464struct InvalidationStack<T>(Vec<T>);
 1465
 1466struct RegisteredInlineCompletionProvider {
 1467    provider: Arc<dyn InlineCompletionProviderHandle>,
 1468    _subscription: Subscription,
 1469}
 1470
 1471#[derive(Debug, PartialEq, Eq)]
 1472pub struct ActiveDiagnosticGroup {
 1473    pub active_range: Range<Anchor>,
 1474    pub active_message: String,
 1475    pub group_id: usize,
 1476    pub blocks: HashSet<CustomBlockId>,
 1477}
 1478
 1479#[derive(Debug, PartialEq, Eq)]
 1480
 1481pub(crate) enum ActiveDiagnostic {
 1482    None,
 1483    All,
 1484    Group(ActiveDiagnosticGroup),
 1485}
 1486
 1487#[derive(Serialize, Deserialize, Clone, Debug)]
 1488pub struct ClipboardSelection {
 1489    /// The number of bytes in this selection.
 1490    pub len: usize,
 1491    /// Whether this was a full-line selection.
 1492    pub is_entire_line: bool,
 1493    /// The indentation of the first line when this content was originally copied.
 1494    pub first_line_indent: u32,
 1495}
 1496
 1497// selections, scroll behavior, was newest selection reversed
 1498type SelectSyntaxNodeHistoryState = (
 1499    Box<[Selection<usize>]>,
 1500    SelectSyntaxNodeScrollBehavior,
 1501    bool,
 1502);
 1503
 1504#[derive(Default)]
 1505struct SelectSyntaxNodeHistory {
 1506    stack: Vec<SelectSyntaxNodeHistoryState>,
 1507    // disable temporarily to allow changing selections without losing the stack
 1508    pub disable_clearing: bool,
 1509}
 1510
 1511impl SelectSyntaxNodeHistory {
 1512    pub fn try_clear(&mut self) {
 1513        if !self.disable_clearing {
 1514            self.stack.clear();
 1515        }
 1516    }
 1517
 1518    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1519        self.stack.push(selection);
 1520    }
 1521
 1522    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1523        self.stack.pop()
 1524    }
 1525}
 1526
 1527enum SelectSyntaxNodeScrollBehavior {
 1528    CursorTop,
 1529    FitSelection,
 1530    CursorBottom,
 1531}
 1532
 1533#[derive(Debug)]
 1534pub(crate) struct NavigationData {
 1535    cursor_anchor: Anchor,
 1536    cursor_position: Point,
 1537    scroll_anchor: ScrollAnchor,
 1538    scroll_top_row: u32,
 1539}
 1540
 1541#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1542pub enum GotoDefinitionKind {
 1543    Symbol,
 1544    Declaration,
 1545    Type,
 1546    Implementation,
 1547}
 1548
 1549#[derive(Debug, Clone)]
 1550enum InlayHintRefreshReason {
 1551    ModifiersChanged(bool),
 1552    Toggle(bool),
 1553    SettingsChange(InlayHintSettings),
 1554    NewLinesShown,
 1555    BufferEdited(HashSet<Arc<Language>>),
 1556    RefreshRequested,
 1557    ExcerptsRemoved(Vec<ExcerptId>),
 1558}
 1559
 1560impl InlayHintRefreshReason {
 1561    fn description(&self) -> &'static str {
 1562        match self {
 1563            Self::ModifiersChanged(_) => "modifiers changed",
 1564            Self::Toggle(_) => "toggle",
 1565            Self::SettingsChange(_) => "settings change",
 1566            Self::NewLinesShown => "new lines shown",
 1567            Self::BufferEdited(_) => "buffer edited",
 1568            Self::RefreshRequested => "refresh requested",
 1569            Self::ExcerptsRemoved(_) => "excerpts removed",
 1570        }
 1571    }
 1572}
 1573
 1574pub enum FormatTarget {
 1575    Buffers(HashSet<Entity<Buffer>>),
 1576    Ranges(Vec<Range<MultiBufferPoint>>),
 1577}
 1578
 1579pub(crate) struct FocusedBlock {
 1580    id: BlockId,
 1581    focus_handle: WeakFocusHandle,
 1582}
 1583
 1584#[derive(Clone)]
 1585enum JumpData {
 1586    MultiBufferRow {
 1587        row: MultiBufferRow,
 1588        line_offset_from_top: u32,
 1589    },
 1590    MultiBufferPoint {
 1591        excerpt_id: ExcerptId,
 1592        position: Point,
 1593        anchor: text::Anchor,
 1594        line_offset_from_top: u32,
 1595    },
 1596}
 1597
 1598pub enum MultibufferSelectionMode {
 1599    First,
 1600    All,
 1601}
 1602
 1603#[derive(Clone, Copy, Debug, Default)]
 1604pub struct RewrapOptions {
 1605    pub override_language_settings: bool,
 1606    pub preserve_existing_whitespace: bool,
 1607}
 1608
 1609impl Editor {
 1610    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1611        let buffer = cx.new(|cx| Buffer::local("", cx));
 1612        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1613        Self::new(
 1614            EditorMode::SingleLine { auto_width: false },
 1615            buffer,
 1616            None,
 1617            window,
 1618            cx,
 1619        )
 1620    }
 1621
 1622    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1623        let buffer = cx.new(|cx| Buffer::local("", cx));
 1624        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1625        Self::new(EditorMode::full(), buffer, None, window, cx)
 1626    }
 1627
 1628    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1629        let buffer = cx.new(|cx| Buffer::local("", cx));
 1630        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1631        Self::new(
 1632            EditorMode::SingleLine { auto_width: true },
 1633            buffer,
 1634            None,
 1635            window,
 1636            cx,
 1637        )
 1638    }
 1639
 1640    pub fn auto_height(
 1641        min_lines: usize,
 1642        max_lines: usize,
 1643        window: &mut Window,
 1644        cx: &mut Context<Self>,
 1645    ) -> Self {
 1646        let buffer = cx.new(|cx| Buffer::local("", cx));
 1647        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1648        Self::new(
 1649            EditorMode::AutoHeight {
 1650                min_lines,
 1651                max_lines,
 1652            },
 1653            buffer,
 1654            None,
 1655            window,
 1656            cx,
 1657        )
 1658    }
 1659
 1660    pub fn for_buffer(
 1661        buffer: Entity<Buffer>,
 1662        project: Option<Entity<Project>>,
 1663        window: &mut Window,
 1664        cx: &mut Context<Self>,
 1665    ) -> Self {
 1666        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1667        Self::new(EditorMode::full(), buffer, project, window, cx)
 1668    }
 1669
 1670    pub fn for_multibuffer(
 1671        buffer: Entity<MultiBuffer>,
 1672        project: Option<Entity<Project>>,
 1673        window: &mut Window,
 1674        cx: &mut Context<Self>,
 1675    ) -> Self {
 1676        Self::new(EditorMode::full(), buffer, project, window, cx)
 1677    }
 1678
 1679    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1680        let mut clone = Self::new(
 1681            self.mode.clone(),
 1682            self.buffer.clone(),
 1683            self.project.clone(),
 1684            window,
 1685            cx,
 1686        );
 1687        self.display_map.update(cx, |display_map, cx| {
 1688            let snapshot = display_map.snapshot(cx);
 1689            clone.display_map.update(cx, |display_map, cx| {
 1690                display_map.set_state(&snapshot, cx);
 1691            });
 1692        });
 1693        clone.folds_did_change(cx);
 1694        clone.selections.clone_state(&self.selections);
 1695        clone.scroll_manager.clone_state(&self.scroll_manager);
 1696        clone.searchable = self.searchable;
 1697        clone.read_only = self.read_only;
 1698        clone
 1699    }
 1700
 1701    pub fn new(
 1702        mode: EditorMode,
 1703        buffer: Entity<MultiBuffer>,
 1704        project: Option<Entity<Project>>,
 1705        window: &mut Window,
 1706        cx: &mut Context<Self>,
 1707    ) -> Self {
 1708        Editor::new_internal(mode, buffer, project, None, window, cx)
 1709    }
 1710
 1711    fn new_internal(
 1712        mode: EditorMode,
 1713        buffer: Entity<MultiBuffer>,
 1714        project: Option<Entity<Project>>,
 1715        display_map: Option<Entity<DisplayMap>>,
 1716        window: &mut Window,
 1717        cx: &mut Context<Self>,
 1718    ) -> Self {
 1719        debug_assert!(
 1720            display_map.is_none() || mode.is_minimap(),
 1721            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1722        );
 1723
 1724        let full_mode = mode.is_full();
 1725        let diagnostics_max_severity = if full_mode {
 1726            EditorSettings::get_global(cx)
 1727                .diagnostics_max_severity
 1728                .unwrap_or(DiagnosticSeverity::Hint)
 1729        } else {
 1730            DiagnosticSeverity::Off
 1731        };
 1732        let style = window.text_style();
 1733        let font_size = style.font_size.to_pixels(window.rem_size());
 1734        let editor = cx.entity().downgrade();
 1735        let fold_placeholder = FoldPlaceholder {
 1736            constrain_width: true,
 1737            render: Arc::new(move |fold_id, fold_range, cx| {
 1738                let editor = editor.clone();
 1739                div()
 1740                    .id(fold_id)
 1741                    .bg(cx.theme().colors().ghost_element_background)
 1742                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1743                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1744                    .rounded_xs()
 1745                    .size_full()
 1746                    .cursor_pointer()
 1747                    .child("")
 1748                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1749                    .on_click(move |_, _window, cx| {
 1750                        editor
 1751                            .update(cx, |editor, cx| {
 1752                                editor.unfold_ranges(
 1753                                    &[fold_range.start..fold_range.end],
 1754                                    true,
 1755                                    false,
 1756                                    cx,
 1757                                );
 1758                                cx.stop_propagation();
 1759                            })
 1760                            .ok();
 1761                    })
 1762                    .into_any()
 1763            }),
 1764            merge_adjacent: true,
 1765            ..FoldPlaceholder::default()
 1766        };
 1767        let display_map = display_map.unwrap_or_else(|| {
 1768            cx.new(|cx| {
 1769                DisplayMap::new(
 1770                    buffer.clone(),
 1771                    style.font(),
 1772                    font_size,
 1773                    None,
 1774                    FILE_HEADER_HEIGHT,
 1775                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1776                    fold_placeholder,
 1777                    diagnostics_max_severity,
 1778                    cx,
 1779                )
 1780            })
 1781        });
 1782
 1783        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1784
 1785        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1786
 1787        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1788            .then(|| language_settings::SoftWrap::None);
 1789
 1790        let mut project_subscriptions = Vec::new();
 1791        if mode.is_full() {
 1792            if let Some(project) = project.as_ref() {
 1793                project_subscriptions.push(cx.subscribe_in(
 1794                    project,
 1795                    window,
 1796                    |editor, _, event, window, cx| match event {
 1797                        project::Event::RefreshCodeLens => {
 1798                            // we always query lens with actions, without storing them, always refreshing them
 1799                        }
 1800                        project::Event::RefreshInlayHints => {
 1801                            editor
 1802                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1803                        }
 1804                        project::Event::LanguageServerAdded(server_id, ..)
 1805                        | project::Event::LanguageServerRemoved(server_id) => {
 1806                            if editor.tasks_update_task.is_none() {
 1807                                editor.tasks_update_task =
 1808                                    Some(editor.refresh_runnables(window, cx));
 1809                            }
 1810                            editor.update_lsp_data(false, Some(*server_id), None, window, cx);
 1811                        }
 1812                        project::Event::SnippetEdit(id, snippet_edits) => {
 1813                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1814                                let focus_handle = editor.focus_handle(cx);
 1815                                if focus_handle.is_focused(window) {
 1816                                    let snapshot = buffer.read(cx).snapshot();
 1817                                    for (range, snippet) in snippet_edits {
 1818                                        let editor_range =
 1819                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1820                                        editor
 1821                                            .insert_snippet(
 1822                                                &[editor_range],
 1823                                                snippet.clone(),
 1824                                                window,
 1825                                                cx,
 1826                                            )
 1827                                            .ok();
 1828                                    }
 1829                                }
 1830                            }
 1831                        }
 1832                        _ => {}
 1833                    },
 1834                ));
 1835                if let Some(task_inventory) = project
 1836                    .read(cx)
 1837                    .task_store()
 1838                    .read(cx)
 1839                    .task_inventory()
 1840                    .cloned()
 1841                {
 1842                    project_subscriptions.push(cx.observe_in(
 1843                        &task_inventory,
 1844                        window,
 1845                        |editor, _, window, cx| {
 1846                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1847                        },
 1848                    ));
 1849                };
 1850
 1851                project_subscriptions.push(cx.subscribe_in(
 1852                    &project.read(cx).breakpoint_store(),
 1853                    window,
 1854                    |editor, _, event, window, cx| match event {
 1855                        BreakpointStoreEvent::ClearDebugLines => {
 1856                            editor.clear_row_highlights::<ActiveDebugLine>();
 1857                            editor.refresh_inline_values(cx);
 1858                        }
 1859                        BreakpointStoreEvent::SetDebugLine => {
 1860                            if editor.go_to_active_debug_line(window, cx) {
 1861                                cx.stop_propagation();
 1862                            }
 1863
 1864                            editor.refresh_inline_values(cx);
 1865                        }
 1866                        _ => {}
 1867                    },
 1868                ));
 1869            }
 1870        }
 1871
 1872        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1873
 1874        let inlay_hint_settings =
 1875            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1876        let focus_handle = cx.focus_handle();
 1877        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1878            .detach();
 1879        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1880            .detach();
 1881        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1882            .detach();
 1883        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1884            .detach();
 1885        cx.observe_pending_input(window, Self::observe_pending_input)
 1886            .detach();
 1887
 1888        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1889            Some(false)
 1890        } else {
 1891            None
 1892        };
 1893
 1894        let breakpoint_store = match (&mode, project.as_ref()) {
 1895            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1896            _ => None,
 1897        };
 1898
 1899        let mut code_action_providers = Vec::new();
 1900        let mut load_uncommitted_diff = None;
 1901        if let Some(project) = project.clone() {
 1902            load_uncommitted_diff = Some(
 1903                update_uncommitted_diff_for_buffer(
 1904                    cx.entity(),
 1905                    &project,
 1906                    buffer.read(cx).all_buffers(),
 1907                    buffer.clone(),
 1908                    cx,
 1909                )
 1910                .shared(),
 1911            );
 1912            code_action_providers.push(Rc::new(project) as Rc<_>);
 1913        }
 1914
 1915        let mut editor = Self {
 1916            focus_handle,
 1917            show_cursor_when_unfocused: false,
 1918            last_focused_descendant: None,
 1919            buffer: buffer.clone(),
 1920            display_map: display_map.clone(),
 1921            selections,
 1922            scroll_manager: ScrollManager::new(cx),
 1923            columnar_selection_state: None,
 1924            add_selections_state: None,
 1925            select_next_state: None,
 1926            select_prev_state: None,
 1927            selection_history: SelectionHistory::default(),
 1928            defer_selection_effects: false,
 1929            deferred_selection_effects_state: None,
 1930            autoclose_regions: Vec::new(),
 1931            snippet_stack: InvalidationStack::default(),
 1932            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1933            ime_transaction: None,
 1934            active_diagnostics: ActiveDiagnostic::None,
 1935            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1936            inline_diagnostics_update: Task::ready(()),
 1937            inline_diagnostics: Vec::new(),
 1938            soft_wrap_mode_override,
 1939            diagnostics_max_severity,
 1940            hard_wrap: None,
 1941            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1942            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1943            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1944            project,
 1945            blink_manager: blink_manager.clone(),
 1946            show_local_selections: true,
 1947            show_scrollbars: ScrollbarAxes {
 1948                horizontal: full_mode,
 1949                vertical: full_mode,
 1950            },
 1951            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1952            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1953            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1954            show_gutter: mode.is_full(),
 1955            show_line_numbers: None,
 1956            use_relative_line_numbers: None,
 1957            disable_expand_excerpt_buttons: false,
 1958            show_git_diff_gutter: None,
 1959            show_code_actions: None,
 1960            show_runnables: None,
 1961            show_breakpoints: None,
 1962            show_wrap_guides: None,
 1963            show_indent_guides,
 1964            placeholder_text: None,
 1965            highlight_order: 0,
 1966            highlighted_rows: HashMap::default(),
 1967            background_highlights: TreeMap::default(),
 1968            gutter_highlights: TreeMap::default(),
 1969            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1970            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1971            nav_history: None,
 1972            context_menu: RefCell::new(None),
 1973            context_menu_options: None,
 1974            mouse_context_menu: None,
 1975            completion_tasks: Vec::new(),
 1976            inline_blame_popover: None,
 1977            inline_blame_popover_show_task: None,
 1978            signature_help_state: SignatureHelpState::default(),
 1979            auto_signature_help: None,
 1980            find_all_references_task_sources: Vec::new(),
 1981            next_completion_id: 0,
 1982            next_inlay_id: 0,
 1983            code_action_providers,
 1984            available_code_actions: None,
 1985            code_actions_task: None,
 1986            quick_selection_highlight_task: None,
 1987            debounced_selection_highlight_task: None,
 1988            document_highlights_task: None,
 1989            linked_editing_range_task: None,
 1990            pending_rename: None,
 1991            searchable: true,
 1992            cursor_shape: EditorSettings::get_global(cx)
 1993                .cursor_shape
 1994                .unwrap_or_default(),
 1995            current_line_highlight: None,
 1996            autoindent_mode: Some(AutoindentMode::EachLine),
 1997            collapse_matches: false,
 1998            workspace: None,
 1999            input_enabled: true,
 2000            use_modal_editing: mode.is_full(),
 2001            read_only: mode.is_minimap(),
 2002            use_autoclose: true,
 2003            use_auto_surround: true,
 2004            auto_replace_emoji_shortcode: false,
 2005            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2006            leader_id: None,
 2007            remote_id: None,
 2008            hover_state: HoverState::default(),
 2009            pending_mouse_down: None,
 2010            hovered_link_state: None,
 2011            edit_prediction_provider: None,
 2012            active_inline_completion: None,
 2013            stale_inline_completion_in_menu: None,
 2014            edit_prediction_preview: EditPredictionPreview::Inactive {
 2015                released_too_fast: false,
 2016            },
 2017            inline_diagnostics_enabled: mode.is_full(),
 2018            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2019            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2020
 2021            gutter_hovered: false,
 2022            pixel_position_of_newest_cursor: None,
 2023            last_bounds: None,
 2024            last_position_map: None,
 2025            expect_bounds_change: None,
 2026            gutter_dimensions: GutterDimensions::default(),
 2027            style: None,
 2028            show_cursor_names: false,
 2029            hovered_cursors: HashMap::default(),
 2030            next_editor_action_id: EditorActionId::default(),
 2031            editor_actions: Rc::default(),
 2032            inline_completions_hidden_for_vim_mode: false,
 2033            show_inline_completions_override: None,
 2034            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2035            edit_prediction_settings: EditPredictionSettings::Disabled,
 2036            edit_prediction_indent_conflict: false,
 2037            edit_prediction_requires_modifier_in_indent_conflict: true,
 2038            custom_context_menu: None,
 2039            show_git_blame_gutter: false,
 2040            show_git_blame_inline: false,
 2041            show_selection_menu: None,
 2042            show_git_blame_inline_delay_task: None,
 2043            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2044            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2045            serialize_dirty_buffers: !mode.is_minimap()
 2046                && ProjectSettings::get_global(cx)
 2047                    .session
 2048                    .restore_unsaved_buffers,
 2049            blame: None,
 2050            blame_subscription: None,
 2051            tasks: BTreeMap::default(),
 2052
 2053            breakpoint_store,
 2054            gutter_breakpoint_indicator: (None, None),
 2055            hovered_diff_hunk_row: None,
 2056            _subscriptions: vec![
 2057                cx.observe(&buffer, Self::on_buffer_changed),
 2058                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2059                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2060                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2061                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2062                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2063                cx.observe_window_activation(window, |editor, window, cx| {
 2064                    let active = window.is_window_active();
 2065                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2066                        if active {
 2067                            blink_manager.enable(cx);
 2068                        } else {
 2069                            blink_manager.disable(cx);
 2070                        }
 2071                    });
 2072                    if active {
 2073                        editor.show_mouse_cursor(cx);
 2074                    }
 2075                }),
 2076            ],
 2077            tasks_update_task: None,
 2078            pull_diagnostics_task: Task::ready(()),
 2079            colors: None,
 2080            next_color_inlay_id: 0,
 2081            linked_edit_ranges: Default::default(),
 2082            in_project_search: false,
 2083            previous_search_ranges: None,
 2084            breadcrumb_header: None,
 2085            focused_block: None,
 2086            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2087            addons: HashMap::default(),
 2088            registered_buffers: HashMap::default(),
 2089            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2090            selection_mark_mode: false,
 2091            toggle_fold_multiple_buffers: Task::ready(()),
 2092            serialize_selections: Task::ready(()),
 2093            serialize_folds: Task::ready(()),
 2094            text_style_refinement: None,
 2095            load_diff_task: load_uncommitted_diff,
 2096            temporary_diff_override: false,
 2097            mouse_cursor_hidden: false,
 2098            minimap: None,
 2099            hide_mouse_mode: EditorSettings::get_global(cx)
 2100                .hide_mouse
 2101                .unwrap_or_default(),
 2102            change_list: ChangeList::new(),
 2103            mode,
 2104            selection_drag_state: SelectionDragState::None,
 2105            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2106        };
 2107        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2108            editor
 2109                ._subscriptions
 2110                .push(cx.observe(breakpoints, |_, _, cx| {
 2111                    cx.notify();
 2112                }));
 2113        }
 2114        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2115        editor._subscriptions.extend(project_subscriptions);
 2116
 2117        editor._subscriptions.push(cx.subscribe_in(
 2118            &cx.entity(),
 2119            window,
 2120            |editor, _, e: &EditorEvent, window, cx| match e {
 2121                EditorEvent::ScrollPositionChanged { local, .. } => {
 2122                    if *local {
 2123                        let new_anchor = editor.scroll_manager.anchor();
 2124                        let snapshot = editor.snapshot(window, cx);
 2125                        editor.update_restoration_data(cx, move |data| {
 2126                            data.scroll_position = (
 2127                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2128                                new_anchor.offset,
 2129                            );
 2130                        });
 2131                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2132                        editor.inline_blame_popover.take();
 2133                    }
 2134                }
 2135                EditorEvent::Edited { .. } => {
 2136                    if !vim_enabled(cx) {
 2137                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2138                        let pop_state = editor
 2139                            .change_list
 2140                            .last()
 2141                            .map(|previous| {
 2142                                previous.len() == selections.len()
 2143                                    && previous.iter().enumerate().all(|(ix, p)| {
 2144                                        p.to_display_point(&map).row()
 2145                                            == selections[ix].head().row()
 2146                                    })
 2147                            })
 2148                            .unwrap_or(false);
 2149                        let new_positions = selections
 2150                            .into_iter()
 2151                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2152                            .collect();
 2153                        editor
 2154                            .change_list
 2155                            .push_to_change_list(pop_state, new_positions);
 2156                    }
 2157                }
 2158                _ => (),
 2159            },
 2160        ));
 2161
 2162        if let Some(dap_store) = editor
 2163            .project
 2164            .as_ref()
 2165            .map(|project| project.read(cx).dap_store())
 2166        {
 2167            let weak_editor = cx.weak_entity();
 2168
 2169            editor
 2170                ._subscriptions
 2171                .push(
 2172                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2173                        let session_entity = cx.entity();
 2174                        weak_editor
 2175                            .update(cx, |editor, cx| {
 2176                                editor._subscriptions.push(
 2177                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2178                                );
 2179                            })
 2180                            .ok();
 2181                    }),
 2182                );
 2183
 2184            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2185                editor
 2186                    ._subscriptions
 2187                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2188            }
 2189        }
 2190
 2191        // skip adding the initial selection to selection history
 2192        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2193        editor.end_selection(window, cx);
 2194        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2195
 2196        editor.scroll_manager.show_scrollbars(window, cx);
 2197        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2198
 2199        if full_mode {
 2200            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2201            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2202
 2203            if editor.git_blame_inline_enabled {
 2204                editor.start_git_blame_inline(false, window, cx);
 2205            }
 2206
 2207            editor.go_to_active_debug_line(window, cx);
 2208
 2209            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2210                if let Some(project) = editor.project.as_ref() {
 2211                    let handle = project.update(cx, |project, cx| {
 2212                        project.register_buffer_with_language_servers(&buffer, cx)
 2213                    });
 2214                    editor
 2215                        .registered_buffers
 2216                        .insert(buffer.read(cx).remote_id(), handle);
 2217                }
 2218            }
 2219
 2220            editor.minimap =
 2221                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2222            editor.colors = Some(LspColorData::new(cx));
 2223            editor.update_lsp_data(false, None, None, window, cx);
 2224        }
 2225
 2226        editor.report_editor_event("Editor Opened", None, cx);
 2227        editor
 2228    }
 2229
 2230    pub fn deploy_mouse_context_menu(
 2231        &mut self,
 2232        position: gpui::Point<Pixels>,
 2233        context_menu: Entity<ContextMenu>,
 2234        window: &mut Window,
 2235        cx: &mut Context<Self>,
 2236    ) {
 2237        self.mouse_context_menu = Some(MouseContextMenu::new(
 2238            self,
 2239            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2240            context_menu,
 2241            window,
 2242            cx,
 2243        ));
 2244    }
 2245
 2246    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2247        self.mouse_context_menu
 2248            .as_ref()
 2249            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2250    }
 2251
 2252    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2253        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2254    }
 2255
 2256    fn key_context_internal(
 2257        &self,
 2258        has_active_edit_prediction: bool,
 2259        window: &Window,
 2260        cx: &App,
 2261    ) -> KeyContext {
 2262        let mut key_context = KeyContext::new_with_defaults();
 2263        key_context.add("Editor");
 2264        let mode = match self.mode {
 2265            EditorMode::SingleLine { .. } => "single_line",
 2266            EditorMode::AutoHeight { .. } => "auto_height",
 2267            EditorMode::Minimap { .. } => "minimap",
 2268            EditorMode::Full { .. } => "full",
 2269        };
 2270
 2271        if EditorSettings::jupyter_enabled(cx) {
 2272            key_context.add("jupyter");
 2273        }
 2274
 2275        key_context.set("mode", mode);
 2276        if self.pending_rename.is_some() {
 2277            key_context.add("renaming");
 2278        }
 2279
 2280        match self.context_menu.borrow().as_ref() {
 2281            Some(CodeContextMenu::Completions(_)) => {
 2282                key_context.add("menu");
 2283                key_context.add("showing_completions");
 2284            }
 2285            Some(CodeContextMenu::CodeActions(_)) => {
 2286                key_context.add("menu");
 2287                key_context.add("showing_code_actions")
 2288            }
 2289            None => {}
 2290        }
 2291
 2292        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2293        if !self.focus_handle(cx).contains_focused(window, cx)
 2294            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2295        {
 2296            for addon in self.addons.values() {
 2297                addon.extend_key_context(&mut key_context, cx)
 2298            }
 2299        }
 2300
 2301        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2302            if let Some(extension) = singleton_buffer
 2303                .read(cx)
 2304                .file()
 2305                .and_then(|file| file.path().extension()?.to_str())
 2306            {
 2307                key_context.set("extension", extension.to_string());
 2308            }
 2309        } else {
 2310            key_context.add("multibuffer");
 2311        }
 2312
 2313        if has_active_edit_prediction {
 2314            if self.edit_prediction_in_conflict() {
 2315                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2316            } else {
 2317                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2318                key_context.add("copilot_suggestion");
 2319            }
 2320        }
 2321
 2322        if self.selection_mark_mode {
 2323            key_context.add("selection_mode");
 2324        }
 2325
 2326        key_context
 2327    }
 2328
 2329    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2330        if self.mouse_cursor_hidden {
 2331            self.mouse_cursor_hidden = false;
 2332            cx.notify();
 2333        }
 2334    }
 2335
 2336    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2337        let hide_mouse_cursor = match origin {
 2338            HideMouseCursorOrigin::TypingAction => {
 2339                matches!(
 2340                    self.hide_mouse_mode,
 2341                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2342                )
 2343            }
 2344            HideMouseCursorOrigin::MovementAction => {
 2345                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2346            }
 2347        };
 2348        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2349            self.mouse_cursor_hidden = hide_mouse_cursor;
 2350            cx.notify();
 2351        }
 2352    }
 2353
 2354    pub fn edit_prediction_in_conflict(&self) -> bool {
 2355        if !self.show_edit_predictions_in_menu() {
 2356            return false;
 2357        }
 2358
 2359        let showing_completions = self
 2360            .context_menu
 2361            .borrow()
 2362            .as_ref()
 2363            .map_or(false, |context| {
 2364                matches!(context, CodeContextMenu::Completions(_))
 2365            });
 2366
 2367        showing_completions
 2368            || self.edit_prediction_requires_modifier()
 2369            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2370            // bindings to insert tab characters.
 2371            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2372    }
 2373
 2374    pub fn accept_edit_prediction_keybind(
 2375        &self,
 2376        accept_partial: bool,
 2377        window: &Window,
 2378        cx: &App,
 2379    ) -> AcceptEditPredictionBinding {
 2380        let key_context = self.key_context_internal(true, window, cx);
 2381        let in_conflict = self.edit_prediction_in_conflict();
 2382
 2383        let bindings = if accept_partial {
 2384            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2385        } else {
 2386            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2387        };
 2388
 2389        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2390        // just the first one.
 2391        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2392            !in_conflict
 2393                || binding
 2394                    .keystrokes()
 2395                    .first()
 2396                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2397        }))
 2398    }
 2399
 2400    pub fn new_file(
 2401        workspace: &mut Workspace,
 2402        _: &workspace::NewFile,
 2403        window: &mut Window,
 2404        cx: &mut Context<Workspace>,
 2405    ) {
 2406        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2407            "Failed to create buffer",
 2408            window,
 2409            cx,
 2410            |e, _, _| match e.error_code() {
 2411                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2412                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2413                e.error_tag("required").unwrap_or("the latest version")
 2414            )),
 2415                _ => None,
 2416            },
 2417        );
 2418    }
 2419
 2420    pub fn new_in_workspace(
 2421        workspace: &mut Workspace,
 2422        window: &mut Window,
 2423        cx: &mut Context<Workspace>,
 2424    ) -> Task<Result<Entity<Editor>>> {
 2425        let project = workspace.project().clone();
 2426        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2427
 2428        cx.spawn_in(window, async move |workspace, cx| {
 2429            let buffer = create.await?;
 2430            workspace.update_in(cx, |workspace, window, cx| {
 2431                let editor =
 2432                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2433                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2434                editor
 2435            })
 2436        })
 2437    }
 2438
 2439    fn new_file_vertical(
 2440        workspace: &mut Workspace,
 2441        _: &workspace::NewFileSplitVertical,
 2442        window: &mut Window,
 2443        cx: &mut Context<Workspace>,
 2444    ) {
 2445        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2446    }
 2447
 2448    fn new_file_horizontal(
 2449        workspace: &mut Workspace,
 2450        _: &workspace::NewFileSplitHorizontal,
 2451        window: &mut Window,
 2452        cx: &mut Context<Workspace>,
 2453    ) {
 2454        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2455    }
 2456
 2457    fn new_file_in_direction(
 2458        workspace: &mut Workspace,
 2459        direction: SplitDirection,
 2460        window: &mut Window,
 2461        cx: &mut Context<Workspace>,
 2462    ) {
 2463        let project = workspace.project().clone();
 2464        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2465
 2466        cx.spawn_in(window, async move |workspace, cx| {
 2467            let buffer = create.await?;
 2468            workspace.update_in(cx, move |workspace, window, cx| {
 2469                workspace.split_item(
 2470                    direction,
 2471                    Box::new(
 2472                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2473                    ),
 2474                    window,
 2475                    cx,
 2476                )
 2477            })?;
 2478            anyhow::Ok(())
 2479        })
 2480        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2481            match e.error_code() {
 2482                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2483                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2484                e.error_tag("required").unwrap_or("the latest version")
 2485            )),
 2486                _ => None,
 2487            }
 2488        });
 2489    }
 2490
 2491    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2492        self.leader_id
 2493    }
 2494
 2495    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2496        &self.buffer
 2497    }
 2498
 2499    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2500        self.workspace.as_ref()?.0.upgrade()
 2501    }
 2502
 2503    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2504        self.buffer().read(cx).title(cx)
 2505    }
 2506
 2507    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2508        let git_blame_gutter_max_author_length = self
 2509            .render_git_blame_gutter(cx)
 2510            .then(|| {
 2511                if let Some(blame) = self.blame.as_ref() {
 2512                    let max_author_length =
 2513                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2514                    Some(max_author_length)
 2515                } else {
 2516                    None
 2517                }
 2518            })
 2519            .flatten();
 2520
 2521        EditorSnapshot {
 2522            mode: self.mode.clone(),
 2523            show_gutter: self.show_gutter,
 2524            show_line_numbers: self.show_line_numbers,
 2525            show_git_diff_gutter: self.show_git_diff_gutter,
 2526            show_code_actions: self.show_code_actions,
 2527            show_runnables: self.show_runnables,
 2528            show_breakpoints: self.show_breakpoints,
 2529            git_blame_gutter_max_author_length,
 2530            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2531            scroll_anchor: self.scroll_manager.anchor(),
 2532            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2533            placeholder_text: self.placeholder_text.clone(),
 2534            is_focused: self.focus_handle.is_focused(window),
 2535            current_line_highlight: self
 2536                .current_line_highlight
 2537                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2538            gutter_hovered: self.gutter_hovered,
 2539        }
 2540    }
 2541
 2542    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2543        self.buffer.read(cx).language_at(point, cx)
 2544    }
 2545
 2546    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2547        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2548    }
 2549
 2550    pub fn active_excerpt(
 2551        &self,
 2552        cx: &App,
 2553    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2554        self.buffer
 2555            .read(cx)
 2556            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2557    }
 2558
 2559    pub fn mode(&self) -> &EditorMode {
 2560        &self.mode
 2561    }
 2562
 2563    pub fn set_mode(&mut self, mode: EditorMode) {
 2564        self.mode = mode;
 2565    }
 2566
 2567    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2568        self.collaboration_hub.as_deref()
 2569    }
 2570
 2571    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2572        self.collaboration_hub = Some(hub);
 2573    }
 2574
 2575    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2576        self.in_project_search = in_project_search;
 2577    }
 2578
 2579    pub fn set_custom_context_menu(
 2580        &mut self,
 2581        f: impl 'static
 2582        + Fn(
 2583            &mut Self,
 2584            DisplayPoint,
 2585            &mut Window,
 2586            &mut Context<Self>,
 2587        ) -> Option<Entity<ui::ContextMenu>>,
 2588    ) {
 2589        self.custom_context_menu = Some(Box::new(f))
 2590    }
 2591
 2592    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2593        self.completion_provider = provider;
 2594    }
 2595
 2596    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2597        self.semantics_provider.clone()
 2598    }
 2599
 2600    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2601        self.semantics_provider = provider;
 2602    }
 2603
 2604    pub fn set_edit_prediction_provider<T>(
 2605        &mut self,
 2606        provider: Option<Entity<T>>,
 2607        window: &mut Window,
 2608        cx: &mut Context<Self>,
 2609    ) where
 2610        T: EditPredictionProvider,
 2611    {
 2612        self.edit_prediction_provider =
 2613            provider.map(|provider| RegisteredInlineCompletionProvider {
 2614                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2615                    if this.focus_handle.is_focused(window) {
 2616                        this.update_visible_inline_completion(window, cx);
 2617                    }
 2618                }),
 2619                provider: Arc::new(provider),
 2620            });
 2621        self.update_edit_prediction_settings(cx);
 2622        self.refresh_inline_completion(false, false, window, cx);
 2623    }
 2624
 2625    pub fn placeholder_text(&self) -> Option<&str> {
 2626        self.placeholder_text.as_deref()
 2627    }
 2628
 2629    pub fn set_placeholder_text(
 2630        &mut self,
 2631        placeholder_text: impl Into<Arc<str>>,
 2632        cx: &mut Context<Self>,
 2633    ) {
 2634        let placeholder_text = Some(placeholder_text.into());
 2635        if self.placeholder_text != placeholder_text {
 2636            self.placeholder_text = placeholder_text;
 2637            cx.notify();
 2638        }
 2639    }
 2640
 2641    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2642        self.cursor_shape = cursor_shape;
 2643
 2644        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2645        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2646
 2647        cx.notify();
 2648    }
 2649
 2650    pub fn set_current_line_highlight(
 2651        &mut self,
 2652        current_line_highlight: Option<CurrentLineHighlight>,
 2653    ) {
 2654        self.current_line_highlight = current_line_highlight;
 2655    }
 2656
 2657    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2658        self.collapse_matches = collapse_matches;
 2659    }
 2660
 2661    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2662        let buffers = self.buffer.read(cx).all_buffers();
 2663        let Some(project) = self.project.as_ref() else {
 2664            return;
 2665        };
 2666        project.update(cx, |project, cx| {
 2667            for buffer in buffers {
 2668                self.registered_buffers
 2669                    .entry(buffer.read(cx).remote_id())
 2670                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2671            }
 2672        })
 2673    }
 2674
 2675    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2676        if self.collapse_matches {
 2677            return range.start..range.start;
 2678        }
 2679        range.clone()
 2680    }
 2681
 2682    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2683        if self.display_map.read(cx).clip_at_line_ends != clip {
 2684            self.display_map
 2685                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2686        }
 2687    }
 2688
 2689    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2690        self.input_enabled = input_enabled;
 2691    }
 2692
 2693    pub fn set_inline_completions_hidden_for_vim_mode(
 2694        &mut self,
 2695        hidden: bool,
 2696        window: &mut Window,
 2697        cx: &mut Context<Self>,
 2698    ) {
 2699        if hidden != self.inline_completions_hidden_for_vim_mode {
 2700            self.inline_completions_hidden_for_vim_mode = hidden;
 2701            if hidden {
 2702                self.update_visible_inline_completion(window, cx);
 2703            } else {
 2704                self.refresh_inline_completion(true, false, window, cx);
 2705            }
 2706        }
 2707    }
 2708
 2709    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2710        self.menu_inline_completions_policy = value;
 2711    }
 2712
 2713    pub fn set_autoindent(&mut self, autoindent: bool) {
 2714        if autoindent {
 2715            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2716        } else {
 2717            self.autoindent_mode = None;
 2718        }
 2719    }
 2720
 2721    pub fn read_only(&self, cx: &App) -> bool {
 2722        self.read_only || self.buffer.read(cx).read_only()
 2723    }
 2724
 2725    pub fn set_read_only(&mut self, read_only: bool) {
 2726        self.read_only = read_only;
 2727    }
 2728
 2729    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2730        self.use_autoclose = autoclose;
 2731    }
 2732
 2733    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2734        self.use_auto_surround = auto_surround;
 2735    }
 2736
 2737    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2738        self.auto_replace_emoji_shortcode = auto_replace;
 2739    }
 2740
 2741    pub fn toggle_edit_predictions(
 2742        &mut self,
 2743        _: &ToggleEditPrediction,
 2744        window: &mut Window,
 2745        cx: &mut Context<Self>,
 2746    ) {
 2747        if self.show_inline_completions_override.is_some() {
 2748            self.set_show_edit_predictions(None, window, cx);
 2749        } else {
 2750            let show_edit_predictions = !self.edit_predictions_enabled();
 2751            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2752        }
 2753    }
 2754
 2755    pub fn set_show_edit_predictions(
 2756        &mut self,
 2757        show_edit_predictions: Option<bool>,
 2758        window: &mut Window,
 2759        cx: &mut Context<Self>,
 2760    ) {
 2761        self.show_inline_completions_override = show_edit_predictions;
 2762        self.update_edit_prediction_settings(cx);
 2763
 2764        if let Some(false) = show_edit_predictions {
 2765            self.discard_inline_completion(false, cx);
 2766        } else {
 2767            self.refresh_inline_completion(false, true, window, cx);
 2768        }
 2769    }
 2770
 2771    fn inline_completions_disabled_in_scope(
 2772        &self,
 2773        buffer: &Entity<Buffer>,
 2774        buffer_position: language::Anchor,
 2775        cx: &App,
 2776    ) -> bool {
 2777        let snapshot = buffer.read(cx).snapshot();
 2778        let settings = snapshot.settings_at(buffer_position, cx);
 2779
 2780        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2781            return false;
 2782        };
 2783
 2784        scope.override_name().map_or(false, |scope_name| {
 2785            settings
 2786                .edit_predictions_disabled_in
 2787                .iter()
 2788                .any(|s| s == scope_name)
 2789        })
 2790    }
 2791
 2792    pub fn set_use_modal_editing(&mut self, to: bool) {
 2793        self.use_modal_editing = to;
 2794    }
 2795
 2796    pub fn use_modal_editing(&self) -> bool {
 2797        self.use_modal_editing
 2798    }
 2799
 2800    fn selections_did_change(
 2801        &mut self,
 2802        local: bool,
 2803        old_cursor_position: &Anchor,
 2804        effects: SelectionEffects,
 2805        window: &mut Window,
 2806        cx: &mut Context<Self>,
 2807    ) {
 2808        window.invalidate_character_coordinates();
 2809
 2810        // Copy selections to primary selection buffer
 2811        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2812        if local {
 2813            let selections = self.selections.all::<usize>(cx);
 2814            let buffer_handle = self.buffer.read(cx).read(cx);
 2815
 2816            let mut text = String::new();
 2817            for (index, selection) in selections.iter().enumerate() {
 2818                let text_for_selection = buffer_handle
 2819                    .text_for_range(selection.start..selection.end)
 2820                    .collect::<String>();
 2821
 2822                text.push_str(&text_for_selection);
 2823                if index != selections.len() - 1 {
 2824                    text.push('\n');
 2825                }
 2826            }
 2827
 2828            if !text.is_empty() {
 2829                cx.write_to_primary(ClipboardItem::new_string(text));
 2830            }
 2831        }
 2832
 2833        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2834            self.buffer.update(cx, |buffer, cx| {
 2835                buffer.set_active_selections(
 2836                    &self.selections.disjoint_anchors(),
 2837                    self.selections.line_mode,
 2838                    self.cursor_shape,
 2839                    cx,
 2840                )
 2841            });
 2842        }
 2843        let display_map = self
 2844            .display_map
 2845            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2846        let buffer = &display_map.buffer_snapshot;
 2847        if self.selections.count() == 1 {
 2848            self.add_selections_state = None;
 2849        }
 2850        self.select_next_state = None;
 2851        self.select_prev_state = None;
 2852        self.select_syntax_node_history.try_clear();
 2853        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2854        self.snippet_stack
 2855            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2856        self.take_rename(false, window, cx);
 2857
 2858        let newest_selection = self.selections.newest_anchor();
 2859        let new_cursor_position = newest_selection.head();
 2860        let selection_start = newest_selection.start;
 2861
 2862        if effects.nav_history {
 2863            self.push_to_nav_history(
 2864                *old_cursor_position,
 2865                Some(new_cursor_position.to_point(buffer)),
 2866                false,
 2867                cx,
 2868            );
 2869        }
 2870
 2871        if local {
 2872            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2873                if !self.registered_buffers.contains_key(&buffer_id) {
 2874                    if let Some(project) = self.project.as_ref() {
 2875                        project.update(cx, |project, cx| {
 2876                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2877                                return;
 2878                            };
 2879                            self.registered_buffers.insert(
 2880                                buffer_id,
 2881                                project.register_buffer_with_language_servers(&buffer, cx),
 2882                            );
 2883                        })
 2884                    }
 2885                }
 2886            }
 2887
 2888            let mut context_menu = self.context_menu.borrow_mut();
 2889            let completion_menu = match context_menu.as_ref() {
 2890                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2891                Some(CodeContextMenu::CodeActions(_)) => {
 2892                    *context_menu = None;
 2893                    None
 2894                }
 2895                None => None,
 2896            };
 2897            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2898            drop(context_menu);
 2899
 2900            if effects.completions {
 2901                if let Some(completion_position) = completion_position {
 2902                    let start_offset = selection_start.to_offset(buffer);
 2903                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2904                    let continue_showing = if position_matches {
 2905                        if self.snippet_stack.is_empty() {
 2906                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2907                        } else {
 2908                            // Snippet choices can be shown even when the cursor is in whitespace.
 2909                            // Dismissing the menu with actions like backspace is handled by
 2910                            // invalidation regions.
 2911                            true
 2912                        }
 2913                    } else {
 2914                        false
 2915                    };
 2916
 2917                    if continue_showing {
 2918                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2919                    } else {
 2920                        self.hide_context_menu(window, cx);
 2921                    }
 2922                }
 2923            }
 2924
 2925            hide_hover(self, cx);
 2926
 2927            if old_cursor_position.to_display_point(&display_map).row()
 2928                != new_cursor_position.to_display_point(&display_map).row()
 2929            {
 2930                self.available_code_actions.take();
 2931            }
 2932            self.refresh_code_actions(window, cx);
 2933            self.refresh_document_highlights(cx);
 2934            self.refresh_selected_text_highlights(false, window, cx);
 2935            refresh_matching_bracket_highlights(self, window, cx);
 2936            self.update_visible_inline_completion(window, cx);
 2937            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2938            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2939            self.inline_blame_popover.take();
 2940            if self.git_blame_inline_enabled {
 2941                self.start_inline_blame_timer(window, cx);
 2942            }
 2943        }
 2944
 2945        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2946        cx.emit(EditorEvent::SelectionsChanged { local });
 2947
 2948        let selections = &self.selections.disjoint;
 2949        if selections.len() == 1 {
 2950            cx.emit(SearchEvent::ActiveMatchChanged)
 2951        }
 2952        if local {
 2953            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2954                let inmemory_selections = selections
 2955                    .iter()
 2956                    .map(|s| {
 2957                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2958                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2959                    })
 2960                    .collect();
 2961                self.update_restoration_data(cx, |data| {
 2962                    data.selections = inmemory_selections;
 2963                });
 2964
 2965                if WorkspaceSettings::get(None, cx).restore_on_startup
 2966                    != RestoreOnStartupBehavior::None
 2967                {
 2968                    if let Some(workspace_id) =
 2969                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2970                    {
 2971                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2972                        let selections = selections.clone();
 2973                        let background_executor = cx.background_executor().clone();
 2974                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2975                        self.serialize_selections = cx.background_spawn(async move {
 2976                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2977                            let db_selections = selections
 2978                                .iter()
 2979                                .map(|selection| {
 2980                                    (
 2981                                        selection.start.to_offset(&snapshot),
 2982                                        selection.end.to_offset(&snapshot),
 2983                                    )
 2984                                })
 2985                                .collect();
 2986
 2987                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2988                                .await
 2989                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2990                                .log_err();
 2991                        });
 2992                    }
 2993                }
 2994            }
 2995        }
 2996
 2997        cx.notify();
 2998    }
 2999
 3000    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3001        use text::ToOffset as _;
 3002        use text::ToPoint as _;
 3003
 3004        if self.mode.is_minimap()
 3005            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3006        {
 3007            return;
 3008        }
 3009
 3010        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3011            return;
 3012        };
 3013
 3014        let snapshot = singleton.read(cx).snapshot();
 3015        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3016            let display_snapshot = display_map.snapshot(cx);
 3017
 3018            display_snapshot
 3019                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3020                .map(|fold| {
 3021                    fold.range.start.text_anchor.to_point(&snapshot)
 3022                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3023                })
 3024                .collect()
 3025        });
 3026        self.update_restoration_data(cx, |data| {
 3027            data.folds = inmemory_folds;
 3028        });
 3029
 3030        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3031            return;
 3032        };
 3033        let background_executor = cx.background_executor().clone();
 3034        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3035        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3036            display_map
 3037                .snapshot(cx)
 3038                .folds_in_range(0..snapshot.len())
 3039                .map(|fold| {
 3040                    (
 3041                        fold.range.start.text_anchor.to_offset(&snapshot),
 3042                        fold.range.end.text_anchor.to_offset(&snapshot),
 3043                    )
 3044                })
 3045                .collect()
 3046        });
 3047        self.serialize_folds = cx.background_spawn(async move {
 3048            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3049            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3050                .await
 3051                .with_context(|| {
 3052                    format!(
 3053                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3054                    )
 3055                })
 3056                .log_err();
 3057        });
 3058    }
 3059
 3060    pub fn sync_selections(
 3061        &mut self,
 3062        other: Entity<Editor>,
 3063        cx: &mut Context<Self>,
 3064    ) -> gpui::Subscription {
 3065        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3066        self.selections.change_with(cx, |selections| {
 3067            selections.select_anchors(other_selections);
 3068        });
 3069
 3070        let other_subscription =
 3071            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3072                EditorEvent::SelectionsChanged { local: true } => {
 3073                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3074                    if other_selections.is_empty() {
 3075                        return;
 3076                    }
 3077                    this.selections.change_with(cx, |selections| {
 3078                        selections.select_anchors(other_selections);
 3079                    });
 3080                }
 3081                _ => {}
 3082            });
 3083
 3084        let this_subscription =
 3085            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3086                EditorEvent::SelectionsChanged { local: true } => {
 3087                    let these_selections = this.selections.disjoint.to_vec();
 3088                    if these_selections.is_empty() {
 3089                        return;
 3090                    }
 3091                    other.update(cx, |other_editor, cx| {
 3092                        other_editor.selections.change_with(cx, |selections| {
 3093                            selections.select_anchors(these_selections);
 3094                        })
 3095                    });
 3096                }
 3097                _ => {}
 3098            });
 3099
 3100        Subscription::join(other_subscription, this_subscription)
 3101    }
 3102
 3103    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3104    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3105    /// effects of selection change occur at the end of the transaction.
 3106    pub fn change_selections<R>(
 3107        &mut self,
 3108        effects: impl Into<SelectionEffects>,
 3109        window: &mut Window,
 3110        cx: &mut Context<Self>,
 3111        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3112    ) -> R {
 3113        let effects = effects.into();
 3114        if let Some(state) = &mut self.deferred_selection_effects_state {
 3115            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3116            state.effects.completions = effects.completions;
 3117            state.effects.nav_history |= effects.nav_history;
 3118            let (changed, result) = self.selections.change_with(cx, change);
 3119            state.changed |= changed;
 3120            return result;
 3121        }
 3122        let mut state = DeferredSelectionEffectsState {
 3123            changed: false,
 3124            effects,
 3125            old_cursor_position: self.selections.newest_anchor().head(),
 3126            history_entry: SelectionHistoryEntry {
 3127                selections: self.selections.disjoint_anchors(),
 3128                select_next_state: self.select_next_state.clone(),
 3129                select_prev_state: self.select_prev_state.clone(),
 3130                add_selections_state: self.add_selections_state.clone(),
 3131            },
 3132        };
 3133        let (changed, result) = self.selections.change_with(cx, change);
 3134        state.changed = state.changed || changed;
 3135        if self.defer_selection_effects {
 3136            self.deferred_selection_effects_state = Some(state);
 3137        } else {
 3138            self.apply_selection_effects(state, window, cx);
 3139        }
 3140        result
 3141    }
 3142
 3143    /// Defers the effects of selection change, so that the effects of multiple calls to
 3144    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3145    /// to selection history and the state of popovers based on selection position aren't
 3146    /// erroneously updated.
 3147    pub fn with_selection_effects_deferred<R>(
 3148        &mut self,
 3149        window: &mut Window,
 3150        cx: &mut Context<Self>,
 3151        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3152    ) -> R {
 3153        let already_deferred = self.defer_selection_effects;
 3154        self.defer_selection_effects = true;
 3155        let result = update(self, window, cx);
 3156        if !already_deferred {
 3157            self.defer_selection_effects = false;
 3158            if let Some(state) = self.deferred_selection_effects_state.take() {
 3159                self.apply_selection_effects(state, window, cx);
 3160            }
 3161        }
 3162        result
 3163    }
 3164
 3165    fn apply_selection_effects(
 3166        &mut self,
 3167        state: DeferredSelectionEffectsState,
 3168        window: &mut Window,
 3169        cx: &mut Context<Self>,
 3170    ) {
 3171        if state.changed {
 3172            self.selection_history.push(state.history_entry);
 3173
 3174            if let Some(autoscroll) = state.effects.scroll {
 3175                self.request_autoscroll(autoscroll, cx);
 3176            }
 3177
 3178            let old_cursor_position = &state.old_cursor_position;
 3179
 3180            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3181
 3182            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3183                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3184            }
 3185        }
 3186    }
 3187
 3188    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3189    where
 3190        I: IntoIterator<Item = (Range<S>, T)>,
 3191        S: ToOffset,
 3192        T: Into<Arc<str>>,
 3193    {
 3194        if self.read_only(cx) {
 3195            return;
 3196        }
 3197
 3198        self.buffer
 3199            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3200    }
 3201
 3202    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3203    where
 3204        I: IntoIterator<Item = (Range<S>, T)>,
 3205        S: ToOffset,
 3206        T: Into<Arc<str>>,
 3207    {
 3208        if self.read_only(cx) {
 3209            return;
 3210        }
 3211
 3212        self.buffer.update(cx, |buffer, cx| {
 3213            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3214        });
 3215    }
 3216
 3217    pub fn edit_with_block_indent<I, S, T>(
 3218        &mut self,
 3219        edits: I,
 3220        original_indent_columns: Vec<Option<u32>>,
 3221        cx: &mut Context<Self>,
 3222    ) where
 3223        I: IntoIterator<Item = (Range<S>, T)>,
 3224        S: ToOffset,
 3225        T: Into<Arc<str>>,
 3226    {
 3227        if self.read_only(cx) {
 3228            return;
 3229        }
 3230
 3231        self.buffer.update(cx, |buffer, cx| {
 3232            buffer.edit(
 3233                edits,
 3234                Some(AutoindentMode::Block {
 3235                    original_indent_columns,
 3236                }),
 3237                cx,
 3238            )
 3239        });
 3240    }
 3241
 3242    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3243        self.hide_context_menu(window, cx);
 3244
 3245        match phase {
 3246            SelectPhase::Begin {
 3247                position,
 3248                add,
 3249                click_count,
 3250            } => self.begin_selection(position, add, click_count, window, cx),
 3251            SelectPhase::BeginColumnar {
 3252                position,
 3253                goal_column,
 3254                reset,
 3255                mode,
 3256            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3257            SelectPhase::Extend {
 3258                position,
 3259                click_count,
 3260            } => self.extend_selection(position, click_count, window, cx),
 3261            SelectPhase::Update {
 3262                position,
 3263                goal_column,
 3264                scroll_delta,
 3265            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3266            SelectPhase::End => self.end_selection(window, cx),
 3267        }
 3268    }
 3269
 3270    fn extend_selection(
 3271        &mut self,
 3272        position: DisplayPoint,
 3273        click_count: usize,
 3274        window: &mut Window,
 3275        cx: &mut Context<Self>,
 3276    ) {
 3277        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3278        let tail = self.selections.newest::<usize>(cx).tail();
 3279        self.begin_selection(position, false, click_count, window, cx);
 3280
 3281        let position = position.to_offset(&display_map, Bias::Left);
 3282        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3283
 3284        let mut pending_selection = self
 3285            .selections
 3286            .pending_anchor()
 3287            .expect("extend_selection not called with pending selection");
 3288        if position >= tail {
 3289            pending_selection.start = tail_anchor;
 3290        } else {
 3291            pending_selection.end = tail_anchor;
 3292            pending_selection.reversed = true;
 3293        }
 3294
 3295        let mut pending_mode = self.selections.pending_mode().unwrap();
 3296        match &mut pending_mode {
 3297            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3298            _ => {}
 3299        }
 3300
 3301        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3302            SelectionEffects::scroll(Autoscroll::fit())
 3303        } else {
 3304            SelectionEffects::no_scroll()
 3305        };
 3306
 3307        self.change_selections(effects, window, cx, |s| {
 3308            s.set_pending(pending_selection, pending_mode)
 3309        });
 3310    }
 3311
 3312    fn begin_selection(
 3313        &mut self,
 3314        position: DisplayPoint,
 3315        add: bool,
 3316        click_count: usize,
 3317        window: &mut Window,
 3318        cx: &mut Context<Self>,
 3319    ) {
 3320        if !self.focus_handle.is_focused(window) {
 3321            self.last_focused_descendant = None;
 3322            window.focus(&self.focus_handle);
 3323        }
 3324
 3325        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3326        let buffer = &display_map.buffer_snapshot;
 3327        let position = display_map.clip_point(position, Bias::Left);
 3328
 3329        let start;
 3330        let end;
 3331        let mode;
 3332        let mut auto_scroll;
 3333        match click_count {
 3334            1 => {
 3335                start = buffer.anchor_before(position.to_point(&display_map));
 3336                end = start;
 3337                mode = SelectMode::Character;
 3338                auto_scroll = true;
 3339            }
 3340            2 => {
 3341                let range = movement::surrounding_word(&display_map, position);
 3342                start = buffer.anchor_before(range.start.to_point(&display_map));
 3343                end = buffer.anchor_before(range.end.to_point(&display_map));
 3344                mode = SelectMode::Word(start..end);
 3345                auto_scroll = true;
 3346            }
 3347            3 => {
 3348                let position = display_map
 3349                    .clip_point(position, Bias::Left)
 3350                    .to_point(&display_map);
 3351                let line_start = display_map.prev_line_boundary(position).0;
 3352                let next_line_start = buffer.clip_point(
 3353                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3354                    Bias::Left,
 3355                );
 3356                start = buffer.anchor_before(line_start);
 3357                end = buffer.anchor_before(next_line_start);
 3358                mode = SelectMode::Line(start..end);
 3359                auto_scroll = true;
 3360            }
 3361            _ => {
 3362                start = buffer.anchor_before(0);
 3363                end = buffer.anchor_before(buffer.len());
 3364                mode = SelectMode::All;
 3365                auto_scroll = false;
 3366            }
 3367        }
 3368        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3369
 3370        let point_to_delete: Option<usize> = {
 3371            let selected_points: Vec<Selection<Point>> =
 3372                self.selections.disjoint_in_range(start..end, cx);
 3373
 3374            if !add || click_count > 1 {
 3375                None
 3376            } else if !selected_points.is_empty() {
 3377                Some(selected_points[0].id)
 3378            } else {
 3379                let clicked_point_already_selected =
 3380                    self.selections.disjoint.iter().find(|selection| {
 3381                        selection.start.to_point(buffer) == start.to_point(buffer)
 3382                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3383                    });
 3384
 3385                clicked_point_already_selected.map(|selection| selection.id)
 3386            }
 3387        };
 3388
 3389        let selections_count = self.selections.count();
 3390
 3391        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3392            if let Some(point_to_delete) = point_to_delete {
 3393                s.delete(point_to_delete);
 3394
 3395                if selections_count == 1 {
 3396                    s.set_pending_anchor_range(start..end, mode);
 3397                }
 3398            } else {
 3399                if !add {
 3400                    s.clear_disjoint();
 3401                }
 3402
 3403                s.set_pending_anchor_range(start..end, mode);
 3404            }
 3405        });
 3406    }
 3407
 3408    fn begin_columnar_selection(
 3409        &mut self,
 3410        position: DisplayPoint,
 3411        goal_column: u32,
 3412        reset: bool,
 3413        mode: ColumnarMode,
 3414        window: &mut Window,
 3415        cx: &mut Context<Self>,
 3416    ) {
 3417        if !self.focus_handle.is_focused(window) {
 3418            self.last_focused_descendant = None;
 3419            window.focus(&self.focus_handle);
 3420        }
 3421
 3422        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3423
 3424        if reset {
 3425            let pointer_position = display_map
 3426                .buffer_snapshot
 3427                .anchor_before(position.to_point(&display_map));
 3428
 3429            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3430                s.clear_disjoint();
 3431                s.set_pending_anchor_range(
 3432                    pointer_position..pointer_position,
 3433                    SelectMode::Character,
 3434                );
 3435            });
 3436        };
 3437
 3438        let tail = self.selections.newest::<Point>(cx).tail();
 3439        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3440        self.columnar_selection_state = match mode {
 3441            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3442                selection_tail: selection_anchor,
 3443                display_point: if reset {
 3444                    if position.column() != goal_column {
 3445                        Some(DisplayPoint::new(position.row(), goal_column))
 3446                    } else {
 3447                        None
 3448                    }
 3449                } else {
 3450                    None
 3451                },
 3452            }),
 3453            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3454                selection_tail: selection_anchor,
 3455            }),
 3456        };
 3457
 3458        if !reset {
 3459            self.select_columns(position, goal_column, &display_map, window, cx);
 3460        }
 3461    }
 3462
 3463    fn update_selection(
 3464        &mut self,
 3465        position: DisplayPoint,
 3466        goal_column: u32,
 3467        scroll_delta: gpui::Point<f32>,
 3468        window: &mut Window,
 3469        cx: &mut Context<Self>,
 3470    ) {
 3471        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3472
 3473        if self.columnar_selection_state.is_some() {
 3474            self.select_columns(position, goal_column, &display_map, window, cx);
 3475        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3476            let buffer = self.buffer.read(cx).snapshot(cx);
 3477            let head;
 3478            let tail;
 3479            let mode = self.selections.pending_mode().unwrap();
 3480            match &mode {
 3481                SelectMode::Character => {
 3482                    head = position.to_point(&display_map);
 3483                    tail = pending.tail().to_point(&buffer);
 3484                }
 3485                SelectMode::Word(original_range) => {
 3486                    let original_display_range = original_range.start.to_display_point(&display_map)
 3487                        ..original_range.end.to_display_point(&display_map);
 3488                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3489                        ..original_display_range.end.to_point(&display_map);
 3490                    if movement::is_inside_word(&display_map, position)
 3491                        || original_display_range.contains(&position)
 3492                    {
 3493                        let word_range = movement::surrounding_word(&display_map, position);
 3494                        if word_range.start < original_display_range.start {
 3495                            head = word_range.start.to_point(&display_map);
 3496                        } else {
 3497                            head = word_range.end.to_point(&display_map);
 3498                        }
 3499                    } else {
 3500                        head = position.to_point(&display_map);
 3501                    }
 3502
 3503                    if head <= original_buffer_range.start {
 3504                        tail = original_buffer_range.end;
 3505                    } else {
 3506                        tail = original_buffer_range.start;
 3507                    }
 3508                }
 3509                SelectMode::Line(original_range) => {
 3510                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3511
 3512                    let position = display_map
 3513                        .clip_point(position, Bias::Left)
 3514                        .to_point(&display_map);
 3515                    let line_start = display_map.prev_line_boundary(position).0;
 3516                    let next_line_start = buffer.clip_point(
 3517                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3518                        Bias::Left,
 3519                    );
 3520
 3521                    if line_start < original_range.start {
 3522                        head = line_start
 3523                    } else {
 3524                        head = next_line_start
 3525                    }
 3526
 3527                    if head <= original_range.start {
 3528                        tail = original_range.end;
 3529                    } else {
 3530                        tail = original_range.start;
 3531                    }
 3532                }
 3533                SelectMode::All => {
 3534                    return;
 3535                }
 3536            };
 3537
 3538            if head < tail {
 3539                pending.start = buffer.anchor_before(head);
 3540                pending.end = buffer.anchor_before(tail);
 3541                pending.reversed = true;
 3542            } else {
 3543                pending.start = buffer.anchor_before(tail);
 3544                pending.end = buffer.anchor_before(head);
 3545                pending.reversed = false;
 3546            }
 3547
 3548            self.change_selections(None, window, cx, |s| {
 3549                s.set_pending(pending, mode);
 3550            });
 3551        } else {
 3552            log::error!("update_selection dispatched with no pending selection");
 3553            return;
 3554        }
 3555
 3556        self.apply_scroll_delta(scroll_delta, window, cx);
 3557        cx.notify();
 3558    }
 3559
 3560    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3561        self.columnar_selection_state.take();
 3562        if self.selections.pending_anchor().is_some() {
 3563            let selections = self.selections.all::<usize>(cx);
 3564            self.change_selections(None, window, cx, |s| {
 3565                s.select(selections);
 3566                s.clear_pending();
 3567            });
 3568        }
 3569    }
 3570
 3571    fn select_columns(
 3572        &mut self,
 3573        head: DisplayPoint,
 3574        goal_column: u32,
 3575        display_map: &DisplaySnapshot,
 3576        window: &mut Window,
 3577        cx: &mut Context<Self>,
 3578    ) {
 3579        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3580            return;
 3581        };
 3582
 3583        let tail = match columnar_state {
 3584            ColumnarSelectionState::FromMouse {
 3585                selection_tail,
 3586                display_point,
 3587            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3588            ColumnarSelectionState::FromSelection { selection_tail } => {
 3589                selection_tail.to_display_point(&display_map)
 3590            }
 3591        };
 3592
 3593        let start_row = cmp::min(tail.row(), head.row());
 3594        let end_row = cmp::max(tail.row(), head.row());
 3595        let start_column = cmp::min(tail.column(), goal_column);
 3596        let end_column = cmp::max(tail.column(), goal_column);
 3597        let reversed = start_column < tail.column();
 3598
 3599        let selection_ranges = (start_row.0..=end_row.0)
 3600            .map(DisplayRow)
 3601            .filter_map(|row| {
 3602                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3603                    || start_column <= display_map.line_len(row))
 3604                    && !display_map.is_block_line(row)
 3605                {
 3606                    let start = display_map
 3607                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3608                        .to_point(display_map);
 3609                    let end = display_map
 3610                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3611                        .to_point(display_map);
 3612                    if reversed {
 3613                        Some(end..start)
 3614                    } else {
 3615                        Some(start..end)
 3616                    }
 3617                } else {
 3618                    None
 3619                }
 3620            })
 3621            .collect::<Vec<_>>();
 3622
 3623        let ranges = match columnar_state {
 3624            ColumnarSelectionState::FromMouse { .. } => {
 3625                let mut non_empty_ranges = selection_ranges
 3626                    .iter()
 3627                    .filter(|selection_range| selection_range.start != selection_range.end)
 3628                    .peekable();
 3629                if non_empty_ranges.peek().is_some() {
 3630                    non_empty_ranges.cloned().collect()
 3631                } else {
 3632                    selection_ranges
 3633                }
 3634            }
 3635            _ => selection_ranges,
 3636        };
 3637
 3638        self.change_selections(None, window, cx, |s| {
 3639            s.select_ranges(ranges);
 3640        });
 3641        cx.notify();
 3642    }
 3643
 3644    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3645        self.selections
 3646            .all_adjusted(cx)
 3647            .iter()
 3648            .any(|selection| !selection.is_empty())
 3649    }
 3650
 3651    pub fn has_pending_nonempty_selection(&self) -> bool {
 3652        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3653            Some(Selection { start, end, .. }) => start != end,
 3654            None => false,
 3655        };
 3656
 3657        pending_nonempty_selection
 3658            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3659    }
 3660
 3661    pub fn has_pending_selection(&self) -> bool {
 3662        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3663    }
 3664
 3665    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3666        self.selection_mark_mode = false;
 3667        self.selection_drag_state = SelectionDragState::None;
 3668
 3669        if self.clear_expanded_diff_hunks(cx) {
 3670            cx.notify();
 3671            return;
 3672        }
 3673        if self.dismiss_menus_and_popups(true, window, cx) {
 3674            return;
 3675        }
 3676
 3677        if self.mode.is_full()
 3678            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3679        {
 3680            return;
 3681        }
 3682
 3683        cx.propagate();
 3684    }
 3685
 3686    pub fn dismiss_menus_and_popups(
 3687        &mut self,
 3688        is_user_requested: bool,
 3689        window: &mut Window,
 3690        cx: &mut Context<Self>,
 3691    ) -> bool {
 3692        if self.take_rename(false, window, cx).is_some() {
 3693            return true;
 3694        }
 3695
 3696        if hide_hover(self, cx) {
 3697            return true;
 3698        }
 3699
 3700        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3701            return true;
 3702        }
 3703
 3704        if self.hide_context_menu(window, cx).is_some() {
 3705            return true;
 3706        }
 3707
 3708        if self.mouse_context_menu.take().is_some() {
 3709            return true;
 3710        }
 3711
 3712        if is_user_requested && self.discard_inline_completion(true, cx) {
 3713            return true;
 3714        }
 3715
 3716        if self.snippet_stack.pop().is_some() {
 3717            return true;
 3718        }
 3719
 3720        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3721            self.dismiss_diagnostics(cx);
 3722            return true;
 3723        }
 3724
 3725        false
 3726    }
 3727
 3728    fn linked_editing_ranges_for(
 3729        &self,
 3730        selection: Range<text::Anchor>,
 3731        cx: &App,
 3732    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3733        if self.linked_edit_ranges.is_empty() {
 3734            return None;
 3735        }
 3736        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3737            selection.end.buffer_id.and_then(|end_buffer_id| {
 3738                if selection.start.buffer_id != Some(end_buffer_id) {
 3739                    return None;
 3740                }
 3741                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3742                let snapshot = buffer.read(cx).snapshot();
 3743                self.linked_edit_ranges
 3744                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3745                    .map(|ranges| (ranges, snapshot, buffer))
 3746            })?;
 3747        use text::ToOffset as TO;
 3748        // find offset from the start of current range to current cursor position
 3749        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3750
 3751        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3752        let start_difference = start_offset - start_byte_offset;
 3753        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3754        let end_difference = end_offset - start_byte_offset;
 3755        // Current range has associated linked ranges.
 3756        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3757        for range in linked_ranges.iter() {
 3758            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3759            let end_offset = start_offset + end_difference;
 3760            let start_offset = start_offset + start_difference;
 3761            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3762                continue;
 3763            }
 3764            if self.selections.disjoint_anchor_ranges().any(|s| {
 3765                if s.start.buffer_id != selection.start.buffer_id
 3766                    || s.end.buffer_id != selection.end.buffer_id
 3767                {
 3768                    return false;
 3769                }
 3770                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3771                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3772            }) {
 3773                continue;
 3774            }
 3775            let start = buffer_snapshot.anchor_after(start_offset);
 3776            let end = buffer_snapshot.anchor_after(end_offset);
 3777            linked_edits
 3778                .entry(buffer.clone())
 3779                .or_default()
 3780                .push(start..end);
 3781        }
 3782        Some(linked_edits)
 3783    }
 3784
 3785    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3786        let text: Arc<str> = text.into();
 3787
 3788        if self.read_only(cx) {
 3789            return;
 3790        }
 3791
 3792        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3793
 3794        let selections = self.selections.all_adjusted(cx);
 3795        let mut bracket_inserted = false;
 3796        let mut edits = Vec::new();
 3797        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3798        let mut new_selections = Vec::with_capacity(selections.len());
 3799        let mut new_autoclose_regions = Vec::new();
 3800        let snapshot = self.buffer.read(cx).read(cx);
 3801        let mut clear_linked_edit_ranges = false;
 3802
 3803        for (selection, autoclose_region) in
 3804            self.selections_with_autoclose_regions(selections, &snapshot)
 3805        {
 3806            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3807                // Determine if the inserted text matches the opening or closing
 3808                // bracket of any of this language's bracket pairs.
 3809                let mut bracket_pair = None;
 3810                let mut is_bracket_pair_start = false;
 3811                let mut is_bracket_pair_end = false;
 3812                if !text.is_empty() {
 3813                    let mut bracket_pair_matching_end = None;
 3814                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3815                    //  and they are removing the character that triggered IME popup.
 3816                    for (pair, enabled) in scope.brackets() {
 3817                        if !pair.close && !pair.surround {
 3818                            continue;
 3819                        }
 3820
 3821                        if enabled && pair.start.ends_with(text.as_ref()) {
 3822                            let prefix_len = pair.start.len() - text.len();
 3823                            let preceding_text_matches_prefix = prefix_len == 0
 3824                                || (selection.start.column >= (prefix_len as u32)
 3825                                    && snapshot.contains_str_at(
 3826                                        Point::new(
 3827                                            selection.start.row,
 3828                                            selection.start.column - (prefix_len as u32),
 3829                                        ),
 3830                                        &pair.start[..prefix_len],
 3831                                    ));
 3832                            if preceding_text_matches_prefix {
 3833                                bracket_pair = Some(pair.clone());
 3834                                is_bracket_pair_start = true;
 3835                                break;
 3836                            }
 3837                        }
 3838                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3839                        {
 3840                            // take first bracket pair matching end, but don't break in case a later bracket
 3841                            // pair matches start
 3842                            bracket_pair_matching_end = Some(pair.clone());
 3843                        }
 3844                    }
 3845                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3846                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3847                        is_bracket_pair_end = true;
 3848                    }
 3849                }
 3850
 3851                if let Some(bracket_pair) = bracket_pair {
 3852                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3853                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3854                    let auto_surround =
 3855                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3856                    if selection.is_empty() {
 3857                        if is_bracket_pair_start {
 3858                            // If the inserted text is a suffix of an opening bracket and the
 3859                            // selection is preceded by the rest of the opening bracket, then
 3860                            // insert the closing bracket.
 3861                            let following_text_allows_autoclose = snapshot
 3862                                .chars_at(selection.start)
 3863                                .next()
 3864                                .map_or(true, |c| scope.should_autoclose_before(c));
 3865
 3866                            let preceding_text_allows_autoclose = selection.start.column == 0
 3867                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3868                                    true,
 3869                                    |c| {
 3870                                        bracket_pair.start != bracket_pair.end
 3871                                            || !snapshot
 3872                                                .char_classifier_at(selection.start)
 3873                                                .is_word(c)
 3874                                    },
 3875                                );
 3876
 3877                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3878                                && bracket_pair.start.len() == 1
 3879                            {
 3880                                let target = bracket_pair.start.chars().next().unwrap();
 3881                                let current_line_count = snapshot
 3882                                    .reversed_chars_at(selection.start)
 3883                                    .take_while(|&c| c != '\n')
 3884                                    .filter(|&c| c == target)
 3885                                    .count();
 3886                                current_line_count % 2 == 1
 3887                            } else {
 3888                                false
 3889                            };
 3890
 3891                            if autoclose
 3892                                && bracket_pair.close
 3893                                && following_text_allows_autoclose
 3894                                && preceding_text_allows_autoclose
 3895                                && !is_closing_quote
 3896                            {
 3897                                let anchor = snapshot.anchor_before(selection.end);
 3898                                new_selections.push((selection.map(|_| anchor), text.len()));
 3899                                new_autoclose_regions.push((
 3900                                    anchor,
 3901                                    text.len(),
 3902                                    selection.id,
 3903                                    bracket_pair.clone(),
 3904                                ));
 3905                                edits.push((
 3906                                    selection.range(),
 3907                                    format!("{}{}", text, bracket_pair.end).into(),
 3908                                ));
 3909                                bracket_inserted = true;
 3910                                continue;
 3911                            }
 3912                        }
 3913
 3914                        if let Some(region) = autoclose_region {
 3915                            // If the selection is followed by an auto-inserted closing bracket,
 3916                            // then don't insert that closing bracket again; just move the selection
 3917                            // past the closing bracket.
 3918                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3919                                && text.as_ref() == region.pair.end.as_str();
 3920                            if should_skip {
 3921                                let anchor = snapshot.anchor_after(selection.end);
 3922                                new_selections
 3923                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3924                                continue;
 3925                            }
 3926                        }
 3927
 3928                        let always_treat_brackets_as_autoclosed = snapshot
 3929                            .language_settings_at(selection.start, cx)
 3930                            .always_treat_brackets_as_autoclosed;
 3931                        if always_treat_brackets_as_autoclosed
 3932                            && is_bracket_pair_end
 3933                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3934                        {
 3935                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3936                            // and the inserted text is a closing bracket and the selection is followed
 3937                            // by the closing bracket then move the selection past the closing bracket.
 3938                            let anchor = snapshot.anchor_after(selection.end);
 3939                            new_selections.push((selection.map(|_| anchor), text.len()));
 3940                            continue;
 3941                        }
 3942                    }
 3943                    // If an opening bracket is 1 character long and is typed while
 3944                    // text is selected, then surround that text with the bracket pair.
 3945                    else if auto_surround
 3946                        && bracket_pair.surround
 3947                        && is_bracket_pair_start
 3948                        && bracket_pair.start.chars().count() == 1
 3949                    {
 3950                        edits.push((selection.start..selection.start, text.clone()));
 3951                        edits.push((
 3952                            selection.end..selection.end,
 3953                            bracket_pair.end.as_str().into(),
 3954                        ));
 3955                        bracket_inserted = true;
 3956                        new_selections.push((
 3957                            Selection {
 3958                                id: selection.id,
 3959                                start: snapshot.anchor_after(selection.start),
 3960                                end: snapshot.anchor_before(selection.end),
 3961                                reversed: selection.reversed,
 3962                                goal: selection.goal,
 3963                            },
 3964                            0,
 3965                        ));
 3966                        continue;
 3967                    }
 3968                }
 3969            }
 3970
 3971            if self.auto_replace_emoji_shortcode
 3972                && selection.is_empty()
 3973                && text.as_ref().ends_with(':')
 3974            {
 3975                if let Some(possible_emoji_short_code) =
 3976                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3977                {
 3978                    if !possible_emoji_short_code.is_empty() {
 3979                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3980                            let emoji_shortcode_start = Point::new(
 3981                                selection.start.row,
 3982                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3983                            );
 3984
 3985                            // Remove shortcode from buffer
 3986                            edits.push((
 3987                                emoji_shortcode_start..selection.start,
 3988                                "".to_string().into(),
 3989                            ));
 3990                            new_selections.push((
 3991                                Selection {
 3992                                    id: selection.id,
 3993                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3994                                    end: snapshot.anchor_before(selection.start),
 3995                                    reversed: selection.reversed,
 3996                                    goal: selection.goal,
 3997                                },
 3998                                0,
 3999                            ));
 4000
 4001                            // Insert emoji
 4002                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4003                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4004                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4005
 4006                            continue;
 4007                        }
 4008                    }
 4009                }
 4010            }
 4011
 4012            // If not handling any auto-close operation, then just replace the selected
 4013            // text with the given input and move the selection to the end of the
 4014            // newly inserted text.
 4015            let anchor = snapshot.anchor_after(selection.end);
 4016            if !self.linked_edit_ranges.is_empty() {
 4017                let start_anchor = snapshot.anchor_before(selection.start);
 4018
 4019                let is_word_char = text.chars().next().map_or(true, |char| {
 4020                    let classifier = snapshot
 4021                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4022                        .ignore_punctuation(true);
 4023                    classifier.is_word(char)
 4024                });
 4025
 4026                if is_word_char {
 4027                    if let Some(ranges) = self
 4028                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4029                    {
 4030                        for (buffer, edits) in ranges {
 4031                            linked_edits
 4032                                .entry(buffer.clone())
 4033                                .or_default()
 4034                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4035                        }
 4036                    }
 4037                } else {
 4038                    clear_linked_edit_ranges = true;
 4039                }
 4040            }
 4041
 4042            new_selections.push((selection.map(|_| anchor), 0));
 4043            edits.push((selection.start..selection.end, text.clone()));
 4044        }
 4045
 4046        drop(snapshot);
 4047
 4048        self.transact(window, cx, |this, window, cx| {
 4049            if clear_linked_edit_ranges {
 4050                this.linked_edit_ranges.clear();
 4051            }
 4052            let initial_buffer_versions =
 4053                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4054
 4055            this.buffer.update(cx, |buffer, cx| {
 4056                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4057            });
 4058            for (buffer, edits) in linked_edits {
 4059                buffer.update(cx, |buffer, cx| {
 4060                    let snapshot = buffer.snapshot();
 4061                    let edits = edits
 4062                        .into_iter()
 4063                        .map(|(range, text)| {
 4064                            use text::ToPoint as TP;
 4065                            let end_point = TP::to_point(&range.end, &snapshot);
 4066                            let start_point = TP::to_point(&range.start, &snapshot);
 4067                            (start_point..end_point, text)
 4068                        })
 4069                        .sorted_by_key(|(range, _)| range.start);
 4070                    buffer.edit(edits, None, cx);
 4071                })
 4072            }
 4073            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4074            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4075            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4076            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4077                .zip(new_selection_deltas)
 4078                .map(|(selection, delta)| Selection {
 4079                    id: selection.id,
 4080                    start: selection.start + delta,
 4081                    end: selection.end + delta,
 4082                    reversed: selection.reversed,
 4083                    goal: SelectionGoal::None,
 4084                })
 4085                .collect::<Vec<_>>();
 4086
 4087            let mut i = 0;
 4088            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4089                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4090                let start = map.buffer_snapshot.anchor_before(position);
 4091                let end = map.buffer_snapshot.anchor_after(position);
 4092                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4093                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4094                        Ordering::Less => i += 1,
 4095                        Ordering::Greater => break,
 4096                        Ordering::Equal => {
 4097                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4098                                Ordering::Less => i += 1,
 4099                                Ordering::Equal => break,
 4100                                Ordering::Greater => break,
 4101                            }
 4102                        }
 4103                    }
 4104                }
 4105                this.autoclose_regions.insert(
 4106                    i,
 4107                    AutocloseRegion {
 4108                        selection_id,
 4109                        range: start..end,
 4110                        pair,
 4111                    },
 4112                );
 4113            }
 4114
 4115            let had_active_inline_completion = this.has_active_inline_completion();
 4116            this.change_selections(
 4117                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4118                window,
 4119                cx,
 4120                |s| s.select(new_selections),
 4121            );
 4122
 4123            if !bracket_inserted {
 4124                if let Some(on_type_format_task) =
 4125                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4126                {
 4127                    on_type_format_task.detach_and_log_err(cx);
 4128                }
 4129            }
 4130
 4131            let editor_settings = EditorSettings::get_global(cx);
 4132            if bracket_inserted
 4133                && (editor_settings.auto_signature_help
 4134                    || editor_settings.show_signature_help_after_edits)
 4135            {
 4136                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4137            }
 4138
 4139            let trigger_in_words =
 4140                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4141            if this.hard_wrap.is_some() {
 4142                let latest: Range<Point> = this.selections.newest(cx).range();
 4143                if latest.is_empty()
 4144                    && this
 4145                        .buffer()
 4146                        .read(cx)
 4147                        .snapshot(cx)
 4148                        .line_len(MultiBufferRow(latest.start.row))
 4149                        == latest.start.column
 4150                {
 4151                    this.rewrap_impl(
 4152                        RewrapOptions {
 4153                            override_language_settings: true,
 4154                            preserve_existing_whitespace: true,
 4155                        },
 4156                        cx,
 4157                    )
 4158                }
 4159            }
 4160            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4161            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4162            this.refresh_inline_completion(true, false, window, cx);
 4163            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4164        });
 4165    }
 4166
 4167    fn find_possible_emoji_shortcode_at_position(
 4168        snapshot: &MultiBufferSnapshot,
 4169        position: Point,
 4170    ) -> Option<String> {
 4171        let mut chars = Vec::new();
 4172        let mut found_colon = false;
 4173        for char in snapshot.reversed_chars_at(position).take(100) {
 4174            // Found a possible emoji shortcode in the middle of the buffer
 4175            if found_colon {
 4176                if char.is_whitespace() {
 4177                    chars.reverse();
 4178                    return Some(chars.iter().collect());
 4179                }
 4180                // If the previous character is not a whitespace, we are in the middle of a word
 4181                // and we only want to complete the shortcode if the word is made up of other emojis
 4182                let mut containing_word = String::new();
 4183                for ch in snapshot
 4184                    .reversed_chars_at(position)
 4185                    .skip(chars.len() + 1)
 4186                    .take(100)
 4187                {
 4188                    if ch.is_whitespace() {
 4189                        break;
 4190                    }
 4191                    containing_word.push(ch);
 4192                }
 4193                let containing_word = containing_word.chars().rev().collect::<String>();
 4194                if util::word_consists_of_emojis(containing_word.as_str()) {
 4195                    chars.reverse();
 4196                    return Some(chars.iter().collect());
 4197                }
 4198            }
 4199
 4200            if char.is_whitespace() || !char.is_ascii() {
 4201                return None;
 4202            }
 4203            if char == ':' {
 4204                found_colon = true;
 4205            } else {
 4206                chars.push(char);
 4207            }
 4208        }
 4209        // Found a possible emoji shortcode at the beginning of the buffer
 4210        chars.reverse();
 4211        Some(chars.iter().collect())
 4212    }
 4213
 4214    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4216        self.transact(window, cx, |this, window, cx| {
 4217            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4218                let selections = this.selections.all::<usize>(cx);
 4219                let multi_buffer = this.buffer.read(cx);
 4220                let buffer = multi_buffer.snapshot(cx);
 4221                selections
 4222                    .iter()
 4223                    .map(|selection| {
 4224                        let start_point = selection.start.to_point(&buffer);
 4225                        let mut existing_indent =
 4226                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4227                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4228                        let start = selection.start;
 4229                        let end = selection.end;
 4230                        let selection_is_empty = start == end;
 4231                        let language_scope = buffer.language_scope_at(start);
 4232                        let (
 4233                            comment_delimiter,
 4234                            doc_delimiter,
 4235                            insert_extra_newline,
 4236                            indent_on_newline,
 4237                            indent_on_extra_newline,
 4238                        ) = if let Some(language) = &language_scope {
 4239                            let mut insert_extra_newline =
 4240                                insert_extra_newline_brackets(&buffer, start..end, language)
 4241                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4242
 4243                            // Comment extension on newline is allowed only for cursor selections
 4244                            let comment_delimiter = maybe!({
 4245                                if !selection_is_empty {
 4246                                    return None;
 4247                                }
 4248
 4249                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4250                                    return None;
 4251                                }
 4252
 4253                                let delimiters = language.line_comment_prefixes();
 4254                                let max_len_of_delimiter =
 4255                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4256                                let (snapshot, range) =
 4257                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4258
 4259                                let num_of_whitespaces = snapshot
 4260                                    .chars_for_range(range.clone())
 4261                                    .take_while(|c| c.is_whitespace())
 4262                                    .count();
 4263                                let comment_candidate = snapshot
 4264                                    .chars_for_range(range)
 4265                                    .skip(num_of_whitespaces)
 4266                                    .take(max_len_of_delimiter)
 4267                                    .collect::<String>();
 4268                                let (delimiter, trimmed_len) = delimiters
 4269                                    .iter()
 4270                                    .filter_map(|delimiter| {
 4271                                        let prefix = delimiter.trim_end();
 4272                                        if comment_candidate.starts_with(prefix) {
 4273                                            Some((delimiter, prefix.len()))
 4274                                        } else {
 4275                                            None
 4276                                        }
 4277                                    })
 4278                                    .max_by_key(|(_, len)| *len)?;
 4279
 4280                                let cursor_is_placed_after_comment_marker =
 4281                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4282                                if cursor_is_placed_after_comment_marker {
 4283                                    Some(delimiter.clone())
 4284                                } else {
 4285                                    None
 4286                                }
 4287                            });
 4288
 4289                            let mut indent_on_newline = IndentSize::spaces(0);
 4290                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4291
 4292                            let doc_delimiter = maybe!({
 4293                                if !selection_is_empty {
 4294                                    return None;
 4295                                }
 4296
 4297                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4298                                    return None;
 4299                                }
 4300
 4301                                let DocumentationConfig {
 4302                                    start: start_tag,
 4303                                    end: end_tag,
 4304                                    prefix: delimiter,
 4305                                    tab_size: len,
 4306                                } = language.documentation()?;
 4307
 4308                                let is_within_block_comment = buffer
 4309                                    .language_scope_at(start_point)
 4310                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4311                                if !is_within_block_comment {
 4312                                    return None;
 4313                                }
 4314
 4315                                let (snapshot, range) =
 4316                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4317
 4318                                let num_of_whitespaces = snapshot
 4319                                    .chars_for_range(range.clone())
 4320                                    .take_while(|c| c.is_whitespace())
 4321                                    .count();
 4322
 4323                                // 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.
 4324                                let column = start_point.column;
 4325                                let cursor_is_after_start_tag = {
 4326                                    let start_tag_len = start_tag.len();
 4327                                    let start_tag_line = snapshot
 4328                                        .chars_for_range(range.clone())
 4329                                        .skip(num_of_whitespaces)
 4330                                        .take(start_tag_len)
 4331                                        .collect::<String>();
 4332                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4333                                        num_of_whitespaces + start_tag_len <= column as usize
 4334                                    } else {
 4335                                        false
 4336                                    }
 4337                                };
 4338
 4339                                let cursor_is_after_delimiter = {
 4340                                    let delimiter_trim = delimiter.trim_end();
 4341                                    let delimiter_line = snapshot
 4342                                        .chars_for_range(range.clone())
 4343                                        .skip(num_of_whitespaces)
 4344                                        .take(delimiter_trim.len())
 4345                                        .collect::<String>();
 4346                                    if delimiter_line.starts_with(delimiter_trim) {
 4347                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4348                                    } else {
 4349                                        false
 4350                                    }
 4351                                };
 4352
 4353                                let cursor_is_before_end_tag_if_exists = {
 4354                                    let mut char_position = 0u32;
 4355                                    let mut end_tag_offset = None;
 4356
 4357                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4358                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4359                                            let chars_before_match =
 4360                                                chunk[..byte_pos].chars().count() as u32;
 4361                                            end_tag_offset =
 4362                                                Some(char_position + chars_before_match);
 4363                                            break 'outer;
 4364                                        }
 4365                                        char_position += chunk.chars().count() as u32;
 4366                                    }
 4367
 4368                                    if let Some(end_tag_offset) = end_tag_offset {
 4369                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4370                                        if cursor_is_after_start_tag {
 4371                                            if cursor_is_before_end_tag {
 4372                                                insert_extra_newline = true;
 4373                                            }
 4374                                            let cursor_is_at_start_of_end_tag =
 4375                                                column == end_tag_offset;
 4376                                            if cursor_is_at_start_of_end_tag {
 4377                                                indent_on_extra_newline.len = (*len).into();
 4378                                            }
 4379                                        }
 4380                                        cursor_is_before_end_tag
 4381                                    } else {
 4382                                        true
 4383                                    }
 4384                                };
 4385
 4386                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4387                                    && cursor_is_before_end_tag_if_exists
 4388                                {
 4389                                    if cursor_is_after_start_tag {
 4390                                        indent_on_newline.len = (*len).into();
 4391                                    }
 4392                                    Some(delimiter.clone())
 4393                                } else {
 4394                                    None
 4395                                }
 4396                            });
 4397
 4398                            (
 4399                                comment_delimiter,
 4400                                doc_delimiter,
 4401                                insert_extra_newline,
 4402                                indent_on_newline,
 4403                                indent_on_extra_newline,
 4404                            )
 4405                        } else {
 4406                            (
 4407                                None,
 4408                                None,
 4409                                false,
 4410                                IndentSize::default(),
 4411                                IndentSize::default(),
 4412                            )
 4413                        };
 4414
 4415                        let prevent_auto_indent = doc_delimiter.is_some();
 4416                        let delimiter = comment_delimiter.or(doc_delimiter);
 4417
 4418                        let capacity_for_delimiter =
 4419                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4420                        let mut new_text = String::with_capacity(
 4421                            1 + capacity_for_delimiter
 4422                                + existing_indent.len as usize
 4423                                + indent_on_newline.len as usize
 4424                                + indent_on_extra_newline.len as usize,
 4425                        );
 4426                        new_text.push('\n');
 4427                        new_text.extend(existing_indent.chars());
 4428                        new_text.extend(indent_on_newline.chars());
 4429
 4430                        if let Some(delimiter) = &delimiter {
 4431                            new_text.push_str(delimiter);
 4432                        }
 4433
 4434                        if insert_extra_newline {
 4435                            new_text.push('\n');
 4436                            new_text.extend(existing_indent.chars());
 4437                            new_text.extend(indent_on_extra_newline.chars());
 4438                        }
 4439
 4440                        let anchor = buffer.anchor_after(end);
 4441                        let new_selection = selection.map(|_| anchor);
 4442                        (
 4443                            ((start..end, new_text), prevent_auto_indent),
 4444                            (insert_extra_newline, new_selection),
 4445                        )
 4446                    })
 4447                    .unzip()
 4448            };
 4449
 4450            let mut auto_indent_edits = Vec::new();
 4451            let mut edits = Vec::new();
 4452            for (edit, prevent_auto_indent) in edits_with_flags {
 4453                if prevent_auto_indent {
 4454                    edits.push(edit);
 4455                } else {
 4456                    auto_indent_edits.push(edit);
 4457                }
 4458            }
 4459            if !edits.is_empty() {
 4460                this.edit(edits, cx);
 4461            }
 4462            if !auto_indent_edits.is_empty() {
 4463                this.edit_with_autoindent(auto_indent_edits, cx);
 4464            }
 4465
 4466            let buffer = this.buffer.read(cx).snapshot(cx);
 4467            let new_selections = selection_info
 4468                .into_iter()
 4469                .map(|(extra_newline_inserted, new_selection)| {
 4470                    let mut cursor = new_selection.end.to_point(&buffer);
 4471                    if extra_newline_inserted {
 4472                        cursor.row -= 1;
 4473                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4474                    }
 4475                    new_selection.map(|_| cursor)
 4476                })
 4477                .collect();
 4478
 4479            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4480                s.select(new_selections)
 4481            });
 4482            this.refresh_inline_completion(true, false, window, cx);
 4483        });
 4484    }
 4485
 4486    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4487        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4488
 4489        let buffer = self.buffer.read(cx);
 4490        let snapshot = buffer.snapshot(cx);
 4491
 4492        let mut edits = Vec::new();
 4493        let mut rows = Vec::new();
 4494
 4495        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4496            let cursor = selection.head();
 4497            let row = cursor.row;
 4498
 4499            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4500
 4501            let newline = "\n".to_string();
 4502            edits.push((start_of_line..start_of_line, newline));
 4503
 4504            rows.push(row + rows_inserted as u32);
 4505        }
 4506
 4507        self.transact(window, cx, |editor, window, cx| {
 4508            editor.edit(edits, cx);
 4509
 4510            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4511                let mut index = 0;
 4512                s.move_cursors_with(|map, _, _| {
 4513                    let row = rows[index];
 4514                    index += 1;
 4515
 4516                    let point = Point::new(row, 0);
 4517                    let boundary = map.next_line_boundary(point).1;
 4518                    let clipped = map.clip_point(boundary, Bias::Left);
 4519
 4520                    (clipped, SelectionGoal::None)
 4521                });
 4522            });
 4523
 4524            let mut indent_edits = Vec::new();
 4525            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4526            for row in rows {
 4527                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4528                for (row, indent) in indents {
 4529                    if indent.len == 0 {
 4530                        continue;
 4531                    }
 4532
 4533                    let text = match indent.kind {
 4534                        IndentKind::Space => " ".repeat(indent.len as usize),
 4535                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4536                    };
 4537                    let point = Point::new(row.0, 0);
 4538                    indent_edits.push((point..point, text));
 4539                }
 4540            }
 4541            editor.edit(indent_edits, cx);
 4542        });
 4543    }
 4544
 4545    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4546        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4547
 4548        let buffer = self.buffer.read(cx);
 4549        let snapshot = buffer.snapshot(cx);
 4550
 4551        let mut edits = Vec::new();
 4552        let mut rows = Vec::new();
 4553        let mut rows_inserted = 0;
 4554
 4555        for selection in self.selections.all_adjusted(cx) {
 4556            let cursor = selection.head();
 4557            let row = cursor.row;
 4558
 4559            let point = Point::new(row + 1, 0);
 4560            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4561
 4562            let newline = "\n".to_string();
 4563            edits.push((start_of_line..start_of_line, newline));
 4564
 4565            rows_inserted += 1;
 4566            rows.push(row + rows_inserted);
 4567        }
 4568
 4569        self.transact(window, cx, |editor, window, cx| {
 4570            editor.edit(edits, cx);
 4571
 4572            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4573                let mut index = 0;
 4574                s.move_cursors_with(|map, _, _| {
 4575                    let row = rows[index];
 4576                    index += 1;
 4577
 4578                    let point = Point::new(row, 0);
 4579                    let boundary = map.next_line_boundary(point).1;
 4580                    let clipped = map.clip_point(boundary, Bias::Left);
 4581
 4582                    (clipped, SelectionGoal::None)
 4583                });
 4584            });
 4585
 4586            let mut indent_edits = Vec::new();
 4587            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4588            for row in rows {
 4589                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4590                for (row, indent) in indents {
 4591                    if indent.len == 0 {
 4592                        continue;
 4593                    }
 4594
 4595                    let text = match indent.kind {
 4596                        IndentKind::Space => " ".repeat(indent.len as usize),
 4597                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4598                    };
 4599                    let point = Point::new(row.0, 0);
 4600                    indent_edits.push((point..point, text));
 4601                }
 4602            }
 4603            editor.edit(indent_edits, cx);
 4604        });
 4605    }
 4606
 4607    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4608        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4609            original_indent_columns: Vec::new(),
 4610        });
 4611        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4612    }
 4613
 4614    fn insert_with_autoindent_mode(
 4615        &mut self,
 4616        text: &str,
 4617        autoindent_mode: Option<AutoindentMode>,
 4618        window: &mut Window,
 4619        cx: &mut Context<Self>,
 4620    ) {
 4621        if self.read_only(cx) {
 4622            return;
 4623        }
 4624
 4625        let text: Arc<str> = text.into();
 4626        self.transact(window, cx, |this, window, cx| {
 4627            let old_selections = this.selections.all_adjusted(cx);
 4628            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4629                let anchors = {
 4630                    let snapshot = buffer.read(cx);
 4631                    old_selections
 4632                        .iter()
 4633                        .map(|s| {
 4634                            let anchor = snapshot.anchor_after(s.head());
 4635                            s.map(|_| anchor)
 4636                        })
 4637                        .collect::<Vec<_>>()
 4638                };
 4639                buffer.edit(
 4640                    old_selections
 4641                        .iter()
 4642                        .map(|s| (s.start..s.end, text.clone())),
 4643                    autoindent_mode,
 4644                    cx,
 4645                );
 4646                anchors
 4647            });
 4648
 4649            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4650                s.select_anchors(selection_anchors);
 4651            });
 4652
 4653            cx.notify();
 4654        });
 4655    }
 4656
 4657    fn trigger_completion_on_input(
 4658        &mut self,
 4659        text: &str,
 4660        trigger_in_words: bool,
 4661        window: &mut Window,
 4662        cx: &mut Context<Self>,
 4663    ) {
 4664        let completions_source = self
 4665            .context_menu
 4666            .borrow()
 4667            .as_ref()
 4668            .and_then(|menu| match menu {
 4669                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4670                CodeContextMenu::CodeActions(_) => None,
 4671            });
 4672
 4673        match completions_source {
 4674            Some(CompletionsMenuSource::Words) => {
 4675                self.show_word_completions(&ShowWordCompletions, window, cx)
 4676            }
 4677            Some(CompletionsMenuSource::Normal)
 4678            | Some(CompletionsMenuSource::SnippetChoices)
 4679            | None
 4680                if self.is_completion_trigger(
 4681                    text,
 4682                    trigger_in_words,
 4683                    completions_source.is_some(),
 4684                    cx,
 4685                ) =>
 4686            {
 4687                self.show_completions(
 4688                    &ShowCompletions {
 4689                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4690                    },
 4691                    window,
 4692                    cx,
 4693                )
 4694            }
 4695            _ => {
 4696                self.hide_context_menu(window, cx);
 4697            }
 4698        }
 4699    }
 4700
 4701    fn is_completion_trigger(
 4702        &self,
 4703        text: &str,
 4704        trigger_in_words: bool,
 4705        menu_is_open: bool,
 4706        cx: &mut Context<Self>,
 4707    ) -> bool {
 4708        let position = self.selections.newest_anchor().head();
 4709        let multibuffer = self.buffer.read(cx);
 4710        let Some(buffer) = position
 4711            .buffer_id
 4712            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4713        else {
 4714            return false;
 4715        };
 4716
 4717        if let Some(completion_provider) = &self.completion_provider {
 4718            completion_provider.is_completion_trigger(
 4719                &buffer,
 4720                position.text_anchor,
 4721                text,
 4722                trigger_in_words,
 4723                menu_is_open,
 4724                cx,
 4725            )
 4726        } else {
 4727            false
 4728        }
 4729    }
 4730
 4731    /// If any empty selections is touching the start of its innermost containing autoclose
 4732    /// region, expand it to select the brackets.
 4733    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4734        let selections = self.selections.all::<usize>(cx);
 4735        let buffer = self.buffer.read(cx).read(cx);
 4736        let new_selections = self
 4737            .selections_with_autoclose_regions(selections, &buffer)
 4738            .map(|(mut selection, region)| {
 4739                if !selection.is_empty() {
 4740                    return selection;
 4741                }
 4742
 4743                if let Some(region) = region {
 4744                    let mut range = region.range.to_offset(&buffer);
 4745                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4746                        range.start -= region.pair.start.len();
 4747                        if buffer.contains_str_at(range.start, &region.pair.start)
 4748                            && buffer.contains_str_at(range.end, &region.pair.end)
 4749                        {
 4750                            range.end += region.pair.end.len();
 4751                            selection.start = range.start;
 4752                            selection.end = range.end;
 4753
 4754                            return selection;
 4755                        }
 4756                    }
 4757                }
 4758
 4759                let always_treat_brackets_as_autoclosed = buffer
 4760                    .language_settings_at(selection.start, cx)
 4761                    .always_treat_brackets_as_autoclosed;
 4762
 4763                if !always_treat_brackets_as_autoclosed {
 4764                    return selection;
 4765                }
 4766
 4767                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4768                    for (pair, enabled) in scope.brackets() {
 4769                        if !enabled || !pair.close {
 4770                            continue;
 4771                        }
 4772
 4773                        if buffer.contains_str_at(selection.start, &pair.end) {
 4774                            let pair_start_len = pair.start.len();
 4775                            if buffer.contains_str_at(
 4776                                selection.start.saturating_sub(pair_start_len),
 4777                                &pair.start,
 4778                            ) {
 4779                                selection.start -= pair_start_len;
 4780                                selection.end += pair.end.len();
 4781
 4782                                return selection;
 4783                            }
 4784                        }
 4785                    }
 4786                }
 4787
 4788                selection
 4789            })
 4790            .collect();
 4791
 4792        drop(buffer);
 4793        self.change_selections(None, window, cx, |selections| {
 4794            selections.select(new_selections)
 4795        });
 4796    }
 4797
 4798    /// Iterate the given selections, and for each one, find the smallest surrounding
 4799    /// autoclose region. This uses the ordering of the selections and the autoclose
 4800    /// regions to avoid repeated comparisons.
 4801    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4802        &'a self,
 4803        selections: impl IntoIterator<Item = Selection<D>>,
 4804        buffer: &'a MultiBufferSnapshot,
 4805    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4806        let mut i = 0;
 4807        let mut regions = self.autoclose_regions.as_slice();
 4808        selections.into_iter().map(move |selection| {
 4809            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4810
 4811            let mut enclosing = None;
 4812            while let Some(pair_state) = regions.get(i) {
 4813                if pair_state.range.end.to_offset(buffer) < range.start {
 4814                    regions = &regions[i + 1..];
 4815                    i = 0;
 4816                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4817                    break;
 4818                } else {
 4819                    if pair_state.selection_id == selection.id {
 4820                        enclosing = Some(pair_state);
 4821                    }
 4822                    i += 1;
 4823                }
 4824            }
 4825
 4826            (selection, enclosing)
 4827        })
 4828    }
 4829
 4830    /// Remove any autoclose regions that no longer contain their selection.
 4831    fn invalidate_autoclose_regions(
 4832        &mut self,
 4833        mut selections: &[Selection<Anchor>],
 4834        buffer: &MultiBufferSnapshot,
 4835    ) {
 4836        self.autoclose_regions.retain(|state| {
 4837            let mut i = 0;
 4838            while let Some(selection) = selections.get(i) {
 4839                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4840                    selections = &selections[1..];
 4841                    continue;
 4842                }
 4843                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4844                    break;
 4845                }
 4846                if selection.id == state.selection_id {
 4847                    return true;
 4848                } else {
 4849                    i += 1;
 4850                }
 4851            }
 4852            false
 4853        });
 4854    }
 4855
 4856    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4857        let offset = position.to_offset(buffer);
 4858        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4859        if offset > word_range.start && kind == Some(CharKind::Word) {
 4860            Some(
 4861                buffer
 4862                    .text_for_range(word_range.start..offset)
 4863                    .collect::<String>(),
 4864            )
 4865        } else {
 4866            None
 4867        }
 4868    }
 4869
 4870    pub fn toggle_inline_values(
 4871        &mut self,
 4872        _: &ToggleInlineValues,
 4873        _: &mut Window,
 4874        cx: &mut Context<Self>,
 4875    ) {
 4876        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4877
 4878        self.refresh_inline_values(cx);
 4879    }
 4880
 4881    pub fn toggle_inlay_hints(
 4882        &mut self,
 4883        _: &ToggleInlayHints,
 4884        _: &mut Window,
 4885        cx: &mut Context<Self>,
 4886    ) {
 4887        self.refresh_inlay_hints(
 4888            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4889            cx,
 4890        );
 4891    }
 4892
 4893    pub fn inlay_hints_enabled(&self) -> bool {
 4894        self.inlay_hint_cache.enabled
 4895    }
 4896
 4897    pub fn inline_values_enabled(&self) -> bool {
 4898        self.inline_value_cache.enabled
 4899    }
 4900
 4901    #[cfg(any(test, feature = "test-support"))]
 4902    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4903        self.display_map
 4904            .read(cx)
 4905            .current_inlays()
 4906            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4907            .cloned()
 4908            .collect()
 4909    }
 4910
 4911    #[cfg(any(test, feature = "test-support"))]
 4912    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 4913        self.display_map
 4914            .read(cx)
 4915            .current_inlays()
 4916            .cloned()
 4917            .collect()
 4918    }
 4919
 4920    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4921        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4922            return;
 4923        }
 4924
 4925        let reason_description = reason.description();
 4926        let ignore_debounce = matches!(
 4927            reason,
 4928            InlayHintRefreshReason::SettingsChange(_)
 4929                | InlayHintRefreshReason::Toggle(_)
 4930                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4931                | InlayHintRefreshReason::ModifiersChanged(_)
 4932        );
 4933        let (invalidate_cache, required_languages) = match reason {
 4934            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4935                match self.inlay_hint_cache.modifiers_override(enabled) {
 4936                    Some(enabled) => {
 4937                        if enabled {
 4938                            (InvalidationStrategy::RefreshRequested, None)
 4939                        } else {
 4940                            self.splice_inlays(
 4941                                &self
 4942                                    .visible_inlay_hints(cx)
 4943                                    .iter()
 4944                                    .map(|inlay| inlay.id)
 4945                                    .collect::<Vec<InlayId>>(),
 4946                                Vec::new(),
 4947                                cx,
 4948                            );
 4949                            return;
 4950                        }
 4951                    }
 4952                    None => return,
 4953                }
 4954            }
 4955            InlayHintRefreshReason::Toggle(enabled) => {
 4956                if self.inlay_hint_cache.toggle(enabled) {
 4957                    if enabled {
 4958                        (InvalidationStrategy::RefreshRequested, None)
 4959                    } else {
 4960                        self.splice_inlays(
 4961                            &self
 4962                                .visible_inlay_hints(cx)
 4963                                .iter()
 4964                                .map(|inlay| inlay.id)
 4965                                .collect::<Vec<InlayId>>(),
 4966                            Vec::new(),
 4967                            cx,
 4968                        );
 4969                        return;
 4970                    }
 4971                } else {
 4972                    return;
 4973                }
 4974            }
 4975            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4976                match self.inlay_hint_cache.update_settings(
 4977                    &self.buffer,
 4978                    new_settings,
 4979                    self.visible_inlay_hints(cx),
 4980                    cx,
 4981                ) {
 4982                    ControlFlow::Break(Some(InlaySplice {
 4983                        to_remove,
 4984                        to_insert,
 4985                    })) => {
 4986                        self.splice_inlays(&to_remove, to_insert, cx);
 4987                        return;
 4988                    }
 4989                    ControlFlow::Break(None) => return,
 4990                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4991                }
 4992            }
 4993            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4994                if let Some(InlaySplice {
 4995                    to_remove,
 4996                    to_insert,
 4997                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4998                {
 4999                    self.splice_inlays(&to_remove, to_insert, cx);
 5000                }
 5001                self.display_map.update(cx, |display_map, _| {
 5002                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5003                });
 5004                return;
 5005            }
 5006            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5007            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5008                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5009            }
 5010            InlayHintRefreshReason::RefreshRequested => {
 5011                (InvalidationStrategy::RefreshRequested, None)
 5012            }
 5013        };
 5014
 5015        if let Some(InlaySplice {
 5016            to_remove,
 5017            to_insert,
 5018        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5019            reason_description,
 5020            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 5021            invalidate_cache,
 5022            ignore_debounce,
 5023            cx,
 5024        ) {
 5025            self.splice_inlays(&to_remove, to_insert, cx);
 5026        }
 5027    }
 5028
 5029    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5030        self.display_map
 5031            .read(cx)
 5032            .current_inlays()
 5033            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5034            .cloned()
 5035            .collect()
 5036    }
 5037
 5038    pub fn excerpts_for_inlay_hints_query(
 5039        &self,
 5040        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5041        cx: &mut Context<Editor>,
 5042    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5043        let Some(project) = self.project.as_ref() else {
 5044            return HashMap::default();
 5045        };
 5046        let project = project.read(cx);
 5047        let multi_buffer = self.buffer().read(cx);
 5048        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5049        let multi_buffer_visible_start = self
 5050            .scroll_manager
 5051            .anchor()
 5052            .anchor
 5053            .to_point(&multi_buffer_snapshot);
 5054        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5055            multi_buffer_visible_start
 5056                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5057            Bias::Left,
 5058        );
 5059        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5060        multi_buffer_snapshot
 5061            .range_to_buffer_ranges(multi_buffer_visible_range)
 5062            .into_iter()
 5063            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5064            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5065                let buffer_file = project::File::from_dyn(buffer.file())?;
 5066                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5067                let worktree_entry = buffer_worktree
 5068                    .read(cx)
 5069                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5070                if worktree_entry.is_ignored {
 5071                    return None;
 5072                }
 5073
 5074                let language = buffer.language()?;
 5075                if let Some(restrict_to_languages) = restrict_to_languages {
 5076                    if !restrict_to_languages.contains(language) {
 5077                        return None;
 5078                    }
 5079                }
 5080                Some((
 5081                    excerpt_id,
 5082                    (
 5083                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5084                        buffer.version().clone(),
 5085                        excerpt_visible_range,
 5086                    ),
 5087                ))
 5088            })
 5089            .collect()
 5090    }
 5091
 5092    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5093        TextLayoutDetails {
 5094            text_system: window.text_system().clone(),
 5095            editor_style: self.style.clone().unwrap(),
 5096            rem_size: window.rem_size(),
 5097            scroll_anchor: self.scroll_manager.anchor(),
 5098            visible_rows: self.visible_line_count(),
 5099            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5100        }
 5101    }
 5102
 5103    pub fn splice_inlays(
 5104        &self,
 5105        to_remove: &[InlayId],
 5106        to_insert: Vec<Inlay>,
 5107        cx: &mut Context<Self>,
 5108    ) {
 5109        self.display_map.update(cx, |display_map, cx| {
 5110            display_map.splice_inlays(to_remove, to_insert, cx)
 5111        });
 5112        cx.notify();
 5113    }
 5114
 5115    fn trigger_on_type_formatting(
 5116        &self,
 5117        input: String,
 5118        window: &mut Window,
 5119        cx: &mut Context<Self>,
 5120    ) -> Option<Task<Result<()>>> {
 5121        if input.len() != 1 {
 5122            return None;
 5123        }
 5124
 5125        let project = self.project.as_ref()?;
 5126        let position = self.selections.newest_anchor().head();
 5127        let (buffer, buffer_position) = self
 5128            .buffer
 5129            .read(cx)
 5130            .text_anchor_for_position(position, cx)?;
 5131
 5132        let settings = language_settings::language_settings(
 5133            buffer
 5134                .read(cx)
 5135                .language_at(buffer_position)
 5136                .map(|l| l.name()),
 5137            buffer.read(cx).file(),
 5138            cx,
 5139        );
 5140        if !settings.use_on_type_format {
 5141            return None;
 5142        }
 5143
 5144        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5145        // hence we do LSP request & edit on host side only — add formats to host's history.
 5146        let push_to_lsp_host_history = true;
 5147        // If this is not the host, append its history with new edits.
 5148        let push_to_client_history = project.read(cx).is_via_collab();
 5149
 5150        let on_type_formatting = project.update(cx, |project, cx| {
 5151            project.on_type_format(
 5152                buffer.clone(),
 5153                buffer_position,
 5154                input,
 5155                push_to_lsp_host_history,
 5156                cx,
 5157            )
 5158        });
 5159        Some(cx.spawn_in(window, async move |editor, cx| {
 5160            if let Some(transaction) = on_type_formatting.await? {
 5161                if push_to_client_history {
 5162                    buffer
 5163                        .update(cx, |buffer, _| {
 5164                            buffer.push_transaction(transaction, Instant::now());
 5165                            buffer.finalize_last_transaction();
 5166                        })
 5167                        .ok();
 5168                }
 5169                editor.update(cx, |editor, cx| {
 5170                    editor.refresh_document_highlights(cx);
 5171                })?;
 5172            }
 5173            Ok(())
 5174        }))
 5175    }
 5176
 5177    pub fn show_word_completions(
 5178        &mut self,
 5179        _: &ShowWordCompletions,
 5180        window: &mut Window,
 5181        cx: &mut Context<Self>,
 5182    ) {
 5183        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5184    }
 5185
 5186    pub fn show_completions(
 5187        &mut self,
 5188        options: &ShowCompletions,
 5189        window: &mut Window,
 5190        cx: &mut Context<Self>,
 5191    ) {
 5192        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5193    }
 5194
 5195    fn open_or_update_completions_menu(
 5196        &mut self,
 5197        requested_source: Option<CompletionsMenuSource>,
 5198        trigger: Option<&str>,
 5199        window: &mut Window,
 5200        cx: &mut Context<Self>,
 5201    ) {
 5202        if self.pending_rename.is_some() {
 5203            return;
 5204        }
 5205
 5206        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5207
 5208        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5209        // inserted and selected. To handle that case, the start of the selection is used so that
 5210        // the menu starts with all choices.
 5211        let position = self
 5212            .selections
 5213            .newest_anchor()
 5214            .start
 5215            .bias_right(&multibuffer_snapshot);
 5216        if position.diff_base_anchor.is_some() {
 5217            return;
 5218        }
 5219        let (buffer, buffer_position) =
 5220            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5221                output
 5222            } else {
 5223                return;
 5224            };
 5225        let buffer_snapshot = buffer.read(cx).snapshot();
 5226
 5227        let query: Option<Arc<String>> =
 5228            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5229
 5230        drop(multibuffer_snapshot);
 5231
 5232        let provider = match requested_source {
 5233            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5234            Some(CompletionsMenuSource::Words) => None,
 5235            Some(CompletionsMenuSource::SnippetChoices) => {
 5236                log::error!("bug: SnippetChoices requested_source is not handled");
 5237                None
 5238            }
 5239        };
 5240
 5241        let sort_completions = provider
 5242            .as_ref()
 5243            .map_or(false, |provider| provider.sort_completions());
 5244
 5245        let filter_completions = provider
 5246            .as_ref()
 5247            .map_or(true, |provider| provider.filter_completions());
 5248
 5249        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5250            if filter_completions {
 5251                menu.filter(query.clone(), provider.clone(), window, cx);
 5252            }
 5253            // When `is_incomplete` is false, no need to re-query completions when the current query
 5254            // is a suffix of the initial query.
 5255            if !menu.is_incomplete {
 5256                // If the new query is a suffix of the old query (typing more characters) and
 5257                // the previous result was complete, the existing completions can be filtered.
 5258                //
 5259                // Note that this is always true for snippet completions.
 5260                let query_matches = match (&menu.initial_query, &query) {
 5261                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5262                    (None, _) => true,
 5263                    _ => false,
 5264                };
 5265                if query_matches {
 5266                    let position_matches = if menu.initial_position == position {
 5267                        true
 5268                    } else {
 5269                        let snapshot = self.buffer.read(cx).read(cx);
 5270                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5271                    };
 5272                    if position_matches {
 5273                        return;
 5274                    }
 5275                }
 5276            }
 5277        };
 5278
 5279        let trigger_kind = match trigger {
 5280            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5281                CompletionTriggerKind::TRIGGER_CHARACTER
 5282            }
 5283            _ => CompletionTriggerKind::INVOKED,
 5284        };
 5285        let completion_context = CompletionContext {
 5286            trigger_character: trigger.and_then(|trigger| {
 5287                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5288                    Some(String::from(trigger))
 5289                } else {
 5290                    None
 5291                }
 5292            }),
 5293            trigger_kind,
 5294        };
 5295
 5296        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5297            buffer_snapshot.surrounding_word(buffer_position)
 5298        {
 5299            let word_to_exclude = buffer_snapshot
 5300                .text_for_range(word_range.clone())
 5301                .collect::<String>();
 5302            (
 5303                buffer_snapshot.anchor_before(word_range.start)
 5304                    ..buffer_snapshot.anchor_after(buffer_position),
 5305                Some(word_to_exclude),
 5306            )
 5307        } else {
 5308            (buffer_position..buffer_position, None)
 5309        };
 5310
 5311        let language = buffer_snapshot
 5312            .language_at(buffer_position)
 5313            .map(|language| language.name());
 5314
 5315        let completion_settings =
 5316            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5317
 5318        let show_completion_documentation = buffer_snapshot
 5319            .settings_at(buffer_position, cx)
 5320            .show_completion_documentation;
 5321
 5322        // The document can be large, so stay in reasonable bounds when searching for words,
 5323        // otherwise completion pop-up might be slow to appear.
 5324        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5325        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5326        let min_word_search = buffer_snapshot.clip_point(
 5327            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5328            Bias::Left,
 5329        );
 5330        let max_word_search = buffer_snapshot.clip_point(
 5331            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5332            Bias::Right,
 5333        );
 5334        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5335            ..buffer_snapshot.point_to_offset(max_word_search);
 5336
 5337        let skip_digits = query
 5338            .as_ref()
 5339            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5340
 5341        let (mut words, provider_responses) = match &provider {
 5342            Some(provider) => {
 5343                let provider_responses = provider.completions(
 5344                    position.excerpt_id,
 5345                    &buffer,
 5346                    buffer_position,
 5347                    completion_context,
 5348                    window,
 5349                    cx,
 5350                );
 5351
 5352                let words = match completion_settings.words {
 5353                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5354                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5355                        .background_spawn(async move {
 5356                            buffer_snapshot.words_in_range(WordsQuery {
 5357                                fuzzy_contents: None,
 5358                                range: word_search_range,
 5359                                skip_digits,
 5360                            })
 5361                        }),
 5362                };
 5363
 5364                (words, provider_responses)
 5365            }
 5366            None => (
 5367                cx.background_spawn(async move {
 5368                    buffer_snapshot.words_in_range(WordsQuery {
 5369                        fuzzy_contents: None,
 5370                        range: word_search_range,
 5371                        skip_digits,
 5372                    })
 5373                }),
 5374                Task::ready(Ok(Vec::new())),
 5375            ),
 5376        };
 5377
 5378        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5379
 5380        let id = post_inc(&mut self.next_completion_id);
 5381        let task = cx.spawn_in(window, async move |editor, cx| {
 5382            let Ok(()) = editor.update(cx, |this, _| {
 5383                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5384            }) else {
 5385                return;
 5386            };
 5387
 5388            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5389            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5390            let mut completions = Vec::new();
 5391            let mut is_incomplete = false;
 5392            if let Some(provider_responses) = provider_responses.await.log_err() {
 5393                if !provider_responses.is_empty() {
 5394                    for response in provider_responses {
 5395                        completions.extend(response.completions);
 5396                        is_incomplete = is_incomplete || response.is_incomplete;
 5397                    }
 5398                    if completion_settings.words == WordsCompletionMode::Fallback {
 5399                        words = Task::ready(BTreeMap::default());
 5400                    }
 5401                }
 5402            }
 5403
 5404            let mut words = words.await;
 5405            if let Some(word_to_exclude) = &word_to_exclude {
 5406                words.remove(word_to_exclude);
 5407            }
 5408            for lsp_completion in &completions {
 5409                words.remove(&lsp_completion.new_text);
 5410            }
 5411            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5412                replace_range: word_replace_range.clone(),
 5413                new_text: word.clone(),
 5414                label: CodeLabel::plain(word, None),
 5415                icon_path: None,
 5416                documentation: None,
 5417                source: CompletionSource::BufferWord {
 5418                    word_range,
 5419                    resolved: false,
 5420                },
 5421                insert_text_mode: Some(InsertTextMode::AS_IS),
 5422                confirm: None,
 5423            }));
 5424
 5425            let menu = if completions.is_empty() {
 5426                None
 5427            } else {
 5428                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5429                    let languages = editor
 5430                        .workspace
 5431                        .as_ref()
 5432                        .and_then(|(workspace, _)| workspace.upgrade())
 5433                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5434                    let menu = CompletionsMenu::new(
 5435                        id,
 5436                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5437                        sort_completions,
 5438                        show_completion_documentation,
 5439                        position,
 5440                        query.clone(),
 5441                        is_incomplete,
 5442                        buffer.clone(),
 5443                        completions.into(),
 5444                        snippet_sort_order,
 5445                        languages,
 5446                        language,
 5447                        cx,
 5448                    );
 5449
 5450                    let query = if filter_completions { query } else { None };
 5451                    let matches_task = if let Some(query) = query {
 5452                        menu.do_async_filtering(query, cx)
 5453                    } else {
 5454                        Task::ready(menu.unfiltered_matches())
 5455                    };
 5456                    (menu, matches_task)
 5457                }) else {
 5458                    return;
 5459                };
 5460
 5461                let matches = matches_task.await;
 5462
 5463                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5464                    // Newer menu already set, so exit.
 5465                    match editor.context_menu.borrow().as_ref() {
 5466                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5467                            if prev_menu.id > id {
 5468                                return;
 5469                            }
 5470                        }
 5471                        _ => {}
 5472                    };
 5473
 5474                    // Only valid to take prev_menu because it the new menu is immediately set
 5475                    // below, or the menu is hidden.
 5476                    match editor.context_menu.borrow_mut().take() {
 5477                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5478                            let position_matches =
 5479                                if prev_menu.initial_position == menu.initial_position {
 5480                                    true
 5481                                } else {
 5482                                    let snapshot = editor.buffer.read(cx).read(cx);
 5483                                    prev_menu.initial_position.to_offset(&snapshot)
 5484                                        == menu.initial_position.to_offset(&snapshot)
 5485                                };
 5486                            if position_matches {
 5487                                // Preserve markdown cache before `set_filter_results` because it will
 5488                                // try to populate the documentation cache.
 5489                                menu.preserve_markdown_cache(prev_menu);
 5490                            }
 5491                        }
 5492                        _ => {}
 5493                    };
 5494
 5495                    menu.set_filter_results(matches, provider, window, cx);
 5496                }) else {
 5497                    return;
 5498                };
 5499
 5500                menu.visible().then_some(menu)
 5501            };
 5502
 5503            editor
 5504                .update_in(cx, |editor, window, cx| {
 5505                    if editor.focus_handle.is_focused(window) {
 5506                        if let Some(menu) = menu {
 5507                            *editor.context_menu.borrow_mut() =
 5508                                Some(CodeContextMenu::Completions(menu));
 5509
 5510                            crate::hover_popover::hide_hover(editor, cx);
 5511                            if editor.show_edit_predictions_in_menu() {
 5512                                editor.update_visible_inline_completion(window, cx);
 5513                            } else {
 5514                                editor.discard_inline_completion(false, cx);
 5515                            }
 5516
 5517                            cx.notify();
 5518                            return;
 5519                        }
 5520                    }
 5521
 5522                    if editor.completion_tasks.len() <= 1 {
 5523                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5524                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5525                        // If it was already hidden and we don't show inline completions in the menu, we should
 5526                        // also show the inline-completion when available.
 5527                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5528                            editor.update_visible_inline_completion(window, cx);
 5529                        }
 5530                    }
 5531                })
 5532                .ok();
 5533        });
 5534
 5535        self.completion_tasks.push((id, task));
 5536    }
 5537
 5538    #[cfg(feature = "test-support")]
 5539    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5540        let menu = self.context_menu.borrow();
 5541        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5542            let completions = menu.completions.borrow();
 5543            Some(completions.to_vec())
 5544        } else {
 5545            None
 5546        }
 5547    }
 5548
 5549    pub fn with_completions_menu_matching_id<R>(
 5550        &self,
 5551        id: CompletionId,
 5552        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5553    ) -> R {
 5554        let mut context_menu = self.context_menu.borrow_mut();
 5555        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5556            return f(None);
 5557        };
 5558        if completions_menu.id != id {
 5559            return f(None);
 5560        }
 5561        f(Some(completions_menu))
 5562    }
 5563
 5564    pub fn confirm_completion(
 5565        &mut self,
 5566        action: &ConfirmCompletion,
 5567        window: &mut Window,
 5568        cx: &mut Context<Self>,
 5569    ) -> Option<Task<Result<()>>> {
 5570        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5571        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5572    }
 5573
 5574    pub fn confirm_completion_insert(
 5575        &mut self,
 5576        _: &ConfirmCompletionInsert,
 5577        window: &mut Window,
 5578        cx: &mut Context<Self>,
 5579    ) -> Option<Task<Result<()>>> {
 5580        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5581        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5582    }
 5583
 5584    pub fn confirm_completion_replace(
 5585        &mut self,
 5586        _: &ConfirmCompletionReplace,
 5587        window: &mut Window,
 5588        cx: &mut Context<Self>,
 5589    ) -> Option<Task<Result<()>>> {
 5590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5591        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5592    }
 5593
 5594    pub fn compose_completion(
 5595        &mut self,
 5596        action: &ComposeCompletion,
 5597        window: &mut Window,
 5598        cx: &mut Context<Self>,
 5599    ) -> Option<Task<Result<()>>> {
 5600        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5601        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5602    }
 5603
 5604    fn do_completion(
 5605        &mut self,
 5606        item_ix: Option<usize>,
 5607        intent: CompletionIntent,
 5608        window: &mut Window,
 5609        cx: &mut Context<Editor>,
 5610    ) -> Option<Task<Result<()>>> {
 5611        use language::ToOffset as _;
 5612
 5613        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5614        else {
 5615            return None;
 5616        };
 5617
 5618        let candidate_id = {
 5619            let entries = completions_menu.entries.borrow();
 5620            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5621            if self.show_edit_predictions_in_menu() {
 5622                self.discard_inline_completion(true, cx);
 5623            }
 5624            mat.candidate_id
 5625        };
 5626
 5627        let completion = completions_menu
 5628            .completions
 5629            .borrow()
 5630            .get(candidate_id)?
 5631            .clone();
 5632        cx.stop_propagation();
 5633
 5634        let buffer_handle = completions_menu.buffer.clone();
 5635
 5636        let CompletionEdit {
 5637            new_text,
 5638            snippet,
 5639            replace_range,
 5640        } = process_completion_for_edit(
 5641            &completion,
 5642            intent,
 5643            &buffer_handle,
 5644            &completions_menu.initial_position.text_anchor,
 5645            cx,
 5646        );
 5647
 5648        let buffer = buffer_handle.read(cx);
 5649        let snapshot = self.buffer.read(cx).snapshot(cx);
 5650        let newest_anchor = self.selections.newest_anchor();
 5651        let replace_range_multibuffer = {
 5652            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5653            let multibuffer_anchor = snapshot
 5654                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5655                .unwrap()
 5656                ..snapshot
 5657                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5658                    .unwrap();
 5659            multibuffer_anchor.start.to_offset(&snapshot)
 5660                ..multibuffer_anchor.end.to_offset(&snapshot)
 5661        };
 5662        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5663            return None;
 5664        }
 5665
 5666        let old_text = buffer
 5667            .text_for_range(replace_range.clone())
 5668            .collect::<String>();
 5669        let lookbehind = newest_anchor
 5670            .start
 5671            .text_anchor
 5672            .to_offset(buffer)
 5673            .saturating_sub(replace_range.start);
 5674        let lookahead = replace_range
 5675            .end
 5676            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5677        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5678        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5679
 5680        let selections = self.selections.all::<usize>(cx);
 5681        let mut ranges = Vec::new();
 5682        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5683
 5684        for selection in &selections {
 5685            let range = if selection.id == newest_anchor.id {
 5686                replace_range_multibuffer.clone()
 5687            } else {
 5688                let mut range = selection.range();
 5689
 5690                // if prefix is present, don't duplicate it
 5691                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5692                    range.start = range.start.saturating_sub(lookbehind);
 5693
 5694                    // if suffix is also present, mimic the newest cursor and replace it
 5695                    if selection.id != newest_anchor.id
 5696                        && snapshot.contains_str_at(range.end, suffix)
 5697                    {
 5698                        range.end += lookahead;
 5699                    }
 5700                }
 5701                range
 5702            };
 5703
 5704            ranges.push(range.clone());
 5705
 5706            if !self.linked_edit_ranges.is_empty() {
 5707                let start_anchor = snapshot.anchor_before(range.start);
 5708                let end_anchor = snapshot.anchor_after(range.end);
 5709                if let Some(ranges) = self
 5710                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5711                {
 5712                    for (buffer, edits) in ranges {
 5713                        linked_edits
 5714                            .entry(buffer.clone())
 5715                            .or_default()
 5716                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5717                    }
 5718                }
 5719            }
 5720        }
 5721
 5722        let common_prefix_len = old_text
 5723            .chars()
 5724            .zip(new_text.chars())
 5725            .take_while(|(a, b)| a == b)
 5726            .map(|(a, _)| a.len_utf8())
 5727            .sum::<usize>();
 5728
 5729        cx.emit(EditorEvent::InputHandled {
 5730            utf16_range_to_replace: None,
 5731            text: new_text[common_prefix_len..].into(),
 5732        });
 5733
 5734        self.transact(window, cx, |this, window, cx| {
 5735            if let Some(mut snippet) = snippet {
 5736                snippet.text = new_text.to_string();
 5737                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5738            } else {
 5739                this.buffer.update(cx, |buffer, cx| {
 5740                    let auto_indent = match completion.insert_text_mode {
 5741                        Some(InsertTextMode::AS_IS) => None,
 5742                        _ => this.autoindent_mode.clone(),
 5743                    };
 5744                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5745                    buffer.edit(edits, auto_indent, cx);
 5746                });
 5747            }
 5748            for (buffer, edits) in linked_edits {
 5749                buffer.update(cx, |buffer, cx| {
 5750                    let snapshot = buffer.snapshot();
 5751                    let edits = edits
 5752                        .into_iter()
 5753                        .map(|(range, text)| {
 5754                            use text::ToPoint as TP;
 5755                            let end_point = TP::to_point(&range.end, &snapshot);
 5756                            let start_point = TP::to_point(&range.start, &snapshot);
 5757                            (start_point..end_point, text)
 5758                        })
 5759                        .sorted_by_key(|(range, _)| range.start);
 5760                    buffer.edit(edits, None, cx);
 5761                })
 5762            }
 5763
 5764            this.refresh_inline_completion(true, false, window, cx);
 5765        });
 5766
 5767        let show_new_completions_on_confirm = completion
 5768            .confirm
 5769            .as_ref()
 5770            .map_or(false, |confirm| confirm(intent, window, cx));
 5771        if show_new_completions_on_confirm {
 5772            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5773        }
 5774
 5775        let provider = self.completion_provider.as_ref()?;
 5776        drop(completion);
 5777        let apply_edits = provider.apply_additional_edits_for_completion(
 5778            buffer_handle,
 5779            completions_menu.completions.clone(),
 5780            candidate_id,
 5781            true,
 5782            cx,
 5783        );
 5784
 5785        let editor_settings = EditorSettings::get_global(cx);
 5786        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5787            // After the code completion is finished, users often want to know what signatures are needed.
 5788            // so we should automatically call signature_help
 5789            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5790        }
 5791
 5792        Some(cx.foreground_executor().spawn(async move {
 5793            apply_edits.await?;
 5794            Ok(())
 5795        }))
 5796    }
 5797
 5798    pub fn toggle_code_actions(
 5799        &mut self,
 5800        action: &ToggleCodeActions,
 5801        window: &mut Window,
 5802        cx: &mut Context<Self>,
 5803    ) {
 5804        let quick_launch = action.quick_launch;
 5805        let mut context_menu = self.context_menu.borrow_mut();
 5806        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5807            if code_actions.deployed_from == action.deployed_from {
 5808                // Toggle if we're selecting the same one
 5809                *context_menu = None;
 5810                cx.notify();
 5811                return;
 5812            } else {
 5813                // Otherwise, clear it and start a new one
 5814                *context_menu = None;
 5815                cx.notify();
 5816            }
 5817        }
 5818        drop(context_menu);
 5819        let snapshot = self.snapshot(window, cx);
 5820        let deployed_from = action.deployed_from.clone();
 5821        let action = action.clone();
 5822        self.completion_tasks.clear();
 5823        self.discard_inline_completion(false, cx);
 5824
 5825        let multibuffer_point = match &action.deployed_from {
 5826            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5827                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5828            }
 5829            _ => self.selections.newest::<Point>(cx).head(),
 5830        };
 5831        let Some((buffer, buffer_row)) = snapshot
 5832            .buffer_snapshot
 5833            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5834            .and_then(|(buffer_snapshot, range)| {
 5835                self.buffer()
 5836                    .read(cx)
 5837                    .buffer(buffer_snapshot.remote_id())
 5838                    .map(|buffer| (buffer, range.start.row))
 5839            })
 5840        else {
 5841            return;
 5842        };
 5843        let buffer_id = buffer.read(cx).remote_id();
 5844        let tasks = self
 5845            .tasks
 5846            .get(&(buffer_id, buffer_row))
 5847            .map(|t| Arc::new(t.to_owned()));
 5848
 5849        if !self.focus_handle.is_focused(window) {
 5850            return;
 5851        }
 5852        let project = self.project.clone();
 5853
 5854        let code_actions_task = match deployed_from {
 5855            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5856            _ => self.code_actions(buffer_row, window, cx),
 5857        };
 5858
 5859        let runnable_task = match deployed_from {
 5860            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5861            _ => {
 5862                let mut task_context_task = Task::ready(None);
 5863                if let Some(tasks) = &tasks {
 5864                    if let Some(project) = project {
 5865                        task_context_task =
 5866                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5867                    }
 5868                }
 5869
 5870                cx.spawn_in(window, {
 5871                    let buffer = buffer.clone();
 5872                    async move |editor, cx| {
 5873                        let task_context = task_context_task.await;
 5874
 5875                        let resolved_tasks =
 5876                            tasks
 5877                                .zip(task_context.clone())
 5878                                .map(|(tasks, task_context)| ResolvedTasks {
 5879                                    templates: tasks.resolve(&task_context).collect(),
 5880                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5881                                        multibuffer_point.row,
 5882                                        tasks.column,
 5883                                    )),
 5884                                });
 5885                        let debug_scenarios = editor
 5886                            .update(cx, |editor, cx| {
 5887                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5888                            })?
 5889                            .await;
 5890                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5891                    }
 5892                })
 5893            }
 5894        };
 5895
 5896        cx.spawn_in(window, async move |editor, cx| {
 5897            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5898            let code_actions = code_actions_task.await;
 5899            let spawn_straight_away = quick_launch
 5900                && resolved_tasks
 5901                    .as_ref()
 5902                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5903                && code_actions
 5904                    .as_ref()
 5905                    .map_or(true, |actions| actions.is_empty())
 5906                && debug_scenarios.is_empty();
 5907
 5908            editor.update_in(cx, |editor, window, cx| {
 5909                crate::hover_popover::hide_hover(editor, cx);
 5910                *editor.context_menu.borrow_mut() =
 5911                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5912                        buffer,
 5913                        actions: CodeActionContents::new(
 5914                            resolved_tasks,
 5915                            code_actions,
 5916                            debug_scenarios,
 5917                            task_context.unwrap_or_default(),
 5918                        ),
 5919                        selected_item: Default::default(),
 5920                        scroll_handle: UniformListScrollHandle::default(),
 5921                        deployed_from,
 5922                    }));
 5923                cx.notify();
 5924                if spawn_straight_away {
 5925                    if let Some(task) = editor.confirm_code_action(
 5926                        &ConfirmCodeAction { item_ix: Some(0) },
 5927                        window,
 5928                        cx,
 5929                    ) {
 5930                        return task;
 5931                    }
 5932                }
 5933
 5934                Task::ready(Ok(()))
 5935            })
 5936        })
 5937        .detach_and_log_err(cx);
 5938    }
 5939
 5940    fn debug_scenarios(
 5941        &mut self,
 5942        resolved_tasks: &Option<ResolvedTasks>,
 5943        buffer: &Entity<Buffer>,
 5944        cx: &mut App,
 5945    ) -> Task<Vec<task::DebugScenario>> {
 5946        if cx.has_flag::<DebuggerFeatureFlag>() {
 5947            maybe!({
 5948                let project = self.project.as_ref()?;
 5949                let dap_store = project.read(cx).dap_store();
 5950                let mut scenarios = vec![];
 5951                let resolved_tasks = resolved_tasks.as_ref()?;
 5952                let buffer = buffer.read(cx);
 5953                let language = buffer.language()?;
 5954                let file = buffer.file();
 5955                let debug_adapter = language_settings(language.name().into(), file, cx)
 5956                    .debuggers
 5957                    .first()
 5958                    .map(SharedString::from)
 5959                    .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 5960
 5961                dap_store.update(cx, |dap_store, cx| {
 5962                    for (_, task) in &resolved_tasks.templates {
 5963                        let maybe_scenario = dap_store.debug_scenario_for_build_task(
 5964                            task.original_task().clone(),
 5965                            debug_adapter.clone().into(),
 5966                            task.display_label().to_owned().into(),
 5967                            cx,
 5968                        );
 5969                        scenarios.push(maybe_scenario);
 5970                    }
 5971                });
 5972                Some(cx.background_spawn(async move {
 5973                    let scenarios = futures::future::join_all(scenarios)
 5974                        .await
 5975                        .into_iter()
 5976                        .flatten()
 5977                        .collect::<Vec<_>>();
 5978                    scenarios
 5979                }))
 5980            })
 5981            .unwrap_or_else(|| Task::ready(vec![]))
 5982        } else {
 5983            Task::ready(vec![])
 5984        }
 5985    }
 5986
 5987    fn code_actions(
 5988        &mut self,
 5989        buffer_row: u32,
 5990        window: &mut Window,
 5991        cx: &mut Context<Self>,
 5992    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 5993        let mut task = self.code_actions_task.take();
 5994        cx.spawn_in(window, async move |editor, cx| {
 5995            while let Some(prev_task) = task {
 5996                prev_task.await.log_err();
 5997                task = editor
 5998                    .update(cx, |this, _| this.code_actions_task.take())
 5999                    .ok()?;
 6000            }
 6001
 6002            editor
 6003                .update(cx, |editor, cx| {
 6004                    editor
 6005                        .available_code_actions
 6006                        .clone()
 6007                        .and_then(|(location, code_actions)| {
 6008                            let snapshot = location.buffer.read(cx).snapshot();
 6009                            let point_range = location.range.to_point(&snapshot);
 6010                            let point_range = point_range.start.row..=point_range.end.row;
 6011                            if point_range.contains(&buffer_row) {
 6012                                Some(code_actions)
 6013                            } else {
 6014                                None
 6015                            }
 6016                        })
 6017                })
 6018                .ok()
 6019                .flatten()
 6020        })
 6021    }
 6022
 6023    pub fn confirm_code_action(
 6024        &mut self,
 6025        action: &ConfirmCodeAction,
 6026        window: &mut Window,
 6027        cx: &mut Context<Self>,
 6028    ) -> Option<Task<Result<()>>> {
 6029        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6030
 6031        let actions_menu =
 6032            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6033                menu
 6034            } else {
 6035                return None;
 6036            };
 6037
 6038        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6039        let action = actions_menu.actions.get(action_ix)?;
 6040        let title = action.label();
 6041        let buffer = actions_menu.buffer;
 6042        let workspace = self.workspace()?;
 6043
 6044        match action {
 6045            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6046                workspace.update(cx, |workspace, cx| {
 6047                    workspace.schedule_resolved_task(
 6048                        task_source_kind,
 6049                        resolved_task,
 6050                        false,
 6051                        window,
 6052                        cx,
 6053                    );
 6054
 6055                    Some(Task::ready(Ok(())))
 6056                })
 6057            }
 6058            CodeActionsItem::CodeAction {
 6059                excerpt_id,
 6060                action,
 6061                provider,
 6062            } => {
 6063                let apply_code_action =
 6064                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6065                let workspace = workspace.downgrade();
 6066                Some(cx.spawn_in(window, async move |editor, cx| {
 6067                    let project_transaction = apply_code_action.await?;
 6068                    Self::open_project_transaction(
 6069                        &editor,
 6070                        workspace,
 6071                        project_transaction,
 6072                        title,
 6073                        cx,
 6074                    )
 6075                    .await
 6076                }))
 6077            }
 6078            CodeActionsItem::DebugScenario(scenario) => {
 6079                let context = actions_menu.actions.context.clone();
 6080
 6081                workspace.update(cx, |workspace, cx| {
 6082                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6083                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6084                });
 6085                Some(Task::ready(Ok(())))
 6086            }
 6087        }
 6088    }
 6089
 6090    pub async fn open_project_transaction(
 6091        this: &WeakEntity<Editor>,
 6092        workspace: WeakEntity<Workspace>,
 6093        transaction: ProjectTransaction,
 6094        title: String,
 6095        cx: &mut AsyncWindowContext,
 6096    ) -> Result<()> {
 6097        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6098        cx.update(|_, cx| {
 6099            entries.sort_unstable_by_key(|(buffer, _)| {
 6100                buffer.read(cx).file().map(|f| f.path().clone())
 6101            });
 6102        })?;
 6103
 6104        // If the project transaction's edits are all contained within this editor, then
 6105        // avoid opening a new editor to display them.
 6106
 6107        if let Some((buffer, transaction)) = entries.first() {
 6108            if entries.len() == 1 {
 6109                let excerpt = this.update(cx, |editor, cx| {
 6110                    editor
 6111                        .buffer()
 6112                        .read(cx)
 6113                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6114                })?;
 6115                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6116                    if excerpted_buffer == *buffer {
 6117                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6118                            let excerpt_range = excerpt_range.to_offset(buffer);
 6119                            buffer
 6120                                .edited_ranges_for_transaction::<usize>(transaction)
 6121                                .all(|range| {
 6122                                    excerpt_range.start <= range.start
 6123                                        && excerpt_range.end >= range.end
 6124                                })
 6125                        })?;
 6126
 6127                        if all_edits_within_excerpt {
 6128                            return Ok(());
 6129                        }
 6130                    }
 6131                }
 6132            }
 6133        } else {
 6134            return Ok(());
 6135        }
 6136
 6137        let mut ranges_to_highlight = Vec::new();
 6138        let excerpt_buffer = cx.new(|cx| {
 6139            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6140            for (buffer_handle, transaction) in &entries {
 6141                let edited_ranges = buffer_handle
 6142                    .read(cx)
 6143                    .edited_ranges_for_transaction::<Point>(transaction)
 6144                    .collect::<Vec<_>>();
 6145                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6146                    PathKey::for_buffer(buffer_handle, cx),
 6147                    buffer_handle.clone(),
 6148                    edited_ranges,
 6149                    DEFAULT_MULTIBUFFER_CONTEXT,
 6150                    cx,
 6151                );
 6152
 6153                ranges_to_highlight.extend(ranges);
 6154            }
 6155            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6156            multibuffer
 6157        })?;
 6158
 6159        workspace.update_in(cx, |workspace, window, cx| {
 6160            let project = workspace.project().clone();
 6161            let editor =
 6162                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6163            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6164            editor.update(cx, |editor, cx| {
 6165                editor.highlight_background::<Self>(
 6166                    &ranges_to_highlight,
 6167                    |theme| theme.colors().editor_highlighted_line_background,
 6168                    cx,
 6169                );
 6170            });
 6171        })?;
 6172
 6173        Ok(())
 6174    }
 6175
 6176    pub fn clear_code_action_providers(&mut self) {
 6177        self.code_action_providers.clear();
 6178        self.available_code_actions.take();
 6179    }
 6180
 6181    pub fn add_code_action_provider(
 6182        &mut self,
 6183        provider: Rc<dyn CodeActionProvider>,
 6184        window: &mut Window,
 6185        cx: &mut Context<Self>,
 6186    ) {
 6187        if self
 6188            .code_action_providers
 6189            .iter()
 6190            .any(|existing_provider| existing_provider.id() == provider.id())
 6191        {
 6192            return;
 6193        }
 6194
 6195        self.code_action_providers.push(provider);
 6196        self.refresh_code_actions(window, cx);
 6197    }
 6198
 6199    pub fn remove_code_action_provider(
 6200        &mut self,
 6201        id: Arc<str>,
 6202        window: &mut Window,
 6203        cx: &mut Context<Self>,
 6204    ) {
 6205        self.code_action_providers
 6206            .retain(|provider| provider.id() != id);
 6207        self.refresh_code_actions(window, cx);
 6208    }
 6209
 6210    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6211        !self.code_action_providers.is_empty()
 6212            && EditorSettings::get_global(cx).toolbar.code_actions
 6213    }
 6214
 6215    pub fn has_available_code_actions(&self) -> bool {
 6216        self.available_code_actions
 6217            .as_ref()
 6218            .is_some_and(|(_, actions)| !actions.is_empty())
 6219    }
 6220
 6221    fn render_inline_code_actions(
 6222        &self,
 6223        icon_size: ui::IconSize,
 6224        display_row: DisplayRow,
 6225        is_active: bool,
 6226        cx: &mut Context<Self>,
 6227    ) -> AnyElement {
 6228        let show_tooltip = !self.context_menu_visible();
 6229        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6230            .icon_size(icon_size)
 6231            .shape(ui::IconButtonShape::Square)
 6232            .style(ButtonStyle::Transparent)
 6233            .icon_color(ui::Color::Hidden)
 6234            .toggle_state(is_active)
 6235            .when(show_tooltip, |this| {
 6236                this.tooltip({
 6237                    let focus_handle = self.focus_handle.clone();
 6238                    move |window, cx| {
 6239                        Tooltip::for_action_in(
 6240                            "Toggle Code Actions",
 6241                            &ToggleCodeActions {
 6242                                deployed_from: None,
 6243                                quick_launch: false,
 6244                            },
 6245                            &focus_handle,
 6246                            window,
 6247                            cx,
 6248                        )
 6249                    }
 6250                })
 6251            })
 6252            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6253                window.focus(&editor.focus_handle(cx));
 6254                editor.toggle_code_actions(
 6255                    &crate::actions::ToggleCodeActions {
 6256                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6257                            display_row,
 6258                        )),
 6259                        quick_launch: false,
 6260                    },
 6261                    window,
 6262                    cx,
 6263                );
 6264            }))
 6265            .into_any_element()
 6266    }
 6267
 6268    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6269        &self.context_menu
 6270    }
 6271
 6272    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6273        let newest_selection = self.selections.newest_anchor().clone();
 6274        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6275        let buffer = self.buffer.read(cx);
 6276        if newest_selection.head().diff_base_anchor.is_some() {
 6277            return None;
 6278        }
 6279        let (start_buffer, start) =
 6280            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6281        let (end_buffer, end) =
 6282            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6283        if start_buffer != end_buffer {
 6284            return None;
 6285        }
 6286
 6287        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6288            cx.background_executor()
 6289                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6290                .await;
 6291
 6292            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6293                let providers = this.code_action_providers.clone();
 6294                let tasks = this
 6295                    .code_action_providers
 6296                    .iter()
 6297                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6298                    .collect::<Vec<_>>();
 6299                (providers, tasks)
 6300            })?;
 6301
 6302            let mut actions = Vec::new();
 6303            for (provider, provider_actions) in
 6304                providers.into_iter().zip(future::join_all(tasks).await)
 6305            {
 6306                if let Some(provider_actions) = provider_actions.log_err() {
 6307                    actions.extend(provider_actions.into_iter().map(|action| {
 6308                        AvailableCodeAction {
 6309                            excerpt_id: newest_selection.start.excerpt_id,
 6310                            action,
 6311                            provider: provider.clone(),
 6312                        }
 6313                    }));
 6314                }
 6315            }
 6316
 6317            this.update(cx, |this, cx| {
 6318                this.available_code_actions = if actions.is_empty() {
 6319                    None
 6320                } else {
 6321                    Some((
 6322                        Location {
 6323                            buffer: start_buffer,
 6324                            range: start..end,
 6325                        },
 6326                        actions.into(),
 6327                    ))
 6328                };
 6329                cx.notify();
 6330            })
 6331        }));
 6332        None
 6333    }
 6334
 6335    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6336        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6337            self.show_git_blame_inline = false;
 6338
 6339            self.show_git_blame_inline_delay_task =
 6340                Some(cx.spawn_in(window, async move |this, cx| {
 6341                    cx.background_executor().timer(delay).await;
 6342
 6343                    this.update(cx, |this, cx| {
 6344                        this.show_git_blame_inline = true;
 6345                        cx.notify();
 6346                    })
 6347                    .log_err();
 6348                }));
 6349        }
 6350    }
 6351
 6352    fn show_blame_popover(
 6353        &mut self,
 6354        blame_entry: &BlameEntry,
 6355        position: gpui::Point<Pixels>,
 6356        cx: &mut Context<Self>,
 6357    ) {
 6358        if let Some(state) = &mut self.inline_blame_popover {
 6359            state.hide_task.take();
 6360        } else {
 6361            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6362            let blame_entry = blame_entry.clone();
 6363            let show_task = cx.spawn(async move |editor, cx| {
 6364                cx.background_executor()
 6365                    .timer(std::time::Duration::from_millis(delay))
 6366                    .await;
 6367                editor
 6368                    .update(cx, |editor, cx| {
 6369                        editor.inline_blame_popover_show_task.take();
 6370                        let Some(blame) = editor.blame.as_ref() else {
 6371                            return;
 6372                        };
 6373                        let blame = blame.read(cx);
 6374                        let details = blame.details_for_entry(&blame_entry);
 6375                        let markdown = cx.new(|cx| {
 6376                            Markdown::new(
 6377                                details
 6378                                    .as_ref()
 6379                                    .map(|message| message.message.clone())
 6380                                    .unwrap_or_default(),
 6381                                None,
 6382                                None,
 6383                                cx,
 6384                            )
 6385                        });
 6386                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6387                            position,
 6388                            hide_task: None,
 6389                            popover_bounds: None,
 6390                            popover_state: InlineBlamePopoverState {
 6391                                scroll_handle: ScrollHandle::new(),
 6392                                commit_message: details,
 6393                                markdown,
 6394                            },
 6395                        });
 6396                        cx.notify();
 6397                    })
 6398                    .ok();
 6399            });
 6400            self.inline_blame_popover_show_task = Some(show_task);
 6401        }
 6402    }
 6403
 6404    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6405        self.inline_blame_popover_show_task.take();
 6406        if let Some(state) = &mut self.inline_blame_popover {
 6407            let hide_task = cx.spawn(async move |editor, cx| {
 6408                cx.background_executor()
 6409                    .timer(std::time::Duration::from_millis(100))
 6410                    .await;
 6411                editor
 6412                    .update(cx, |editor, cx| {
 6413                        editor.inline_blame_popover.take();
 6414                        cx.notify();
 6415                    })
 6416                    .ok();
 6417            });
 6418            state.hide_task = Some(hide_task);
 6419        }
 6420    }
 6421
 6422    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6423        if self.pending_rename.is_some() {
 6424            return None;
 6425        }
 6426
 6427        let provider = self.semantics_provider.clone()?;
 6428        let buffer = self.buffer.read(cx);
 6429        let newest_selection = self.selections.newest_anchor().clone();
 6430        let cursor_position = newest_selection.head();
 6431        let (cursor_buffer, cursor_buffer_position) =
 6432            buffer.text_anchor_for_position(cursor_position, cx)?;
 6433        let (tail_buffer, tail_buffer_position) =
 6434            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6435        if cursor_buffer != tail_buffer {
 6436            return None;
 6437        }
 6438
 6439        let snapshot = cursor_buffer.read(cx).snapshot();
 6440        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6441        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6442        if start_word_range != end_word_range {
 6443            self.document_highlights_task.take();
 6444            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6445            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6446            return None;
 6447        }
 6448
 6449        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6450        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6451            cx.background_executor()
 6452                .timer(Duration::from_millis(debounce))
 6453                .await;
 6454
 6455            let highlights = if let Some(highlights) = cx
 6456                .update(|cx| {
 6457                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6458                })
 6459                .ok()
 6460                .flatten()
 6461            {
 6462                highlights.await.log_err()
 6463            } else {
 6464                None
 6465            };
 6466
 6467            if let Some(highlights) = highlights {
 6468                this.update(cx, |this, cx| {
 6469                    if this.pending_rename.is_some() {
 6470                        return;
 6471                    }
 6472
 6473                    let buffer_id = cursor_position.buffer_id;
 6474                    let buffer = this.buffer.read(cx);
 6475                    if !buffer
 6476                        .text_anchor_for_position(cursor_position, cx)
 6477                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6478                    {
 6479                        return;
 6480                    }
 6481
 6482                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6483                    let mut write_ranges = Vec::new();
 6484                    let mut read_ranges = Vec::new();
 6485                    for highlight in highlights {
 6486                        for (excerpt_id, excerpt_range) in
 6487                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6488                        {
 6489                            let start = highlight
 6490                                .range
 6491                                .start
 6492                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6493                            let end = highlight
 6494                                .range
 6495                                .end
 6496                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6497                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6498                                continue;
 6499                            }
 6500
 6501                            let range = Anchor {
 6502                                buffer_id,
 6503                                excerpt_id,
 6504                                text_anchor: start,
 6505                                diff_base_anchor: None,
 6506                            }..Anchor {
 6507                                buffer_id,
 6508                                excerpt_id,
 6509                                text_anchor: end,
 6510                                diff_base_anchor: None,
 6511                            };
 6512                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6513                                write_ranges.push(range);
 6514                            } else {
 6515                                read_ranges.push(range);
 6516                            }
 6517                        }
 6518                    }
 6519
 6520                    this.highlight_background::<DocumentHighlightRead>(
 6521                        &read_ranges,
 6522                        |theme| theme.colors().editor_document_highlight_read_background,
 6523                        cx,
 6524                    );
 6525                    this.highlight_background::<DocumentHighlightWrite>(
 6526                        &write_ranges,
 6527                        |theme| theme.colors().editor_document_highlight_write_background,
 6528                        cx,
 6529                    );
 6530                    cx.notify();
 6531                })
 6532                .log_err();
 6533            }
 6534        }));
 6535        None
 6536    }
 6537
 6538    fn prepare_highlight_query_from_selection(
 6539        &mut self,
 6540        cx: &mut Context<Editor>,
 6541    ) -> Option<(String, Range<Anchor>)> {
 6542        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6543            return None;
 6544        }
 6545        if !EditorSettings::get_global(cx).selection_highlight {
 6546            return None;
 6547        }
 6548        if self.selections.count() != 1 || self.selections.line_mode {
 6549            return None;
 6550        }
 6551        let selection = self.selections.newest::<Point>(cx);
 6552        if selection.is_empty() || selection.start.row != selection.end.row {
 6553            return None;
 6554        }
 6555        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6556        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6557        let query = multi_buffer_snapshot
 6558            .text_for_range(selection_anchor_range.clone())
 6559            .collect::<String>();
 6560        if query.trim().is_empty() {
 6561            return None;
 6562        }
 6563        Some((query, selection_anchor_range))
 6564    }
 6565
 6566    fn update_selection_occurrence_highlights(
 6567        &mut self,
 6568        query_text: String,
 6569        query_range: Range<Anchor>,
 6570        multi_buffer_range_to_query: Range<Point>,
 6571        use_debounce: bool,
 6572        window: &mut Window,
 6573        cx: &mut Context<Editor>,
 6574    ) -> Task<()> {
 6575        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6576        cx.spawn_in(window, async move |editor, cx| {
 6577            if use_debounce {
 6578                cx.background_executor()
 6579                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6580                    .await;
 6581            }
 6582            let match_task = cx.background_spawn(async move {
 6583                let buffer_ranges = multi_buffer_snapshot
 6584                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6585                    .into_iter()
 6586                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6587                let mut match_ranges = Vec::new();
 6588                let Ok(regex) = project::search::SearchQuery::text(
 6589                    query_text.clone(),
 6590                    false,
 6591                    false,
 6592                    false,
 6593                    Default::default(),
 6594                    Default::default(),
 6595                    false,
 6596                    None,
 6597                ) else {
 6598                    return Vec::default();
 6599                };
 6600                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6601                    match_ranges.extend(
 6602                        regex
 6603                            .search(&buffer_snapshot, Some(search_range.clone()))
 6604                            .await
 6605                            .into_iter()
 6606                            .filter_map(|match_range| {
 6607                                let match_start = buffer_snapshot
 6608                                    .anchor_after(search_range.start + match_range.start);
 6609                                let match_end = buffer_snapshot
 6610                                    .anchor_before(search_range.start + match_range.end);
 6611                                let match_anchor_range = Anchor::range_in_buffer(
 6612                                    excerpt_id,
 6613                                    buffer_snapshot.remote_id(),
 6614                                    match_start..match_end,
 6615                                );
 6616                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6617                            }),
 6618                    );
 6619                }
 6620                match_ranges
 6621            });
 6622            let match_ranges = match_task.await;
 6623            editor
 6624                .update_in(cx, |editor, _, cx| {
 6625                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6626                    if !match_ranges.is_empty() {
 6627                        editor.highlight_background::<SelectedTextHighlight>(
 6628                            &match_ranges,
 6629                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6630                            cx,
 6631                        )
 6632                    }
 6633                })
 6634                .log_err();
 6635        })
 6636    }
 6637
 6638    fn refresh_selected_text_highlights(
 6639        &mut self,
 6640        on_buffer_edit: bool,
 6641        window: &mut Window,
 6642        cx: &mut Context<Editor>,
 6643    ) {
 6644        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6645        else {
 6646            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6647            self.quick_selection_highlight_task.take();
 6648            self.debounced_selection_highlight_task.take();
 6649            return;
 6650        };
 6651        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6652        if on_buffer_edit
 6653            || self
 6654                .quick_selection_highlight_task
 6655                .as_ref()
 6656                .map_or(true, |(prev_anchor_range, _)| {
 6657                    prev_anchor_range != &query_range
 6658                })
 6659        {
 6660            let multi_buffer_visible_start = self
 6661                .scroll_manager
 6662                .anchor()
 6663                .anchor
 6664                .to_point(&multi_buffer_snapshot);
 6665            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6666                multi_buffer_visible_start
 6667                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6668                Bias::Left,
 6669            );
 6670            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6671            self.quick_selection_highlight_task = Some((
 6672                query_range.clone(),
 6673                self.update_selection_occurrence_highlights(
 6674                    query_text.clone(),
 6675                    query_range.clone(),
 6676                    multi_buffer_visible_range,
 6677                    false,
 6678                    window,
 6679                    cx,
 6680                ),
 6681            ));
 6682        }
 6683        if on_buffer_edit
 6684            || self
 6685                .debounced_selection_highlight_task
 6686                .as_ref()
 6687                .map_or(true, |(prev_anchor_range, _)| {
 6688                    prev_anchor_range != &query_range
 6689                })
 6690        {
 6691            let multi_buffer_start = multi_buffer_snapshot
 6692                .anchor_before(0)
 6693                .to_point(&multi_buffer_snapshot);
 6694            let multi_buffer_end = multi_buffer_snapshot
 6695                .anchor_after(multi_buffer_snapshot.len())
 6696                .to_point(&multi_buffer_snapshot);
 6697            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6698            self.debounced_selection_highlight_task = Some((
 6699                query_range.clone(),
 6700                self.update_selection_occurrence_highlights(
 6701                    query_text,
 6702                    query_range,
 6703                    multi_buffer_full_range,
 6704                    true,
 6705                    window,
 6706                    cx,
 6707                ),
 6708            ));
 6709        }
 6710    }
 6711
 6712    pub fn refresh_inline_completion(
 6713        &mut self,
 6714        debounce: bool,
 6715        user_requested: bool,
 6716        window: &mut Window,
 6717        cx: &mut Context<Self>,
 6718    ) -> Option<()> {
 6719        let provider = self.edit_prediction_provider()?;
 6720        let cursor = self.selections.newest_anchor().head();
 6721        let (buffer, cursor_buffer_position) =
 6722            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6723
 6724        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6725            self.discard_inline_completion(false, cx);
 6726            return None;
 6727        }
 6728
 6729        if !user_requested
 6730            && (!self.should_show_edit_predictions()
 6731                || !self.is_focused(window)
 6732                || buffer.read(cx).is_empty())
 6733        {
 6734            self.discard_inline_completion(false, cx);
 6735            return None;
 6736        }
 6737
 6738        self.update_visible_inline_completion(window, cx);
 6739        provider.refresh(
 6740            self.project.clone(),
 6741            buffer,
 6742            cursor_buffer_position,
 6743            debounce,
 6744            cx,
 6745        );
 6746        Some(())
 6747    }
 6748
 6749    fn show_edit_predictions_in_menu(&self) -> bool {
 6750        match self.edit_prediction_settings {
 6751            EditPredictionSettings::Disabled => false,
 6752            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6753        }
 6754    }
 6755
 6756    pub fn edit_predictions_enabled(&self) -> bool {
 6757        match self.edit_prediction_settings {
 6758            EditPredictionSettings::Disabled => false,
 6759            EditPredictionSettings::Enabled { .. } => true,
 6760        }
 6761    }
 6762
 6763    fn edit_prediction_requires_modifier(&self) -> bool {
 6764        match self.edit_prediction_settings {
 6765            EditPredictionSettings::Disabled => false,
 6766            EditPredictionSettings::Enabled {
 6767                preview_requires_modifier,
 6768                ..
 6769            } => preview_requires_modifier,
 6770        }
 6771    }
 6772
 6773    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6774        if self.edit_prediction_provider.is_none() {
 6775            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6776        } else {
 6777            let selection = self.selections.newest_anchor();
 6778            let cursor = selection.head();
 6779
 6780            if let Some((buffer, cursor_buffer_position)) =
 6781                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6782            {
 6783                self.edit_prediction_settings =
 6784                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6785            }
 6786        }
 6787    }
 6788
 6789    fn edit_prediction_settings_at_position(
 6790        &self,
 6791        buffer: &Entity<Buffer>,
 6792        buffer_position: language::Anchor,
 6793        cx: &App,
 6794    ) -> EditPredictionSettings {
 6795        if !self.mode.is_full()
 6796            || !self.show_inline_completions_override.unwrap_or(true)
 6797            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6798        {
 6799            return EditPredictionSettings::Disabled;
 6800        }
 6801
 6802        let buffer = buffer.read(cx);
 6803
 6804        let file = buffer.file();
 6805
 6806        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6807            return EditPredictionSettings::Disabled;
 6808        };
 6809
 6810        let by_provider = matches!(
 6811            self.menu_inline_completions_policy,
 6812            MenuInlineCompletionsPolicy::ByProvider
 6813        );
 6814
 6815        let show_in_menu = by_provider
 6816            && self
 6817                .edit_prediction_provider
 6818                .as_ref()
 6819                .map_or(false, |provider| {
 6820                    provider.provider.show_completions_in_menu()
 6821                });
 6822
 6823        let preview_requires_modifier =
 6824            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6825
 6826        EditPredictionSettings::Enabled {
 6827            show_in_menu,
 6828            preview_requires_modifier,
 6829        }
 6830    }
 6831
 6832    fn should_show_edit_predictions(&self) -> bool {
 6833        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6834    }
 6835
 6836    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6837        matches!(
 6838            self.edit_prediction_preview,
 6839            EditPredictionPreview::Active { .. }
 6840        )
 6841    }
 6842
 6843    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6844        let cursor = self.selections.newest_anchor().head();
 6845        if let Some((buffer, cursor_position)) =
 6846            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6847        {
 6848            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6849        } else {
 6850            false
 6851        }
 6852    }
 6853
 6854    pub fn supports_minimap(&self, cx: &App) -> bool {
 6855        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6856    }
 6857
 6858    fn edit_predictions_enabled_in_buffer(
 6859        &self,
 6860        buffer: &Entity<Buffer>,
 6861        buffer_position: language::Anchor,
 6862        cx: &App,
 6863    ) -> bool {
 6864        maybe!({
 6865            if self.read_only(cx) {
 6866                return Some(false);
 6867            }
 6868            let provider = self.edit_prediction_provider()?;
 6869            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6870                return Some(false);
 6871            }
 6872            let buffer = buffer.read(cx);
 6873            let Some(file) = buffer.file() else {
 6874                return Some(true);
 6875            };
 6876            let settings = all_language_settings(Some(file), cx);
 6877            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6878        })
 6879        .unwrap_or(false)
 6880    }
 6881
 6882    fn cycle_inline_completion(
 6883        &mut self,
 6884        direction: Direction,
 6885        window: &mut Window,
 6886        cx: &mut Context<Self>,
 6887    ) -> Option<()> {
 6888        let provider = self.edit_prediction_provider()?;
 6889        let cursor = self.selections.newest_anchor().head();
 6890        let (buffer, cursor_buffer_position) =
 6891            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6892        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6893            return None;
 6894        }
 6895
 6896        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6897        self.update_visible_inline_completion(window, cx);
 6898
 6899        Some(())
 6900    }
 6901
 6902    pub fn show_inline_completion(
 6903        &mut self,
 6904        _: &ShowEditPrediction,
 6905        window: &mut Window,
 6906        cx: &mut Context<Self>,
 6907    ) {
 6908        if !self.has_active_inline_completion() {
 6909            self.refresh_inline_completion(false, true, window, cx);
 6910            return;
 6911        }
 6912
 6913        self.update_visible_inline_completion(window, cx);
 6914    }
 6915
 6916    pub fn display_cursor_names(
 6917        &mut self,
 6918        _: &DisplayCursorNames,
 6919        window: &mut Window,
 6920        cx: &mut Context<Self>,
 6921    ) {
 6922        self.show_cursor_names(window, cx);
 6923    }
 6924
 6925    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6926        self.show_cursor_names = true;
 6927        cx.notify();
 6928        cx.spawn_in(window, async move |this, cx| {
 6929            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6930            this.update(cx, |this, cx| {
 6931                this.show_cursor_names = false;
 6932                cx.notify()
 6933            })
 6934            .ok()
 6935        })
 6936        .detach();
 6937    }
 6938
 6939    pub fn next_edit_prediction(
 6940        &mut self,
 6941        _: &NextEditPrediction,
 6942        window: &mut Window,
 6943        cx: &mut Context<Self>,
 6944    ) {
 6945        if self.has_active_inline_completion() {
 6946            self.cycle_inline_completion(Direction::Next, window, cx);
 6947        } else {
 6948            let is_copilot_disabled = self
 6949                .refresh_inline_completion(false, true, window, cx)
 6950                .is_none();
 6951            if is_copilot_disabled {
 6952                cx.propagate();
 6953            }
 6954        }
 6955    }
 6956
 6957    pub fn previous_edit_prediction(
 6958        &mut self,
 6959        _: &PreviousEditPrediction,
 6960        window: &mut Window,
 6961        cx: &mut Context<Self>,
 6962    ) {
 6963        if self.has_active_inline_completion() {
 6964            self.cycle_inline_completion(Direction::Prev, window, cx);
 6965        } else {
 6966            let is_copilot_disabled = self
 6967                .refresh_inline_completion(false, true, window, cx)
 6968                .is_none();
 6969            if is_copilot_disabled {
 6970                cx.propagate();
 6971            }
 6972        }
 6973    }
 6974
 6975    pub fn accept_edit_prediction(
 6976        &mut self,
 6977        _: &AcceptEditPrediction,
 6978        window: &mut Window,
 6979        cx: &mut Context<Self>,
 6980    ) {
 6981        if self.show_edit_predictions_in_menu() {
 6982            self.hide_context_menu(window, cx);
 6983        }
 6984
 6985        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6986            return;
 6987        };
 6988
 6989        self.report_inline_completion_event(
 6990            active_inline_completion.completion_id.clone(),
 6991            true,
 6992            cx,
 6993        );
 6994
 6995        match &active_inline_completion.completion {
 6996            InlineCompletion::Move { target, .. } => {
 6997                let target = *target;
 6998
 6999                if let Some(position_map) = &self.last_position_map {
 7000                    if position_map
 7001                        .visible_row_range
 7002                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7003                        || !self.edit_prediction_requires_modifier()
 7004                    {
 7005                        self.unfold_ranges(&[target..target], true, false, cx);
 7006                        // Note that this is also done in vim's handler of the Tab action.
 7007                        self.change_selections(
 7008                            Some(Autoscroll::newest()),
 7009                            window,
 7010                            cx,
 7011                            |selections| {
 7012                                selections.select_anchor_ranges([target..target]);
 7013                            },
 7014                        );
 7015                        self.clear_row_highlights::<EditPredictionPreview>();
 7016
 7017                        self.edit_prediction_preview
 7018                            .set_previous_scroll_position(None);
 7019                    } else {
 7020                        self.edit_prediction_preview
 7021                            .set_previous_scroll_position(Some(
 7022                                position_map.snapshot.scroll_anchor,
 7023                            ));
 7024
 7025                        self.highlight_rows::<EditPredictionPreview>(
 7026                            target..target,
 7027                            cx.theme().colors().editor_highlighted_line_background,
 7028                            RowHighlightOptions {
 7029                                autoscroll: true,
 7030                                ..Default::default()
 7031                            },
 7032                            cx,
 7033                        );
 7034                        self.request_autoscroll(Autoscroll::fit(), cx);
 7035                    }
 7036                }
 7037            }
 7038            InlineCompletion::Edit { edits, .. } => {
 7039                if let Some(provider) = self.edit_prediction_provider() {
 7040                    provider.accept(cx);
 7041                }
 7042
 7043                // Store the transaction ID and selections before applying the edit
 7044                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7045
 7046                let snapshot = self.buffer.read(cx).snapshot(cx);
 7047                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7048
 7049                self.buffer.update(cx, |buffer, cx| {
 7050                    buffer.edit(edits.iter().cloned(), None, cx)
 7051                });
 7052
 7053                self.change_selections(None, window, cx, |s| {
 7054                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7055                });
 7056
 7057                let selections = self.selections.disjoint_anchors();
 7058                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7059                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7060                    if has_new_transaction {
 7061                        self.selection_history
 7062                            .insert_transaction(transaction_id_now, selections);
 7063                    }
 7064                }
 7065
 7066                self.update_visible_inline_completion(window, cx);
 7067                if self.active_inline_completion.is_none() {
 7068                    self.refresh_inline_completion(true, true, window, cx);
 7069                }
 7070
 7071                cx.notify();
 7072            }
 7073        }
 7074
 7075        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7076    }
 7077
 7078    pub fn accept_partial_inline_completion(
 7079        &mut self,
 7080        _: &AcceptPartialEditPrediction,
 7081        window: &mut Window,
 7082        cx: &mut Context<Self>,
 7083    ) {
 7084        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7085            return;
 7086        };
 7087        if self.selections.count() != 1 {
 7088            return;
 7089        }
 7090
 7091        self.report_inline_completion_event(
 7092            active_inline_completion.completion_id.clone(),
 7093            true,
 7094            cx,
 7095        );
 7096
 7097        match &active_inline_completion.completion {
 7098            InlineCompletion::Move { target, .. } => {
 7099                let target = *target;
 7100                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7101                    selections.select_anchor_ranges([target..target]);
 7102                });
 7103            }
 7104            InlineCompletion::Edit { edits, .. } => {
 7105                // Find an insertion that starts at the cursor position.
 7106                let snapshot = self.buffer.read(cx).snapshot(cx);
 7107                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7108                let insertion = edits.iter().find_map(|(range, text)| {
 7109                    let range = range.to_offset(&snapshot);
 7110                    if range.is_empty() && range.start == cursor_offset {
 7111                        Some(text)
 7112                    } else {
 7113                        None
 7114                    }
 7115                });
 7116
 7117                if let Some(text) = insertion {
 7118                    let mut partial_completion = text
 7119                        .chars()
 7120                        .by_ref()
 7121                        .take_while(|c| c.is_alphabetic())
 7122                        .collect::<String>();
 7123                    if partial_completion.is_empty() {
 7124                        partial_completion = text
 7125                            .chars()
 7126                            .by_ref()
 7127                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7128                            .collect::<String>();
 7129                    }
 7130
 7131                    cx.emit(EditorEvent::InputHandled {
 7132                        utf16_range_to_replace: None,
 7133                        text: partial_completion.clone().into(),
 7134                    });
 7135
 7136                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7137
 7138                    self.refresh_inline_completion(true, true, window, cx);
 7139                    cx.notify();
 7140                } else {
 7141                    self.accept_edit_prediction(&Default::default(), window, cx);
 7142                }
 7143            }
 7144        }
 7145    }
 7146
 7147    fn discard_inline_completion(
 7148        &mut self,
 7149        should_report_inline_completion_event: bool,
 7150        cx: &mut Context<Self>,
 7151    ) -> bool {
 7152        if should_report_inline_completion_event {
 7153            let completion_id = self
 7154                .active_inline_completion
 7155                .as_ref()
 7156                .and_then(|active_completion| active_completion.completion_id.clone());
 7157
 7158            self.report_inline_completion_event(completion_id, false, cx);
 7159        }
 7160
 7161        if let Some(provider) = self.edit_prediction_provider() {
 7162            provider.discard(cx);
 7163        }
 7164
 7165        self.take_active_inline_completion(cx)
 7166    }
 7167
 7168    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7169        let Some(provider) = self.edit_prediction_provider() else {
 7170            return;
 7171        };
 7172
 7173        let Some((_, buffer, _)) = self
 7174            .buffer
 7175            .read(cx)
 7176            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7177        else {
 7178            return;
 7179        };
 7180
 7181        let extension = buffer
 7182            .read(cx)
 7183            .file()
 7184            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7185
 7186        let event_type = match accepted {
 7187            true => "Edit Prediction Accepted",
 7188            false => "Edit Prediction Discarded",
 7189        };
 7190        telemetry::event!(
 7191            event_type,
 7192            provider = provider.name(),
 7193            prediction_id = id,
 7194            suggestion_accepted = accepted,
 7195            file_extension = extension,
 7196        );
 7197    }
 7198
 7199    pub fn has_active_inline_completion(&self) -> bool {
 7200        self.active_inline_completion.is_some()
 7201    }
 7202
 7203    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7204        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7205            return false;
 7206        };
 7207
 7208        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7209        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7210        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7211        true
 7212    }
 7213
 7214    /// Returns true when we're displaying the edit prediction popover below the cursor
 7215    /// like we are not previewing and the LSP autocomplete menu is visible
 7216    /// or we are in `when_holding_modifier` mode.
 7217    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7218        if self.edit_prediction_preview_is_active()
 7219            || !self.show_edit_predictions_in_menu()
 7220            || !self.edit_predictions_enabled()
 7221        {
 7222            return false;
 7223        }
 7224
 7225        if self.has_visible_completions_menu() {
 7226            return true;
 7227        }
 7228
 7229        has_completion && self.edit_prediction_requires_modifier()
 7230    }
 7231
 7232    fn handle_modifiers_changed(
 7233        &mut self,
 7234        modifiers: Modifiers,
 7235        position_map: &PositionMap,
 7236        window: &mut Window,
 7237        cx: &mut Context<Self>,
 7238    ) {
 7239        if self.show_edit_predictions_in_menu() {
 7240            self.update_edit_prediction_preview(&modifiers, window, cx);
 7241        }
 7242
 7243        self.update_selection_mode(&modifiers, position_map, window, cx);
 7244
 7245        let mouse_position = window.mouse_position();
 7246        if !position_map.text_hitbox.is_hovered(window) {
 7247            return;
 7248        }
 7249
 7250        self.update_hovered_link(
 7251            position_map.point_for_position(mouse_position),
 7252            &position_map.snapshot,
 7253            modifiers,
 7254            window,
 7255            cx,
 7256        )
 7257    }
 7258
 7259    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7260        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7261        if invert {
 7262            match multi_cursor_setting {
 7263                MultiCursorModifier::Alt => modifiers.alt,
 7264                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7265            }
 7266        } else {
 7267            match multi_cursor_setting {
 7268                MultiCursorModifier::Alt => modifiers.secondary(),
 7269                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7270            }
 7271        }
 7272    }
 7273
 7274    fn columnar_selection_mode(
 7275        modifiers: &Modifiers,
 7276        cx: &mut Context<Self>,
 7277    ) -> Option<ColumnarMode> {
 7278        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7279            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7280                Some(ColumnarMode::FromMouse)
 7281            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7282                Some(ColumnarMode::FromSelection)
 7283            } else {
 7284                None
 7285            }
 7286        } else {
 7287            None
 7288        }
 7289    }
 7290
 7291    fn update_selection_mode(
 7292        &mut self,
 7293        modifiers: &Modifiers,
 7294        position_map: &PositionMap,
 7295        window: &mut Window,
 7296        cx: &mut Context<Self>,
 7297    ) {
 7298        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7299            return;
 7300        };
 7301        if self.selections.pending.is_none() {
 7302            return;
 7303        }
 7304
 7305        let mouse_position = window.mouse_position();
 7306        let point_for_position = position_map.point_for_position(mouse_position);
 7307        let position = point_for_position.previous_valid;
 7308
 7309        self.select(
 7310            SelectPhase::BeginColumnar {
 7311                position,
 7312                reset: false,
 7313                mode,
 7314                goal_column: point_for_position.exact_unclipped.column(),
 7315            },
 7316            window,
 7317            cx,
 7318        );
 7319    }
 7320
 7321    fn update_edit_prediction_preview(
 7322        &mut self,
 7323        modifiers: &Modifiers,
 7324        window: &mut Window,
 7325        cx: &mut Context<Self>,
 7326    ) {
 7327        let mut modifiers_held = false;
 7328        if let Some(accept_keystroke) = self
 7329            .accept_edit_prediction_keybind(false, window, cx)
 7330            .keystroke()
 7331        {
 7332            modifiers_held = modifiers_held
 7333                || (&accept_keystroke.modifiers == modifiers
 7334                    && accept_keystroke.modifiers.modified());
 7335        };
 7336        if let Some(accept_partial_keystroke) = self
 7337            .accept_edit_prediction_keybind(true, window, cx)
 7338            .keystroke()
 7339        {
 7340            modifiers_held = modifiers_held
 7341                || (&accept_partial_keystroke.modifiers == modifiers
 7342                    && accept_partial_keystroke.modifiers.modified());
 7343        }
 7344
 7345        if modifiers_held {
 7346            if matches!(
 7347                self.edit_prediction_preview,
 7348                EditPredictionPreview::Inactive { .. }
 7349            ) {
 7350                self.edit_prediction_preview = EditPredictionPreview::Active {
 7351                    previous_scroll_position: None,
 7352                    since: Instant::now(),
 7353                };
 7354
 7355                self.update_visible_inline_completion(window, cx);
 7356                cx.notify();
 7357            }
 7358        } else if let EditPredictionPreview::Active {
 7359            previous_scroll_position,
 7360            since,
 7361        } = self.edit_prediction_preview
 7362        {
 7363            if let (Some(previous_scroll_position), Some(position_map)) =
 7364                (previous_scroll_position, self.last_position_map.as_ref())
 7365            {
 7366                self.set_scroll_position(
 7367                    previous_scroll_position
 7368                        .scroll_position(&position_map.snapshot.display_snapshot),
 7369                    window,
 7370                    cx,
 7371                );
 7372            }
 7373
 7374            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7375                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7376            };
 7377            self.clear_row_highlights::<EditPredictionPreview>();
 7378            self.update_visible_inline_completion(window, cx);
 7379            cx.notify();
 7380        }
 7381    }
 7382
 7383    fn update_visible_inline_completion(
 7384        &mut self,
 7385        _window: &mut Window,
 7386        cx: &mut Context<Self>,
 7387    ) -> Option<()> {
 7388        let selection = self.selections.newest_anchor();
 7389        let cursor = selection.head();
 7390        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7391        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7392        let excerpt_id = cursor.excerpt_id;
 7393
 7394        let show_in_menu = self.show_edit_predictions_in_menu();
 7395        let completions_menu_has_precedence = !show_in_menu
 7396            && (self.context_menu.borrow().is_some()
 7397                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7398
 7399        if completions_menu_has_precedence
 7400            || !offset_selection.is_empty()
 7401            || self
 7402                .active_inline_completion
 7403                .as_ref()
 7404                .map_or(false, |completion| {
 7405                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7406                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7407                    !invalidation_range.contains(&offset_selection.head())
 7408                })
 7409        {
 7410            self.discard_inline_completion(false, cx);
 7411            return None;
 7412        }
 7413
 7414        self.take_active_inline_completion(cx);
 7415        let Some(provider) = self.edit_prediction_provider() else {
 7416            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7417            return None;
 7418        };
 7419
 7420        let (buffer, cursor_buffer_position) =
 7421            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7422
 7423        self.edit_prediction_settings =
 7424            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7425
 7426        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7427
 7428        if self.edit_prediction_indent_conflict {
 7429            let cursor_point = cursor.to_point(&multibuffer);
 7430
 7431            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7432
 7433            if let Some((_, indent)) = indents.iter().next() {
 7434                if indent.len == cursor_point.column {
 7435                    self.edit_prediction_indent_conflict = false;
 7436                }
 7437            }
 7438        }
 7439
 7440        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7441        let edits = inline_completion
 7442            .edits
 7443            .into_iter()
 7444            .flat_map(|(range, new_text)| {
 7445                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7446                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7447                Some((start..end, new_text))
 7448            })
 7449            .collect::<Vec<_>>();
 7450        if edits.is_empty() {
 7451            return None;
 7452        }
 7453
 7454        let first_edit_start = edits.first().unwrap().0.start;
 7455        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7456        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7457
 7458        let last_edit_end = edits.last().unwrap().0.end;
 7459        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7460        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7461
 7462        let cursor_row = cursor.to_point(&multibuffer).row;
 7463
 7464        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7465
 7466        let mut inlay_ids = Vec::new();
 7467        let invalidation_row_range;
 7468        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7469            Some(cursor_row..edit_end_row)
 7470        } else if cursor_row > edit_end_row {
 7471            Some(edit_start_row..cursor_row)
 7472        } else {
 7473            None
 7474        };
 7475        let is_move =
 7476            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7477        let completion = if is_move {
 7478            invalidation_row_range =
 7479                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7480            let target = first_edit_start;
 7481            InlineCompletion::Move { target, snapshot }
 7482        } else {
 7483            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7484                && !self.inline_completions_hidden_for_vim_mode;
 7485
 7486            if show_completions_in_buffer {
 7487                if edits
 7488                    .iter()
 7489                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7490                {
 7491                    let mut inlays = Vec::new();
 7492                    for (range, new_text) in &edits {
 7493                        let inlay = Inlay::inline_completion(
 7494                            post_inc(&mut self.next_inlay_id),
 7495                            range.start,
 7496                            new_text.as_str(),
 7497                        );
 7498                        inlay_ids.push(inlay.id);
 7499                        inlays.push(inlay);
 7500                    }
 7501
 7502                    self.splice_inlays(&[], inlays, cx);
 7503                } else {
 7504                    let background_color = cx.theme().status().deleted_background;
 7505                    let style = HighlightStyle {
 7506                        background_color: Some(background_color),
 7507                        ..Default::default()
 7508                    };
 7509                    self.highlight_text::<InlineCompletionHighlight>(
 7510                        edits
 7511                            .iter()
 7512                            .map(|(range, _)| (range.clone(), style))
 7513                            .collect(),
 7514                        cx,
 7515                    );
 7516                }
 7517            }
 7518
 7519            invalidation_row_range = edit_start_row..edit_end_row;
 7520
 7521            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7522                if provider.show_tab_accept_marker() {
 7523                    EditDisplayMode::TabAccept
 7524                } else {
 7525                    EditDisplayMode::Inline
 7526                }
 7527            } else {
 7528                EditDisplayMode::DiffPopover
 7529            };
 7530
 7531            InlineCompletion::Edit {
 7532                edits,
 7533                edit_preview: inline_completion.edit_preview,
 7534                display_mode,
 7535                snapshot,
 7536            }
 7537        };
 7538
 7539        let invalidation_range = multibuffer
 7540            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7541            ..multibuffer.anchor_after(Point::new(
 7542                invalidation_row_range.end,
 7543                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7544            ));
 7545
 7546        self.stale_inline_completion_in_menu = None;
 7547        self.active_inline_completion = Some(InlineCompletionState {
 7548            inlay_ids,
 7549            completion,
 7550            completion_id: inline_completion.id,
 7551            invalidation_range,
 7552        });
 7553
 7554        cx.notify();
 7555
 7556        Some(())
 7557    }
 7558
 7559    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7560        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7561    }
 7562
 7563    fn clear_tasks(&mut self) {
 7564        self.tasks.clear()
 7565    }
 7566
 7567    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7568        if self.tasks.insert(key, value).is_some() {
 7569            // This case should hopefully be rare, but just in case...
 7570            log::error!(
 7571                "multiple different run targets found on a single line, only the last target will be rendered"
 7572            )
 7573        }
 7574    }
 7575
 7576    /// Get all display points of breakpoints that will be rendered within editor
 7577    ///
 7578    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7579    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7580    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7581    fn active_breakpoints(
 7582        &self,
 7583        range: Range<DisplayRow>,
 7584        window: &mut Window,
 7585        cx: &mut Context<Self>,
 7586    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7587        let mut breakpoint_display_points = HashMap::default();
 7588
 7589        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7590            return breakpoint_display_points;
 7591        };
 7592
 7593        let snapshot = self.snapshot(window, cx);
 7594
 7595        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7596        let Some(project) = self.project.as_ref() else {
 7597            return breakpoint_display_points;
 7598        };
 7599
 7600        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7601            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7602
 7603        for (buffer_snapshot, range, excerpt_id) in
 7604            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7605        {
 7606            let Some(buffer) = project
 7607                .read(cx)
 7608                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7609            else {
 7610                continue;
 7611            };
 7612            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7613                &buffer,
 7614                Some(
 7615                    buffer_snapshot.anchor_before(range.start)
 7616                        ..buffer_snapshot.anchor_after(range.end),
 7617                ),
 7618                buffer_snapshot,
 7619                cx,
 7620            );
 7621            for (breakpoint, state) in breakpoints {
 7622                let multi_buffer_anchor =
 7623                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7624                let position = multi_buffer_anchor
 7625                    .to_point(&multi_buffer_snapshot)
 7626                    .to_display_point(&snapshot);
 7627
 7628                breakpoint_display_points.insert(
 7629                    position.row(),
 7630                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7631                );
 7632            }
 7633        }
 7634
 7635        breakpoint_display_points
 7636    }
 7637
 7638    fn breakpoint_context_menu(
 7639        &self,
 7640        anchor: Anchor,
 7641        window: &mut Window,
 7642        cx: &mut Context<Self>,
 7643    ) -> Entity<ui::ContextMenu> {
 7644        let weak_editor = cx.weak_entity();
 7645        let focus_handle = self.focus_handle(cx);
 7646
 7647        let row = self
 7648            .buffer
 7649            .read(cx)
 7650            .snapshot(cx)
 7651            .summary_for_anchor::<Point>(&anchor)
 7652            .row;
 7653
 7654        let breakpoint = self
 7655            .breakpoint_at_row(row, window, cx)
 7656            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7657
 7658        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7659            "Edit Log Breakpoint"
 7660        } else {
 7661            "Set Log Breakpoint"
 7662        };
 7663
 7664        let condition_breakpoint_msg = if breakpoint
 7665            .as_ref()
 7666            .is_some_and(|bp| bp.1.condition.is_some())
 7667        {
 7668            "Edit Condition Breakpoint"
 7669        } else {
 7670            "Set Condition Breakpoint"
 7671        };
 7672
 7673        let hit_condition_breakpoint_msg = if breakpoint
 7674            .as_ref()
 7675            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7676        {
 7677            "Edit Hit Condition Breakpoint"
 7678        } else {
 7679            "Set Hit Condition Breakpoint"
 7680        };
 7681
 7682        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7683            "Unset Breakpoint"
 7684        } else {
 7685            "Set Breakpoint"
 7686        };
 7687
 7688        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7689
 7690        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7691            BreakpointState::Enabled => Some("Disable"),
 7692            BreakpointState::Disabled => Some("Enable"),
 7693        });
 7694
 7695        let (anchor, breakpoint) =
 7696            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7697
 7698        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7699            menu.on_blur_subscription(Subscription::new(|| {}))
 7700                .context(focus_handle)
 7701                .when(run_to_cursor, |this| {
 7702                    let weak_editor = weak_editor.clone();
 7703                    this.entry("Run to cursor", None, move |window, cx| {
 7704                        weak_editor
 7705                            .update(cx, |editor, cx| {
 7706                                editor.change_selections(None, window, cx, |s| {
 7707                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7708                                });
 7709                            })
 7710                            .ok();
 7711
 7712                        window.dispatch_action(Box::new(RunToCursor), cx);
 7713                    })
 7714                    .separator()
 7715                })
 7716                .when_some(toggle_state_msg, |this, msg| {
 7717                    this.entry(msg, None, {
 7718                        let weak_editor = weak_editor.clone();
 7719                        let breakpoint = breakpoint.clone();
 7720                        move |_window, cx| {
 7721                            weak_editor
 7722                                .update(cx, |this, cx| {
 7723                                    this.edit_breakpoint_at_anchor(
 7724                                        anchor,
 7725                                        breakpoint.as_ref().clone(),
 7726                                        BreakpointEditAction::InvertState,
 7727                                        cx,
 7728                                    );
 7729                                })
 7730                                .log_err();
 7731                        }
 7732                    })
 7733                })
 7734                .entry(set_breakpoint_msg, None, {
 7735                    let weak_editor = weak_editor.clone();
 7736                    let breakpoint = breakpoint.clone();
 7737                    move |_window, cx| {
 7738                        weak_editor
 7739                            .update(cx, |this, cx| {
 7740                                this.edit_breakpoint_at_anchor(
 7741                                    anchor,
 7742                                    breakpoint.as_ref().clone(),
 7743                                    BreakpointEditAction::Toggle,
 7744                                    cx,
 7745                                );
 7746                            })
 7747                            .log_err();
 7748                    }
 7749                })
 7750                .entry(log_breakpoint_msg, None, {
 7751                    let breakpoint = breakpoint.clone();
 7752                    let weak_editor = weak_editor.clone();
 7753                    move |window, cx| {
 7754                        weak_editor
 7755                            .update(cx, |this, cx| {
 7756                                this.add_edit_breakpoint_block(
 7757                                    anchor,
 7758                                    breakpoint.as_ref(),
 7759                                    BreakpointPromptEditAction::Log,
 7760                                    window,
 7761                                    cx,
 7762                                );
 7763                            })
 7764                            .log_err();
 7765                    }
 7766                })
 7767                .entry(condition_breakpoint_msg, None, {
 7768                    let breakpoint = breakpoint.clone();
 7769                    let weak_editor = weak_editor.clone();
 7770                    move |window, cx| {
 7771                        weak_editor
 7772                            .update(cx, |this, cx| {
 7773                                this.add_edit_breakpoint_block(
 7774                                    anchor,
 7775                                    breakpoint.as_ref(),
 7776                                    BreakpointPromptEditAction::Condition,
 7777                                    window,
 7778                                    cx,
 7779                                );
 7780                            })
 7781                            .log_err();
 7782                    }
 7783                })
 7784                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7785                    weak_editor
 7786                        .update(cx, |this, cx| {
 7787                            this.add_edit_breakpoint_block(
 7788                                anchor,
 7789                                breakpoint.as_ref(),
 7790                                BreakpointPromptEditAction::HitCondition,
 7791                                window,
 7792                                cx,
 7793                            );
 7794                        })
 7795                        .log_err();
 7796                })
 7797        })
 7798    }
 7799
 7800    fn render_breakpoint(
 7801        &self,
 7802        position: Anchor,
 7803        row: DisplayRow,
 7804        breakpoint: &Breakpoint,
 7805        state: Option<BreakpointSessionState>,
 7806        cx: &mut Context<Self>,
 7807    ) -> IconButton {
 7808        let is_rejected = state.is_some_and(|s| !s.verified);
 7809        // Is it a breakpoint that shows up when hovering over gutter?
 7810        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7811            (false, false),
 7812            |PhantomBreakpointIndicator {
 7813                 is_active,
 7814                 display_row,
 7815                 collides_with_existing_breakpoint,
 7816             }| {
 7817                (
 7818                    is_active && display_row == row,
 7819                    collides_with_existing_breakpoint,
 7820                )
 7821            },
 7822        );
 7823
 7824        let (color, icon) = {
 7825            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7826                (false, false) => ui::IconName::DebugBreakpoint,
 7827                (true, false) => ui::IconName::DebugLogBreakpoint,
 7828                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7829                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7830            };
 7831
 7832            let color = if is_phantom {
 7833                Color::Hint
 7834            } else if is_rejected {
 7835                Color::Disabled
 7836            } else {
 7837                Color::Debugger
 7838            };
 7839
 7840            (color, icon)
 7841        };
 7842
 7843        let breakpoint = Arc::from(breakpoint.clone());
 7844
 7845        let alt_as_text = gpui::Keystroke {
 7846            modifiers: Modifiers::secondary_key(),
 7847            ..Default::default()
 7848        };
 7849        let primary_action_text = if breakpoint.is_disabled() {
 7850            "Enable breakpoint"
 7851        } else if is_phantom && !collides_with_existing {
 7852            "Set breakpoint"
 7853        } else {
 7854            "Unset breakpoint"
 7855        };
 7856        let focus_handle = self.focus_handle.clone();
 7857
 7858        let meta = if is_rejected {
 7859            SharedString::from("No executable code is associated with this line.")
 7860        } else if collides_with_existing && !breakpoint.is_disabled() {
 7861            SharedString::from(format!(
 7862                "{alt_as_text}-click to disable,\nright-click for more options."
 7863            ))
 7864        } else {
 7865            SharedString::from("Right-click for more options.")
 7866        };
 7867        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7868            .icon_size(IconSize::XSmall)
 7869            .size(ui::ButtonSize::None)
 7870            .when(is_rejected, |this| {
 7871                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7872            })
 7873            .icon_color(color)
 7874            .style(ButtonStyle::Transparent)
 7875            .on_click(cx.listener({
 7876                let breakpoint = breakpoint.clone();
 7877
 7878                move |editor, event: &ClickEvent, window, cx| {
 7879                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7880                        BreakpointEditAction::InvertState
 7881                    } else {
 7882                        BreakpointEditAction::Toggle
 7883                    };
 7884
 7885                    window.focus(&editor.focus_handle(cx));
 7886                    editor.edit_breakpoint_at_anchor(
 7887                        position,
 7888                        breakpoint.as_ref().clone(),
 7889                        edit_action,
 7890                        cx,
 7891                    );
 7892                }
 7893            }))
 7894            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7895                editor.set_breakpoint_context_menu(
 7896                    row,
 7897                    Some(position),
 7898                    event.down.position,
 7899                    window,
 7900                    cx,
 7901                );
 7902            }))
 7903            .tooltip(move |window, cx| {
 7904                Tooltip::with_meta_in(
 7905                    primary_action_text,
 7906                    Some(&ToggleBreakpoint),
 7907                    meta.clone(),
 7908                    &focus_handle,
 7909                    window,
 7910                    cx,
 7911                )
 7912            })
 7913    }
 7914
 7915    fn build_tasks_context(
 7916        project: &Entity<Project>,
 7917        buffer: &Entity<Buffer>,
 7918        buffer_row: u32,
 7919        tasks: &Arc<RunnableTasks>,
 7920        cx: &mut Context<Self>,
 7921    ) -> Task<Option<task::TaskContext>> {
 7922        let position = Point::new(buffer_row, tasks.column);
 7923        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7924        let location = Location {
 7925            buffer: buffer.clone(),
 7926            range: range_start..range_start,
 7927        };
 7928        // Fill in the environmental variables from the tree-sitter captures
 7929        let mut captured_task_variables = TaskVariables::default();
 7930        for (capture_name, value) in tasks.extra_variables.clone() {
 7931            captured_task_variables.insert(
 7932                task::VariableName::Custom(capture_name.into()),
 7933                value.clone(),
 7934            );
 7935        }
 7936        project.update(cx, |project, cx| {
 7937            project.task_store().update(cx, |task_store, cx| {
 7938                task_store.task_context_for_location(captured_task_variables, location, cx)
 7939            })
 7940        })
 7941    }
 7942
 7943    pub fn spawn_nearest_task(
 7944        &mut self,
 7945        action: &SpawnNearestTask,
 7946        window: &mut Window,
 7947        cx: &mut Context<Self>,
 7948    ) {
 7949        let Some((workspace, _)) = self.workspace.clone() else {
 7950            return;
 7951        };
 7952        let Some(project) = self.project.clone() else {
 7953            return;
 7954        };
 7955
 7956        // Try to find a closest, enclosing node using tree-sitter that has a
 7957        // task
 7958        let Some((buffer, buffer_row, tasks)) = self
 7959            .find_enclosing_node_task(cx)
 7960            // Or find the task that's closest in row-distance.
 7961            .or_else(|| self.find_closest_task(cx))
 7962        else {
 7963            return;
 7964        };
 7965
 7966        let reveal_strategy = action.reveal;
 7967        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7968        cx.spawn_in(window, async move |_, cx| {
 7969            let context = task_context.await?;
 7970            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7971
 7972            let resolved = &mut resolved_task.resolved;
 7973            resolved.reveal = reveal_strategy;
 7974
 7975            workspace
 7976                .update_in(cx, |workspace, window, cx| {
 7977                    workspace.schedule_resolved_task(
 7978                        task_source_kind,
 7979                        resolved_task,
 7980                        false,
 7981                        window,
 7982                        cx,
 7983                    );
 7984                })
 7985                .ok()
 7986        })
 7987        .detach();
 7988    }
 7989
 7990    fn find_closest_task(
 7991        &mut self,
 7992        cx: &mut Context<Self>,
 7993    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7994        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7995
 7996        let ((buffer_id, row), tasks) = self
 7997            .tasks
 7998            .iter()
 7999            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8000
 8001        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8002        let tasks = Arc::new(tasks.to_owned());
 8003        Some((buffer, *row, tasks))
 8004    }
 8005
 8006    fn find_enclosing_node_task(
 8007        &mut self,
 8008        cx: &mut Context<Self>,
 8009    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8010        let snapshot = self.buffer.read(cx).snapshot(cx);
 8011        let offset = self.selections.newest::<usize>(cx).head();
 8012        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8013        let buffer_id = excerpt.buffer().remote_id();
 8014
 8015        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8016        let mut cursor = layer.node().walk();
 8017
 8018        while cursor.goto_first_child_for_byte(offset).is_some() {
 8019            if cursor.node().end_byte() == offset {
 8020                cursor.goto_next_sibling();
 8021            }
 8022        }
 8023
 8024        // Ascend to the smallest ancestor that contains the range and has a task.
 8025        loop {
 8026            let node = cursor.node();
 8027            let node_range = node.byte_range();
 8028            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8029
 8030            // Check if this node contains our offset
 8031            if node_range.start <= offset && node_range.end >= offset {
 8032                // If it contains offset, check for task
 8033                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8034                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8035                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8036                }
 8037            }
 8038
 8039            if !cursor.goto_parent() {
 8040                break;
 8041            }
 8042        }
 8043        None
 8044    }
 8045
 8046    fn render_run_indicator(
 8047        &self,
 8048        _style: &EditorStyle,
 8049        is_active: bool,
 8050        row: DisplayRow,
 8051        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8052        cx: &mut Context<Self>,
 8053    ) -> IconButton {
 8054        let color = Color::Muted;
 8055        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8056
 8057        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8058            .shape(ui::IconButtonShape::Square)
 8059            .icon_size(IconSize::XSmall)
 8060            .icon_color(color)
 8061            .toggle_state(is_active)
 8062            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8063                let quick_launch = e.down.button == MouseButton::Left;
 8064                window.focus(&editor.focus_handle(cx));
 8065                editor.toggle_code_actions(
 8066                    &ToggleCodeActions {
 8067                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8068                        quick_launch,
 8069                    },
 8070                    window,
 8071                    cx,
 8072                );
 8073            }))
 8074            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8075                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8076            }))
 8077    }
 8078
 8079    pub fn context_menu_visible(&self) -> bool {
 8080        !self.edit_prediction_preview_is_active()
 8081            && self
 8082                .context_menu
 8083                .borrow()
 8084                .as_ref()
 8085                .map_or(false, |menu| menu.visible())
 8086    }
 8087
 8088    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8089        self.context_menu
 8090            .borrow()
 8091            .as_ref()
 8092            .map(|menu| menu.origin())
 8093    }
 8094
 8095    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8096        self.context_menu_options = Some(options);
 8097    }
 8098
 8099    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8100    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8101
 8102    fn render_edit_prediction_popover(
 8103        &mut self,
 8104        text_bounds: &Bounds<Pixels>,
 8105        content_origin: gpui::Point<Pixels>,
 8106        right_margin: Pixels,
 8107        editor_snapshot: &EditorSnapshot,
 8108        visible_row_range: Range<DisplayRow>,
 8109        scroll_top: f32,
 8110        scroll_bottom: f32,
 8111        line_layouts: &[LineWithInvisibles],
 8112        line_height: Pixels,
 8113        scroll_pixel_position: gpui::Point<Pixels>,
 8114        newest_selection_head: Option<DisplayPoint>,
 8115        editor_width: Pixels,
 8116        style: &EditorStyle,
 8117        window: &mut Window,
 8118        cx: &mut App,
 8119    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8120        if self.mode().is_minimap() {
 8121            return None;
 8122        }
 8123        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8124
 8125        if self.edit_prediction_visible_in_cursor_popover(true) {
 8126            return None;
 8127        }
 8128
 8129        match &active_inline_completion.completion {
 8130            InlineCompletion::Move { target, .. } => {
 8131                let target_display_point = target.to_display_point(editor_snapshot);
 8132
 8133                if self.edit_prediction_requires_modifier() {
 8134                    if !self.edit_prediction_preview_is_active() {
 8135                        return None;
 8136                    }
 8137
 8138                    self.render_edit_prediction_modifier_jump_popover(
 8139                        text_bounds,
 8140                        content_origin,
 8141                        visible_row_range,
 8142                        line_layouts,
 8143                        line_height,
 8144                        scroll_pixel_position,
 8145                        newest_selection_head,
 8146                        target_display_point,
 8147                        window,
 8148                        cx,
 8149                    )
 8150                } else {
 8151                    self.render_edit_prediction_eager_jump_popover(
 8152                        text_bounds,
 8153                        content_origin,
 8154                        editor_snapshot,
 8155                        visible_row_range,
 8156                        scroll_top,
 8157                        scroll_bottom,
 8158                        line_height,
 8159                        scroll_pixel_position,
 8160                        target_display_point,
 8161                        editor_width,
 8162                        window,
 8163                        cx,
 8164                    )
 8165                }
 8166            }
 8167            InlineCompletion::Edit {
 8168                display_mode: EditDisplayMode::Inline,
 8169                ..
 8170            } => None,
 8171            InlineCompletion::Edit {
 8172                display_mode: EditDisplayMode::TabAccept,
 8173                edits,
 8174                ..
 8175            } => {
 8176                let range = &edits.first()?.0;
 8177                let target_display_point = range.end.to_display_point(editor_snapshot);
 8178
 8179                self.render_edit_prediction_end_of_line_popover(
 8180                    "Accept",
 8181                    editor_snapshot,
 8182                    visible_row_range,
 8183                    target_display_point,
 8184                    line_height,
 8185                    scroll_pixel_position,
 8186                    content_origin,
 8187                    editor_width,
 8188                    window,
 8189                    cx,
 8190                )
 8191            }
 8192            InlineCompletion::Edit {
 8193                edits,
 8194                edit_preview,
 8195                display_mode: EditDisplayMode::DiffPopover,
 8196                snapshot,
 8197            } => self.render_edit_prediction_diff_popover(
 8198                text_bounds,
 8199                content_origin,
 8200                right_margin,
 8201                editor_snapshot,
 8202                visible_row_range,
 8203                line_layouts,
 8204                line_height,
 8205                scroll_pixel_position,
 8206                newest_selection_head,
 8207                editor_width,
 8208                style,
 8209                edits,
 8210                edit_preview,
 8211                snapshot,
 8212                window,
 8213                cx,
 8214            ),
 8215        }
 8216    }
 8217
 8218    fn render_edit_prediction_modifier_jump_popover(
 8219        &mut self,
 8220        text_bounds: &Bounds<Pixels>,
 8221        content_origin: gpui::Point<Pixels>,
 8222        visible_row_range: Range<DisplayRow>,
 8223        line_layouts: &[LineWithInvisibles],
 8224        line_height: Pixels,
 8225        scroll_pixel_position: gpui::Point<Pixels>,
 8226        newest_selection_head: Option<DisplayPoint>,
 8227        target_display_point: DisplayPoint,
 8228        window: &mut Window,
 8229        cx: &mut App,
 8230    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8231        let scrolled_content_origin =
 8232            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8233
 8234        const SCROLL_PADDING_Y: Pixels = px(12.);
 8235
 8236        if target_display_point.row() < visible_row_range.start {
 8237            return self.render_edit_prediction_scroll_popover(
 8238                |_| SCROLL_PADDING_Y,
 8239                IconName::ArrowUp,
 8240                visible_row_range,
 8241                line_layouts,
 8242                newest_selection_head,
 8243                scrolled_content_origin,
 8244                window,
 8245                cx,
 8246            );
 8247        } else if target_display_point.row() >= visible_row_range.end {
 8248            return self.render_edit_prediction_scroll_popover(
 8249                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8250                IconName::ArrowDown,
 8251                visible_row_range,
 8252                line_layouts,
 8253                newest_selection_head,
 8254                scrolled_content_origin,
 8255                window,
 8256                cx,
 8257            );
 8258        }
 8259
 8260        const POLE_WIDTH: Pixels = px(2.);
 8261
 8262        let line_layout =
 8263            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8264        let target_column = target_display_point.column() as usize;
 8265
 8266        let target_x = line_layout.x_for_index(target_column);
 8267        let target_y =
 8268            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8269
 8270        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8271
 8272        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8273        border_color.l += 0.001;
 8274
 8275        let mut element = v_flex()
 8276            .items_end()
 8277            .when(flag_on_right, |el| el.items_start())
 8278            .child(if flag_on_right {
 8279                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8280                    .rounded_bl(px(0.))
 8281                    .rounded_tl(px(0.))
 8282                    .border_l_2()
 8283                    .border_color(border_color)
 8284            } else {
 8285                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8286                    .rounded_br(px(0.))
 8287                    .rounded_tr(px(0.))
 8288                    .border_r_2()
 8289                    .border_color(border_color)
 8290            })
 8291            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8292            .into_any();
 8293
 8294        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8295
 8296        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8297            - point(
 8298                if flag_on_right {
 8299                    POLE_WIDTH
 8300                } else {
 8301                    size.width - POLE_WIDTH
 8302                },
 8303                size.height - line_height,
 8304            );
 8305
 8306        origin.x = origin.x.max(content_origin.x);
 8307
 8308        element.prepaint_at(origin, window, cx);
 8309
 8310        Some((element, origin))
 8311    }
 8312
 8313    fn render_edit_prediction_scroll_popover(
 8314        &mut self,
 8315        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8316        scroll_icon: IconName,
 8317        visible_row_range: Range<DisplayRow>,
 8318        line_layouts: &[LineWithInvisibles],
 8319        newest_selection_head: Option<DisplayPoint>,
 8320        scrolled_content_origin: gpui::Point<Pixels>,
 8321        window: &mut Window,
 8322        cx: &mut App,
 8323    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8324        let mut element = self
 8325            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8326            .into_any();
 8327
 8328        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8329
 8330        let cursor = newest_selection_head?;
 8331        let cursor_row_layout =
 8332            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8333        let cursor_column = cursor.column() as usize;
 8334
 8335        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8336
 8337        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8338
 8339        element.prepaint_at(origin, window, cx);
 8340        Some((element, origin))
 8341    }
 8342
 8343    fn render_edit_prediction_eager_jump_popover(
 8344        &mut self,
 8345        text_bounds: &Bounds<Pixels>,
 8346        content_origin: gpui::Point<Pixels>,
 8347        editor_snapshot: &EditorSnapshot,
 8348        visible_row_range: Range<DisplayRow>,
 8349        scroll_top: f32,
 8350        scroll_bottom: f32,
 8351        line_height: Pixels,
 8352        scroll_pixel_position: gpui::Point<Pixels>,
 8353        target_display_point: DisplayPoint,
 8354        editor_width: Pixels,
 8355        window: &mut Window,
 8356        cx: &mut App,
 8357    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8358        if target_display_point.row().as_f32() < scroll_top {
 8359            let mut element = self
 8360                .render_edit_prediction_line_popover(
 8361                    "Jump to Edit",
 8362                    Some(IconName::ArrowUp),
 8363                    window,
 8364                    cx,
 8365                )?
 8366                .into_any();
 8367
 8368            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8369            let offset = point(
 8370                (text_bounds.size.width - size.width) / 2.,
 8371                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8372            );
 8373
 8374            let origin = text_bounds.origin + offset;
 8375            element.prepaint_at(origin, window, cx);
 8376            Some((element, origin))
 8377        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8378            let mut element = self
 8379                .render_edit_prediction_line_popover(
 8380                    "Jump to Edit",
 8381                    Some(IconName::ArrowDown),
 8382                    window,
 8383                    cx,
 8384                )?
 8385                .into_any();
 8386
 8387            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8388            let offset = point(
 8389                (text_bounds.size.width - size.width) / 2.,
 8390                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8391            );
 8392
 8393            let origin = text_bounds.origin + offset;
 8394            element.prepaint_at(origin, window, cx);
 8395            Some((element, origin))
 8396        } else {
 8397            self.render_edit_prediction_end_of_line_popover(
 8398                "Jump to Edit",
 8399                editor_snapshot,
 8400                visible_row_range,
 8401                target_display_point,
 8402                line_height,
 8403                scroll_pixel_position,
 8404                content_origin,
 8405                editor_width,
 8406                window,
 8407                cx,
 8408            )
 8409        }
 8410    }
 8411
 8412    fn render_edit_prediction_end_of_line_popover(
 8413        self: &mut Editor,
 8414        label: &'static str,
 8415        editor_snapshot: &EditorSnapshot,
 8416        visible_row_range: Range<DisplayRow>,
 8417        target_display_point: DisplayPoint,
 8418        line_height: Pixels,
 8419        scroll_pixel_position: gpui::Point<Pixels>,
 8420        content_origin: gpui::Point<Pixels>,
 8421        editor_width: Pixels,
 8422        window: &mut Window,
 8423        cx: &mut App,
 8424    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8425        let target_line_end = DisplayPoint::new(
 8426            target_display_point.row(),
 8427            editor_snapshot.line_len(target_display_point.row()),
 8428        );
 8429
 8430        let mut element = self
 8431            .render_edit_prediction_line_popover(label, None, window, cx)?
 8432            .into_any();
 8433
 8434        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8435
 8436        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8437
 8438        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8439        let mut origin = start_point
 8440            + line_origin
 8441            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8442        origin.x = origin.x.max(content_origin.x);
 8443
 8444        let max_x = content_origin.x + editor_width - size.width;
 8445
 8446        if origin.x > max_x {
 8447            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8448
 8449            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8450                origin.y += offset;
 8451                IconName::ArrowUp
 8452            } else {
 8453                origin.y -= offset;
 8454                IconName::ArrowDown
 8455            };
 8456
 8457            element = self
 8458                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8459                .into_any();
 8460
 8461            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8462
 8463            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8464        }
 8465
 8466        element.prepaint_at(origin, window, cx);
 8467        Some((element, origin))
 8468    }
 8469
 8470    fn render_edit_prediction_diff_popover(
 8471        self: &Editor,
 8472        text_bounds: &Bounds<Pixels>,
 8473        content_origin: gpui::Point<Pixels>,
 8474        right_margin: Pixels,
 8475        editor_snapshot: &EditorSnapshot,
 8476        visible_row_range: Range<DisplayRow>,
 8477        line_layouts: &[LineWithInvisibles],
 8478        line_height: Pixels,
 8479        scroll_pixel_position: gpui::Point<Pixels>,
 8480        newest_selection_head: Option<DisplayPoint>,
 8481        editor_width: Pixels,
 8482        style: &EditorStyle,
 8483        edits: &Vec<(Range<Anchor>, String)>,
 8484        edit_preview: &Option<language::EditPreview>,
 8485        snapshot: &language::BufferSnapshot,
 8486        window: &mut Window,
 8487        cx: &mut App,
 8488    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8489        let edit_start = edits
 8490            .first()
 8491            .unwrap()
 8492            .0
 8493            .start
 8494            .to_display_point(editor_snapshot);
 8495        let edit_end = edits
 8496            .last()
 8497            .unwrap()
 8498            .0
 8499            .end
 8500            .to_display_point(editor_snapshot);
 8501
 8502        let is_visible = visible_row_range.contains(&edit_start.row())
 8503            || visible_row_range.contains(&edit_end.row());
 8504        if !is_visible {
 8505            return None;
 8506        }
 8507
 8508        let highlighted_edits =
 8509            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8510
 8511        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8512        let line_count = highlighted_edits.text.lines().count();
 8513
 8514        const BORDER_WIDTH: Pixels = px(1.);
 8515
 8516        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8517        let has_keybind = keybind.is_some();
 8518
 8519        let mut element = h_flex()
 8520            .items_start()
 8521            .child(
 8522                h_flex()
 8523                    .bg(cx.theme().colors().editor_background)
 8524                    .border(BORDER_WIDTH)
 8525                    .shadow_sm()
 8526                    .border_color(cx.theme().colors().border)
 8527                    .rounded_l_lg()
 8528                    .when(line_count > 1, |el| el.rounded_br_lg())
 8529                    .pr_1()
 8530                    .child(styled_text),
 8531            )
 8532            .child(
 8533                h_flex()
 8534                    .h(line_height + BORDER_WIDTH * 2.)
 8535                    .px_1p5()
 8536                    .gap_1()
 8537                    // Workaround: For some reason, there's a gap if we don't do this
 8538                    .ml(-BORDER_WIDTH)
 8539                    .shadow(vec![gpui::BoxShadow {
 8540                        color: gpui::black().opacity(0.05),
 8541                        offset: point(px(1.), px(1.)),
 8542                        blur_radius: px(2.),
 8543                        spread_radius: px(0.),
 8544                    }])
 8545                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8546                    .border(BORDER_WIDTH)
 8547                    .border_color(cx.theme().colors().border)
 8548                    .rounded_r_lg()
 8549                    .id("edit_prediction_diff_popover_keybind")
 8550                    .when(!has_keybind, |el| {
 8551                        let status_colors = cx.theme().status();
 8552
 8553                        el.bg(status_colors.error_background)
 8554                            .border_color(status_colors.error.opacity(0.6))
 8555                            .child(Icon::new(IconName::Info).color(Color::Error))
 8556                            .cursor_default()
 8557                            .hoverable_tooltip(move |_window, cx| {
 8558                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8559                            })
 8560                    })
 8561                    .children(keybind),
 8562            )
 8563            .into_any();
 8564
 8565        let longest_row =
 8566            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8567        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8568            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8569        } else {
 8570            layout_line(
 8571                longest_row,
 8572                editor_snapshot,
 8573                style,
 8574                editor_width,
 8575                |_| false,
 8576                window,
 8577                cx,
 8578            )
 8579            .width
 8580        };
 8581
 8582        let viewport_bounds =
 8583            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8584                right: -right_margin,
 8585                ..Default::default()
 8586            });
 8587
 8588        let x_after_longest =
 8589            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8590                - scroll_pixel_position.x;
 8591
 8592        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8593
 8594        // Fully visible if it can be displayed within the window (allow overlapping other
 8595        // panes). However, this is only allowed if the popover starts within text_bounds.
 8596        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8597            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8598
 8599        let mut origin = if can_position_to_the_right {
 8600            point(
 8601                x_after_longest,
 8602                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8603                    - scroll_pixel_position.y,
 8604            )
 8605        } else {
 8606            let cursor_row = newest_selection_head.map(|head| head.row());
 8607            let above_edit = edit_start
 8608                .row()
 8609                .0
 8610                .checked_sub(line_count as u32)
 8611                .map(DisplayRow);
 8612            let below_edit = Some(edit_end.row() + 1);
 8613            let above_cursor =
 8614                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8615            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8616
 8617            // Place the edit popover adjacent to the edit if there is a location
 8618            // available that is onscreen and does not obscure the cursor. Otherwise,
 8619            // place it adjacent to the cursor.
 8620            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8621                .into_iter()
 8622                .flatten()
 8623                .find(|&start_row| {
 8624                    let end_row = start_row + line_count as u32;
 8625                    visible_row_range.contains(&start_row)
 8626                        && visible_row_range.contains(&end_row)
 8627                        && cursor_row.map_or(true, |cursor_row| {
 8628                            !((start_row..end_row).contains(&cursor_row))
 8629                        })
 8630                })?;
 8631
 8632            content_origin
 8633                + point(
 8634                    -scroll_pixel_position.x,
 8635                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8636                )
 8637        };
 8638
 8639        origin.x -= BORDER_WIDTH;
 8640
 8641        window.defer_draw(element, origin, 1);
 8642
 8643        // Do not return an element, since it will already be drawn due to defer_draw.
 8644        None
 8645    }
 8646
 8647    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8648        px(30.)
 8649    }
 8650
 8651    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8652        if self.read_only(cx) {
 8653            cx.theme().players().read_only()
 8654        } else {
 8655            self.style.as_ref().unwrap().local_player
 8656        }
 8657    }
 8658
 8659    fn render_edit_prediction_accept_keybind(
 8660        &self,
 8661        window: &mut Window,
 8662        cx: &App,
 8663    ) -> Option<AnyElement> {
 8664        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8665        let accept_keystroke = accept_binding.keystroke()?;
 8666
 8667        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8668
 8669        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8670            Color::Accent
 8671        } else {
 8672            Color::Muted
 8673        };
 8674
 8675        h_flex()
 8676            .px_0p5()
 8677            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8678            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8679            .text_size(TextSize::XSmall.rems(cx))
 8680            .child(h_flex().children(ui::render_modifiers(
 8681                &accept_keystroke.modifiers,
 8682                PlatformStyle::platform(),
 8683                Some(modifiers_color),
 8684                Some(IconSize::XSmall.rems().into()),
 8685                true,
 8686            )))
 8687            .when(is_platform_style_mac, |parent| {
 8688                parent.child(accept_keystroke.key.clone())
 8689            })
 8690            .when(!is_platform_style_mac, |parent| {
 8691                parent.child(
 8692                    Key::new(
 8693                        util::capitalize(&accept_keystroke.key),
 8694                        Some(Color::Default),
 8695                    )
 8696                    .size(Some(IconSize::XSmall.rems().into())),
 8697                )
 8698            })
 8699            .into_any()
 8700            .into()
 8701    }
 8702
 8703    fn render_edit_prediction_line_popover(
 8704        &self,
 8705        label: impl Into<SharedString>,
 8706        icon: Option<IconName>,
 8707        window: &mut Window,
 8708        cx: &App,
 8709    ) -> Option<Stateful<Div>> {
 8710        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8711
 8712        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8713        let has_keybind = keybind.is_some();
 8714
 8715        let result = h_flex()
 8716            .id("ep-line-popover")
 8717            .py_0p5()
 8718            .pl_1()
 8719            .pr(padding_right)
 8720            .gap_1()
 8721            .rounded_md()
 8722            .border_1()
 8723            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8724            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8725            .shadow_sm()
 8726            .when(!has_keybind, |el| {
 8727                let status_colors = cx.theme().status();
 8728
 8729                el.bg(status_colors.error_background)
 8730                    .border_color(status_colors.error.opacity(0.6))
 8731                    .pl_2()
 8732                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8733                    .cursor_default()
 8734                    .hoverable_tooltip(move |_window, cx| {
 8735                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8736                    })
 8737            })
 8738            .children(keybind)
 8739            .child(
 8740                Label::new(label)
 8741                    .size(LabelSize::Small)
 8742                    .when(!has_keybind, |el| {
 8743                        el.color(cx.theme().status().error.into()).strikethrough()
 8744                    }),
 8745            )
 8746            .when(!has_keybind, |el| {
 8747                el.child(
 8748                    h_flex().ml_1().child(
 8749                        Icon::new(IconName::Info)
 8750                            .size(IconSize::Small)
 8751                            .color(cx.theme().status().error.into()),
 8752                    ),
 8753                )
 8754            })
 8755            .when_some(icon, |element, icon| {
 8756                element.child(
 8757                    div()
 8758                        .mt(px(1.5))
 8759                        .child(Icon::new(icon).size(IconSize::Small)),
 8760                )
 8761            });
 8762
 8763        Some(result)
 8764    }
 8765
 8766    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8767        let accent_color = cx.theme().colors().text_accent;
 8768        let editor_bg_color = cx.theme().colors().editor_background;
 8769        editor_bg_color.blend(accent_color.opacity(0.1))
 8770    }
 8771
 8772    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8773        let accent_color = cx.theme().colors().text_accent;
 8774        let editor_bg_color = cx.theme().colors().editor_background;
 8775        editor_bg_color.blend(accent_color.opacity(0.6))
 8776    }
 8777
 8778    fn render_edit_prediction_cursor_popover(
 8779        &self,
 8780        min_width: Pixels,
 8781        max_width: Pixels,
 8782        cursor_point: Point,
 8783        style: &EditorStyle,
 8784        accept_keystroke: Option<&gpui::Keystroke>,
 8785        _window: &Window,
 8786        cx: &mut Context<Editor>,
 8787    ) -> Option<AnyElement> {
 8788        let provider = self.edit_prediction_provider.as_ref()?;
 8789
 8790        if provider.provider.needs_terms_acceptance(cx) {
 8791            return Some(
 8792                h_flex()
 8793                    .min_w(min_width)
 8794                    .flex_1()
 8795                    .px_2()
 8796                    .py_1()
 8797                    .gap_3()
 8798                    .elevation_2(cx)
 8799                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8800                    .id("accept-terms")
 8801                    .cursor_pointer()
 8802                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8803                    .on_click(cx.listener(|this, _event, window, cx| {
 8804                        cx.stop_propagation();
 8805                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8806                        window.dispatch_action(
 8807                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8808                            cx,
 8809                        );
 8810                    }))
 8811                    .child(
 8812                        h_flex()
 8813                            .flex_1()
 8814                            .gap_2()
 8815                            .child(Icon::new(IconName::ZedPredict))
 8816                            .child(Label::new("Accept Terms of Service"))
 8817                            .child(div().w_full())
 8818                            .child(
 8819                                Icon::new(IconName::ArrowUpRight)
 8820                                    .color(Color::Muted)
 8821                                    .size(IconSize::Small),
 8822                            )
 8823                            .into_any_element(),
 8824                    )
 8825                    .into_any(),
 8826            );
 8827        }
 8828
 8829        let is_refreshing = provider.provider.is_refreshing(cx);
 8830
 8831        fn pending_completion_container() -> Div {
 8832            h_flex()
 8833                .h_full()
 8834                .flex_1()
 8835                .gap_2()
 8836                .child(Icon::new(IconName::ZedPredict))
 8837        }
 8838
 8839        let completion = match &self.active_inline_completion {
 8840            Some(prediction) => {
 8841                if !self.has_visible_completions_menu() {
 8842                    const RADIUS: Pixels = px(6.);
 8843                    const BORDER_WIDTH: Pixels = px(1.);
 8844
 8845                    return Some(
 8846                        h_flex()
 8847                            .elevation_2(cx)
 8848                            .border(BORDER_WIDTH)
 8849                            .border_color(cx.theme().colors().border)
 8850                            .when(accept_keystroke.is_none(), |el| {
 8851                                el.border_color(cx.theme().status().error)
 8852                            })
 8853                            .rounded(RADIUS)
 8854                            .rounded_tl(px(0.))
 8855                            .overflow_hidden()
 8856                            .child(div().px_1p5().child(match &prediction.completion {
 8857                                InlineCompletion::Move { target, snapshot } => {
 8858                                    use text::ToPoint as _;
 8859                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8860                                    {
 8861                                        Icon::new(IconName::ZedPredictDown)
 8862                                    } else {
 8863                                        Icon::new(IconName::ZedPredictUp)
 8864                                    }
 8865                                }
 8866                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8867                            }))
 8868                            .child(
 8869                                h_flex()
 8870                                    .gap_1()
 8871                                    .py_1()
 8872                                    .px_2()
 8873                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8874                                    .border_l_1()
 8875                                    .border_color(cx.theme().colors().border)
 8876                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8877                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8878                                        el.child(
 8879                                            Label::new("Hold")
 8880                                                .size(LabelSize::Small)
 8881                                                .when(accept_keystroke.is_none(), |el| {
 8882                                                    el.strikethrough()
 8883                                                })
 8884                                                .line_height_style(LineHeightStyle::UiLabel),
 8885                                        )
 8886                                    })
 8887                                    .id("edit_prediction_cursor_popover_keybind")
 8888                                    .when(accept_keystroke.is_none(), |el| {
 8889                                        let status_colors = cx.theme().status();
 8890
 8891                                        el.bg(status_colors.error_background)
 8892                                            .border_color(status_colors.error.opacity(0.6))
 8893                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8894                                            .cursor_default()
 8895                                            .hoverable_tooltip(move |_window, cx| {
 8896                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8897                                                    .into()
 8898                                            })
 8899                                    })
 8900                                    .when_some(
 8901                                        accept_keystroke.as_ref(),
 8902                                        |el, accept_keystroke| {
 8903                                            el.child(h_flex().children(ui::render_modifiers(
 8904                                                &accept_keystroke.modifiers,
 8905                                                PlatformStyle::platform(),
 8906                                                Some(Color::Default),
 8907                                                Some(IconSize::XSmall.rems().into()),
 8908                                                false,
 8909                                            )))
 8910                                        },
 8911                                    ),
 8912                            )
 8913                            .into_any(),
 8914                    );
 8915                }
 8916
 8917                self.render_edit_prediction_cursor_popover_preview(
 8918                    prediction,
 8919                    cursor_point,
 8920                    style,
 8921                    cx,
 8922                )?
 8923            }
 8924
 8925            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8926                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8927                    stale_completion,
 8928                    cursor_point,
 8929                    style,
 8930                    cx,
 8931                )?,
 8932
 8933                None => {
 8934                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8935                }
 8936            },
 8937
 8938            None => pending_completion_container().child(Label::new("No Prediction")),
 8939        };
 8940
 8941        let completion = if is_refreshing {
 8942            completion
 8943                .with_animation(
 8944                    "loading-completion",
 8945                    Animation::new(Duration::from_secs(2))
 8946                        .repeat()
 8947                        .with_easing(pulsating_between(0.4, 0.8)),
 8948                    |label, delta| label.opacity(delta),
 8949                )
 8950                .into_any_element()
 8951        } else {
 8952            completion.into_any_element()
 8953        };
 8954
 8955        let has_completion = self.active_inline_completion.is_some();
 8956
 8957        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8958        Some(
 8959            h_flex()
 8960                .min_w(min_width)
 8961                .max_w(max_width)
 8962                .flex_1()
 8963                .elevation_2(cx)
 8964                .border_color(cx.theme().colors().border)
 8965                .child(
 8966                    div()
 8967                        .flex_1()
 8968                        .py_1()
 8969                        .px_2()
 8970                        .overflow_hidden()
 8971                        .child(completion),
 8972                )
 8973                .when_some(accept_keystroke, |el, accept_keystroke| {
 8974                    if !accept_keystroke.modifiers.modified() {
 8975                        return el;
 8976                    }
 8977
 8978                    el.child(
 8979                        h_flex()
 8980                            .h_full()
 8981                            .border_l_1()
 8982                            .rounded_r_lg()
 8983                            .border_color(cx.theme().colors().border)
 8984                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8985                            .gap_1()
 8986                            .py_1()
 8987                            .px_2()
 8988                            .child(
 8989                                h_flex()
 8990                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8991                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8992                                    .child(h_flex().children(ui::render_modifiers(
 8993                                        &accept_keystroke.modifiers,
 8994                                        PlatformStyle::platform(),
 8995                                        Some(if !has_completion {
 8996                                            Color::Muted
 8997                                        } else {
 8998                                            Color::Default
 8999                                        }),
 9000                                        None,
 9001                                        false,
 9002                                    ))),
 9003                            )
 9004                            .child(Label::new("Preview").into_any_element())
 9005                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9006                    )
 9007                })
 9008                .into_any(),
 9009        )
 9010    }
 9011
 9012    fn render_edit_prediction_cursor_popover_preview(
 9013        &self,
 9014        completion: &InlineCompletionState,
 9015        cursor_point: Point,
 9016        style: &EditorStyle,
 9017        cx: &mut Context<Editor>,
 9018    ) -> Option<Div> {
 9019        use text::ToPoint as _;
 9020
 9021        fn render_relative_row_jump(
 9022            prefix: impl Into<String>,
 9023            current_row: u32,
 9024            target_row: u32,
 9025        ) -> Div {
 9026            let (row_diff, arrow) = if target_row < current_row {
 9027                (current_row - target_row, IconName::ArrowUp)
 9028            } else {
 9029                (target_row - current_row, IconName::ArrowDown)
 9030            };
 9031
 9032            h_flex()
 9033                .child(
 9034                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9035                        .color(Color::Muted)
 9036                        .size(LabelSize::Small),
 9037                )
 9038                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9039        }
 9040
 9041        match &completion.completion {
 9042            InlineCompletion::Move {
 9043                target, snapshot, ..
 9044            } => Some(
 9045                h_flex()
 9046                    .px_2()
 9047                    .gap_2()
 9048                    .flex_1()
 9049                    .child(
 9050                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9051                            Icon::new(IconName::ZedPredictDown)
 9052                        } else {
 9053                            Icon::new(IconName::ZedPredictUp)
 9054                        },
 9055                    )
 9056                    .child(Label::new("Jump to Edit")),
 9057            ),
 9058
 9059            InlineCompletion::Edit {
 9060                edits,
 9061                edit_preview,
 9062                snapshot,
 9063                display_mode: _,
 9064            } => {
 9065                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9066
 9067                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9068                    &snapshot,
 9069                    &edits,
 9070                    edit_preview.as_ref()?,
 9071                    true,
 9072                    cx,
 9073                )
 9074                .first_line_preview();
 9075
 9076                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9077                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9078
 9079                let preview = h_flex()
 9080                    .gap_1()
 9081                    .min_w_16()
 9082                    .child(styled_text)
 9083                    .when(has_more_lines, |parent| parent.child(""));
 9084
 9085                let left = if first_edit_row != cursor_point.row {
 9086                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9087                        .into_any_element()
 9088                } else {
 9089                    Icon::new(IconName::ZedPredict).into_any_element()
 9090                };
 9091
 9092                Some(
 9093                    h_flex()
 9094                        .h_full()
 9095                        .flex_1()
 9096                        .gap_2()
 9097                        .pr_1()
 9098                        .overflow_x_hidden()
 9099                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9100                        .child(left)
 9101                        .child(preview),
 9102                )
 9103            }
 9104        }
 9105    }
 9106
 9107    pub fn render_context_menu(
 9108        &self,
 9109        style: &EditorStyle,
 9110        max_height_in_lines: u32,
 9111        window: &mut Window,
 9112        cx: &mut Context<Editor>,
 9113    ) -> Option<AnyElement> {
 9114        let menu = self.context_menu.borrow();
 9115        let menu = menu.as_ref()?;
 9116        if !menu.visible() {
 9117            return None;
 9118        };
 9119        Some(menu.render(style, max_height_in_lines, window, cx))
 9120    }
 9121
 9122    fn render_context_menu_aside(
 9123        &mut self,
 9124        max_size: Size<Pixels>,
 9125        window: &mut Window,
 9126        cx: &mut Context<Editor>,
 9127    ) -> Option<AnyElement> {
 9128        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9129            if menu.visible() {
 9130                menu.render_aside(max_size, window, cx)
 9131            } else {
 9132                None
 9133            }
 9134        })
 9135    }
 9136
 9137    fn hide_context_menu(
 9138        &mut self,
 9139        window: &mut Window,
 9140        cx: &mut Context<Self>,
 9141    ) -> Option<CodeContextMenu> {
 9142        cx.notify();
 9143        self.completion_tasks.clear();
 9144        let context_menu = self.context_menu.borrow_mut().take();
 9145        self.stale_inline_completion_in_menu.take();
 9146        self.update_visible_inline_completion(window, cx);
 9147        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9148            if let Some(completion_provider) = &self.completion_provider {
 9149                completion_provider.selection_changed(None, window, cx);
 9150            }
 9151        }
 9152        context_menu
 9153    }
 9154
 9155    fn show_snippet_choices(
 9156        &mut self,
 9157        choices: &Vec<String>,
 9158        selection: Range<Anchor>,
 9159        cx: &mut Context<Self>,
 9160    ) {
 9161        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9162            (Some(a), Some(b)) if a == b => a,
 9163            _ => {
 9164                log::error!("expected anchor range to have matching buffer IDs");
 9165                return;
 9166            }
 9167        };
 9168        let multi_buffer = self.buffer().read(cx);
 9169        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9170            return;
 9171        };
 9172
 9173        let id = post_inc(&mut self.next_completion_id);
 9174        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9175        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9176            CompletionsMenu::new_snippet_choices(
 9177                id,
 9178                true,
 9179                choices,
 9180                selection,
 9181                buffer,
 9182                snippet_sort_order,
 9183            ),
 9184        ));
 9185    }
 9186
 9187    pub fn insert_snippet(
 9188        &mut self,
 9189        insertion_ranges: &[Range<usize>],
 9190        snippet: Snippet,
 9191        window: &mut Window,
 9192        cx: &mut Context<Self>,
 9193    ) -> Result<()> {
 9194        struct Tabstop<T> {
 9195            is_end_tabstop: bool,
 9196            ranges: Vec<Range<T>>,
 9197            choices: Option<Vec<String>>,
 9198        }
 9199
 9200        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9201            let snippet_text: Arc<str> = snippet.text.clone().into();
 9202            let edits = insertion_ranges
 9203                .iter()
 9204                .cloned()
 9205                .map(|range| (range, snippet_text.clone()));
 9206            let autoindent_mode = AutoindentMode::Block {
 9207                original_indent_columns: Vec::new(),
 9208            };
 9209            buffer.edit(edits, Some(autoindent_mode), cx);
 9210
 9211            let snapshot = &*buffer.read(cx);
 9212            let snippet = &snippet;
 9213            snippet
 9214                .tabstops
 9215                .iter()
 9216                .map(|tabstop| {
 9217                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9218                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9219                    });
 9220                    let mut tabstop_ranges = tabstop
 9221                        .ranges
 9222                        .iter()
 9223                        .flat_map(|tabstop_range| {
 9224                            let mut delta = 0_isize;
 9225                            insertion_ranges.iter().map(move |insertion_range| {
 9226                                let insertion_start = insertion_range.start as isize + delta;
 9227                                delta +=
 9228                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9229
 9230                                let start = ((insertion_start + tabstop_range.start) as usize)
 9231                                    .min(snapshot.len());
 9232                                let end = ((insertion_start + tabstop_range.end) as usize)
 9233                                    .min(snapshot.len());
 9234                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9235                            })
 9236                        })
 9237                        .collect::<Vec<_>>();
 9238                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9239
 9240                    Tabstop {
 9241                        is_end_tabstop,
 9242                        ranges: tabstop_ranges,
 9243                        choices: tabstop.choices.clone(),
 9244                    }
 9245                })
 9246                .collect::<Vec<_>>()
 9247        });
 9248        if let Some(tabstop) = tabstops.first() {
 9249            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9250                // Reverse order so that the first range is the newest created selection.
 9251                // Completions will use it and autoscroll will prioritize it.
 9252                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9253            });
 9254
 9255            if let Some(choices) = &tabstop.choices {
 9256                if let Some(selection) = tabstop.ranges.first() {
 9257                    self.show_snippet_choices(choices, selection.clone(), cx)
 9258                }
 9259            }
 9260
 9261            // If we're already at the last tabstop and it's at the end of the snippet,
 9262            // we're done, we don't need to keep the state around.
 9263            if !tabstop.is_end_tabstop {
 9264                let choices = tabstops
 9265                    .iter()
 9266                    .map(|tabstop| tabstop.choices.clone())
 9267                    .collect();
 9268
 9269                let ranges = tabstops
 9270                    .into_iter()
 9271                    .map(|tabstop| tabstop.ranges)
 9272                    .collect::<Vec<_>>();
 9273
 9274                self.snippet_stack.push(SnippetState {
 9275                    active_index: 0,
 9276                    ranges,
 9277                    choices,
 9278                });
 9279            }
 9280
 9281            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9282            if self.autoclose_regions.is_empty() {
 9283                let snapshot = self.buffer.read(cx).snapshot(cx);
 9284                for selection in &mut self.selections.all::<Point>(cx) {
 9285                    let selection_head = selection.head();
 9286                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9287                        continue;
 9288                    };
 9289
 9290                    let mut bracket_pair = None;
 9291                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9292                    let prev_chars = snapshot
 9293                        .reversed_chars_at(selection_head)
 9294                        .collect::<String>();
 9295                    for (pair, enabled) in scope.brackets() {
 9296                        if enabled
 9297                            && pair.close
 9298                            && prev_chars.starts_with(pair.start.as_str())
 9299                            && next_chars.starts_with(pair.end.as_str())
 9300                        {
 9301                            bracket_pair = Some(pair.clone());
 9302                            break;
 9303                        }
 9304                    }
 9305                    if let Some(pair) = bracket_pair {
 9306                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9307                        let autoclose_enabled =
 9308                            self.use_autoclose && snapshot_settings.use_autoclose;
 9309                        if autoclose_enabled {
 9310                            let start = snapshot.anchor_after(selection_head);
 9311                            let end = snapshot.anchor_after(selection_head);
 9312                            self.autoclose_regions.push(AutocloseRegion {
 9313                                selection_id: selection.id,
 9314                                range: start..end,
 9315                                pair,
 9316                            });
 9317                        }
 9318                    }
 9319                }
 9320            }
 9321        }
 9322        Ok(())
 9323    }
 9324
 9325    pub fn move_to_next_snippet_tabstop(
 9326        &mut self,
 9327        window: &mut Window,
 9328        cx: &mut Context<Self>,
 9329    ) -> bool {
 9330        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9331    }
 9332
 9333    pub fn move_to_prev_snippet_tabstop(
 9334        &mut self,
 9335        window: &mut Window,
 9336        cx: &mut Context<Self>,
 9337    ) -> bool {
 9338        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9339    }
 9340
 9341    pub fn move_to_snippet_tabstop(
 9342        &mut self,
 9343        bias: Bias,
 9344        window: &mut Window,
 9345        cx: &mut Context<Self>,
 9346    ) -> bool {
 9347        if let Some(mut snippet) = self.snippet_stack.pop() {
 9348            match bias {
 9349                Bias::Left => {
 9350                    if snippet.active_index > 0 {
 9351                        snippet.active_index -= 1;
 9352                    } else {
 9353                        self.snippet_stack.push(snippet);
 9354                        return false;
 9355                    }
 9356                }
 9357                Bias::Right => {
 9358                    if snippet.active_index + 1 < snippet.ranges.len() {
 9359                        snippet.active_index += 1;
 9360                    } else {
 9361                        self.snippet_stack.push(snippet);
 9362                        return false;
 9363                    }
 9364                }
 9365            }
 9366            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9367                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9368                    // Reverse order so that the first range is the newest created selection.
 9369                    // Completions will use it and autoscroll will prioritize it.
 9370                    s.select_ranges(current_ranges.iter().rev().cloned())
 9371                });
 9372
 9373                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9374                    if let Some(selection) = current_ranges.first() {
 9375                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9376                    }
 9377                }
 9378
 9379                // If snippet state is not at the last tabstop, push it back on the stack
 9380                if snippet.active_index + 1 < snippet.ranges.len() {
 9381                    self.snippet_stack.push(snippet);
 9382                }
 9383                return true;
 9384            }
 9385        }
 9386
 9387        false
 9388    }
 9389
 9390    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9391        self.transact(window, cx, |this, window, cx| {
 9392            this.select_all(&SelectAll, window, cx);
 9393            this.insert("", window, cx);
 9394        });
 9395    }
 9396
 9397    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9399        self.transact(window, cx, |this, window, cx| {
 9400            this.select_autoclose_pair(window, cx);
 9401            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9402            if !this.linked_edit_ranges.is_empty() {
 9403                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9404                let snapshot = this.buffer.read(cx).snapshot(cx);
 9405
 9406                for selection in selections.iter() {
 9407                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9408                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9409                    if selection_start.buffer_id != selection_end.buffer_id {
 9410                        continue;
 9411                    }
 9412                    if let Some(ranges) =
 9413                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9414                    {
 9415                        for (buffer, entries) in ranges {
 9416                            linked_ranges.entry(buffer).or_default().extend(entries);
 9417                        }
 9418                    }
 9419                }
 9420            }
 9421
 9422            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9423            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9424            for selection in &mut selections {
 9425                if selection.is_empty() {
 9426                    let old_head = selection.head();
 9427                    let mut new_head =
 9428                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9429                            .to_point(&display_map);
 9430                    if let Some((buffer, line_buffer_range)) = display_map
 9431                        .buffer_snapshot
 9432                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9433                    {
 9434                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9435                        let indent_len = match indent_size.kind {
 9436                            IndentKind::Space => {
 9437                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9438                            }
 9439                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9440                        };
 9441                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9442                            let indent_len = indent_len.get();
 9443                            new_head = cmp::min(
 9444                                new_head,
 9445                                MultiBufferPoint::new(
 9446                                    old_head.row,
 9447                                    ((old_head.column - 1) / indent_len) * indent_len,
 9448                                ),
 9449                            );
 9450                        }
 9451                    }
 9452
 9453                    selection.set_head(new_head, SelectionGoal::None);
 9454                }
 9455            }
 9456
 9457            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9458                s.select(selections)
 9459            });
 9460            this.insert("", window, cx);
 9461            let empty_str: Arc<str> = Arc::from("");
 9462            for (buffer, edits) in linked_ranges {
 9463                let snapshot = buffer.read(cx).snapshot();
 9464                use text::ToPoint as TP;
 9465
 9466                let edits = edits
 9467                    .into_iter()
 9468                    .map(|range| {
 9469                        let end_point = TP::to_point(&range.end, &snapshot);
 9470                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9471
 9472                        if end_point == start_point {
 9473                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9474                                .saturating_sub(1);
 9475                            start_point =
 9476                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9477                        };
 9478
 9479                        (start_point..end_point, empty_str.clone())
 9480                    })
 9481                    .sorted_by_key(|(range, _)| range.start)
 9482                    .collect::<Vec<_>>();
 9483                buffer.update(cx, |this, cx| {
 9484                    this.edit(edits, None, cx);
 9485                })
 9486            }
 9487            this.refresh_inline_completion(true, false, window, cx);
 9488            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9489        });
 9490    }
 9491
 9492    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9493        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9494        self.transact(window, cx, |this, window, cx| {
 9495            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9496                s.move_with(|map, selection| {
 9497                    if selection.is_empty() {
 9498                        let cursor = movement::right(map, selection.head());
 9499                        selection.end = cursor;
 9500                        selection.reversed = true;
 9501                        selection.goal = SelectionGoal::None;
 9502                    }
 9503                })
 9504            });
 9505            this.insert("", window, cx);
 9506            this.refresh_inline_completion(true, false, window, cx);
 9507        });
 9508    }
 9509
 9510    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9511        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9512        if self.move_to_prev_snippet_tabstop(window, cx) {
 9513            return;
 9514        }
 9515        self.outdent(&Outdent, window, cx);
 9516    }
 9517
 9518    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9519        if self.move_to_next_snippet_tabstop(window, cx) {
 9520            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9521            return;
 9522        }
 9523        if self.read_only(cx) {
 9524            return;
 9525        }
 9526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9527        let mut selections = self.selections.all_adjusted(cx);
 9528        let buffer = self.buffer.read(cx);
 9529        let snapshot = buffer.snapshot(cx);
 9530        let rows_iter = selections.iter().map(|s| s.head().row);
 9531        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9532
 9533        let has_some_cursor_in_whitespace = selections
 9534            .iter()
 9535            .filter(|selection| selection.is_empty())
 9536            .any(|selection| {
 9537                let cursor = selection.head();
 9538                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9539                cursor.column < current_indent.len
 9540            });
 9541
 9542        let mut edits = Vec::new();
 9543        let mut prev_edited_row = 0;
 9544        let mut row_delta = 0;
 9545        for selection in &mut selections {
 9546            if selection.start.row != prev_edited_row {
 9547                row_delta = 0;
 9548            }
 9549            prev_edited_row = selection.end.row;
 9550
 9551            // If the selection is non-empty, then increase the indentation of the selected lines.
 9552            if !selection.is_empty() {
 9553                row_delta =
 9554                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9555                continue;
 9556            }
 9557
 9558            let cursor = selection.head();
 9559            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9560            if let Some(suggested_indent) =
 9561                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9562            {
 9563                // Don't do anything if already at suggested indent
 9564                // and there is any other cursor which is not
 9565                if has_some_cursor_in_whitespace
 9566                    && cursor.column == current_indent.len
 9567                    && current_indent.len == suggested_indent.len
 9568                {
 9569                    continue;
 9570                }
 9571
 9572                // Adjust line and move cursor to suggested indent
 9573                // if cursor is not at suggested indent
 9574                if cursor.column < suggested_indent.len
 9575                    && cursor.column <= current_indent.len
 9576                    && current_indent.len <= suggested_indent.len
 9577                {
 9578                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9579                    selection.end = selection.start;
 9580                    if row_delta == 0 {
 9581                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9582                            cursor.row,
 9583                            current_indent,
 9584                            suggested_indent,
 9585                        ));
 9586                        row_delta = suggested_indent.len - current_indent.len;
 9587                    }
 9588                    continue;
 9589                }
 9590
 9591                // If current indent is more than suggested indent
 9592                // only move cursor to current indent and skip indent
 9593                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9594                    selection.start = Point::new(cursor.row, current_indent.len);
 9595                    selection.end = selection.start;
 9596                    continue;
 9597                }
 9598            }
 9599
 9600            // Otherwise, insert a hard or soft tab.
 9601            let settings = buffer.language_settings_at(cursor, cx);
 9602            let tab_size = if settings.hard_tabs {
 9603                IndentSize::tab()
 9604            } else {
 9605                let tab_size = settings.tab_size.get();
 9606                let indent_remainder = snapshot
 9607                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9608                    .flat_map(str::chars)
 9609                    .fold(row_delta % tab_size, |counter: u32, c| {
 9610                        if c == '\t' {
 9611                            0
 9612                        } else {
 9613                            (counter + 1) % tab_size
 9614                        }
 9615                    });
 9616
 9617                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9618                IndentSize::spaces(chars_to_next_tab_stop)
 9619            };
 9620            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9621            selection.end = selection.start;
 9622            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9623            row_delta += tab_size.len;
 9624        }
 9625
 9626        self.transact(window, cx, |this, window, cx| {
 9627            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9628            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9629                s.select(selections)
 9630            });
 9631            this.refresh_inline_completion(true, false, window, cx);
 9632        });
 9633    }
 9634
 9635    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9636        if self.read_only(cx) {
 9637            return;
 9638        }
 9639        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9640        let mut selections = self.selections.all::<Point>(cx);
 9641        let mut prev_edited_row = 0;
 9642        let mut row_delta = 0;
 9643        let mut edits = Vec::new();
 9644        let buffer = self.buffer.read(cx);
 9645        let snapshot = buffer.snapshot(cx);
 9646        for selection in &mut selections {
 9647            if selection.start.row != prev_edited_row {
 9648                row_delta = 0;
 9649            }
 9650            prev_edited_row = selection.end.row;
 9651
 9652            row_delta =
 9653                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9654        }
 9655
 9656        self.transact(window, cx, |this, window, cx| {
 9657            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9658            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9659                s.select(selections)
 9660            });
 9661        });
 9662    }
 9663
 9664    fn indent_selection(
 9665        buffer: &MultiBuffer,
 9666        snapshot: &MultiBufferSnapshot,
 9667        selection: &mut Selection<Point>,
 9668        edits: &mut Vec<(Range<Point>, String)>,
 9669        delta_for_start_row: u32,
 9670        cx: &App,
 9671    ) -> u32 {
 9672        let settings = buffer.language_settings_at(selection.start, cx);
 9673        let tab_size = settings.tab_size.get();
 9674        let indent_kind = if settings.hard_tabs {
 9675            IndentKind::Tab
 9676        } else {
 9677            IndentKind::Space
 9678        };
 9679        let mut start_row = selection.start.row;
 9680        let mut end_row = selection.end.row + 1;
 9681
 9682        // If a selection ends at the beginning of a line, don't indent
 9683        // that last line.
 9684        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9685            end_row -= 1;
 9686        }
 9687
 9688        // Avoid re-indenting a row that has already been indented by a
 9689        // previous selection, but still update this selection's column
 9690        // to reflect that indentation.
 9691        if delta_for_start_row > 0 {
 9692            start_row += 1;
 9693            selection.start.column += delta_for_start_row;
 9694            if selection.end.row == selection.start.row {
 9695                selection.end.column += delta_for_start_row;
 9696            }
 9697        }
 9698
 9699        let mut delta_for_end_row = 0;
 9700        let has_multiple_rows = start_row + 1 != end_row;
 9701        for row in start_row..end_row {
 9702            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9703            let indent_delta = match (current_indent.kind, indent_kind) {
 9704                (IndentKind::Space, IndentKind::Space) => {
 9705                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9706                    IndentSize::spaces(columns_to_next_tab_stop)
 9707                }
 9708                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9709                (_, IndentKind::Tab) => IndentSize::tab(),
 9710            };
 9711
 9712            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9713                0
 9714            } else {
 9715                selection.start.column
 9716            };
 9717            let row_start = Point::new(row, start);
 9718            edits.push((
 9719                row_start..row_start,
 9720                indent_delta.chars().collect::<String>(),
 9721            ));
 9722
 9723            // Update this selection's endpoints to reflect the indentation.
 9724            if row == selection.start.row {
 9725                selection.start.column += indent_delta.len;
 9726            }
 9727            if row == selection.end.row {
 9728                selection.end.column += indent_delta.len;
 9729                delta_for_end_row = indent_delta.len;
 9730            }
 9731        }
 9732
 9733        if selection.start.row == selection.end.row {
 9734            delta_for_start_row + delta_for_end_row
 9735        } else {
 9736            delta_for_end_row
 9737        }
 9738    }
 9739
 9740    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9741        if self.read_only(cx) {
 9742            return;
 9743        }
 9744        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9745        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9746        let selections = self.selections.all::<Point>(cx);
 9747        let mut deletion_ranges = Vec::new();
 9748        let mut last_outdent = None;
 9749        {
 9750            let buffer = self.buffer.read(cx);
 9751            let snapshot = buffer.snapshot(cx);
 9752            for selection in &selections {
 9753                let settings = buffer.language_settings_at(selection.start, cx);
 9754                let tab_size = settings.tab_size.get();
 9755                let mut rows = selection.spanned_rows(false, &display_map);
 9756
 9757                // Avoid re-outdenting a row that has already been outdented by a
 9758                // previous selection.
 9759                if let Some(last_row) = last_outdent {
 9760                    if last_row == rows.start {
 9761                        rows.start = rows.start.next_row();
 9762                    }
 9763                }
 9764                let has_multiple_rows = rows.len() > 1;
 9765                for row in rows.iter_rows() {
 9766                    let indent_size = snapshot.indent_size_for_line(row);
 9767                    if indent_size.len > 0 {
 9768                        let deletion_len = match indent_size.kind {
 9769                            IndentKind::Space => {
 9770                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9771                                if columns_to_prev_tab_stop == 0 {
 9772                                    tab_size
 9773                                } else {
 9774                                    columns_to_prev_tab_stop
 9775                                }
 9776                            }
 9777                            IndentKind::Tab => 1,
 9778                        };
 9779                        let start = if has_multiple_rows
 9780                            || deletion_len > selection.start.column
 9781                            || indent_size.len < selection.start.column
 9782                        {
 9783                            0
 9784                        } else {
 9785                            selection.start.column - deletion_len
 9786                        };
 9787                        deletion_ranges.push(
 9788                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9789                        );
 9790                        last_outdent = Some(row);
 9791                    }
 9792                }
 9793            }
 9794        }
 9795
 9796        self.transact(window, cx, |this, window, cx| {
 9797            this.buffer.update(cx, |buffer, cx| {
 9798                let empty_str: Arc<str> = Arc::default();
 9799                buffer.edit(
 9800                    deletion_ranges
 9801                        .into_iter()
 9802                        .map(|range| (range, empty_str.clone())),
 9803                    None,
 9804                    cx,
 9805                );
 9806            });
 9807            let selections = this.selections.all::<usize>(cx);
 9808            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9809                s.select(selections)
 9810            });
 9811        });
 9812    }
 9813
 9814    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9815        if self.read_only(cx) {
 9816            return;
 9817        }
 9818        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9819        let selections = self
 9820            .selections
 9821            .all::<usize>(cx)
 9822            .into_iter()
 9823            .map(|s| s.range());
 9824
 9825        self.transact(window, cx, |this, window, cx| {
 9826            this.buffer.update(cx, |buffer, cx| {
 9827                buffer.autoindent_ranges(selections, cx);
 9828            });
 9829            let selections = this.selections.all::<usize>(cx);
 9830            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9831                s.select(selections)
 9832            });
 9833        });
 9834    }
 9835
 9836    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9837        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9838        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9839        let selections = self.selections.all::<Point>(cx);
 9840
 9841        let mut new_cursors = Vec::new();
 9842        let mut edit_ranges = Vec::new();
 9843        let mut selections = selections.iter().peekable();
 9844        while let Some(selection) = selections.next() {
 9845            let mut rows = selection.spanned_rows(false, &display_map);
 9846            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9847
 9848            // Accumulate contiguous regions of rows that we want to delete.
 9849            while let Some(next_selection) = selections.peek() {
 9850                let next_rows = next_selection.spanned_rows(false, &display_map);
 9851                if next_rows.start <= rows.end {
 9852                    rows.end = next_rows.end;
 9853                    selections.next().unwrap();
 9854                } else {
 9855                    break;
 9856                }
 9857            }
 9858
 9859            let buffer = &display_map.buffer_snapshot;
 9860            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9861            let edit_end;
 9862            let cursor_buffer_row;
 9863            if buffer.max_point().row >= rows.end.0 {
 9864                // If there's a line after the range, delete the \n from the end of the row range
 9865                // and position the cursor on the next line.
 9866                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9867                cursor_buffer_row = rows.end;
 9868            } else {
 9869                // If there isn't a line after the range, delete the \n from the line before the
 9870                // start of the row range and position the cursor there.
 9871                edit_start = edit_start.saturating_sub(1);
 9872                edit_end = buffer.len();
 9873                cursor_buffer_row = rows.start.previous_row();
 9874            }
 9875
 9876            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9877            *cursor.column_mut() =
 9878                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9879
 9880            new_cursors.push((
 9881                selection.id,
 9882                buffer.anchor_after(cursor.to_point(&display_map)),
 9883            ));
 9884            edit_ranges.push(edit_start..edit_end);
 9885        }
 9886
 9887        self.transact(window, cx, |this, window, cx| {
 9888            let buffer = this.buffer.update(cx, |buffer, cx| {
 9889                let empty_str: Arc<str> = Arc::default();
 9890                buffer.edit(
 9891                    edit_ranges
 9892                        .into_iter()
 9893                        .map(|range| (range, empty_str.clone())),
 9894                    None,
 9895                    cx,
 9896                );
 9897                buffer.snapshot(cx)
 9898            });
 9899            let new_selections = new_cursors
 9900                .into_iter()
 9901                .map(|(id, cursor)| {
 9902                    let cursor = cursor.to_point(&buffer);
 9903                    Selection {
 9904                        id,
 9905                        start: cursor,
 9906                        end: cursor,
 9907                        reversed: false,
 9908                        goal: SelectionGoal::None,
 9909                    }
 9910                })
 9911                .collect();
 9912
 9913            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9914                s.select(new_selections);
 9915            });
 9916        });
 9917    }
 9918
 9919    pub fn join_lines_impl(
 9920        &mut self,
 9921        insert_whitespace: bool,
 9922        window: &mut Window,
 9923        cx: &mut Context<Self>,
 9924    ) {
 9925        if self.read_only(cx) {
 9926            return;
 9927        }
 9928        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9929        for selection in self.selections.all::<Point>(cx) {
 9930            let start = MultiBufferRow(selection.start.row);
 9931            // Treat single line selections as if they include the next line. Otherwise this action
 9932            // would do nothing for single line selections individual cursors.
 9933            let end = if selection.start.row == selection.end.row {
 9934                MultiBufferRow(selection.start.row + 1)
 9935            } else {
 9936                MultiBufferRow(selection.end.row)
 9937            };
 9938
 9939            if let Some(last_row_range) = row_ranges.last_mut() {
 9940                if start <= last_row_range.end {
 9941                    last_row_range.end = end;
 9942                    continue;
 9943                }
 9944            }
 9945            row_ranges.push(start..end);
 9946        }
 9947
 9948        let snapshot = self.buffer.read(cx).snapshot(cx);
 9949        let mut cursor_positions = Vec::new();
 9950        for row_range in &row_ranges {
 9951            let anchor = snapshot.anchor_before(Point::new(
 9952                row_range.end.previous_row().0,
 9953                snapshot.line_len(row_range.end.previous_row()),
 9954            ));
 9955            cursor_positions.push(anchor..anchor);
 9956        }
 9957
 9958        self.transact(window, cx, |this, window, cx| {
 9959            for row_range in row_ranges.into_iter().rev() {
 9960                for row in row_range.iter_rows().rev() {
 9961                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9962                    let next_line_row = row.next_row();
 9963                    let indent = snapshot.indent_size_for_line(next_line_row);
 9964                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9965
 9966                    let replace =
 9967                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9968                            " "
 9969                        } else {
 9970                            ""
 9971                        };
 9972
 9973                    this.buffer.update(cx, |buffer, cx| {
 9974                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9975                    });
 9976                }
 9977            }
 9978
 9979            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9980                s.select_anchor_ranges(cursor_positions)
 9981            });
 9982        });
 9983    }
 9984
 9985    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9986        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9987        self.join_lines_impl(true, window, cx);
 9988    }
 9989
 9990    pub fn sort_lines_case_sensitive(
 9991        &mut self,
 9992        _: &SortLinesCaseSensitive,
 9993        window: &mut Window,
 9994        cx: &mut Context<Self>,
 9995    ) {
 9996        self.manipulate_lines(window, cx, |lines| lines.sort())
 9997    }
 9998
 9999    pub fn sort_lines_case_insensitive(
10000        &mut self,
10001        _: &SortLinesCaseInsensitive,
10002        window: &mut Window,
10003        cx: &mut Context<Self>,
10004    ) {
10005        self.manipulate_lines(window, cx, |lines| {
10006            lines.sort_by_key(|line| line.to_lowercase())
10007        })
10008    }
10009
10010    pub fn unique_lines_case_insensitive(
10011        &mut self,
10012        _: &UniqueLinesCaseInsensitive,
10013        window: &mut Window,
10014        cx: &mut Context<Self>,
10015    ) {
10016        self.manipulate_lines(window, cx, |lines| {
10017            let mut seen = HashSet::default();
10018            lines.retain(|line| seen.insert(line.to_lowercase()));
10019        })
10020    }
10021
10022    pub fn unique_lines_case_sensitive(
10023        &mut self,
10024        _: &UniqueLinesCaseSensitive,
10025        window: &mut Window,
10026        cx: &mut Context<Self>,
10027    ) {
10028        self.manipulate_lines(window, cx, |lines| {
10029            let mut seen = HashSet::default();
10030            lines.retain(|line| seen.insert(*line));
10031        })
10032    }
10033
10034    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10035        let Some(project) = self.project.clone() else {
10036            return;
10037        };
10038        self.reload(project, window, cx)
10039            .detach_and_notify_err(window, cx);
10040    }
10041
10042    pub fn restore_file(
10043        &mut self,
10044        _: &::git::RestoreFile,
10045        window: &mut Window,
10046        cx: &mut Context<Self>,
10047    ) {
10048        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10049        let mut buffer_ids = HashSet::default();
10050        let snapshot = self.buffer().read(cx).snapshot(cx);
10051        for selection in self.selections.all::<usize>(cx) {
10052            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10053        }
10054
10055        let buffer = self.buffer().read(cx);
10056        let ranges = buffer_ids
10057            .into_iter()
10058            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10059            .collect::<Vec<_>>();
10060
10061        self.restore_hunks_in_ranges(ranges, window, cx);
10062    }
10063
10064    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10065        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10066        let selections = self
10067            .selections
10068            .all(cx)
10069            .into_iter()
10070            .map(|s| s.range())
10071            .collect();
10072        self.restore_hunks_in_ranges(selections, window, cx);
10073    }
10074
10075    pub fn restore_hunks_in_ranges(
10076        &mut self,
10077        ranges: Vec<Range<Point>>,
10078        window: &mut Window,
10079        cx: &mut Context<Editor>,
10080    ) {
10081        let mut revert_changes = HashMap::default();
10082        let chunk_by = self
10083            .snapshot(window, cx)
10084            .hunks_for_ranges(ranges)
10085            .into_iter()
10086            .chunk_by(|hunk| hunk.buffer_id);
10087        for (buffer_id, hunks) in &chunk_by {
10088            let hunks = hunks.collect::<Vec<_>>();
10089            for hunk in &hunks {
10090                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10091            }
10092            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10093        }
10094        drop(chunk_by);
10095        if !revert_changes.is_empty() {
10096            self.transact(window, cx, |editor, window, cx| {
10097                editor.restore(revert_changes, window, cx);
10098            });
10099        }
10100    }
10101
10102    pub fn open_active_item_in_terminal(
10103        &mut self,
10104        _: &OpenInTerminal,
10105        window: &mut Window,
10106        cx: &mut Context<Self>,
10107    ) {
10108        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10109            let project_path = buffer.read(cx).project_path(cx)?;
10110            let project = self.project.as_ref()?.read(cx);
10111            let entry = project.entry_for_path(&project_path, cx)?;
10112            let parent = match &entry.canonical_path {
10113                Some(canonical_path) => canonical_path.to_path_buf(),
10114                None => project.absolute_path(&project_path, cx)?,
10115            }
10116            .parent()?
10117            .to_path_buf();
10118            Some(parent)
10119        }) {
10120            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10121        }
10122    }
10123
10124    fn set_breakpoint_context_menu(
10125        &mut self,
10126        display_row: DisplayRow,
10127        position: Option<Anchor>,
10128        clicked_point: gpui::Point<Pixels>,
10129        window: &mut Window,
10130        cx: &mut Context<Self>,
10131    ) {
10132        if !cx.has_flag::<DebuggerFeatureFlag>() {
10133            return;
10134        }
10135        let source = self
10136            .buffer
10137            .read(cx)
10138            .snapshot(cx)
10139            .anchor_before(Point::new(display_row.0, 0u32));
10140
10141        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10142
10143        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10144            self,
10145            source,
10146            clicked_point,
10147            context_menu,
10148            window,
10149            cx,
10150        );
10151    }
10152
10153    fn add_edit_breakpoint_block(
10154        &mut self,
10155        anchor: Anchor,
10156        breakpoint: &Breakpoint,
10157        edit_action: BreakpointPromptEditAction,
10158        window: &mut Window,
10159        cx: &mut Context<Self>,
10160    ) {
10161        let weak_editor = cx.weak_entity();
10162        let bp_prompt = cx.new(|cx| {
10163            BreakpointPromptEditor::new(
10164                weak_editor,
10165                anchor,
10166                breakpoint.clone(),
10167                edit_action,
10168                window,
10169                cx,
10170            )
10171        });
10172
10173        let height = bp_prompt.update(cx, |this, cx| {
10174            this.prompt
10175                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10176        });
10177        let cloned_prompt = bp_prompt.clone();
10178        let blocks = vec![BlockProperties {
10179            style: BlockStyle::Sticky,
10180            placement: BlockPlacement::Above(anchor),
10181            height: Some(height),
10182            render: Arc::new(move |cx| {
10183                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10184                cloned_prompt.clone().into_any_element()
10185            }),
10186            priority: 0,
10187            render_in_minimap: true,
10188        }];
10189
10190        let focus_handle = bp_prompt.focus_handle(cx);
10191        window.focus(&focus_handle);
10192
10193        let block_ids = self.insert_blocks(blocks, None, cx);
10194        bp_prompt.update(cx, |prompt, _| {
10195            prompt.add_block_ids(block_ids);
10196        });
10197    }
10198
10199    pub(crate) fn breakpoint_at_row(
10200        &self,
10201        row: u32,
10202        window: &mut Window,
10203        cx: &mut Context<Self>,
10204    ) -> Option<(Anchor, Breakpoint)> {
10205        let snapshot = self.snapshot(window, cx);
10206        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10207
10208        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10209    }
10210
10211    pub(crate) fn breakpoint_at_anchor(
10212        &self,
10213        breakpoint_position: Anchor,
10214        snapshot: &EditorSnapshot,
10215        cx: &mut Context<Self>,
10216    ) -> Option<(Anchor, Breakpoint)> {
10217        let project = self.project.clone()?;
10218
10219        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10220            snapshot
10221                .buffer_snapshot
10222                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10223        })?;
10224
10225        let enclosing_excerpt = breakpoint_position.excerpt_id;
10226        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10227        let buffer_snapshot = buffer.read(cx).snapshot();
10228
10229        let row = buffer_snapshot
10230            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10231            .row;
10232
10233        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10234        let anchor_end = snapshot
10235            .buffer_snapshot
10236            .anchor_after(Point::new(row, line_len));
10237
10238        let bp = self
10239            .breakpoint_store
10240            .as_ref()?
10241            .read_with(cx, |breakpoint_store, cx| {
10242                breakpoint_store
10243                    .breakpoints(
10244                        &buffer,
10245                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10246                        &buffer_snapshot,
10247                        cx,
10248                    )
10249                    .next()
10250                    .and_then(|(bp, _)| {
10251                        let breakpoint_row = buffer_snapshot
10252                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10253                            .row;
10254
10255                        if breakpoint_row == row {
10256                            snapshot
10257                                .buffer_snapshot
10258                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10259                                .map(|position| (position, bp.bp.clone()))
10260                        } else {
10261                            None
10262                        }
10263                    })
10264            });
10265        bp
10266    }
10267
10268    pub fn edit_log_breakpoint(
10269        &mut self,
10270        _: &EditLogBreakpoint,
10271        window: &mut Window,
10272        cx: &mut Context<Self>,
10273    ) {
10274        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10275            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10276                message: None,
10277                state: BreakpointState::Enabled,
10278                condition: None,
10279                hit_condition: None,
10280            });
10281
10282            self.add_edit_breakpoint_block(
10283                anchor,
10284                &breakpoint,
10285                BreakpointPromptEditAction::Log,
10286                window,
10287                cx,
10288            );
10289        }
10290    }
10291
10292    fn breakpoints_at_cursors(
10293        &self,
10294        window: &mut Window,
10295        cx: &mut Context<Self>,
10296    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10297        let snapshot = self.snapshot(window, cx);
10298        let cursors = self
10299            .selections
10300            .disjoint_anchors()
10301            .into_iter()
10302            .map(|selection| {
10303                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10304
10305                let breakpoint_position = self
10306                    .breakpoint_at_row(cursor_position.row, window, cx)
10307                    .map(|bp| bp.0)
10308                    .unwrap_or_else(|| {
10309                        snapshot
10310                            .display_snapshot
10311                            .buffer_snapshot
10312                            .anchor_after(Point::new(cursor_position.row, 0))
10313                    });
10314
10315                let breakpoint = self
10316                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10317                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10318
10319                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10320            })
10321            // 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.
10322            .collect::<HashMap<Anchor, _>>();
10323
10324        cursors.into_iter().collect()
10325    }
10326
10327    pub fn enable_breakpoint(
10328        &mut self,
10329        _: &crate::actions::EnableBreakpoint,
10330        window: &mut Window,
10331        cx: &mut Context<Self>,
10332    ) {
10333        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10334            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10335                continue;
10336            };
10337            self.edit_breakpoint_at_anchor(
10338                anchor,
10339                breakpoint,
10340                BreakpointEditAction::InvertState,
10341                cx,
10342            );
10343        }
10344    }
10345
10346    pub fn disable_breakpoint(
10347        &mut self,
10348        _: &crate::actions::DisableBreakpoint,
10349        window: &mut Window,
10350        cx: &mut Context<Self>,
10351    ) {
10352        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10353            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10354                continue;
10355            };
10356            self.edit_breakpoint_at_anchor(
10357                anchor,
10358                breakpoint,
10359                BreakpointEditAction::InvertState,
10360                cx,
10361            );
10362        }
10363    }
10364
10365    pub fn toggle_breakpoint(
10366        &mut self,
10367        _: &crate::actions::ToggleBreakpoint,
10368        window: &mut Window,
10369        cx: &mut Context<Self>,
10370    ) {
10371        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10372            if let Some(breakpoint) = breakpoint {
10373                self.edit_breakpoint_at_anchor(
10374                    anchor,
10375                    breakpoint,
10376                    BreakpointEditAction::Toggle,
10377                    cx,
10378                );
10379            } else {
10380                self.edit_breakpoint_at_anchor(
10381                    anchor,
10382                    Breakpoint::new_standard(),
10383                    BreakpointEditAction::Toggle,
10384                    cx,
10385                );
10386            }
10387        }
10388    }
10389
10390    pub fn edit_breakpoint_at_anchor(
10391        &mut self,
10392        breakpoint_position: Anchor,
10393        breakpoint: Breakpoint,
10394        edit_action: BreakpointEditAction,
10395        cx: &mut Context<Self>,
10396    ) {
10397        let Some(breakpoint_store) = &self.breakpoint_store else {
10398            return;
10399        };
10400
10401        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10402            if breakpoint_position == Anchor::min() {
10403                self.buffer()
10404                    .read(cx)
10405                    .excerpt_buffer_ids()
10406                    .into_iter()
10407                    .next()
10408            } else {
10409                None
10410            }
10411        }) else {
10412            return;
10413        };
10414
10415        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10416            return;
10417        };
10418
10419        breakpoint_store.update(cx, |breakpoint_store, cx| {
10420            breakpoint_store.toggle_breakpoint(
10421                buffer,
10422                BreakpointWithPosition {
10423                    position: breakpoint_position.text_anchor,
10424                    bp: breakpoint,
10425                },
10426                edit_action,
10427                cx,
10428            );
10429        });
10430
10431        cx.notify();
10432    }
10433
10434    #[cfg(any(test, feature = "test-support"))]
10435    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10436        self.breakpoint_store.clone()
10437    }
10438
10439    pub fn prepare_restore_change(
10440        &self,
10441        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10442        hunk: &MultiBufferDiffHunk,
10443        cx: &mut App,
10444    ) -> Option<()> {
10445        if hunk.is_created_file() {
10446            return None;
10447        }
10448        let buffer = self.buffer.read(cx);
10449        let diff = buffer.diff_for(hunk.buffer_id)?;
10450        let buffer = buffer.buffer(hunk.buffer_id)?;
10451        let buffer = buffer.read(cx);
10452        let original_text = diff
10453            .read(cx)
10454            .base_text()
10455            .as_rope()
10456            .slice(hunk.diff_base_byte_range.clone());
10457        let buffer_snapshot = buffer.snapshot();
10458        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10459        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10460            probe
10461                .0
10462                .start
10463                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10464                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10465        }) {
10466            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10467            Some(())
10468        } else {
10469            None
10470        }
10471    }
10472
10473    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10474        self.manipulate_lines(window, cx, |lines| lines.reverse())
10475    }
10476
10477    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10478        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10479    }
10480
10481    fn manipulate_lines<Fn>(
10482        &mut self,
10483        window: &mut Window,
10484        cx: &mut Context<Self>,
10485        mut callback: Fn,
10486    ) where
10487        Fn: FnMut(&mut Vec<&str>),
10488    {
10489        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10490
10491        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10492        let buffer = self.buffer.read(cx).snapshot(cx);
10493
10494        let mut edits = Vec::new();
10495
10496        let selections = self.selections.all::<Point>(cx);
10497        let mut selections = selections.iter().peekable();
10498        let mut contiguous_row_selections = Vec::new();
10499        let mut new_selections = Vec::new();
10500        let mut added_lines = 0;
10501        let mut removed_lines = 0;
10502
10503        while let Some(selection) = selections.next() {
10504            let (start_row, end_row) = consume_contiguous_rows(
10505                &mut contiguous_row_selections,
10506                selection,
10507                &display_map,
10508                &mut selections,
10509            );
10510
10511            let start_point = Point::new(start_row.0, 0);
10512            let end_point = Point::new(
10513                end_row.previous_row().0,
10514                buffer.line_len(end_row.previous_row()),
10515            );
10516            let text = buffer
10517                .text_for_range(start_point..end_point)
10518                .collect::<String>();
10519
10520            let mut lines = text.split('\n').collect_vec();
10521
10522            let lines_before = lines.len();
10523            callback(&mut lines);
10524            let lines_after = lines.len();
10525
10526            edits.push((start_point..end_point, lines.join("\n")));
10527
10528            // Selections must change based on added and removed line count
10529            let start_row =
10530                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10531            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10532            new_selections.push(Selection {
10533                id: selection.id,
10534                start: start_row,
10535                end: end_row,
10536                goal: SelectionGoal::None,
10537                reversed: selection.reversed,
10538            });
10539
10540            if lines_after > lines_before {
10541                added_lines += lines_after - lines_before;
10542            } else if lines_before > lines_after {
10543                removed_lines += lines_before - lines_after;
10544            }
10545        }
10546
10547        self.transact(window, cx, |this, window, cx| {
10548            let buffer = this.buffer.update(cx, |buffer, cx| {
10549                buffer.edit(edits, None, cx);
10550                buffer.snapshot(cx)
10551            });
10552
10553            // Recalculate offsets on newly edited buffer
10554            let new_selections = new_selections
10555                .iter()
10556                .map(|s| {
10557                    let start_point = Point::new(s.start.0, 0);
10558                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10559                    Selection {
10560                        id: s.id,
10561                        start: buffer.point_to_offset(start_point),
10562                        end: buffer.point_to_offset(end_point),
10563                        goal: s.goal,
10564                        reversed: s.reversed,
10565                    }
10566                })
10567                .collect();
10568
10569            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10570                s.select(new_selections);
10571            });
10572
10573            this.request_autoscroll(Autoscroll::fit(), cx);
10574        });
10575    }
10576
10577    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10578        self.manipulate_text(window, cx, |text| {
10579            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10580            if has_upper_case_characters {
10581                text.to_lowercase()
10582            } else {
10583                text.to_uppercase()
10584            }
10585        })
10586    }
10587
10588    pub fn convert_to_upper_case(
10589        &mut self,
10590        _: &ConvertToUpperCase,
10591        window: &mut Window,
10592        cx: &mut Context<Self>,
10593    ) {
10594        self.manipulate_text(window, cx, |text| text.to_uppercase())
10595    }
10596
10597    pub fn convert_to_lower_case(
10598        &mut self,
10599        _: &ConvertToLowerCase,
10600        window: &mut Window,
10601        cx: &mut Context<Self>,
10602    ) {
10603        self.manipulate_text(window, cx, |text| text.to_lowercase())
10604    }
10605
10606    pub fn convert_to_title_case(
10607        &mut self,
10608        _: &ConvertToTitleCase,
10609        window: &mut Window,
10610        cx: &mut Context<Self>,
10611    ) {
10612        self.manipulate_text(window, cx, |text| {
10613            text.split('\n')
10614                .map(|line| line.to_case(Case::Title))
10615                .join("\n")
10616        })
10617    }
10618
10619    pub fn convert_to_snake_case(
10620        &mut self,
10621        _: &ConvertToSnakeCase,
10622        window: &mut Window,
10623        cx: &mut Context<Self>,
10624    ) {
10625        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10626    }
10627
10628    pub fn convert_to_kebab_case(
10629        &mut self,
10630        _: &ConvertToKebabCase,
10631        window: &mut Window,
10632        cx: &mut Context<Self>,
10633    ) {
10634        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10635    }
10636
10637    pub fn convert_to_upper_camel_case(
10638        &mut self,
10639        _: &ConvertToUpperCamelCase,
10640        window: &mut Window,
10641        cx: &mut Context<Self>,
10642    ) {
10643        self.manipulate_text(window, cx, |text| {
10644            text.split('\n')
10645                .map(|line| line.to_case(Case::UpperCamel))
10646                .join("\n")
10647        })
10648    }
10649
10650    pub fn convert_to_lower_camel_case(
10651        &mut self,
10652        _: &ConvertToLowerCamelCase,
10653        window: &mut Window,
10654        cx: &mut Context<Self>,
10655    ) {
10656        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10657    }
10658
10659    pub fn convert_to_opposite_case(
10660        &mut self,
10661        _: &ConvertToOppositeCase,
10662        window: &mut Window,
10663        cx: &mut Context<Self>,
10664    ) {
10665        self.manipulate_text(window, cx, |text| {
10666            text.chars()
10667                .fold(String::with_capacity(text.len()), |mut t, c| {
10668                    if c.is_uppercase() {
10669                        t.extend(c.to_lowercase());
10670                    } else {
10671                        t.extend(c.to_uppercase());
10672                    }
10673                    t
10674                })
10675        })
10676    }
10677
10678    pub fn convert_to_rot13(
10679        &mut self,
10680        _: &ConvertToRot13,
10681        window: &mut Window,
10682        cx: &mut Context<Self>,
10683    ) {
10684        self.manipulate_text(window, cx, |text| {
10685            text.chars()
10686                .map(|c| match c {
10687                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10688                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10689                    _ => c,
10690                })
10691                .collect()
10692        })
10693    }
10694
10695    pub fn convert_to_rot47(
10696        &mut self,
10697        _: &ConvertToRot47,
10698        window: &mut Window,
10699        cx: &mut Context<Self>,
10700    ) {
10701        self.manipulate_text(window, cx, |text| {
10702            text.chars()
10703                .map(|c| {
10704                    let code_point = c as u32;
10705                    if code_point >= 33 && code_point <= 126 {
10706                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10707                    }
10708                    c
10709                })
10710                .collect()
10711        })
10712    }
10713
10714    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10715    where
10716        Fn: FnMut(&str) -> String,
10717    {
10718        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10719        let buffer = self.buffer.read(cx).snapshot(cx);
10720
10721        let mut new_selections = Vec::new();
10722        let mut edits = Vec::new();
10723        let mut selection_adjustment = 0i32;
10724
10725        for selection in self.selections.all::<usize>(cx) {
10726            let selection_is_empty = selection.is_empty();
10727
10728            let (start, end) = if selection_is_empty {
10729                let word_range = movement::surrounding_word(
10730                    &display_map,
10731                    selection.start.to_display_point(&display_map),
10732                );
10733                let start = word_range.start.to_offset(&display_map, Bias::Left);
10734                let end = word_range.end.to_offset(&display_map, Bias::Left);
10735                (start, end)
10736            } else {
10737                (selection.start, selection.end)
10738            };
10739
10740            let text = buffer.text_for_range(start..end).collect::<String>();
10741            let old_length = text.len() as i32;
10742            let text = callback(&text);
10743
10744            new_selections.push(Selection {
10745                start: (start as i32 - selection_adjustment) as usize,
10746                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10747                goal: SelectionGoal::None,
10748                ..selection
10749            });
10750
10751            selection_adjustment += old_length - text.len() as i32;
10752
10753            edits.push((start..end, text));
10754        }
10755
10756        self.transact(window, cx, |this, window, cx| {
10757            this.buffer.update(cx, |buffer, cx| {
10758                buffer.edit(edits, None, cx);
10759            });
10760
10761            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10762                s.select(new_selections);
10763            });
10764
10765            this.request_autoscroll(Autoscroll::fit(), cx);
10766        });
10767    }
10768
10769    pub fn move_selection_on_drop(
10770        &mut self,
10771        selection: &Selection<Anchor>,
10772        target: DisplayPoint,
10773        is_cut: bool,
10774        window: &mut Window,
10775        cx: &mut Context<Self>,
10776    ) {
10777        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10778        let buffer = &display_map.buffer_snapshot;
10779        let mut edits = Vec::new();
10780        let insert_point = display_map
10781            .clip_point(target, Bias::Left)
10782            .to_point(&display_map);
10783        let text = buffer
10784            .text_for_range(selection.start..selection.end)
10785            .collect::<String>();
10786        if is_cut {
10787            edits.push(((selection.start..selection.end), String::new()));
10788        }
10789        let insert_anchor = buffer.anchor_before(insert_point);
10790        edits.push(((insert_anchor..insert_anchor), text));
10791        let last_edit_start = insert_anchor.bias_left(buffer);
10792        let last_edit_end = insert_anchor.bias_right(buffer);
10793        self.transact(window, cx, |this, window, cx| {
10794            this.buffer.update(cx, |buffer, cx| {
10795                buffer.edit(edits, None, cx);
10796            });
10797            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10798                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10799            });
10800        });
10801    }
10802
10803    pub fn clear_selection_drag_state(&mut self) {
10804        self.selection_drag_state = SelectionDragState::None;
10805    }
10806
10807    pub fn duplicate(
10808        &mut self,
10809        upwards: bool,
10810        whole_lines: bool,
10811        window: &mut Window,
10812        cx: &mut Context<Self>,
10813    ) {
10814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10815
10816        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10817        let buffer = &display_map.buffer_snapshot;
10818        let selections = self.selections.all::<Point>(cx);
10819
10820        let mut edits = Vec::new();
10821        let mut selections_iter = selections.iter().peekable();
10822        while let Some(selection) = selections_iter.next() {
10823            let mut rows = selection.spanned_rows(false, &display_map);
10824            // duplicate line-wise
10825            if whole_lines || selection.start == selection.end {
10826                // Avoid duplicating the same lines twice.
10827                while let Some(next_selection) = selections_iter.peek() {
10828                    let next_rows = next_selection.spanned_rows(false, &display_map);
10829                    if next_rows.start < rows.end {
10830                        rows.end = next_rows.end;
10831                        selections_iter.next().unwrap();
10832                    } else {
10833                        break;
10834                    }
10835                }
10836
10837                // Copy the text from the selected row region and splice it either at the start
10838                // or end of the region.
10839                let start = Point::new(rows.start.0, 0);
10840                let end = Point::new(
10841                    rows.end.previous_row().0,
10842                    buffer.line_len(rows.end.previous_row()),
10843                );
10844                let text = buffer
10845                    .text_for_range(start..end)
10846                    .chain(Some("\n"))
10847                    .collect::<String>();
10848                let insert_location = if upwards {
10849                    Point::new(rows.end.0, 0)
10850                } else {
10851                    start
10852                };
10853                edits.push((insert_location..insert_location, text));
10854            } else {
10855                // duplicate character-wise
10856                let start = selection.start;
10857                let end = selection.end;
10858                let text = buffer.text_for_range(start..end).collect::<String>();
10859                edits.push((selection.end..selection.end, text));
10860            }
10861        }
10862
10863        self.transact(window, cx, |this, _, cx| {
10864            this.buffer.update(cx, |buffer, cx| {
10865                buffer.edit(edits, None, cx);
10866            });
10867
10868            this.request_autoscroll(Autoscroll::fit(), cx);
10869        });
10870    }
10871
10872    pub fn duplicate_line_up(
10873        &mut self,
10874        _: &DuplicateLineUp,
10875        window: &mut Window,
10876        cx: &mut Context<Self>,
10877    ) {
10878        self.duplicate(true, true, window, cx);
10879    }
10880
10881    pub fn duplicate_line_down(
10882        &mut self,
10883        _: &DuplicateLineDown,
10884        window: &mut Window,
10885        cx: &mut Context<Self>,
10886    ) {
10887        self.duplicate(false, true, window, cx);
10888    }
10889
10890    pub fn duplicate_selection(
10891        &mut self,
10892        _: &DuplicateSelection,
10893        window: &mut Window,
10894        cx: &mut Context<Self>,
10895    ) {
10896        self.duplicate(false, false, window, cx);
10897    }
10898
10899    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10900        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10901
10902        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10903        let buffer = self.buffer.read(cx).snapshot(cx);
10904
10905        let mut edits = Vec::new();
10906        let mut unfold_ranges = Vec::new();
10907        let mut refold_creases = Vec::new();
10908
10909        let selections = self.selections.all::<Point>(cx);
10910        let mut selections = selections.iter().peekable();
10911        let mut contiguous_row_selections = Vec::new();
10912        let mut new_selections = Vec::new();
10913
10914        while let Some(selection) = selections.next() {
10915            // Find all the selections that span a contiguous row range
10916            let (start_row, end_row) = consume_contiguous_rows(
10917                &mut contiguous_row_selections,
10918                selection,
10919                &display_map,
10920                &mut selections,
10921            );
10922
10923            // Move the text spanned by the row range to be before the line preceding the row range
10924            if start_row.0 > 0 {
10925                let range_to_move = Point::new(
10926                    start_row.previous_row().0,
10927                    buffer.line_len(start_row.previous_row()),
10928                )
10929                    ..Point::new(
10930                        end_row.previous_row().0,
10931                        buffer.line_len(end_row.previous_row()),
10932                    );
10933                let insertion_point = display_map
10934                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10935                    .0;
10936
10937                // Don't move lines across excerpts
10938                if buffer
10939                    .excerpt_containing(insertion_point..range_to_move.end)
10940                    .is_some()
10941                {
10942                    let text = buffer
10943                        .text_for_range(range_to_move.clone())
10944                        .flat_map(|s| s.chars())
10945                        .skip(1)
10946                        .chain(['\n'])
10947                        .collect::<String>();
10948
10949                    edits.push((
10950                        buffer.anchor_after(range_to_move.start)
10951                            ..buffer.anchor_before(range_to_move.end),
10952                        String::new(),
10953                    ));
10954                    let insertion_anchor = buffer.anchor_after(insertion_point);
10955                    edits.push((insertion_anchor..insertion_anchor, text));
10956
10957                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10958
10959                    // Move selections up
10960                    new_selections.extend(contiguous_row_selections.drain(..).map(
10961                        |mut selection| {
10962                            selection.start.row -= row_delta;
10963                            selection.end.row -= row_delta;
10964                            selection
10965                        },
10966                    ));
10967
10968                    // Move folds up
10969                    unfold_ranges.push(range_to_move.clone());
10970                    for fold in display_map.folds_in_range(
10971                        buffer.anchor_before(range_to_move.start)
10972                            ..buffer.anchor_after(range_to_move.end),
10973                    ) {
10974                        let mut start = fold.range.start.to_point(&buffer);
10975                        let mut end = fold.range.end.to_point(&buffer);
10976                        start.row -= row_delta;
10977                        end.row -= row_delta;
10978                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10979                    }
10980                }
10981            }
10982
10983            // If we didn't move line(s), preserve the existing selections
10984            new_selections.append(&mut contiguous_row_selections);
10985        }
10986
10987        self.transact(window, cx, |this, window, cx| {
10988            this.unfold_ranges(&unfold_ranges, true, true, cx);
10989            this.buffer.update(cx, |buffer, cx| {
10990                for (range, text) in edits {
10991                    buffer.edit([(range, text)], None, cx);
10992                }
10993            });
10994            this.fold_creases(refold_creases, true, window, cx);
10995            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10996                s.select(new_selections);
10997            })
10998        });
10999    }
11000
11001    pub fn move_line_down(
11002        &mut self,
11003        _: &MoveLineDown,
11004        window: &mut Window,
11005        cx: &mut Context<Self>,
11006    ) {
11007        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11008
11009        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11010        let buffer = self.buffer.read(cx).snapshot(cx);
11011
11012        let mut edits = Vec::new();
11013        let mut unfold_ranges = Vec::new();
11014        let mut refold_creases = Vec::new();
11015
11016        let selections = self.selections.all::<Point>(cx);
11017        let mut selections = selections.iter().peekable();
11018        let mut contiguous_row_selections = Vec::new();
11019        let mut new_selections = Vec::new();
11020
11021        while let Some(selection) = selections.next() {
11022            // Find all the selections that span a contiguous row range
11023            let (start_row, end_row) = consume_contiguous_rows(
11024                &mut contiguous_row_selections,
11025                selection,
11026                &display_map,
11027                &mut selections,
11028            );
11029
11030            // Move the text spanned by the row range to be after the last line of the row range
11031            if end_row.0 <= buffer.max_point().row {
11032                let range_to_move =
11033                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11034                let insertion_point = display_map
11035                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11036                    .0;
11037
11038                // Don't move lines across excerpt boundaries
11039                if buffer
11040                    .excerpt_containing(range_to_move.start..insertion_point)
11041                    .is_some()
11042                {
11043                    let mut text = String::from("\n");
11044                    text.extend(buffer.text_for_range(range_to_move.clone()));
11045                    text.pop(); // Drop trailing newline
11046                    edits.push((
11047                        buffer.anchor_after(range_to_move.start)
11048                            ..buffer.anchor_before(range_to_move.end),
11049                        String::new(),
11050                    ));
11051                    let insertion_anchor = buffer.anchor_after(insertion_point);
11052                    edits.push((insertion_anchor..insertion_anchor, text));
11053
11054                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11055
11056                    // Move selections down
11057                    new_selections.extend(contiguous_row_selections.drain(..).map(
11058                        |mut selection| {
11059                            selection.start.row += row_delta;
11060                            selection.end.row += row_delta;
11061                            selection
11062                        },
11063                    ));
11064
11065                    // Move folds down
11066                    unfold_ranges.push(range_to_move.clone());
11067                    for fold in display_map.folds_in_range(
11068                        buffer.anchor_before(range_to_move.start)
11069                            ..buffer.anchor_after(range_to_move.end),
11070                    ) {
11071                        let mut start = fold.range.start.to_point(&buffer);
11072                        let mut end = fold.range.end.to_point(&buffer);
11073                        start.row += row_delta;
11074                        end.row += row_delta;
11075                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11076                    }
11077                }
11078            }
11079
11080            // If we didn't move line(s), preserve the existing selections
11081            new_selections.append(&mut contiguous_row_selections);
11082        }
11083
11084        self.transact(window, cx, |this, window, cx| {
11085            this.unfold_ranges(&unfold_ranges, true, true, cx);
11086            this.buffer.update(cx, |buffer, cx| {
11087                for (range, text) in edits {
11088                    buffer.edit([(range, text)], None, cx);
11089                }
11090            });
11091            this.fold_creases(refold_creases, true, window, cx);
11092            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11093                s.select(new_selections)
11094            });
11095        });
11096    }
11097
11098    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11099        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11100        let text_layout_details = &self.text_layout_details(window);
11101        self.transact(window, cx, |this, window, cx| {
11102            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11103                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11104                s.move_with(|display_map, selection| {
11105                    if !selection.is_empty() {
11106                        return;
11107                    }
11108
11109                    let mut head = selection.head();
11110                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11111                    if head.column() == display_map.line_len(head.row()) {
11112                        transpose_offset = display_map
11113                            .buffer_snapshot
11114                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11115                    }
11116
11117                    if transpose_offset == 0 {
11118                        return;
11119                    }
11120
11121                    *head.column_mut() += 1;
11122                    head = display_map.clip_point(head, Bias::Right);
11123                    let goal = SelectionGoal::HorizontalPosition(
11124                        display_map
11125                            .x_for_display_point(head, text_layout_details)
11126                            .into(),
11127                    );
11128                    selection.collapse_to(head, goal);
11129
11130                    let transpose_start = display_map
11131                        .buffer_snapshot
11132                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11133                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11134                        let transpose_end = display_map
11135                            .buffer_snapshot
11136                            .clip_offset(transpose_offset + 1, Bias::Right);
11137                        if let Some(ch) =
11138                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11139                        {
11140                            edits.push((transpose_start..transpose_offset, String::new()));
11141                            edits.push((transpose_end..transpose_end, ch.to_string()));
11142                        }
11143                    }
11144                });
11145                edits
11146            });
11147            this.buffer
11148                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11149            let selections = this.selections.all::<usize>(cx);
11150            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11151                s.select(selections);
11152            });
11153        });
11154    }
11155
11156    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11157        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11158        self.rewrap_impl(RewrapOptions::default(), cx)
11159    }
11160
11161    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11162        let buffer = self.buffer.read(cx).snapshot(cx);
11163        let selections = self.selections.all::<Point>(cx);
11164
11165        // Shrink and split selections to respect paragraph boundaries.
11166        let ranges = selections.into_iter().flat_map(|selection| {
11167            let language_settings = buffer.language_settings_at(selection.head(), cx);
11168            let language_scope = buffer.language_scope_at(selection.head());
11169
11170            let Some(start_row) = (selection.start.row..=selection.end.row)
11171                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11172            else {
11173                return vec![];
11174            };
11175            let Some(end_row) = (selection.start.row..=selection.end.row)
11176                .rev()
11177                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11178            else {
11179                return vec![];
11180            };
11181
11182            let mut row = start_row;
11183            let mut ranges = Vec::new();
11184            while let Some(blank_row) =
11185                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11186            {
11187                let next_paragraph_start = (blank_row + 1..=end_row)
11188                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11189                    .unwrap();
11190                ranges.push((
11191                    language_settings.clone(),
11192                    language_scope.clone(),
11193                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11194                ));
11195                row = next_paragraph_start;
11196            }
11197            ranges.push((
11198                language_settings.clone(),
11199                language_scope.clone(),
11200                Point::new(row, 0)..Point::new(end_row, 0),
11201            ));
11202
11203            ranges
11204        });
11205
11206        let mut edits = Vec::new();
11207        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11208
11209        for (language_settings, language_scope, range) in ranges {
11210            let mut start_row = range.start.row;
11211            let mut end_row = range.end.row;
11212
11213            // Skip selections that overlap with a range that has already been rewrapped.
11214            let selection_range = start_row..end_row;
11215            if rewrapped_row_ranges
11216                .iter()
11217                .any(|range| range.overlaps(&selection_range))
11218            {
11219                continue;
11220            }
11221
11222            let tab_size = language_settings.tab_size;
11223
11224            // Since not all lines in the selection may be at the same indent
11225            // level, choose the indent size that is the most common between all
11226            // of the lines.
11227            //
11228            // If there is a tie, we use the deepest indent.
11229            let (indent_size, indent_end) = {
11230                let mut indent_size_occurrences = HashMap::default();
11231                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11232
11233                for row in start_row..=end_row {
11234                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11235                    rows_by_indent_size.entry(indent).or_default().push(row);
11236                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11237                }
11238
11239                let indent_size = indent_size_occurrences
11240                    .into_iter()
11241                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11242                    .map(|(indent, _)| indent)
11243                    .unwrap_or_default();
11244                let row = rows_by_indent_size[&indent_size][0];
11245                let indent_end = Point::new(row, indent_size.len);
11246
11247                (indent_size, indent_end)
11248            };
11249
11250            let mut line_prefix = indent_size.chars().collect::<String>();
11251
11252            let mut inside_comment = false;
11253            if let Some(comment_prefix) = language_scope.and_then(|language| {
11254                language
11255                    .line_comment_prefixes()
11256                    .iter()
11257                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11258                    .cloned()
11259            }) {
11260                line_prefix.push_str(&comment_prefix);
11261                inside_comment = true;
11262            }
11263
11264            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11265                RewrapBehavior::InComments => inside_comment,
11266                RewrapBehavior::InSelections => !range.is_empty(),
11267                RewrapBehavior::Anywhere => true,
11268            };
11269
11270            let should_rewrap = options.override_language_settings
11271                || allow_rewrap_based_on_language
11272                || self.hard_wrap.is_some();
11273            if !should_rewrap {
11274                continue;
11275            }
11276
11277            if range.is_empty() {
11278                'expand_upwards: while start_row > 0 {
11279                    let prev_row = start_row - 1;
11280                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11281                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11282                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11283                    {
11284                        start_row = prev_row;
11285                    } else {
11286                        break 'expand_upwards;
11287                    }
11288                }
11289
11290                'expand_downwards: while end_row < buffer.max_point().row {
11291                    let next_row = end_row + 1;
11292                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11293                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11294                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11295                    {
11296                        end_row = next_row;
11297                    } else {
11298                        break 'expand_downwards;
11299                    }
11300                }
11301            }
11302
11303            let start = Point::new(start_row, 0);
11304            let start_offset = start.to_offset(&buffer);
11305            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11306            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11307            let Some(lines_without_prefixes) = selection_text
11308                .lines()
11309                .map(|line| {
11310                    line.strip_prefix(&line_prefix)
11311                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11312                        .with_context(|| {
11313                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11314                        })
11315                })
11316                .collect::<Result<Vec<_>, _>>()
11317                .log_err()
11318            else {
11319                continue;
11320            };
11321
11322            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11323                buffer
11324                    .language_settings_at(Point::new(start_row, 0), cx)
11325                    .preferred_line_length as usize
11326            });
11327            let wrapped_text = wrap_with_prefix(
11328                line_prefix,
11329                lines_without_prefixes.join("\n"),
11330                wrap_column,
11331                tab_size,
11332                options.preserve_existing_whitespace,
11333            );
11334
11335            // TODO: should always use char-based diff while still supporting cursor behavior that
11336            // matches vim.
11337            let mut diff_options = DiffOptions::default();
11338            if options.override_language_settings {
11339                diff_options.max_word_diff_len = 0;
11340                diff_options.max_word_diff_line_count = 0;
11341            } else {
11342                diff_options.max_word_diff_len = usize::MAX;
11343                diff_options.max_word_diff_line_count = usize::MAX;
11344            }
11345
11346            for (old_range, new_text) in
11347                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11348            {
11349                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11350                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11351                edits.push((edit_start..edit_end, new_text));
11352            }
11353
11354            rewrapped_row_ranges.push(start_row..=end_row);
11355        }
11356
11357        self.buffer
11358            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11359    }
11360
11361    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11362        let mut text = String::new();
11363        let buffer = self.buffer.read(cx).snapshot(cx);
11364        let mut selections = self.selections.all::<Point>(cx);
11365        let mut clipboard_selections = Vec::with_capacity(selections.len());
11366        {
11367            let max_point = buffer.max_point();
11368            let mut is_first = true;
11369            for selection in &mut selections {
11370                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11371                if is_entire_line {
11372                    selection.start = Point::new(selection.start.row, 0);
11373                    if !selection.is_empty() && selection.end.column == 0 {
11374                        selection.end = cmp::min(max_point, selection.end);
11375                    } else {
11376                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11377                    }
11378                    selection.goal = SelectionGoal::None;
11379                }
11380                if is_first {
11381                    is_first = false;
11382                } else {
11383                    text += "\n";
11384                }
11385                let mut len = 0;
11386                for chunk in buffer.text_for_range(selection.start..selection.end) {
11387                    text.push_str(chunk);
11388                    len += chunk.len();
11389                }
11390                clipboard_selections.push(ClipboardSelection {
11391                    len,
11392                    is_entire_line,
11393                    first_line_indent: buffer
11394                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11395                        .len,
11396                });
11397            }
11398        }
11399
11400        self.transact(window, cx, |this, window, cx| {
11401            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11402                s.select(selections);
11403            });
11404            this.insert("", window, cx);
11405        });
11406        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11407    }
11408
11409    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11411        let item = self.cut_common(window, cx);
11412        cx.write_to_clipboard(item);
11413    }
11414
11415    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11416        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11417        self.change_selections(None, window, cx, |s| {
11418            s.move_with(|snapshot, sel| {
11419                if sel.is_empty() {
11420                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11421                }
11422            });
11423        });
11424        let item = self.cut_common(window, cx);
11425        cx.set_global(KillRing(item))
11426    }
11427
11428    pub fn kill_ring_yank(
11429        &mut self,
11430        _: &KillRingYank,
11431        window: &mut Window,
11432        cx: &mut Context<Self>,
11433    ) {
11434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11435        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11436            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11437                (kill_ring.text().to_string(), kill_ring.metadata_json())
11438            } else {
11439                return;
11440            }
11441        } else {
11442            return;
11443        };
11444        self.do_paste(&text, metadata, false, window, cx);
11445    }
11446
11447    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11448        self.do_copy(true, cx);
11449    }
11450
11451    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11452        self.do_copy(false, cx);
11453    }
11454
11455    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11456        let selections = self.selections.all::<Point>(cx);
11457        let buffer = self.buffer.read(cx).read(cx);
11458        let mut text = String::new();
11459
11460        let mut clipboard_selections = Vec::with_capacity(selections.len());
11461        {
11462            let max_point = buffer.max_point();
11463            let mut is_first = true;
11464            for selection in &selections {
11465                let mut start = selection.start;
11466                let mut end = selection.end;
11467                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11468                if is_entire_line {
11469                    start = Point::new(start.row, 0);
11470                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11471                }
11472
11473                let mut trimmed_selections = Vec::new();
11474                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11475                    let row = MultiBufferRow(start.row);
11476                    let first_indent = buffer.indent_size_for_line(row);
11477                    if first_indent.len == 0 || start.column > first_indent.len {
11478                        trimmed_selections.push(start..end);
11479                    } else {
11480                        trimmed_selections.push(
11481                            Point::new(row.0, first_indent.len)
11482                                ..Point::new(row.0, buffer.line_len(row)),
11483                        );
11484                        for row in start.row + 1..=end.row {
11485                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11486                            if row == end.row {
11487                                line_len = end.column;
11488                            }
11489                            if line_len == 0 {
11490                                trimmed_selections
11491                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11492                                continue;
11493                            }
11494                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11495                            if row_indent_size.len >= first_indent.len {
11496                                trimmed_selections.push(
11497                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11498                                );
11499                            } else {
11500                                trimmed_selections.clear();
11501                                trimmed_selections.push(start..end);
11502                                break;
11503                            }
11504                        }
11505                    }
11506                } else {
11507                    trimmed_selections.push(start..end);
11508                }
11509
11510                for trimmed_range in trimmed_selections {
11511                    if is_first {
11512                        is_first = false;
11513                    } else {
11514                        text += "\n";
11515                    }
11516                    let mut len = 0;
11517                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11518                        text.push_str(chunk);
11519                        len += chunk.len();
11520                    }
11521                    clipboard_selections.push(ClipboardSelection {
11522                        len,
11523                        is_entire_line,
11524                        first_line_indent: buffer
11525                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11526                            .len,
11527                    });
11528                }
11529            }
11530        }
11531
11532        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11533            text,
11534            clipboard_selections,
11535        ));
11536    }
11537
11538    pub fn do_paste(
11539        &mut self,
11540        text: &String,
11541        clipboard_selections: Option<Vec<ClipboardSelection>>,
11542        handle_entire_lines: bool,
11543        window: &mut Window,
11544        cx: &mut Context<Self>,
11545    ) {
11546        if self.read_only(cx) {
11547            return;
11548        }
11549
11550        let clipboard_text = Cow::Borrowed(text);
11551
11552        self.transact(window, cx, |this, window, cx| {
11553            if let Some(mut clipboard_selections) = clipboard_selections {
11554                let old_selections = this.selections.all::<usize>(cx);
11555                let all_selections_were_entire_line =
11556                    clipboard_selections.iter().all(|s| s.is_entire_line);
11557                let first_selection_indent_column =
11558                    clipboard_selections.first().map(|s| s.first_line_indent);
11559                if clipboard_selections.len() != old_selections.len() {
11560                    clipboard_selections.drain(..);
11561                }
11562                let cursor_offset = this.selections.last::<usize>(cx).head();
11563                let mut auto_indent_on_paste = true;
11564
11565                this.buffer.update(cx, |buffer, cx| {
11566                    let snapshot = buffer.read(cx);
11567                    auto_indent_on_paste = snapshot
11568                        .language_settings_at(cursor_offset, cx)
11569                        .auto_indent_on_paste;
11570
11571                    let mut start_offset = 0;
11572                    let mut edits = Vec::new();
11573                    let mut original_indent_columns = Vec::new();
11574                    for (ix, selection) in old_selections.iter().enumerate() {
11575                        let to_insert;
11576                        let entire_line;
11577                        let original_indent_column;
11578                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11579                            let end_offset = start_offset + clipboard_selection.len;
11580                            to_insert = &clipboard_text[start_offset..end_offset];
11581                            entire_line = clipboard_selection.is_entire_line;
11582                            start_offset = end_offset + 1;
11583                            original_indent_column = Some(clipboard_selection.first_line_indent);
11584                        } else {
11585                            to_insert = clipboard_text.as_str();
11586                            entire_line = all_selections_were_entire_line;
11587                            original_indent_column = first_selection_indent_column
11588                        }
11589
11590                        // If the corresponding selection was empty when this slice of the
11591                        // clipboard text was written, then the entire line containing the
11592                        // selection was copied. If this selection is also currently empty,
11593                        // then paste the line before the current line of the buffer.
11594                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11595                            let column = selection.start.to_point(&snapshot).column as usize;
11596                            let line_start = selection.start - column;
11597                            line_start..line_start
11598                        } else {
11599                            selection.range()
11600                        };
11601
11602                        edits.push((range, to_insert));
11603                        original_indent_columns.push(original_indent_column);
11604                    }
11605                    drop(snapshot);
11606
11607                    buffer.edit(
11608                        edits,
11609                        if auto_indent_on_paste {
11610                            Some(AutoindentMode::Block {
11611                                original_indent_columns,
11612                            })
11613                        } else {
11614                            None
11615                        },
11616                        cx,
11617                    );
11618                });
11619
11620                let selections = this.selections.all::<usize>(cx);
11621                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11622                    s.select(selections)
11623                });
11624            } else {
11625                this.insert(&clipboard_text, window, cx);
11626            }
11627        });
11628    }
11629
11630    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11631        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11632        if let Some(item) = cx.read_from_clipboard() {
11633            let entries = item.entries();
11634
11635            match entries.first() {
11636                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11637                // of all the pasted entries.
11638                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11639                    .do_paste(
11640                        clipboard_string.text(),
11641                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11642                        true,
11643                        window,
11644                        cx,
11645                    ),
11646                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11647            }
11648        }
11649    }
11650
11651    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11652        if self.read_only(cx) {
11653            return;
11654        }
11655
11656        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11657
11658        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11659            if let Some((selections, _)) =
11660                self.selection_history.transaction(transaction_id).cloned()
11661            {
11662                self.change_selections(None, window, cx, |s| {
11663                    s.select_anchors(selections.to_vec());
11664                });
11665            } else {
11666                log::error!(
11667                    "No entry in selection_history found for undo. \
11668                     This may correspond to a bug where undo does not update the selection. \
11669                     If this is occurring, please add details to \
11670                     https://github.com/zed-industries/zed/issues/22692"
11671                );
11672            }
11673            self.request_autoscroll(Autoscroll::fit(), cx);
11674            self.unmark_text(window, cx);
11675            self.refresh_inline_completion(true, false, window, cx);
11676            cx.emit(EditorEvent::Edited { transaction_id });
11677            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11678        }
11679    }
11680
11681    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11682        if self.read_only(cx) {
11683            return;
11684        }
11685
11686        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11687
11688        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11689            if let Some((_, Some(selections))) =
11690                self.selection_history.transaction(transaction_id).cloned()
11691            {
11692                self.change_selections(None, window, cx, |s| {
11693                    s.select_anchors(selections.to_vec());
11694                });
11695            } else {
11696                log::error!(
11697                    "No entry in selection_history found for redo. \
11698                     This may correspond to a bug where undo does not update the selection. \
11699                     If this is occurring, please add details to \
11700                     https://github.com/zed-industries/zed/issues/22692"
11701                );
11702            }
11703            self.request_autoscroll(Autoscroll::fit(), cx);
11704            self.unmark_text(window, cx);
11705            self.refresh_inline_completion(true, false, window, cx);
11706            cx.emit(EditorEvent::Edited { transaction_id });
11707        }
11708    }
11709
11710    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11711        self.buffer
11712            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11713    }
11714
11715    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11716        self.buffer
11717            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11718    }
11719
11720    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11721        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11722        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11723            s.move_with(|map, selection| {
11724                let cursor = if selection.is_empty() {
11725                    movement::left(map, selection.start)
11726                } else {
11727                    selection.start
11728                };
11729                selection.collapse_to(cursor, SelectionGoal::None);
11730            });
11731        })
11732    }
11733
11734    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11736        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11737            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11738        })
11739    }
11740
11741    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11742        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11743        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11744            s.move_with(|map, selection| {
11745                let cursor = if selection.is_empty() {
11746                    movement::right(map, selection.end)
11747                } else {
11748                    selection.end
11749                };
11750                selection.collapse_to(cursor, SelectionGoal::None)
11751            });
11752        })
11753    }
11754
11755    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11757        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11758            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11759        })
11760    }
11761
11762    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11763        if self.take_rename(true, window, cx).is_some() {
11764            return;
11765        }
11766
11767        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11768            cx.propagate();
11769            return;
11770        }
11771
11772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11773
11774        let text_layout_details = &self.text_layout_details(window);
11775        let selection_count = self.selections.count();
11776        let first_selection = self.selections.first_anchor();
11777
11778        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11779            s.move_with(|map, selection| {
11780                if !selection.is_empty() {
11781                    selection.goal = SelectionGoal::None;
11782                }
11783                let (cursor, goal) = movement::up(
11784                    map,
11785                    selection.start,
11786                    selection.goal,
11787                    false,
11788                    text_layout_details,
11789                );
11790                selection.collapse_to(cursor, goal);
11791            });
11792        });
11793
11794        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11795        {
11796            cx.propagate();
11797        }
11798    }
11799
11800    pub fn move_up_by_lines(
11801        &mut self,
11802        action: &MoveUpByLines,
11803        window: &mut Window,
11804        cx: &mut Context<Self>,
11805    ) {
11806        if self.take_rename(true, window, cx).is_some() {
11807            return;
11808        }
11809
11810        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11811            cx.propagate();
11812            return;
11813        }
11814
11815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11816
11817        let text_layout_details = &self.text_layout_details(window);
11818
11819        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11820            s.move_with(|map, selection| {
11821                if !selection.is_empty() {
11822                    selection.goal = SelectionGoal::None;
11823                }
11824                let (cursor, goal) = movement::up_by_rows(
11825                    map,
11826                    selection.start,
11827                    action.lines,
11828                    selection.goal,
11829                    false,
11830                    text_layout_details,
11831                );
11832                selection.collapse_to(cursor, goal);
11833            });
11834        })
11835    }
11836
11837    pub fn move_down_by_lines(
11838        &mut self,
11839        action: &MoveDownByLines,
11840        window: &mut Window,
11841        cx: &mut Context<Self>,
11842    ) {
11843        if self.take_rename(true, window, cx).is_some() {
11844            return;
11845        }
11846
11847        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11848            cx.propagate();
11849            return;
11850        }
11851
11852        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11853
11854        let text_layout_details = &self.text_layout_details(window);
11855
11856        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11857            s.move_with(|map, selection| {
11858                if !selection.is_empty() {
11859                    selection.goal = SelectionGoal::None;
11860                }
11861                let (cursor, goal) = movement::down_by_rows(
11862                    map,
11863                    selection.start,
11864                    action.lines,
11865                    selection.goal,
11866                    false,
11867                    text_layout_details,
11868                );
11869                selection.collapse_to(cursor, goal);
11870            });
11871        })
11872    }
11873
11874    pub fn select_down_by_lines(
11875        &mut self,
11876        action: &SelectDownByLines,
11877        window: &mut Window,
11878        cx: &mut Context<Self>,
11879    ) {
11880        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11881        let text_layout_details = &self.text_layout_details(window);
11882        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11883            s.move_heads_with(|map, head, goal| {
11884                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11885            })
11886        })
11887    }
11888
11889    pub fn select_up_by_lines(
11890        &mut self,
11891        action: &SelectUpByLines,
11892        window: &mut Window,
11893        cx: &mut Context<Self>,
11894    ) {
11895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11896        let text_layout_details = &self.text_layout_details(window);
11897        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11898            s.move_heads_with(|map, head, goal| {
11899                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11900            })
11901        })
11902    }
11903
11904    pub fn select_page_up(
11905        &mut self,
11906        _: &SelectPageUp,
11907        window: &mut Window,
11908        cx: &mut Context<Self>,
11909    ) {
11910        let Some(row_count) = self.visible_row_count() else {
11911            return;
11912        };
11913
11914        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11915
11916        let text_layout_details = &self.text_layout_details(window);
11917
11918        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11919            s.move_heads_with(|map, head, goal| {
11920                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11921            })
11922        })
11923    }
11924
11925    pub fn move_page_up(
11926        &mut self,
11927        action: &MovePageUp,
11928        window: &mut Window,
11929        cx: &mut Context<Self>,
11930    ) {
11931        if self.take_rename(true, window, cx).is_some() {
11932            return;
11933        }
11934
11935        if self
11936            .context_menu
11937            .borrow_mut()
11938            .as_mut()
11939            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11940            .unwrap_or(false)
11941        {
11942            return;
11943        }
11944
11945        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11946            cx.propagate();
11947            return;
11948        }
11949
11950        let Some(row_count) = self.visible_row_count() else {
11951            return;
11952        };
11953
11954        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11955
11956        let autoscroll = if action.center_cursor {
11957            Autoscroll::center()
11958        } else {
11959            Autoscroll::fit()
11960        };
11961
11962        let text_layout_details = &self.text_layout_details(window);
11963
11964        self.change_selections(Some(autoscroll), window, cx, |s| {
11965            s.move_with(|map, selection| {
11966                if !selection.is_empty() {
11967                    selection.goal = SelectionGoal::None;
11968                }
11969                let (cursor, goal) = movement::up_by_rows(
11970                    map,
11971                    selection.end,
11972                    row_count,
11973                    selection.goal,
11974                    false,
11975                    text_layout_details,
11976                );
11977                selection.collapse_to(cursor, goal);
11978            });
11979        });
11980    }
11981
11982    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11983        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11984        let text_layout_details = &self.text_layout_details(window);
11985        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11986            s.move_heads_with(|map, head, goal| {
11987                movement::up(map, head, goal, false, text_layout_details)
11988            })
11989        })
11990    }
11991
11992    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11993        self.take_rename(true, window, cx);
11994
11995        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11996            cx.propagate();
11997            return;
11998        }
11999
12000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12001
12002        let text_layout_details = &self.text_layout_details(window);
12003        let selection_count = self.selections.count();
12004        let first_selection = self.selections.first_anchor();
12005
12006        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12007            s.move_with(|map, selection| {
12008                if !selection.is_empty() {
12009                    selection.goal = SelectionGoal::None;
12010                }
12011                let (cursor, goal) = movement::down(
12012                    map,
12013                    selection.end,
12014                    selection.goal,
12015                    false,
12016                    text_layout_details,
12017                );
12018                selection.collapse_to(cursor, goal);
12019            });
12020        });
12021
12022        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12023        {
12024            cx.propagate();
12025        }
12026    }
12027
12028    pub fn select_page_down(
12029        &mut self,
12030        _: &SelectPageDown,
12031        window: &mut Window,
12032        cx: &mut Context<Self>,
12033    ) {
12034        let Some(row_count) = self.visible_row_count() else {
12035            return;
12036        };
12037
12038        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12039
12040        let text_layout_details = &self.text_layout_details(window);
12041
12042        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12043            s.move_heads_with(|map, head, goal| {
12044                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12045            })
12046        })
12047    }
12048
12049    pub fn move_page_down(
12050        &mut self,
12051        action: &MovePageDown,
12052        window: &mut Window,
12053        cx: &mut Context<Self>,
12054    ) {
12055        if self.take_rename(true, window, cx).is_some() {
12056            return;
12057        }
12058
12059        if self
12060            .context_menu
12061            .borrow_mut()
12062            .as_mut()
12063            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12064            .unwrap_or(false)
12065        {
12066            return;
12067        }
12068
12069        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12070            cx.propagate();
12071            return;
12072        }
12073
12074        let Some(row_count) = self.visible_row_count() else {
12075            return;
12076        };
12077
12078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12079
12080        let autoscroll = if action.center_cursor {
12081            Autoscroll::center()
12082        } else {
12083            Autoscroll::fit()
12084        };
12085
12086        let text_layout_details = &self.text_layout_details(window);
12087        self.change_selections(Some(autoscroll), window, cx, |s| {
12088            s.move_with(|map, selection| {
12089                if !selection.is_empty() {
12090                    selection.goal = SelectionGoal::None;
12091                }
12092                let (cursor, goal) = movement::down_by_rows(
12093                    map,
12094                    selection.end,
12095                    row_count,
12096                    selection.goal,
12097                    false,
12098                    text_layout_details,
12099                );
12100                selection.collapse_to(cursor, goal);
12101            });
12102        });
12103    }
12104
12105    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12106        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12107        let text_layout_details = &self.text_layout_details(window);
12108        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12109            s.move_heads_with(|map, head, goal| {
12110                movement::down(map, head, goal, false, text_layout_details)
12111            })
12112        });
12113    }
12114
12115    pub fn context_menu_first(
12116        &mut self,
12117        _: &ContextMenuFirst,
12118        window: &mut Window,
12119        cx: &mut Context<Self>,
12120    ) {
12121        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12122            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12123        }
12124    }
12125
12126    pub fn context_menu_prev(
12127        &mut self,
12128        _: &ContextMenuPrevious,
12129        window: &mut Window,
12130        cx: &mut Context<Self>,
12131    ) {
12132        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12133            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12134        }
12135    }
12136
12137    pub fn context_menu_next(
12138        &mut self,
12139        _: &ContextMenuNext,
12140        window: &mut Window,
12141        cx: &mut Context<Self>,
12142    ) {
12143        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12144            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12145        }
12146    }
12147
12148    pub fn context_menu_last(
12149        &mut self,
12150        _: &ContextMenuLast,
12151        window: &mut Window,
12152        cx: &mut Context<Self>,
12153    ) {
12154        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12155            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12156        }
12157    }
12158
12159    pub fn move_to_previous_word_start(
12160        &mut self,
12161        _: &MoveToPreviousWordStart,
12162        window: &mut Window,
12163        cx: &mut Context<Self>,
12164    ) {
12165        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12166        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12167            s.move_cursors_with(|map, head, _| {
12168                (
12169                    movement::previous_word_start(map, head),
12170                    SelectionGoal::None,
12171                )
12172            });
12173        })
12174    }
12175
12176    pub fn move_to_previous_subword_start(
12177        &mut self,
12178        _: &MoveToPreviousSubwordStart,
12179        window: &mut Window,
12180        cx: &mut Context<Self>,
12181    ) {
12182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12183        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12184            s.move_cursors_with(|map, head, _| {
12185                (
12186                    movement::previous_subword_start(map, head),
12187                    SelectionGoal::None,
12188                )
12189            });
12190        })
12191    }
12192
12193    pub fn select_to_previous_word_start(
12194        &mut self,
12195        _: &SelectToPreviousWordStart,
12196        window: &mut Window,
12197        cx: &mut Context<Self>,
12198    ) {
12199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12200        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12201            s.move_heads_with(|map, head, _| {
12202                (
12203                    movement::previous_word_start(map, head),
12204                    SelectionGoal::None,
12205                )
12206            });
12207        })
12208    }
12209
12210    pub fn select_to_previous_subword_start(
12211        &mut self,
12212        _: &SelectToPreviousSubwordStart,
12213        window: &mut Window,
12214        cx: &mut Context<Self>,
12215    ) {
12216        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12217        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12218            s.move_heads_with(|map, head, _| {
12219                (
12220                    movement::previous_subword_start(map, head),
12221                    SelectionGoal::None,
12222                )
12223            });
12224        })
12225    }
12226
12227    pub fn delete_to_previous_word_start(
12228        &mut self,
12229        action: &DeleteToPreviousWordStart,
12230        window: &mut Window,
12231        cx: &mut Context<Self>,
12232    ) {
12233        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12234        self.transact(window, cx, |this, window, cx| {
12235            this.select_autoclose_pair(window, cx);
12236            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12237                s.move_with(|map, selection| {
12238                    if selection.is_empty() {
12239                        let cursor = if action.ignore_newlines {
12240                            movement::previous_word_start(map, selection.head())
12241                        } else {
12242                            movement::previous_word_start_or_newline(map, selection.head())
12243                        };
12244                        selection.set_head(cursor, SelectionGoal::None);
12245                    }
12246                });
12247            });
12248            this.insert("", window, cx);
12249        });
12250    }
12251
12252    pub fn delete_to_previous_subword_start(
12253        &mut self,
12254        _: &DeleteToPreviousSubwordStart,
12255        window: &mut Window,
12256        cx: &mut Context<Self>,
12257    ) {
12258        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12259        self.transact(window, cx, |this, window, cx| {
12260            this.select_autoclose_pair(window, cx);
12261            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12262                s.move_with(|map, selection| {
12263                    if selection.is_empty() {
12264                        let cursor = movement::previous_subword_start(map, selection.head());
12265                        selection.set_head(cursor, SelectionGoal::None);
12266                    }
12267                });
12268            });
12269            this.insert("", window, cx);
12270        });
12271    }
12272
12273    pub fn move_to_next_word_end(
12274        &mut self,
12275        _: &MoveToNextWordEnd,
12276        window: &mut Window,
12277        cx: &mut Context<Self>,
12278    ) {
12279        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12280        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12281            s.move_cursors_with(|map, head, _| {
12282                (movement::next_word_end(map, head), SelectionGoal::None)
12283            });
12284        })
12285    }
12286
12287    pub fn move_to_next_subword_end(
12288        &mut self,
12289        _: &MoveToNextSubwordEnd,
12290        window: &mut Window,
12291        cx: &mut Context<Self>,
12292    ) {
12293        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12294        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12295            s.move_cursors_with(|map, head, _| {
12296                (movement::next_subword_end(map, head), SelectionGoal::None)
12297            });
12298        })
12299    }
12300
12301    pub fn select_to_next_word_end(
12302        &mut self,
12303        _: &SelectToNextWordEnd,
12304        window: &mut Window,
12305        cx: &mut Context<Self>,
12306    ) {
12307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12308        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12309            s.move_heads_with(|map, head, _| {
12310                (movement::next_word_end(map, head), SelectionGoal::None)
12311            });
12312        })
12313    }
12314
12315    pub fn select_to_next_subword_end(
12316        &mut self,
12317        _: &SelectToNextSubwordEnd,
12318        window: &mut Window,
12319        cx: &mut Context<Self>,
12320    ) {
12321        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12322        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12323            s.move_heads_with(|map, head, _| {
12324                (movement::next_subword_end(map, head), SelectionGoal::None)
12325            });
12326        })
12327    }
12328
12329    pub fn delete_to_next_word_end(
12330        &mut self,
12331        action: &DeleteToNextWordEnd,
12332        window: &mut Window,
12333        cx: &mut Context<Self>,
12334    ) {
12335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12336        self.transact(window, cx, |this, window, cx| {
12337            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12338                s.move_with(|map, selection| {
12339                    if selection.is_empty() {
12340                        let cursor = if action.ignore_newlines {
12341                            movement::next_word_end(map, selection.head())
12342                        } else {
12343                            movement::next_word_end_or_newline(map, selection.head())
12344                        };
12345                        selection.set_head(cursor, SelectionGoal::None);
12346                    }
12347                });
12348            });
12349            this.insert("", window, cx);
12350        });
12351    }
12352
12353    pub fn delete_to_next_subword_end(
12354        &mut self,
12355        _: &DeleteToNextSubwordEnd,
12356        window: &mut Window,
12357        cx: &mut Context<Self>,
12358    ) {
12359        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12360        self.transact(window, cx, |this, window, cx| {
12361            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12362                s.move_with(|map, selection| {
12363                    if selection.is_empty() {
12364                        let cursor = movement::next_subword_end(map, selection.head());
12365                        selection.set_head(cursor, SelectionGoal::None);
12366                    }
12367                });
12368            });
12369            this.insert("", window, cx);
12370        });
12371    }
12372
12373    pub fn move_to_beginning_of_line(
12374        &mut self,
12375        action: &MoveToBeginningOfLine,
12376        window: &mut Window,
12377        cx: &mut Context<Self>,
12378    ) {
12379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12380        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12381            s.move_cursors_with(|map, head, _| {
12382                (
12383                    movement::indented_line_beginning(
12384                        map,
12385                        head,
12386                        action.stop_at_soft_wraps,
12387                        action.stop_at_indent,
12388                    ),
12389                    SelectionGoal::None,
12390                )
12391            });
12392        })
12393    }
12394
12395    pub fn select_to_beginning_of_line(
12396        &mut self,
12397        action: &SelectToBeginningOfLine,
12398        window: &mut Window,
12399        cx: &mut Context<Self>,
12400    ) {
12401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12402        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12403            s.move_heads_with(|map, head, _| {
12404                (
12405                    movement::indented_line_beginning(
12406                        map,
12407                        head,
12408                        action.stop_at_soft_wraps,
12409                        action.stop_at_indent,
12410                    ),
12411                    SelectionGoal::None,
12412                )
12413            });
12414        });
12415    }
12416
12417    pub fn delete_to_beginning_of_line(
12418        &mut self,
12419        action: &DeleteToBeginningOfLine,
12420        window: &mut Window,
12421        cx: &mut Context<Self>,
12422    ) {
12423        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12424        self.transact(window, cx, |this, window, cx| {
12425            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12426                s.move_with(|_, selection| {
12427                    selection.reversed = true;
12428                });
12429            });
12430
12431            this.select_to_beginning_of_line(
12432                &SelectToBeginningOfLine {
12433                    stop_at_soft_wraps: false,
12434                    stop_at_indent: action.stop_at_indent,
12435                },
12436                window,
12437                cx,
12438            );
12439            this.backspace(&Backspace, window, cx);
12440        });
12441    }
12442
12443    pub fn move_to_end_of_line(
12444        &mut self,
12445        action: &MoveToEndOfLine,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) {
12449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12450        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12451            s.move_cursors_with(|map, head, _| {
12452                (
12453                    movement::line_end(map, head, action.stop_at_soft_wraps),
12454                    SelectionGoal::None,
12455                )
12456            });
12457        })
12458    }
12459
12460    pub fn select_to_end_of_line(
12461        &mut self,
12462        action: &SelectToEndOfLine,
12463        window: &mut Window,
12464        cx: &mut Context<Self>,
12465    ) {
12466        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12467        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12468            s.move_heads_with(|map, head, _| {
12469                (
12470                    movement::line_end(map, head, action.stop_at_soft_wraps),
12471                    SelectionGoal::None,
12472                )
12473            });
12474        })
12475    }
12476
12477    pub fn delete_to_end_of_line(
12478        &mut self,
12479        _: &DeleteToEndOfLine,
12480        window: &mut Window,
12481        cx: &mut Context<Self>,
12482    ) {
12483        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12484        self.transact(window, cx, |this, window, cx| {
12485            this.select_to_end_of_line(
12486                &SelectToEndOfLine {
12487                    stop_at_soft_wraps: false,
12488                },
12489                window,
12490                cx,
12491            );
12492            this.delete(&Delete, window, cx);
12493        });
12494    }
12495
12496    pub fn cut_to_end_of_line(
12497        &mut self,
12498        _: &CutToEndOfLine,
12499        window: &mut Window,
12500        cx: &mut Context<Self>,
12501    ) {
12502        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12503        self.transact(window, cx, |this, window, cx| {
12504            this.select_to_end_of_line(
12505                &SelectToEndOfLine {
12506                    stop_at_soft_wraps: false,
12507                },
12508                window,
12509                cx,
12510            );
12511            this.cut(&Cut, window, cx);
12512        });
12513    }
12514
12515    pub fn move_to_start_of_paragraph(
12516        &mut self,
12517        _: &MoveToStartOfParagraph,
12518        window: &mut Window,
12519        cx: &mut Context<Self>,
12520    ) {
12521        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12522            cx.propagate();
12523            return;
12524        }
12525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12526        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12527            s.move_with(|map, selection| {
12528                selection.collapse_to(
12529                    movement::start_of_paragraph(map, selection.head(), 1),
12530                    SelectionGoal::None,
12531                )
12532            });
12533        })
12534    }
12535
12536    pub fn move_to_end_of_paragraph(
12537        &mut self,
12538        _: &MoveToEndOfParagraph,
12539        window: &mut Window,
12540        cx: &mut Context<Self>,
12541    ) {
12542        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12543            cx.propagate();
12544            return;
12545        }
12546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12547        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12548            s.move_with(|map, selection| {
12549                selection.collapse_to(
12550                    movement::end_of_paragraph(map, selection.head(), 1),
12551                    SelectionGoal::None,
12552                )
12553            });
12554        })
12555    }
12556
12557    pub fn select_to_start_of_paragraph(
12558        &mut self,
12559        _: &SelectToStartOfParagraph,
12560        window: &mut Window,
12561        cx: &mut Context<Self>,
12562    ) {
12563        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12564            cx.propagate();
12565            return;
12566        }
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12568        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12569            s.move_heads_with(|map, head, _| {
12570                (
12571                    movement::start_of_paragraph(map, head, 1),
12572                    SelectionGoal::None,
12573                )
12574            });
12575        })
12576    }
12577
12578    pub fn select_to_end_of_paragraph(
12579        &mut self,
12580        _: &SelectToEndOfParagraph,
12581        window: &mut Window,
12582        cx: &mut Context<Self>,
12583    ) {
12584        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12585            cx.propagate();
12586            return;
12587        }
12588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12589        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12590            s.move_heads_with(|map, head, _| {
12591                (
12592                    movement::end_of_paragraph(map, head, 1),
12593                    SelectionGoal::None,
12594                )
12595            });
12596        })
12597    }
12598
12599    pub fn move_to_start_of_excerpt(
12600        &mut self,
12601        _: &MoveToStartOfExcerpt,
12602        window: &mut Window,
12603        cx: &mut Context<Self>,
12604    ) {
12605        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12606            cx.propagate();
12607            return;
12608        }
12609        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12610        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12611            s.move_with(|map, selection| {
12612                selection.collapse_to(
12613                    movement::start_of_excerpt(
12614                        map,
12615                        selection.head(),
12616                        workspace::searchable::Direction::Prev,
12617                    ),
12618                    SelectionGoal::None,
12619                )
12620            });
12621        })
12622    }
12623
12624    pub fn move_to_start_of_next_excerpt(
12625        &mut self,
12626        _: &MoveToStartOfNextExcerpt,
12627        window: &mut Window,
12628        cx: &mut Context<Self>,
12629    ) {
12630        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12631            cx.propagate();
12632            return;
12633        }
12634
12635        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12636            s.move_with(|map, selection| {
12637                selection.collapse_to(
12638                    movement::start_of_excerpt(
12639                        map,
12640                        selection.head(),
12641                        workspace::searchable::Direction::Next,
12642                    ),
12643                    SelectionGoal::None,
12644                )
12645            });
12646        })
12647    }
12648
12649    pub fn move_to_end_of_excerpt(
12650        &mut self,
12651        _: &MoveToEndOfExcerpt,
12652        window: &mut Window,
12653        cx: &mut Context<Self>,
12654    ) {
12655        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12656            cx.propagate();
12657            return;
12658        }
12659        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12660        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12661            s.move_with(|map, selection| {
12662                selection.collapse_to(
12663                    movement::end_of_excerpt(
12664                        map,
12665                        selection.head(),
12666                        workspace::searchable::Direction::Next,
12667                    ),
12668                    SelectionGoal::None,
12669                )
12670            });
12671        })
12672    }
12673
12674    pub fn move_to_end_of_previous_excerpt(
12675        &mut self,
12676        _: &MoveToEndOfPreviousExcerpt,
12677        window: &mut Window,
12678        cx: &mut Context<Self>,
12679    ) {
12680        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12681            cx.propagate();
12682            return;
12683        }
12684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12685        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12686            s.move_with(|map, selection| {
12687                selection.collapse_to(
12688                    movement::end_of_excerpt(
12689                        map,
12690                        selection.head(),
12691                        workspace::searchable::Direction::Prev,
12692                    ),
12693                    SelectionGoal::None,
12694                )
12695            });
12696        })
12697    }
12698
12699    pub fn select_to_start_of_excerpt(
12700        &mut self,
12701        _: &SelectToStartOfExcerpt,
12702        window: &mut Window,
12703        cx: &mut Context<Self>,
12704    ) {
12705        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12706            cx.propagate();
12707            return;
12708        }
12709        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12710        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12711            s.move_heads_with(|map, head, _| {
12712                (
12713                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12714                    SelectionGoal::None,
12715                )
12716            });
12717        })
12718    }
12719
12720    pub fn select_to_start_of_next_excerpt(
12721        &mut self,
12722        _: &SelectToStartOfNextExcerpt,
12723        window: &mut Window,
12724        cx: &mut Context<Self>,
12725    ) {
12726        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12727            cx.propagate();
12728            return;
12729        }
12730        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12731        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12732            s.move_heads_with(|map, head, _| {
12733                (
12734                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12735                    SelectionGoal::None,
12736                )
12737            });
12738        })
12739    }
12740
12741    pub fn select_to_end_of_excerpt(
12742        &mut self,
12743        _: &SelectToEndOfExcerpt,
12744        window: &mut Window,
12745        cx: &mut Context<Self>,
12746    ) {
12747        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12748            cx.propagate();
12749            return;
12750        }
12751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12752        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12753            s.move_heads_with(|map, head, _| {
12754                (
12755                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12756                    SelectionGoal::None,
12757                )
12758            });
12759        })
12760    }
12761
12762    pub fn select_to_end_of_previous_excerpt(
12763        &mut self,
12764        _: &SelectToEndOfPreviousExcerpt,
12765        window: &mut Window,
12766        cx: &mut Context<Self>,
12767    ) {
12768        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12769            cx.propagate();
12770            return;
12771        }
12772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12773        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12774            s.move_heads_with(|map, head, _| {
12775                (
12776                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12777                    SelectionGoal::None,
12778                )
12779            });
12780        })
12781    }
12782
12783    pub fn move_to_beginning(
12784        &mut self,
12785        _: &MoveToBeginning,
12786        window: &mut Window,
12787        cx: &mut Context<Self>,
12788    ) {
12789        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12790            cx.propagate();
12791            return;
12792        }
12793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12794        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12795            s.select_ranges(vec![0..0]);
12796        });
12797    }
12798
12799    pub fn select_to_beginning(
12800        &mut self,
12801        _: &SelectToBeginning,
12802        window: &mut Window,
12803        cx: &mut Context<Self>,
12804    ) {
12805        let mut selection = self.selections.last::<Point>(cx);
12806        selection.set_head(Point::zero(), SelectionGoal::None);
12807        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12808        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12809            s.select(vec![selection]);
12810        });
12811    }
12812
12813    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12814        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12815            cx.propagate();
12816            return;
12817        }
12818        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12819        let cursor = self.buffer.read(cx).read(cx).len();
12820        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12821            s.select_ranges(vec![cursor..cursor])
12822        });
12823    }
12824
12825    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12826        self.nav_history = nav_history;
12827    }
12828
12829    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12830        self.nav_history.as_ref()
12831    }
12832
12833    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12834        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12835    }
12836
12837    fn push_to_nav_history(
12838        &mut self,
12839        cursor_anchor: Anchor,
12840        new_position: Option<Point>,
12841        is_deactivate: bool,
12842        cx: &mut Context<Self>,
12843    ) {
12844        if let Some(nav_history) = self.nav_history.as_mut() {
12845            let buffer = self.buffer.read(cx).read(cx);
12846            let cursor_position = cursor_anchor.to_point(&buffer);
12847            let scroll_state = self.scroll_manager.anchor();
12848            let scroll_top_row = scroll_state.top_row(&buffer);
12849            drop(buffer);
12850
12851            if let Some(new_position) = new_position {
12852                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12853                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12854                    return;
12855                }
12856            }
12857
12858            nav_history.push(
12859                Some(NavigationData {
12860                    cursor_anchor,
12861                    cursor_position,
12862                    scroll_anchor: scroll_state,
12863                    scroll_top_row,
12864                }),
12865                cx,
12866            );
12867            cx.emit(EditorEvent::PushedToNavHistory {
12868                anchor: cursor_anchor,
12869                is_deactivate,
12870            })
12871        }
12872    }
12873
12874    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12876        let buffer = self.buffer.read(cx).snapshot(cx);
12877        let mut selection = self.selections.first::<usize>(cx);
12878        selection.set_head(buffer.len(), SelectionGoal::None);
12879        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12880            s.select(vec![selection]);
12881        });
12882    }
12883
12884    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886        let end = self.buffer.read(cx).read(cx).len();
12887        self.change_selections(None, window, cx, |s| {
12888            s.select_ranges(vec![0..end]);
12889        });
12890    }
12891
12892    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12894        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12895        let mut selections = self.selections.all::<Point>(cx);
12896        let max_point = display_map.buffer_snapshot.max_point();
12897        for selection in &mut selections {
12898            let rows = selection.spanned_rows(true, &display_map);
12899            selection.start = Point::new(rows.start.0, 0);
12900            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12901            selection.reversed = false;
12902        }
12903        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12904            s.select(selections);
12905        });
12906    }
12907
12908    pub fn split_selection_into_lines(
12909        &mut self,
12910        _: &SplitSelectionIntoLines,
12911        window: &mut Window,
12912        cx: &mut Context<Self>,
12913    ) {
12914        let selections = self
12915            .selections
12916            .all::<Point>(cx)
12917            .into_iter()
12918            .map(|selection| selection.start..selection.end)
12919            .collect::<Vec<_>>();
12920        self.unfold_ranges(&selections, true, true, cx);
12921
12922        let mut new_selection_ranges = Vec::new();
12923        {
12924            let buffer = self.buffer.read(cx).read(cx);
12925            for selection in selections {
12926                for row in selection.start.row..selection.end.row {
12927                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12928                    new_selection_ranges.push(cursor..cursor);
12929                }
12930
12931                let is_multiline_selection = selection.start.row != selection.end.row;
12932                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12933                // so this action feels more ergonomic when paired with other selection operations
12934                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12935                if !should_skip_last {
12936                    new_selection_ranges.push(selection.end..selection.end);
12937                }
12938            }
12939        }
12940        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12941            s.select_ranges(new_selection_ranges);
12942        });
12943    }
12944
12945    pub fn add_selection_above(
12946        &mut self,
12947        _: &AddSelectionAbove,
12948        window: &mut Window,
12949        cx: &mut Context<Self>,
12950    ) {
12951        self.add_selection(true, window, cx);
12952    }
12953
12954    pub fn add_selection_below(
12955        &mut self,
12956        _: &AddSelectionBelow,
12957        window: &mut Window,
12958        cx: &mut Context<Self>,
12959    ) {
12960        self.add_selection(false, window, cx);
12961    }
12962
12963    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12965
12966        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12967        let all_selections = self.selections.all::<Point>(cx);
12968        let text_layout_details = self.text_layout_details(window);
12969
12970        let (mut columnar_selections, new_selections_to_columnarize) = {
12971            if let Some(state) = self.add_selections_state.as_ref() {
12972                let columnar_selection_ids: HashSet<_> = state
12973                    .groups
12974                    .iter()
12975                    .flat_map(|group| group.stack.iter())
12976                    .copied()
12977                    .collect();
12978
12979                all_selections
12980                    .into_iter()
12981                    .partition(|s| columnar_selection_ids.contains(&s.id))
12982            } else {
12983                (Vec::new(), all_selections)
12984            }
12985        };
12986
12987        let mut state = self
12988            .add_selections_state
12989            .take()
12990            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12991
12992        for selection in new_selections_to_columnarize {
12993            let range = selection.display_range(&display_map).sorted();
12994            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12995            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12996            let positions = start_x.min(end_x)..start_x.max(end_x);
12997            let mut stack = Vec::new();
12998            for row in range.start.row().0..=range.end.row().0 {
12999                if let Some(selection) = self.selections.build_columnar_selection(
13000                    &display_map,
13001                    DisplayRow(row),
13002                    &positions,
13003                    selection.reversed,
13004                    &text_layout_details,
13005                ) {
13006                    stack.push(selection.id);
13007                    columnar_selections.push(selection);
13008                }
13009            }
13010            if !stack.is_empty() {
13011                if above {
13012                    stack.reverse();
13013                }
13014                state.groups.push(AddSelectionsGroup { above, stack });
13015            }
13016        }
13017
13018        let mut final_selections = Vec::new();
13019        let end_row = if above {
13020            DisplayRow(0)
13021        } else {
13022            display_map.max_point().row()
13023        };
13024
13025        let mut last_added_item_per_group = HashMap::default();
13026        for group in state.groups.iter_mut() {
13027            if let Some(last_id) = group.stack.last() {
13028                last_added_item_per_group.insert(*last_id, group);
13029            }
13030        }
13031
13032        for selection in columnar_selections {
13033            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13034                if above == group.above {
13035                    let range = selection.display_range(&display_map).sorted();
13036                    debug_assert_eq!(range.start.row(), range.end.row());
13037                    let mut row = range.start.row();
13038                    let positions =
13039                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13040                            px(start)..px(end)
13041                        } else {
13042                            let start_x =
13043                                display_map.x_for_display_point(range.start, &text_layout_details);
13044                            let end_x =
13045                                display_map.x_for_display_point(range.end, &text_layout_details);
13046                            start_x.min(end_x)..start_x.max(end_x)
13047                        };
13048
13049                    let mut maybe_new_selection = None;
13050                    while row != end_row {
13051                        if above {
13052                            row.0 -= 1;
13053                        } else {
13054                            row.0 += 1;
13055                        }
13056                        if let Some(new_selection) = self.selections.build_columnar_selection(
13057                            &display_map,
13058                            row,
13059                            &positions,
13060                            selection.reversed,
13061                            &text_layout_details,
13062                        ) {
13063                            maybe_new_selection = Some(new_selection);
13064                            break;
13065                        }
13066                    }
13067
13068                    if let Some(new_selection) = maybe_new_selection {
13069                        group.stack.push(new_selection.id);
13070                        if above {
13071                            final_selections.push(new_selection);
13072                            final_selections.push(selection);
13073                        } else {
13074                            final_selections.push(selection);
13075                            final_selections.push(new_selection);
13076                        }
13077                    } else {
13078                        final_selections.push(selection);
13079                    }
13080                } else {
13081                    group.stack.pop();
13082                }
13083            } else {
13084                final_selections.push(selection);
13085            }
13086        }
13087
13088        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13089            s.select(final_selections);
13090        });
13091
13092        let final_selection_ids: HashSet<_> = self
13093            .selections
13094            .all::<Point>(cx)
13095            .iter()
13096            .map(|s| s.id)
13097            .collect();
13098        state.groups.retain_mut(|group| {
13099            // selections might get merged above so we remove invalid items from stacks
13100            group.stack.retain(|id| final_selection_ids.contains(id));
13101
13102            // single selection in stack can be treated as initial state
13103            group.stack.len() > 1
13104        });
13105
13106        if !state.groups.is_empty() {
13107            self.add_selections_state = Some(state);
13108        }
13109    }
13110
13111    fn select_match_ranges(
13112        &mut self,
13113        range: Range<usize>,
13114        reversed: bool,
13115        replace_newest: bool,
13116        auto_scroll: Option<Autoscroll>,
13117        window: &mut Window,
13118        cx: &mut Context<Editor>,
13119    ) {
13120        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13121        self.change_selections(auto_scroll, window, cx, |s| {
13122            if replace_newest {
13123                s.delete(s.newest_anchor().id);
13124            }
13125            if reversed {
13126                s.insert_range(range.end..range.start);
13127            } else {
13128                s.insert_range(range);
13129            }
13130        });
13131    }
13132
13133    pub fn select_next_match_internal(
13134        &mut self,
13135        display_map: &DisplaySnapshot,
13136        replace_newest: bool,
13137        autoscroll: Option<Autoscroll>,
13138        window: &mut Window,
13139        cx: &mut Context<Self>,
13140    ) -> Result<()> {
13141        let buffer = &display_map.buffer_snapshot;
13142        let mut selections = self.selections.all::<usize>(cx);
13143        if let Some(mut select_next_state) = self.select_next_state.take() {
13144            let query = &select_next_state.query;
13145            if !select_next_state.done {
13146                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13147                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13148                let mut next_selected_range = None;
13149
13150                let bytes_after_last_selection =
13151                    buffer.bytes_in_range(last_selection.end..buffer.len());
13152                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13153                let query_matches = query
13154                    .stream_find_iter(bytes_after_last_selection)
13155                    .map(|result| (last_selection.end, result))
13156                    .chain(
13157                        query
13158                            .stream_find_iter(bytes_before_first_selection)
13159                            .map(|result| (0, result)),
13160                    );
13161
13162                for (start_offset, query_match) in query_matches {
13163                    let query_match = query_match.unwrap(); // can only fail due to I/O
13164                    let offset_range =
13165                        start_offset + query_match.start()..start_offset + query_match.end();
13166                    let display_range = offset_range.start.to_display_point(display_map)
13167                        ..offset_range.end.to_display_point(display_map);
13168
13169                    if !select_next_state.wordwise
13170                        || (!movement::is_inside_word(display_map, display_range.start)
13171                            && !movement::is_inside_word(display_map, display_range.end))
13172                    {
13173                        // TODO: This is n^2, because we might check all the selections
13174                        if !selections
13175                            .iter()
13176                            .any(|selection| selection.range().overlaps(&offset_range))
13177                        {
13178                            next_selected_range = Some(offset_range);
13179                            break;
13180                        }
13181                    }
13182                }
13183
13184                if let Some(next_selected_range) = next_selected_range {
13185                    self.select_match_ranges(
13186                        next_selected_range,
13187                        last_selection.reversed,
13188                        replace_newest,
13189                        autoscroll,
13190                        window,
13191                        cx,
13192                    );
13193                } else {
13194                    select_next_state.done = true;
13195                }
13196            }
13197
13198            self.select_next_state = Some(select_next_state);
13199        } else {
13200            let mut only_carets = true;
13201            let mut same_text_selected = true;
13202            let mut selected_text = None;
13203
13204            let mut selections_iter = selections.iter().peekable();
13205            while let Some(selection) = selections_iter.next() {
13206                if selection.start != selection.end {
13207                    only_carets = false;
13208                }
13209
13210                if same_text_selected {
13211                    if selected_text.is_none() {
13212                        selected_text =
13213                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13214                    }
13215
13216                    if let Some(next_selection) = selections_iter.peek() {
13217                        if next_selection.range().len() == selection.range().len() {
13218                            let next_selected_text = buffer
13219                                .text_for_range(next_selection.range())
13220                                .collect::<String>();
13221                            if Some(next_selected_text) != selected_text {
13222                                same_text_selected = false;
13223                                selected_text = None;
13224                            }
13225                        } else {
13226                            same_text_selected = false;
13227                            selected_text = None;
13228                        }
13229                    }
13230                }
13231            }
13232
13233            if only_carets {
13234                for selection in &mut selections {
13235                    let word_range = movement::surrounding_word(
13236                        display_map,
13237                        selection.start.to_display_point(display_map),
13238                    );
13239                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13240                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13241                    selection.goal = SelectionGoal::None;
13242                    selection.reversed = false;
13243                    self.select_match_ranges(
13244                        selection.start..selection.end,
13245                        selection.reversed,
13246                        replace_newest,
13247                        autoscroll,
13248                        window,
13249                        cx,
13250                    );
13251                }
13252
13253                if selections.len() == 1 {
13254                    let selection = selections
13255                        .last()
13256                        .expect("ensured that there's only one selection");
13257                    let query = buffer
13258                        .text_for_range(selection.start..selection.end)
13259                        .collect::<String>();
13260                    let is_empty = query.is_empty();
13261                    let select_state = SelectNextState {
13262                        query: AhoCorasick::new(&[query])?,
13263                        wordwise: true,
13264                        done: is_empty,
13265                    };
13266                    self.select_next_state = Some(select_state);
13267                } else {
13268                    self.select_next_state = None;
13269                }
13270            } else if let Some(selected_text) = selected_text {
13271                self.select_next_state = Some(SelectNextState {
13272                    query: AhoCorasick::new(&[selected_text])?,
13273                    wordwise: false,
13274                    done: false,
13275                });
13276                self.select_next_match_internal(
13277                    display_map,
13278                    replace_newest,
13279                    autoscroll,
13280                    window,
13281                    cx,
13282                )?;
13283            }
13284        }
13285        Ok(())
13286    }
13287
13288    pub fn select_all_matches(
13289        &mut self,
13290        _action: &SelectAllMatches,
13291        window: &mut Window,
13292        cx: &mut Context<Self>,
13293    ) -> Result<()> {
13294        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13295
13296        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13297
13298        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13299        let Some(select_next_state) = self.select_next_state.as_mut() else {
13300            return Ok(());
13301        };
13302        if select_next_state.done {
13303            return Ok(());
13304        }
13305
13306        let mut new_selections = Vec::new();
13307
13308        let reversed = self.selections.oldest::<usize>(cx).reversed;
13309        let buffer = &display_map.buffer_snapshot;
13310        let query_matches = select_next_state
13311            .query
13312            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13313
13314        for query_match in query_matches.into_iter() {
13315            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13316            let offset_range = if reversed {
13317                query_match.end()..query_match.start()
13318            } else {
13319                query_match.start()..query_match.end()
13320            };
13321            let display_range = offset_range.start.to_display_point(&display_map)
13322                ..offset_range.end.to_display_point(&display_map);
13323
13324            if !select_next_state.wordwise
13325                || (!movement::is_inside_word(&display_map, display_range.start)
13326                    && !movement::is_inside_word(&display_map, display_range.end))
13327            {
13328                new_selections.push(offset_range.start..offset_range.end);
13329            }
13330        }
13331
13332        select_next_state.done = true;
13333        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13334        self.change_selections(None, window, cx, |selections| {
13335            selections.select_ranges(new_selections)
13336        });
13337
13338        Ok(())
13339    }
13340
13341    pub fn select_next(
13342        &mut self,
13343        action: &SelectNext,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) -> Result<()> {
13347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13348        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13349        self.select_next_match_internal(
13350            &display_map,
13351            action.replace_newest,
13352            Some(Autoscroll::newest()),
13353            window,
13354            cx,
13355        )?;
13356        Ok(())
13357    }
13358
13359    pub fn select_previous(
13360        &mut self,
13361        action: &SelectPrevious,
13362        window: &mut Window,
13363        cx: &mut Context<Self>,
13364    ) -> Result<()> {
13365        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13366        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13367        let buffer = &display_map.buffer_snapshot;
13368        let mut selections = self.selections.all::<usize>(cx);
13369        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13370            let query = &select_prev_state.query;
13371            if !select_prev_state.done {
13372                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13373                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13374                let mut next_selected_range = None;
13375                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13376                let bytes_before_last_selection =
13377                    buffer.reversed_bytes_in_range(0..last_selection.start);
13378                let bytes_after_first_selection =
13379                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13380                let query_matches = query
13381                    .stream_find_iter(bytes_before_last_selection)
13382                    .map(|result| (last_selection.start, result))
13383                    .chain(
13384                        query
13385                            .stream_find_iter(bytes_after_first_selection)
13386                            .map(|result| (buffer.len(), result)),
13387                    );
13388                for (end_offset, query_match) in query_matches {
13389                    let query_match = query_match.unwrap(); // can only fail due to I/O
13390                    let offset_range =
13391                        end_offset - query_match.end()..end_offset - query_match.start();
13392                    let display_range = offset_range.start.to_display_point(&display_map)
13393                        ..offset_range.end.to_display_point(&display_map);
13394
13395                    if !select_prev_state.wordwise
13396                        || (!movement::is_inside_word(&display_map, display_range.start)
13397                            && !movement::is_inside_word(&display_map, display_range.end))
13398                    {
13399                        next_selected_range = Some(offset_range);
13400                        break;
13401                    }
13402                }
13403
13404                if let Some(next_selected_range) = next_selected_range {
13405                    self.select_match_ranges(
13406                        next_selected_range,
13407                        last_selection.reversed,
13408                        action.replace_newest,
13409                        Some(Autoscroll::newest()),
13410                        window,
13411                        cx,
13412                    );
13413                } else {
13414                    select_prev_state.done = true;
13415                }
13416            }
13417
13418            self.select_prev_state = Some(select_prev_state);
13419        } else {
13420            let mut only_carets = true;
13421            let mut same_text_selected = true;
13422            let mut selected_text = None;
13423
13424            let mut selections_iter = selections.iter().peekable();
13425            while let Some(selection) = selections_iter.next() {
13426                if selection.start != selection.end {
13427                    only_carets = false;
13428                }
13429
13430                if same_text_selected {
13431                    if selected_text.is_none() {
13432                        selected_text =
13433                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13434                    }
13435
13436                    if let Some(next_selection) = selections_iter.peek() {
13437                        if next_selection.range().len() == selection.range().len() {
13438                            let next_selected_text = buffer
13439                                .text_for_range(next_selection.range())
13440                                .collect::<String>();
13441                            if Some(next_selected_text) != selected_text {
13442                                same_text_selected = false;
13443                                selected_text = None;
13444                            }
13445                        } else {
13446                            same_text_selected = false;
13447                            selected_text = None;
13448                        }
13449                    }
13450                }
13451            }
13452
13453            if only_carets {
13454                for selection in &mut selections {
13455                    let word_range = movement::surrounding_word(
13456                        &display_map,
13457                        selection.start.to_display_point(&display_map),
13458                    );
13459                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13460                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13461                    selection.goal = SelectionGoal::None;
13462                    selection.reversed = false;
13463                    self.select_match_ranges(
13464                        selection.start..selection.end,
13465                        selection.reversed,
13466                        action.replace_newest,
13467                        Some(Autoscroll::newest()),
13468                        window,
13469                        cx,
13470                    );
13471                }
13472                if selections.len() == 1 {
13473                    let selection = selections
13474                        .last()
13475                        .expect("ensured that there's only one selection");
13476                    let query = buffer
13477                        .text_for_range(selection.start..selection.end)
13478                        .collect::<String>();
13479                    let is_empty = query.is_empty();
13480                    let select_state = SelectNextState {
13481                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13482                        wordwise: true,
13483                        done: is_empty,
13484                    };
13485                    self.select_prev_state = Some(select_state);
13486                } else {
13487                    self.select_prev_state = None;
13488                }
13489            } else if let Some(selected_text) = selected_text {
13490                self.select_prev_state = Some(SelectNextState {
13491                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13492                    wordwise: false,
13493                    done: false,
13494                });
13495                self.select_previous(action, window, cx)?;
13496            }
13497        }
13498        Ok(())
13499    }
13500
13501    pub fn find_next_match(
13502        &mut self,
13503        _: &FindNextMatch,
13504        window: &mut Window,
13505        cx: &mut Context<Self>,
13506    ) -> Result<()> {
13507        let selections = self.selections.disjoint_anchors();
13508        match selections.first() {
13509            Some(first) if selections.len() >= 2 => {
13510                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13511                    s.select_ranges([first.range()]);
13512                });
13513            }
13514            _ => self.select_next(
13515                &SelectNext {
13516                    replace_newest: true,
13517                },
13518                window,
13519                cx,
13520            )?,
13521        }
13522        Ok(())
13523    }
13524
13525    pub fn find_previous_match(
13526        &mut self,
13527        _: &FindPreviousMatch,
13528        window: &mut Window,
13529        cx: &mut Context<Self>,
13530    ) -> Result<()> {
13531        let selections = self.selections.disjoint_anchors();
13532        match selections.last() {
13533            Some(last) if selections.len() >= 2 => {
13534                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13535                    s.select_ranges([last.range()]);
13536                });
13537            }
13538            _ => self.select_previous(
13539                &SelectPrevious {
13540                    replace_newest: true,
13541                },
13542                window,
13543                cx,
13544            )?,
13545        }
13546        Ok(())
13547    }
13548
13549    pub fn toggle_comments(
13550        &mut self,
13551        action: &ToggleComments,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        if self.read_only(cx) {
13556            return;
13557        }
13558        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13559        let text_layout_details = &self.text_layout_details(window);
13560        self.transact(window, cx, |this, window, cx| {
13561            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13562            let mut edits = Vec::new();
13563            let mut selection_edit_ranges = Vec::new();
13564            let mut last_toggled_row = None;
13565            let snapshot = this.buffer.read(cx).read(cx);
13566            let empty_str: Arc<str> = Arc::default();
13567            let mut suffixes_inserted = Vec::new();
13568            let ignore_indent = action.ignore_indent;
13569
13570            fn comment_prefix_range(
13571                snapshot: &MultiBufferSnapshot,
13572                row: MultiBufferRow,
13573                comment_prefix: &str,
13574                comment_prefix_whitespace: &str,
13575                ignore_indent: bool,
13576            ) -> Range<Point> {
13577                let indent_size = if ignore_indent {
13578                    0
13579                } else {
13580                    snapshot.indent_size_for_line(row).len
13581                };
13582
13583                let start = Point::new(row.0, indent_size);
13584
13585                let mut line_bytes = snapshot
13586                    .bytes_in_range(start..snapshot.max_point())
13587                    .flatten()
13588                    .copied();
13589
13590                // If this line currently begins with the line comment prefix, then record
13591                // the range containing the prefix.
13592                if line_bytes
13593                    .by_ref()
13594                    .take(comment_prefix.len())
13595                    .eq(comment_prefix.bytes())
13596                {
13597                    // Include any whitespace that matches the comment prefix.
13598                    let matching_whitespace_len = line_bytes
13599                        .zip(comment_prefix_whitespace.bytes())
13600                        .take_while(|(a, b)| a == b)
13601                        .count() as u32;
13602                    let end = Point::new(
13603                        start.row,
13604                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13605                    );
13606                    start..end
13607                } else {
13608                    start..start
13609                }
13610            }
13611
13612            fn comment_suffix_range(
13613                snapshot: &MultiBufferSnapshot,
13614                row: MultiBufferRow,
13615                comment_suffix: &str,
13616                comment_suffix_has_leading_space: bool,
13617            ) -> Range<Point> {
13618                let end = Point::new(row.0, snapshot.line_len(row));
13619                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13620
13621                let mut line_end_bytes = snapshot
13622                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13623                    .flatten()
13624                    .copied();
13625
13626                let leading_space_len = if suffix_start_column > 0
13627                    && line_end_bytes.next() == Some(b' ')
13628                    && comment_suffix_has_leading_space
13629                {
13630                    1
13631                } else {
13632                    0
13633                };
13634
13635                // If this line currently begins with the line comment prefix, then record
13636                // the range containing the prefix.
13637                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13638                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13639                    start..end
13640                } else {
13641                    end..end
13642                }
13643            }
13644
13645            // TODO: Handle selections that cross excerpts
13646            for selection in &mut selections {
13647                let start_column = snapshot
13648                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13649                    .len;
13650                let language = if let Some(language) =
13651                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13652                {
13653                    language
13654                } else {
13655                    continue;
13656                };
13657
13658                selection_edit_ranges.clear();
13659
13660                // If multiple selections contain a given row, avoid processing that
13661                // row more than once.
13662                let mut start_row = MultiBufferRow(selection.start.row);
13663                if last_toggled_row == Some(start_row) {
13664                    start_row = start_row.next_row();
13665                }
13666                let end_row =
13667                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13668                        MultiBufferRow(selection.end.row - 1)
13669                    } else {
13670                        MultiBufferRow(selection.end.row)
13671                    };
13672                last_toggled_row = Some(end_row);
13673
13674                if start_row > end_row {
13675                    continue;
13676                }
13677
13678                // If the language has line comments, toggle those.
13679                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13680
13681                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13682                if ignore_indent {
13683                    full_comment_prefixes = full_comment_prefixes
13684                        .into_iter()
13685                        .map(|s| Arc::from(s.trim_end()))
13686                        .collect();
13687                }
13688
13689                if !full_comment_prefixes.is_empty() {
13690                    let first_prefix = full_comment_prefixes
13691                        .first()
13692                        .expect("prefixes is non-empty");
13693                    let prefix_trimmed_lengths = full_comment_prefixes
13694                        .iter()
13695                        .map(|p| p.trim_end_matches(' ').len())
13696                        .collect::<SmallVec<[usize; 4]>>();
13697
13698                    let mut all_selection_lines_are_comments = true;
13699
13700                    for row in start_row.0..=end_row.0 {
13701                        let row = MultiBufferRow(row);
13702                        if start_row < end_row && snapshot.is_line_blank(row) {
13703                            continue;
13704                        }
13705
13706                        let prefix_range = full_comment_prefixes
13707                            .iter()
13708                            .zip(prefix_trimmed_lengths.iter().copied())
13709                            .map(|(prefix, trimmed_prefix_len)| {
13710                                comment_prefix_range(
13711                                    snapshot.deref(),
13712                                    row,
13713                                    &prefix[..trimmed_prefix_len],
13714                                    &prefix[trimmed_prefix_len..],
13715                                    ignore_indent,
13716                                )
13717                            })
13718                            .max_by_key(|range| range.end.column - range.start.column)
13719                            .expect("prefixes is non-empty");
13720
13721                        if prefix_range.is_empty() {
13722                            all_selection_lines_are_comments = false;
13723                        }
13724
13725                        selection_edit_ranges.push(prefix_range);
13726                    }
13727
13728                    if all_selection_lines_are_comments {
13729                        edits.extend(
13730                            selection_edit_ranges
13731                                .iter()
13732                                .cloned()
13733                                .map(|range| (range, empty_str.clone())),
13734                        );
13735                    } else {
13736                        let min_column = selection_edit_ranges
13737                            .iter()
13738                            .map(|range| range.start.column)
13739                            .min()
13740                            .unwrap_or(0);
13741                        edits.extend(selection_edit_ranges.iter().map(|range| {
13742                            let position = Point::new(range.start.row, min_column);
13743                            (position..position, first_prefix.clone())
13744                        }));
13745                    }
13746                } else if let Some((full_comment_prefix, comment_suffix)) =
13747                    language.block_comment_delimiters()
13748                {
13749                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13750                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13751                    let prefix_range = comment_prefix_range(
13752                        snapshot.deref(),
13753                        start_row,
13754                        comment_prefix,
13755                        comment_prefix_whitespace,
13756                        ignore_indent,
13757                    );
13758                    let suffix_range = comment_suffix_range(
13759                        snapshot.deref(),
13760                        end_row,
13761                        comment_suffix.trim_start_matches(' '),
13762                        comment_suffix.starts_with(' '),
13763                    );
13764
13765                    if prefix_range.is_empty() || suffix_range.is_empty() {
13766                        edits.push((
13767                            prefix_range.start..prefix_range.start,
13768                            full_comment_prefix.clone(),
13769                        ));
13770                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13771                        suffixes_inserted.push((end_row, comment_suffix.len()));
13772                    } else {
13773                        edits.push((prefix_range, empty_str.clone()));
13774                        edits.push((suffix_range, empty_str.clone()));
13775                    }
13776                } else {
13777                    continue;
13778                }
13779            }
13780
13781            drop(snapshot);
13782            this.buffer.update(cx, |buffer, cx| {
13783                buffer.edit(edits, None, cx);
13784            });
13785
13786            // Adjust selections so that they end before any comment suffixes that
13787            // were inserted.
13788            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13789            let mut selections = this.selections.all::<Point>(cx);
13790            let snapshot = this.buffer.read(cx).read(cx);
13791            for selection in &mut selections {
13792                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13793                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13794                        Ordering::Less => {
13795                            suffixes_inserted.next();
13796                            continue;
13797                        }
13798                        Ordering::Greater => break,
13799                        Ordering::Equal => {
13800                            if selection.end.column == snapshot.line_len(row) {
13801                                if selection.is_empty() {
13802                                    selection.start.column -= suffix_len as u32;
13803                                }
13804                                selection.end.column -= suffix_len as u32;
13805                            }
13806                            break;
13807                        }
13808                    }
13809                }
13810            }
13811
13812            drop(snapshot);
13813            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13814                s.select(selections)
13815            });
13816
13817            let selections = this.selections.all::<Point>(cx);
13818            let selections_on_single_row = selections.windows(2).all(|selections| {
13819                selections[0].start.row == selections[1].start.row
13820                    && selections[0].end.row == selections[1].end.row
13821                    && selections[0].start.row == selections[0].end.row
13822            });
13823            let selections_selecting = selections
13824                .iter()
13825                .any(|selection| selection.start != selection.end);
13826            let advance_downwards = action.advance_downwards
13827                && selections_on_single_row
13828                && !selections_selecting
13829                && !matches!(this.mode, EditorMode::SingleLine { .. });
13830
13831            if advance_downwards {
13832                let snapshot = this.buffer.read(cx).snapshot(cx);
13833
13834                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13835                    s.move_cursors_with(|display_snapshot, display_point, _| {
13836                        let mut point = display_point.to_point(display_snapshot);
13837                        point.row += 1;
13838                        point = snapshot.clip_point(point, Bias::Left);
13839                        let display_point = point.to_display_point(display_snapshot);
13840                        let goal = SelectionGoal::HorizontalPosition(
13841                            display_snapshot
13842                                .x_for_display_point(display_point, text_layout_details)
13843                                .into(),
13844                        );
13845                        (display_point, goal)
13846                    })
13847                });
13848            }
13849        });
13850    }
13851
13852    pub fn select_enclosing_symbol(
13853        &mut self,
13854        _: &SelectEnclosingSymbol,
13855        window: &mut Window,
13856        cx: &mut Context<Self>,
13857    ) {
13858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13859
13860        let buffer = self.buffer.read(cx).snapshot(cx);
13861        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13862
13863        fn update_selection(
13864            selection: &Selection<usize>,
13865            buffer_snap: &MultiBufferSnapshot,
13866        ) -> Option<Selection<usize>> {
13867            let cursor = selection.head();
13868            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13869            for symbol in symbols.iter().rev() {
13870                let start = symbol.range.start.to_offset(buffer_snap);
13871                let end = symbol.range.end.to_offset(buffer_snap);
13872                let new_range = start..end;
13873                if start < selection.start || end > selection.end {
13874                    return Some(Selection {
13875                        id: selection.id,
13876                        start: new_range.start,
13877                        end: new_range.end,
13878                        goal: SelectionGoal::None,
13879                        reversed: selection.reversed,
13880                    });
13881                }
13882            }
13883            None
13884        }
13885
13886        let mut selected_larger_symbol = false;
13887        let new_selections = old_selections
13888            .iter()
13889            .map(|selection| match update_selection(selection, &buffer) {
13890                Some(new_selection) => {
13891                    if new_selection.range() != selection.range() {
13892                        selected_larger_symbol = true;
13893                    }
13894                    new_selection
13895                }
13896                None => selection.clone(),
13897            })
13898            .collect::<Vec<_>>();
13899
13900        if selected_larger_symbol {
13901            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13902                s.select(new_selections);
13903            });
13904        }
13905    }
13906
13907    pub fn select_larger_syntax_node(
13908        &mut self,
13909        _: &SelectLargerSyntaxNode,
13910        window: &mut Window,
13911        cx: &mut Context<Self>,
13912    ) {
13913        let Some(visible_row_count) = self.visible_row_count() else {
13914            return;
13915        };
13916        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13917        if old_selections.is_empty() {
13918            return;
13919        }
13920
13921        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13922
13923        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13924        let buffer = self.buffer.read(cx).snapshot(cx);
13925
13926        let mut selected_larger_node = false;
13927        let mut new_selections = old_selections
13928            .iter()
13929            .map(|selection| {
13930                let old_range = selection.start..selection.end;
13931
13932                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13933                    // manually select word at selection
13934                    if ["string_content", "inline"].contains(&node.kind()) {
13935                        let word_range = {
13936                            let display_point = buffer
13937                                .offset_to_point(old_range.start)
13938                                .to_display_point(&display_map);
13939                            let Range { start, end } =
13940                                movement::surrounding_word(&display_map, display_point);
13941                            start.to_point(&display_map).to_offset(&buffer)
13942                                ..end.to_point(&display_map).to_offset(&buffer)
13943                        };
13944                        // ignore if word is already selected
13945                        if !word_range.is_empty() && old_range != word_range {
13946                            let last_word_range = {
13947                                let display_point = buffer
13948                                    .offset_to_point(old_range.end)
13949                                    .to_display_point(&display_map);
13950                                let Range { start, end } =
13951                                    movement::surrounding_word(&display_map, display_point);
13952                                start.to_point(&display_map).to_offset(&buffer)
13953                                    ..end.to_point(&display_map).to_offset(&buffer)
13954                            };
13955                            // only select word if start and end point belongs to same word
13956                            if word_range == last_word_range {
13957                                selected_larger_node = true;
13958                                return Selection {
13959                                    id: selection.id,
13960                                    start: word_range.start,
13961                                    end: word_range.end,
13962                                    goal: SelectionGoal::None,
13963                                    reversed: selection.reversed,
13964                                };
13965                            }
13966                        }
13967                    }
13968                }
13969
13970                let mut new_range = old_range.clone();
13971                while let Some((_node, containing_range)) =
13972                    buffer.syntax_ancestor(new_range.clone())
13973                {
13974                    new_range = match containing_range {
13975                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13976                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13977                    };
13978                    if !display_map.intersects_fold(new_range.start)
13979                        && !display_map.intersects_fold(new_range.end)
13980                    {
13981                        break;
13982                    }
13983                }
13984
13985                selected_larger_node |= new_range != old_range;
13986                Selection {
13987                    id: selection.id,
13988                    start: new_range.start,
13989                    end: new_range.end,
13990                    goal: SelectionGoal::None,
13991                    reversed: selection.reversed,
13992                }
13993            })
13994            .collect::<Vec<_>>();
13995
13996        if !selected_larger_node {
13997            return; // don't put this call in the history
13998        }
13999
14000        // scroll based on transformation done to the last selection created by the user
14001        let (last_old, last_new) = old_selections
14002            .last()
14003            .zip(new_selections.last().cloned())
14004            .expect("old_selections isn't empty");
14005
14006        // revert selection
14007        let is_selection_reversed = {
14008            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14009            new_selections.last_mut().expect("checked above").reversed =
14010                should_newest_selection_be_reversed;
14011            should_newest_selection_be_reversed
14012        };
14013
14014        if selected_larger_node {
14015            self.select_syntax_node_history.disable_clearing = true;
14016            self.change_selections(None, window, cx, |s| {
14017                s.select(new_selections.clone());
14018            });
14019            self.select_syntax_node_history.disable_clearing = false;
14020        }
14021
14022        let start_row = last_new.start.to_display_point(&display_map).row().0;
14023        let end_row = last_new.end.to_display_point(&display_map).row().0;
14024        let selection_height = end_row - start_row + 1;
14025        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14026
14027        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14028        let scroll_behavior = if fits_on_the_screen {
14029            self.request_autoscroll(Autoscroll::fit(), cx);
14030            SelectSyntaxNodeScrollBehavior::FitSelection
14031        } else if is_selection_reversed {
14032            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14033            SelectSyntaxNodeScrollBehavior::CursorTop
14034        } else {
14035            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14036            SelectSyntaxNodeScrollBehavior::CursorBottom
14037        };
14038
14039        self.select_syntax_node_history.push((
14040            old_selections,
14041            scroll_behavior,
14042            is_selection_reversed,
14043        ));
14044    }
14045
14046    pub fn select_smaller_syntax_node(
14047        &mut self,
14048        _: &SelectSmallerSyntaxNode,
14049        window: &mut Window,
14050        cx: &mut Context<Self>,
14051    ) {
14052        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14053
14054        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14055            self.select_syntax_node_history.pop()
14056        {
14057            if let Some(selection) = selections.last_mut() {
14058                selection.reversed = is_selection_reversed;
14059            }
14060
14061            self.select_syntax_node_history.disable_clearing = true;
14062            self.change_selections(None, window, cx, |s| {
14063                s.select(selections.to_vec());
14064            });
14065            self.select_syntax_node_history.disable_clearing = false;
14066
14067            match scroll_behavior {
14068                SelectSyntaxNodeScrollBehavior::CursorTop => {
14069                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14070                }
14071                SelectSyntaxNodeScrollBehavior::FitSelection => {
14072                    self.request_autoscroll(Autoscroll::fit(), cx);
14073                }
14074                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14075                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14076                }
14077            }
14078        }
14079    }
14080
14081    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14082        if !EditorSettings::get_global(cx).gutter.runnables {
14083            self.clear_tasks();
14084            return Task::ready(());
14085        }
14086        let project = self.project.as_ref().map(Entity::downgrade);
14087        let task_sources = self.lsp_task_sources(cx);
14088        let multi_buffer = self.buffer.downgrade();
14089        cx.spawn_in(window, async move |editor, cx| {
14090            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14091            let Some(project) = project.and_then(|p| p.upgrade()) else {
14092                return;
14093            };
14094            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14095                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14096            }) else {
14097                return;
14098            };
14099
14100            let hide_runnables = project
14101                .update(cx, |project, cx| {
14102                    // Do not display any test indicators in non-dev server remote projects.
14103                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14104                })
14105                .unwrap_or(true);
14106            if hide_runnables {
14107                return;
14108            }
14109            let new_rows =
14110                cx.background_spawn({
14111                    let snapshot = display_snapshot.clone();
14112                    async move {
14113                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14114                    }
14115                })
14116                    .await;
14117            let Ok(lsp_tasks) =
14118                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14119            else {
14120                return;
14121            };
14122            let lsp_tasks = lsp_tasks.await;
14123
14124            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14125                lsp_tasks
14126                    .into_iter()
14127                    .flat_map(|(kind, tasks)| {
14128                        tasks.into_iter().filter_map(move |(location, task)| {
14129                            Some((kind.clone(), location?, task))
14130                        })
14131                    })
14132                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14133                        let buffer = location.target.buffer;
14134                        let buffer_snapshot = buffer.read(cx).snapshot();
14135                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14136                            |(excerpt_id, snapshot, _)| {
14137                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14138                                    display_snapshot
14139                                        .buffer_snapshot
14140                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14141                                } else {
14142                                    None
14143                                }
14144                            },
14145                        );
14146                        if let Some(offset) = offset {
14147                            let task_buffer_range =
14148                                location.target.range.to_point(&buffer_snapshot);
14149                            let context_buffer_range =
14150                                task_buffer_range.to_offset(&buffer_snapshot);
14151                            let context_range = BufferOffset(context_buffer_range.start)
14152                                ..BufferOffset(context_buffer_range.end);
14153
14154                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14155                                .or_insert_with(|| RunnableTasks {
14156                                    templates: Vec::new(),
14157                                    offset,
14158                                    column: task_buffer_range.start.column,
14159                                    extra_variables: HashMap::default(),
14160                                    context_range,
14161                                })
14162                                .templates
14163                                .push((kind, task.original_task().clone()));
14164                        }
14165
14166                        acc
14167                    })
14168            }) else {
14169                return;
14170            };
14171
14172            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14173                buffer.language_settings(cx).tasks.prefer_lsp
14174            }) else {
14175                return;
14176            };
14177
14178            let rows = Self::runnable_rows(
14179                project,
14180                display_snapshot,
14181                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14182                new_rows,
14183                cx.clone(),
14184            )
14185            .await;
14186            editor
14187                .update(cx, |editor, _| {
14188                    editor.clear_tasks();
14189                    for (key, mut value) in rows {
14190                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14191                            value.templates.extend(lsp_tasks.templates);
14192                        }
14193
14194                        editor.insert_tasks(key, value);
14195                    }
14196                    for (key, value) in lsp_tasks_by_rows {
14197                        editor.insert_tasks(key, value);
14198                    }
14199                })
14200                .ok();
14201        })
14202    }
14203    fn fetch_runnable_ranges(
14204        snapshot: &DisplaySnapshot,
14205        range: Range<Anchor>,
14206    ) -> Vec<language::RunnableRange> {
14207        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14208    }
14209
14210    fn runnable_rows(
14211        project: Entity<Project>,
14212        snapshot: DisplaySnapshot,
14213        prefer_lsp: bool,
14214        runnable_ranges: Vec<RunnableRange>,
14215        cx: AsyncWindowContext,
14216    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14217        cx.spawn(async move |cx| {
14218            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14219            for mut runnable in runnable_ranges {
14220                let Some(tasks) = cx
14221                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14222                    .ok()
14223                else {
14224                    continue;
14225                };
14226                let mut tasks = tasks.await;
14227
14228                if prefer_lsp {
14229                    tasks.retain(|(task_kind, _)| {
14230                        !matches!(task_kind, TaskSourceKind::Language { .. })
14231                    });
14232                }
14233                if tasks.is_empty() {
14234                    continue;
14235                }
14236
14237                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14238                let Some(row) = snapshot
14239                    .buffer_snapshot
14240                    .buffer_line_for_row(MultiBufferRow(point.row))
14241                    .map(|(_, range)| range.start.row)
14242                else {
14243                    continue;
14244                };
14245
14246                let context_range =
14247                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14248                runnable_rows.push((
14249                    (runnable.buffer_id, row),
14250                    RunnableTasks {
14251                        templates: tasks,
14252                        offset: snapshot
14253                            .buffer_snapshot
14254                            .anchor_before(runnable.run_range.start),
14255                        context_range,
14256                        column: point.column,
14257                        extra_variables: runnable.extra_captures,
14258                    },
14259                ));
14260            }
14261            runnable_rows
14262        })
14263    }
14264
14265    fn templates_with_tags(
14266        project: &Entity<Project>,
14267        runnable: &mut Runnable,
14268        cx: &mut App,
14269    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14270        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14271            let (worktree_id, file) = project
14272                .buffer_for_id(runnable.buffer, cx)
14273                .and_then(|buffer| buffer.read(cx).file())
14274                .map(|file| (file.worktree_id(cx), file.clone()))
14275                .unzip();
14276
14277            (
14278                project.task_store().read(cx).task_inventory().cloned(),
14279                worktree_id,
14280                file,
14281            )
14282        });
14283
14284        let tags = mem::take(&mut runnable.tags);
14285        let language = runnable.language.clone();
14286        cx.spawn(async move |cx| {
14287            let mut templates_with_tags = Vec::new();
14288            if let Some(inventory) = inventory {
14289                for RunnableTag(tag) in tags {
14290                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14291                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14292                    }) else {
14293                        return templates_with_tags;
14294                    };
14295                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14296                        move |(_, template)| {
14297                            template.tags.iter().any(|source_tag| source_tag == &tag)
14298                        },
14299                    ));
14300                }
14301            }
14302            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14303
14304            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14305                // Strongest source wins; if we have worktree tag binding, prefer that to
14306                // global and language bindings;
14307                // if we have a global binding, prefer that to language binding.
14308                let first_mismatch = templates_with_tags
14309                    .iter()
14310                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14311                if let Some(index) = first_mismatch {
14312                    templates_with_tags.truncate(index);
14313                }
14314            }
14315
14316            templates_with_tags
14317        })
14318    }
14319
14320    pub fn move_to_enclosing_bracket(
14321        &mut self,
14322        _: &MoveToEnclosingBracket,
14323        window: &mut Window,
14324        cx: &mut Context<Self>,
14325    ) {
14326        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14327        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14328            s.move_offsets_with(|snapshot, selection| {
14329                let Some(enclosing_bracket_ranges) =
14330                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14331                else {
14332                    return;
14333                };
14334
14335                let mut best_length = usize::MAX;
14336                let mut best_inside = false;
14337                let mut best_in_bracket_range = false;
14338                let mut best_destination = None;
14339                for (open, close) in enclosing_bracket_ranges {
14340                    let close = close.to_inclusive();
14341                    let length = close.end() - open.start;
14342                    let inside = selection.start >= open.end && selection.end <= *close.start();
14343                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14344                        || close.contains(&selection.head());
14345
14346                    // If best is next to a bracket and current isn't, skip
14347                    if !in_bracket_range && best_in_bracket_range {
14348                        continue;
14349                    }
14350
14351                    // Prefer smaller lengths unless best is inside and current isn't
14352                    if length > best_length && (best_inside || !inside) {
14353                        continue;
14354                    }
14355
14356                    best_length = length;
14357                    best_inside = inside;
14358                    best_in_bracket_range = in_bracket_range;
14359                    best_destination = Some(
14360                        if close.contains(&selection.start) && close.contains(&selection.end) {
14361                            if inside { open.end } else { open.start }
14362                        } else if inside {
14363                            *close.start()
14364                        } else {
14365                            *close.end()
14366                        },
14367                    );
14368                }
14369
14370                if let Some(destination) = best_destination {
14371                    selection.collapse_to(destination, SelectionGoal::None);
14372                }
14373            })
14374        });
14375    }
14376
14377    pub fn undo_selection(
14378        &mut self,
14379        _: &UndoSelection,
14380        window: &mut Window,
14381        cx: &mut Context<Self>,
14382    ) {
14383        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14384        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14385            self.selection_history.mode = SelectionHistoryMode::Undoing;
14386            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14387                this.end_selection(window, cx);
14388                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14389                    s.select_anchors(entry.selections.to_vec())
14390                });
14391            });
14392            self.selection_history.mode = SelectionHistoryMode::Normal;
14393
14394            self.select_next_state = entry.select_next_state;
14395            self.select_prev_state = entry.select_prev_state;
14396            self.add_selections_state = entry.add_selections_state;
14397        }
14398    }
14399
14400    pub fn redo_selection(
14401        &mut self,
14402        _: &RedoSelection,
14403        window: &mut Window,
14404        cx: &mut Context<Self>,
14405    ) {
14406        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14407        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14408            self.selection_history.mode = SelectionHistoryMode::Redoing;
14409            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14410                this.end_selection(window, cx);
14411                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14412                    s.select_anchors(entry.selections.to_vec())
14413                });
14414            });
14415            self.selection_history.mode = SelectionHistoryMode::Normal;
14416
14417            self.select_next_state = entry.select_next_state;
14418            self.select_prev_state = entry.select_prev_state;
14419            self.add_selections_state = entry.add_selections_state;
14420        }
14421    }
14422
14423    pub fn expand_excerpts(
14424        &mut self,
14425        action: &ExpandExcerpts,
14426        _: &mut Window,
14427        cx: &mut Context<Self>,
14428    ) {
14429        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14430    }
14431
14432    pub fn expand_excerpts_down(
14433        &mut self,
14434        action: &ExpandExcerptsDown,
14435        _: &mut Window,
14436        cx: &mut Context<Self>,
14437    ) {
14438        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14439    }
14440
14441    pub fn expand_excerpts_up(
14442        &mut self,
14443        action: &ExpandExcerptsUp,
14444        _: &mut Window,
14445        cx: &mut Context<Self>,
14446    ) {
14447        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14448    }
14449
14450    pub fn expand_excerpts_for_direction(
14451        &mut self,
14452        lines: u32,
14453        direction: ExpandExcerptDirection,
14454
14455        cx: &mut Context<Self>,
14456    ) {
14457        let selections = self.selections.disjoint_anchors();
14458
14459        let lines = if lines == 0 {
14460            EditorSettings::get_global(cx).expand_excerpt_lines
14461        } else {
14462            lines
14463        };
14464
14465        self.buffer.update(cx, |buffer, cx| {
14466            let snapshot = buffer.snapshot(cx);
14467            let mut excerpt_ids = selections
14468                .iter()
14469                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14470                .collect::<Vec<_>>();
14471            excerpt_ids.sort();
14472            excerpt_ids.dedup();
14473            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14474        })
14475    }
14476
14477    pub fn expand_excerpt(
14478        &mut self,
14479        excerpt: ExcerptId,
14480        direction: ExpandExcerptDirection,
14481        window: &mut Window,
14482        cx: &mut Context<Self>,
14483    ) {
14484        let current_scroll_position = self.scroll_position(cx);
14485        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14486        let mut should_scroll_up = false;
14487
14488        if direction == ExpandExcerptDirection::Down {
14489            let multi_buffer = self.buffer.read(cx);
14490            let snapshot = multi_buffer.snapshot(cx);
14491            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14492                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14493                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14494                        let buffer_snapshot = buffer.read(cx).snapshot();
14495                        let excerpt_end_row =
14496                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14497                        let last_row = buffer_snapshot.max_point().row;
14498                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14499                        should_scroll_up = lines_below >= lines_to_expand;
14500                    }
14501                }
14502            }
14503        }
14504
14505        self.buffer.update(cx, |buffer, cx| {
14506            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14507        });
14508
14509        if should_scroll_up {
14510            let new_scroll_position =
14511                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14512            self.set_scroll_position(new_scroll_position, window, cx);
14513        }
14514    }
14515
14516    pub fn go_to_singleton_buffer_point(
14517        &mut self,
14518        point: Point,
14519        window: &mut Window,
14520        cx: &mut Context<Self>,
14521    ) {
14522        self.go_to_singleton_buffer_range(point..point, window, cx);
14523    }
14524
14525    pub fn go_to_singleton_buffer_range(
14526        &mut self,
14527        range: Range<Point>,
14528        window: &mut Window,
14529        cx: &mut Context<Self>,
14530    ) {
14531        let multibuffer = self.buffer().read(cx);
14532        let Some(buffer) = multibuffer.as_singleton() else {
14533            return;
14534        };
14535        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14536            return;
14537        };
14538        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14539            return;
14540        };
14541        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14542            s.select_anchor_ranges([start..end])
14543        });
14544    }
14545
14546    pub fn go_to_diagnostic(
14547        &mut self,
14548        _: &GoToDiagnostic,
14549        window: &mut Window,
14550        cx: &mut Context<Self>,
14551    ) {
14552        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14553        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14554    }
14555
14556    pub fn go_to_prev_diagnostic(
14557        &mut self,
14558        _: &GoToPreviousDiagnostic,
14559        window: &mut Window,
14560        cx: &mut Context<Self>,
14561    ) {
14562        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14563        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14564    }
14565
14566    pub fn go_to_diagnostic_impl(
14567        &mut self,
14568        direction: Direction,
14569        window: &mut Window,
14570        cx: &mut Context<Self>,
14571    ) {
14572        let buffer = self.buffer.read(cx).snapshot(cx);
14573        let selection = self.selections.newest::<usize>(cx);
14574
14575        let mut active_group_id = None;
14576        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14577            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14578                active_group_id = Some(active_group.group_id);
14579            }
14580        }
14581
14582        fn filtered(
14583            snapshot: EditorSnapshot,
14584            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14585        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14586            diagnostics
14587                .filter(|entry| entry.range.start != entry.range.end)
14588                .filter(|entry| !entry.diagnostic.is_unnecessary)
14589                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14590        }
14591
14592        let snapshot = self.snapshot(window, cx);
14593        let before = filtered(
14594            snapshot.clone(),
14595            buffer
14596                .diagnostics_in_range(0..selection.start)
14597                .filter(|entry| entry.range.start <= selection.start),
14598        );
14599        let after = filtered(
14600            snapshot,
14601            buffer
14602                .diagnostics_in_range(selection.start..buffer.len())
14603                .filter(|entry| entry.range.start >= selection.start),
14604        );
14605
14606        let mut found: Option<DiagnosticEntry<usize>> = None;
14607        if direction == Direction::Prev {
14608            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14609            {
14610                for diagnostic in prev_diagnostics.into_iter().rev() {
14611                    if diagnostic.range.start != selection.start
14612                        || active_group_id
14613                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14614                    {
14615                        found = Some(diagnostic);
14616                        break 'outer;
14617                    }
14618                }
14619            }
14620        } else {
14621            for diagnostic in after.chain(before) {
14622                if diagnostic.range.start != selection.start
14623                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14624                {
14625                    found = Some(diagnostic);
14626                    break;
14627                }
14628            }
14629        }
14630        let Some(next_diagnostic) = found else {
14631            return;
14632        };
14633
14634        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14635            return;
14636        };
14637        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14638            s.select_ranges(vec![
14639                next_diagnostic.range.start..next_diagnostic.range.start,
14640            ])
14641        });
14642        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14643        self.refresh_inline_completion(false, true, window, cx);
14644    }
14645
14646    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14648        let snapshot = self.snapshot(window, cx);
14649        let selection = self.selections.newest::<Point>(cx);
14650        self.go_to_hunk_before_or_after_position(
14651            &snapshot,
14652            selection.head(),
14653            Direction::Next,
14654            window,
14655            cx,
14656        );
14657    }
14658
14659    pub fn go_to_hunk_before_or_after_position(
14660        &mut self,
14661        snapshot: &EditorSnapshot,
14662        position: Point,
14663        direction: Direction,
14664        window: &mut Window,
14665        cx: &mut Context<Editor>,
14666    ) {
14667        let row = if direction == Direction::Next {
14668            self.hunk_after_position(snapshot, position)
14669                .map(|hunk| hunk.row_range.start)
14670        } else {
14671            self.hunk_before_position(snapshot, position)
14672        };
14673
14674        if let Some(row) = row {
14675            let destination = Point::new(row.0, 0);
14676            let autoscroll = Autoscroll::center();
14677
14678            self.unfold_ranges(&[destination..destination], false, false, cx);
14679            self.change_selections(Some(autoscroll), window, cx, |s| {
14680                s.select_ranges([destination..destination]);
14681            });
14682        }
14683    }
14684
14685    fn hunk_after_position(
14686        &mut self,
14687        snapshot: &EditorSnapshot,
14688        position: Point,
14689    ) -> Option<MultiBufferDiffHunk> {
14690        snapshot
14691            .buffer_snapshot
14692            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14693            .find(|hunk| hunk.row_range.start.0 > position.row)
14694            .or_else(|| {
14695                snapshot
14696                    .buffer_snapshot
14697                    .diff_hunks_in_range(Point::zero()..position)
14698                    .find(|hunk| hunk.row_range.end.0 < position.row)
14699            })
14700    }
14701
14702    fn go_to_prev_hunk(
14703        &mut self,
14704        _: &GoToPreviousHunk,
14705        window: &mut Window,
14706        cx: &mut Context<Self>,
14707    ) {
14708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14709        let snapshot = self.snapshot(window, cx);
14710        let selection = self.selections.newest::<Point>(cx);
14711        self.go_to_hunk_before_or_after_position(
14712            &snapshot,
14713            selection.head(),
14714            Direction::Prev,
14715            window,
14716            cx,
14717        );
14718    }
14719
14720    fn hunk_before_position(
14721        &mut self,
14722        snapshot: &EditorSnapshot,
14723        position: Point,
14724    ) -> Option<MultiBufferRow> {
14725        snapshot
14726            .buffer_snapshot
14727            .diff_hunk_before(position)
14728            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14729    }
14730
14731    fn go_to_next_change(
14732        &mut self,
14733        _: &GoToNextChange,
14734        window: &mut Window,
14735        cx: &mut Context<Self>,
14736    ) {
14737        if let Some(selections) = self
14738            .change_list
14739            .next_change(1, Direction::Next)
14740            .map(|s| s.to_vec())
14741        {
14742            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14743                let map = s.display_map();
14744                s.select_display_ranges(selections.iter().map(|a| {
14745                    let point = a.to_display_point(&map);
14746                    point..point
14747                }))
14748            })
14749        }
14750    }
14751
14752    fn go_to_previous_change(
14753        &mut self,
14754        _: &GoToPreviousChange,
14755        window: &mut Window,
14756        cx: &mut Context<Self>,
14757    ) {
14758        if let Some(selections) = self
14759            .change_list
14760            .next_change(1, Direction::Prev)
14761            .map(|s| s.to_vec())
14762        {
14763            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14764                let map = s.display_map();
14765                s.select_display_ranges(selections.iter().map(|a| {
14766                    let point = a.to_display_point(&map);
14767                    point..point
14768                }))
14769            })
14770        }
14771    }
14772
14773    fn go_to_line<T: 'static>(
14774        &mut self,
14775        position: Anchor,
14776        highlight_color: Option<Hsla>,
14777        window: &mut Window,
14778        cx: &mut Context<Self>,
14779    ) {
14780        let snapshot = self.snapshot(window, cx).display_snapshot;
14781        let position = position.to_point(&snapshot.buffer_snapshot);
14782        let start = snapshot
14783            .buffer_snapshot
14784            .clip_point(Point::new(position.row, 0), Bias::Left);
14785        let end = start + Point::new(1, 0);
14786        let start = snapshot.buffer_snapshot.anchor_before(start);
14787        let end = snapshot.buffer_snapshot.anchor_before(end);
14788
14789        self.highlight_rows::<T>(
14790            start..end,
14791            highlight_color
14792                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14793            Default::default(),
14794            cx,
14795        );
14796
14797        if self.buffer.read(cx).is_singleton() {
14798            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14799        }
14800    }
14801
14802    pub fn go_to_definition(
14803        &mut self,
14804        _: &GoToDefinition,
14805        window: &mut Window,
14806        cx: &mut Context<Self>,
14807    ) -> Task<Result<Navigated>> {
14808        let definition =
14809            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14810        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14811        cx.spawn_in(window, async move |editor, cx| {
14812            if definition.await? == Navigated::Yes {
14813                return Ok(Navigated::Yes);
14814            }
14815            match fallback_strategy {
14816                GoToDefinitionFallback::None => Ok(Navigated::No),
14817                GoToDefinitionFallback::FindAllReferences => {
14818                    match editor.update_in(cx, |editor, window, cx| {
14819                        editor.find_all_references(&FindAllReferences, window, cx)
14820                    })? {
14821                        Some(references) => references.await,
14822                        None => Ok(Navigated::No),
14823                    }
14824                }
14825            }
14826        })
14827    }
14828
14829    pub fn go_to_declaration(
14830        &mut self,
14831        _: &GoToDeclaration,
14832        window: &mut Window,
14833        cx: &mut Context<Self>,
14834    ) -> Task<Result<Navigated>> {
14835        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14836    }
14837
14838    pub fn go_to_declaration_split(
14839        &mut self,
14840        _: &GoToDeclaration,
14841        window: &mut Window,
14842        cx: &mut Context<Self>,
14843    ) -> Task<Result<Navigated>> {
14844        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14845    }
14846
14847    pub fn go_to_implementation(
14848        &mut self,
14849        _: &GoToImplementation,
14850        window: &mut Window,
14851        cx: &mut Context<Self>,
14852    ) -> Task<Result<Navigated>> {
14853        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14854    }
14855
14856    pub fn go_to_implementation_split(
14857        &mut self,
14858        _: &GoToImplementationSplit,
14859        window: &mut Window,
14860        cx: &mut Context<Self>,
14861    ) -> Task<Result<Navigated>> {
14862        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14863    }
14864
14865    pub fn go_to_type_definition(
14866        &mut self,
14867        _: &GoToTypeDefinition,
14868        window: &mut Window,
14869        cx: &mut Context<Self>,
14870    ) -> Task<Result<Navigated>> {
14871        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14872    }
14873
14874    pub fn go_to_definition_split(
14875        &mut self,
14876        _: &GoToDefinitionSplit,
14877        window: &mut Window,
14878        cx: &mut Context<Self>,
14879    ) -> Task<Result<Navigated>> {
14880        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14881    }
14882
14883    pub fn go_to_type_definition_split(
14884        &mut self,
14885        _: &GoToTypeDefinitionSplit,
14886        window: &mut Window,
14887        cx: &mut Context<Self>,
14888    ) -> Task<Result<Navigated>> {
14889        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14890    }
14891
14892    fn go_to_definition_of_kind(
14893        &mut self,
14894        kind: GotoDefinitionKind,
14895        split: bool,
14896        window: &mut Window,
14897        cx: &mut Context<Self>,
14898    ) -> Task<Result<Navigated>> {
14899        let Some(provider) = self.semantics_provider.clone() else {
14900            return Task::ready(Ok(Navigated::No));
14901        };
14902        let head = self.selections.newest::<usize>(cx).head();
14903        let buffer = self.buffer.read(cx);
14904        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14905            text_anchor
14906        } else {
14907            return Task::ready(Ok(Navigated::No));
14908        };
14909
14910        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14911            return Task::ready(Ok(Navigated::No));
14912        };
14913
14914        cx.spawn_in(window, async move |editor, cx| {
14915            let definitions = definitions.await?;
14916            let navigated = editor
14917                .update_in(cx, |editor, window, cx| {
14918                    editor.navigate_to_hover_links(
14919                        Some(kind),
14920                        definitions
14921                            .into_iter()
14922                            .filter(|location| {
14923                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14924                            })
14925                            .map(HoverLink::Text)
14926                            .collect::<Vec<_>>(),
14927                        split,
14928                        window,
14929                        cx,
14930                    )
14931                })?
14932                .await?;
14933            anyhow::Ok(navigated)
14934        })
14935    }
14936
14937    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14938        let selection = self.selections.newest_anchor();
14939        let head = selection.head();
14940        let tail = selection.tail();
14941
14942        let Some((buffer, start_position)) =
14943            self.buffer.read(cx).text_anchor_for_position(head, cx)
14944        else {
14945            return;
14946        };
14947
14948        let end_position = if head != tail {
14949            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14950                return;
14951            };
14952            Some(pos)
14953        } else {
14954            None
14955        };
14956
14957        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14958            let url = if let Some(end_pos) = end_position {
14959                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14960            } else {
14961                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14962            };
14963
14964            if let Some(url) = url {
14965                editor.update(cx, |_, cx| {
14966                    cx.open_url(&url);
14967                })
14968            } else {
14969                Ok(())
14970            }
14971        });
14972
14973        url_finder.detach();
14974    }
14975
14976    pub fn open_selected_filename(
14977        &mut self,
14978        _: &OpenSelectedFilename,
14979        window: &mut Window,
14980        cx: &mut Context<Self>,
14981    ) {
14982        let Some(workspace) = self.workspace() else {
14983            return;
14984        };
14985
14986        let position = self.selections.newest_anchor().head();
14987
14988        let Some((buffer, buffer_position)) =
14989            self.buffer.read(cx).text_anchor_for_position(position, cx)
14990        else {
14991            return;
14992        };
14993
14994        let project = self.project.clone();
14995
14996        cx.spawn_in(window, async move |_, cx| {
14997            let result = find_file(&buffer, project, buffer_position, cx).await;
14998
14999            if let Some((_, path)) = result {
15000                workspace
15001                    .update_in(cx, |workspace, window, cx| {
15002                        workspace.open_resolved_path(path, window, cx)
15003                    })?
15004                    .await?;
15005            }
15006            anyhow::Ok(())
15007        })
15008        .detach();
15009    }
15010
15011    pub(crate) fn navigate_to_hover_links(
15012        &mut self,
15013        kind: Option<GotoDefinitionKind>,
15014        mut definitions: Vec<HoverLink>,
15015        split: bool,
15016        window: &mut Window,
15017        cx: &mut Context<Editor>,
15018    ) -> Task<Result<Navigated>> {
15019        // If there is one definition, just open it directly
15020        if definitions.len() == 1 {
15021            let definition = definitions.pop().unwrap();
15022
15023            enum TargetTaskResult {
15024                Location(Option<Location>),
15025                AlreadyNavigated,
15026            }
15027
15028            let target_task = match definition {
15029                HoverLink::Text(link) => {
15030                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15031                }
15032                HoverLink::InlayHint(lsp_location, server_id) => {
15033                    let computation =
15034                        self.compute_target_location(lsp_location, server_id, window, cx);
15035                    cx.background_spawn(async move {
15036                        let location = computation.await?;
15037                        Ok(TargetTaskResult::Location(location))
15038                    })
15039                }
15040                HoverLink::Url(url) => {
15041                    cx.open_url(&url);
15042                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15043                }
15044                HoverLink::File(path) => {
15045                    if let Some(workspace) = self.workspace() {
15046                        cx.spawn_in(window, async move |_, cx| {
15047                            workspace
15048                                .update_in(cx, |workspace, window, cx| {
15049                                    workspace.open_resolved_path(path, window, cx)
15050                                })?
15051                                .await
15052                                .map(|_| TargetTaskResult::AlreadyNavigated)
15053                        })
15054                    } else {
15055                        Task::ready(Ok(TargetTaskResult::Location(None)))
15056                    }
15057                }
15058            };
15059            cx.spawn_in(window, async move |editor, cx| {
15060                let target = match target_task.await.context("target resolution task")? {
15061                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15062                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15063                    TargetTaskResult::Location(Some(target)) => target,
15064                };
15065
15066                editor.update_in(cx, |editor, window, cx| {
15067                    let Some(workspace) = editor.workspace() else {
15068                        return Navigated::No;
15069                    };
15070                    let pane = workspace.read(cx).active_pane().clone();
15071
15072                    let range = target.range.to_point(target.buffer.read(cx));
15073                    let range = editor.range_for_match(&range);
15074                    let range = collapse_multiline_range(range);
15075
15076                    if !split
15077                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15078                    {
15079                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15080                    } else {
15081                        window.defer(cx, move |window, cx| {
15082                            let target_editor: Entity<Self> =
15083                                workspace.update(cx, |workspace, cx| {
15084                                    let pane = if split {
15085                                        workspace.adjacent_pane(window, cx)
15086                                    } else {
15087                                        workspace.active_pane().clone()
15088                                    };
15089
15090                                    workspace.open_project_item(
15091                                        pane,
15092                                        target.buffer.clone(),
15093                                        true,
15094                                        true,
15095                                        window,
15096                                        cx,
15097                                    )
15098                                });
15099                            target_editor.update(cx, |target_editor, cx| {
15100                                // When selecting a definition in a different buffer, disable the nav history
15101                                // to avoid creating a history entry at the previous cursor location.
15102                                pane.update(cx, |pane, _| pane.disable_history());
15103                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15104                                pane.update(cx, |pane, _| pane.enable_history());
15105                            });
15106                        });
15107                    }
15108                    Navigated::Yes
15109                })
15110            })
15111        } else if !definitions.is_empty() {
15112            cx.spawn_in(window, async move |editor, cx| {
15113                let (title, location_tasks, workspace) = editor
15114                    .update_in(cx, |editor, window, cx| {
15115                        let tab_kind = match kind {
15116                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15117                            _ => "Definitions",
15118                        };
15119                        let title = definitions
15120                            .iter()
15121                            .find_map(|definition| match definition {
15122                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15123                                    let buffer = origin.buffer.read(cx);
15124                                    format!(
15125                                        "{} for {}",
15126                                        tab_kind,
15127                                        buffer
15128                                            .text_for_range(origin.range.clone())
15129                                            .collect::<String>()
15130                                    )
15131                                }),
15132                                HoverLink::InlayHint(_, _) => None,
15133                                HoverLink::Url(_) => None,
15134                                HoverLink::File(_) => None,
15135                            })
15136                            .unwrap_or(tab_kind.to_string());
15137                        let location_tasks = definitions
15138                            .into_iter()
15139                            .map(|definition| match definition {
15140                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15141                                HoverLink::InlayHint(lsp_location, server_id) => editor
15142                                    .compute_target_location(lsp_location, server_id, window, cx),
15143                                HoverLink::Url(_) => Task::ready(Ok(None)),
15144                                HoverLink::File(_) => Task::ready(Ok(None)),
15145                            })
15146                            .collect::<Vec<_>>();
15147                        (title, location_tasks, editor.workspace().clone())
15148                    })
15149                    .context("location tasks preparation")?;
15150
15151                let locations: Vec<Location> = future::join_all(location_tasks)
15152                    .await
15153                    .into_iter()
15154                    .filter_map(|location| location.transpose())
15155                    .collect::<Result<_>>()
15156                    .context("location tasks")?;
15157
15158                if locations.is_empty() {
15159                    return Ok(Navigated::No);
15160                }
15161
15162                let Some(workspace) = workspace else {
15163                    return Ok(Navigated::No);
15164                };
15165
15166                let opened = workspace
15167                    .update_in(cx, |workspace, window, cx| {
15168                        Self::open_locations_in_multibuffer(
15169                            workspace,
15170                            locations,
15171                            title,
15172                            split,
15173                            MultibufferSelectionMode::First,
15174                            window,
15175                            cx,
15176                        )
15177                    })
15178                    .ok();
15179
15180                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15181            })
15182        } else {
15183            Task::ready(Ok(Navigated::No))
15184        }
15185    }
15186
15187    fn compute_target_location(
15188        &self,
15189        lsp_location: lsp::Location,
15190        server_id: LanguageServerId,
15191        window: &mut Window,
15192        cx: &mut Context<Self>,
15193    ) -> Task<anyhow::Result<Option<Location>>> {
15194        let Some(project) = self.project.clone() else {
15195            return Task::ready(Ok(None));
15196        };
15197
15198        cx.spawn_in(window, async move |editor, cx| {
15199            let location_task = editor.update(cx, |_, cx| {
15200                project.update(cx, |project, cx| {
15201                    let language_server_name = project
15202                        .language_server_statuses(cx)
15203                        .find(|(id, _)| server_id == *id)
15204                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15205                    language_server_name.map(|language_server_name| {
15206                        project.open_local_buffer_via_lsp(
15207                            lsp_location.uri.clone(),
15208                            server_id,
15209                            language_server_name,
15210                            cx,
15211                        )
15212                    })
15213                })
15214            })?;
15215            let location = match location_task {
15216                Some(task) => Some({
15217                    let target_buffer_handle = task.await.context("open local buffer")?;
15218                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15219                        let target_start = target_buffer
15220                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15221                        let target_end = target_buffer
15222                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15223                        target_buffer.anchor_after(target_start)
15224                            ..target_buffer.anchor_before(target_end)
15225                    })?;
15226                    Location {
15227                        buffer: target_buffer_handle,
15228                        range,
15229                    }
15230                }),
15231                None => None,
15232            };
15233            Ok(location)
15234        })
15235    }
15236
15237    pub fn find_all_references(
15238        &mut self,
15239        _: &FindAllReferences,
15240        window: &mut Window,
15241        cx: &mut Context<Self>,
15242    ) -> Option<Task<Result<Navigated>>> {
15243        let selection = self.selections.newest::<usize>(cx);
15244        let multi_buffer = self.buffer.read(cx);
15245        let head = selection.head();
15246
15247        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15248        let head_anchor = multi_buffer_snapshot.anchor_at(
15249            head,
15250            if head < selection.tail() {
15251                Bias::Right
15252            } else {
15253                Bias::Left
15254            },
15255        );
15256
15257        match self
15258            .find_all_references_task_sources
15259            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15260        {
15261            Ok(_) => {
15262                log::info!(
15263                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15264                );
15265                return None;
15266            }
15267            Err(i) => {
15268                self.find_all_references_task_sources.insert(i, head_anchor);
15269            }
15270        }
15271
15272        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15273        let workspace = self.workspace()?;
15274        let project = workspace.read(cx).project().clone();
15275        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15276        Some(cx.spawn_in(window, async move |editor, cx| {
15277            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15278                if let Ok(i) = editor
15279                    .find_all_references_task_sources
15280                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15281                {
15282                    editor.find_all_references_task_sources.remove(i);
15283                }
15284            });
15285
15286            let locations = references.await?;
15287            if locations.is_empty() {
15288                return anyhow::Ok(Navigated::No);
15289            }
15290
15291            workspace.update_in(cx, |workspace, window, cx| {
15292                let title = locations
15293                    .first()
15294                    .as_ref()
15295                    .map(|location| {
15296                        let buffer = location.buffer.read(cx);
15297                        format!(
15298                            "References to `{}`",
15299                            buffer
15300                                .text_for_range(location.range.clone())
15301                                .collect::<String>()
15302                        )
15303                    })
15304                    .unwrap();
15305                Self::open_locations_in_multibuffer(
15306                    workspace,
15307                    locations,
15308                    title,
15309                    false,
15310                    MultibufferSelectionMode::First,
15311                    window,
15312                    cx,
15313                );
15314                Navigated::Yes
15315            })
15316        }))
15317    }
15318
15319    /// Opens a multibuffer with the given project locations in it
15320    pub fn open_locations_in_multibuffer(
15321        workspace: &mut Workspace,
15322        mut locations: Vec<Location>,
15323        title: String,
15324        split: bool,
15325        multibuffer_selection_mode: MultibufferSelectionMode,
15326        window: &mut Window,
15327        cx: &mut Context<Workspace>,
15328    ) {
15329        if locations.is_empty() {
15330            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15331            return;
15332        }
15333
15334        // If there are multiple definitions, open them in a multibuffer
15335        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15336        let mut locations = locations.into_iter().peekable();
15337        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15338        let capability = workspace.project().read(cx).capability();
15339
15340        let excerpt_buffer = cx.new(|cx| {
15341            let mut multibuffer = MultiBuffer::new(capability);
15342            while let Some(location) = locations.next() {
15343                let buffer = location.buffer.read(cx);
15344                let mut ranges_for_buffer = Vec::new();
15345                let range = location.range.to_point(buffer);
15346                ranges_for_buffer.push(range.clone());
15347
15348                while let Some(next_location) = locations.peek() {
15349                    if next_location.buffer == location.buffer {
15350                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15351                        locations.next();
15352                    } else {
15353                        break;
15354                    }
15355                }
15356
15357                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15358                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15359                    PathKey::for_buffer(&location.buffer, cx),
15360                    location.buffer.clone(),
15361                    ranges_for_buffer,
15362                    DEFAULT_MULTIBUFFER_CONTEXT,
15363                    cx,
15364                );
15365                ranges.extend(new_ranges)
15366            }
15367
15368            multibuffer.with_title(title)
15369        });
15370
15371        let editor = cx.new(|cx| {
15372            Editor::for_multibuffer(
15373                excerpt_buffer,
15374                Some(workspace.project().clone()),
15375                window,
15376                cx,
15377            )
15378        });
15379        editor.update(cx, |editor, cx| {
15380            match multibuffer_selection_mode {
15381                MultibufferSelectionMode::First => {
15382                    if let Some(first_range) = ranges.first() {
15383                        editor.change_selections(None, window, cx, |selections| {
15384                            selections.clear_disjoint();
15385                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15386                        });
15387                    }
15388                    editor.highlight_background::<Self>(
15389                        &ranges,
15390                        |theme| theme.colors().editor_highlighted_line_background,
15391                        cx,
15392                    );
15393                }
15394                MultibufferSelectionMode::All => {
15395                    editor.change_selections(None, window, cx, |selections| {
15396                        selections.clear_disjoint();
15397                        selections.select_anchor_ranges(ranges);
15398                    });
15399                }
15400            }
15401            editor.register_buffers_with_language_servers(cx);
15402        });
15403
15404        let item = Box::new(editor);
15405        let item_id = item.item_id();
15406
15407        if split {
15408            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15409        } else {
15410            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15411                let (preview_item_id, preview_item_idx) =
15412                    workspace.active_pane().read_with(cx, |pane, _| {
15413                        (pane.preview_item_id(), pane.preview_item_idx())
15414                    });
15415
15416                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15417
15418                if let Some(preview_item_id) = preview_item_id {
15419                    workspace.active_pane().update(cx, |pane, cx| {
15420                        pane.remove_item(preview_item_id, false, false, window, cx);
15421                    });
15422                }
15423            } else {
15424                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15425            }
15426        }
15427        workspace.active_pane().update(cx, |pane, cx| {
15428            pane.set_preview_item_id(Some(item_id), cx);
15429        });
15430    }
15431
15432    pub fn rename(
15433        &mut self,
15434        _: &Rename,
15435        window: &mut Window,
15436        cx: &mut Context<Self>,
15437    ) -> Option<Task<Result<()>>> {
15438        use language::ToOffset as _;
15439
15440        let provider = self.semantics_provider.clone()?;
15441        let selection = self.selections.newest_anchor().clone();
15442        let (cursor_buffer, cursor_buffer_position) = self
15443            .buffer
15444            .read(cx)
15445            .text_anchor_for_position(selection.head(), cx)?;
15446        let (tail_buffer, cursor_buffer_position_end) = self
15447            .buffer
15448            .read(cx)
15449            .text_anchor_for_position(selection.tail(), cx)?;
15450        if tail_buffer != cursor_buffer {
15451            return None;
15452        }
15453
15454        let snapshot = cursor_buffer.read(cx).snapshot();
15455        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15456        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15457        let prepare_rename = provider
15458            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15459            .unwrap_or_else(|| Task::ready(Ok(None)));
15460        drop(snapshot);
15461
15462        Some(cx.spawn_in(window, async move |this, cx| {
15463            let rename_range = if let Some(range) = prepare_rename.await? {
15464                Some(range)
15465            } else {
15466                this.update(cx, |this, cx| {
15467                    let buffer = this.buffer.read(cx).snapshot(cx);
15468                    let mut buffer_highlights = this
15469                        .document_highlights_for_position(selection.head(), &buffer)
15470                        .filter(|highlight| {
15471                            highlight.start.excerpt_id == selection.head().excerpt_id
15472                                && highlight.end.excerpt_id == selection.head().excerpt_id
15473                        });
15474                    buffer_highlights
15475                        .next()
15476                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15477                })?
15478            };
15479            if let Some(rename_range) = rename_range {
15480                this.update_in(cx, |this, window, cx| {
15481                    let snapshot = cursor_buffer.read(cx).snapshot();
15482                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15483                    let cursor_offset_in_rename_range =
15484                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15485                    let cursor_offset_in_rename_range_end =
15486                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15487
15488                    this.take_rename(false, window, cx);
15489                    let buffer = this.buffer.read(cx).read(cx);
15490                    let cursor_offset = selection.head().to_offset(&buffer);
15491                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15492                    let rename_end = rename_start + rename_buffer_range.len();
15493                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15494                    let mut old_highlight_id = None;
15495                    let old_name: Arc<str> = buffer
15496                        .chunks(rename_start..rename_end, true)
15497                        .map(|chunk| {
15498                            if old_highlight_id.is_none() {
15499                                old_highlight_id = chunk.syntax_highlight_id;
15500                            }
15501                            chunk.text
15502                        })
15503                        .collect::<String>()
15504                        .into();
15505
15506                    drop(buffer);
15507
15508                    // Position the selection in the rename editor so that it matches the current selection.
15509                    this.show_local_selections = false;
15510                    let rename_editor = cx.new(|cx| {
15511                        let mut editor = Editor::single_line(window, cx);
15512                        editor.buffer.update(cx, |buffer, cx| {
15513                            buffer.edit([(0..0, old_name.clone())], None, cx)
15514                        });
15515                        let rename_selection_range = match cursor_offset_in_rename_range
15516                            .cmp(&cursor_offset_in_rename_range_end)
15517                        {
15518                            Ordering::Equal => {
15519                                editor.select_all(&SelectAll, window, cx);
15520                                return editor;
15521                            }
15522                            Ordering::Less => {
15523                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15524                            }
15525                            Ordering::Greater => {
15526                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15527                            }
15528                        };
15529                        if rename_selection_range.end > old_name.len() {
15530                            editor.select_all(&SelectAll, window, cx);
15531                        } else {
15532                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15533                                s.select_ranges([rename_selection_range]);
15534                            });
15535                        }
15536                        editor
15537                    });
15538                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15539                        if e == &EditorEvent::Focused {
15540                            cx.emit(EditorEvent::FocusedIn)
15541                        }
15542                    })
15543                    .detach();
15544
15545                    let write_highlights = this
15546                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
15547                        .unwrap_or_default();
15548                    let read_highlights = this
15549                        .clear_background_highlights::<DocumentHighlightRead>(cx)
15550                        .unwrap_or_default();
15551                    let ranges = write_highlights
15552                        .iter()
15553                        .chain(read_highlights.iter())
15554                        .cloned()
15555                        .map(|highlight| {
15556                            (
15557                                highlight.range,
15558                                HighlightStyle {
15559                                    fade_out: Some(0.6),
15560                                    ..Default::default()
15561                                },
15562                            )
15563                        })
15564                        .collect();
15565
15566                    this.highlight_text::<Rename>(ranges, cx);
15567                    let rename_focus_handle = rename_editor.focus_handle(cx);
15568                    window.focus(&rename_focus_handle);
15569                    let block_id = this.insert_blocks(
15570                        [BlockProperties {
15571                            style: BlockStyle::Flex,
15572                            placement: BlockPlacement::Below(range.start),
15573                            height: Some(1),
15574                            render: Arc::new({
15575                                let rename_editor = rename_editor.clone();
15576                                move |cx: &mut BlockContext| {
15577                                    let mut text_style = cx.editor_style.text.clone();
15578                                    if let Some(highlight_style) = old_highlight_id
15579                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15580                                    {
15581                                        text_style = text_style.highlight(highlight_style);
15582                                    }
15583                                    div()
15584                                        .block_mouse_except_scroll()
15585                                        .pl(cx.anchor_x)
15586                                        .child(EditorElement::new(
15587                                            &rename_editor,
15588                                            EditorStyle {
15589                                                background: cx.theme().system().transparent,
15590                                                local_player: cx.editor_style.local_player,
15591                                                text: text_style,
15592                                                scrollbar_width: cx.editor_style.scrollbar_width,
15593                                                syntax: cx.editor_style.syntax.clone(),
15594                                                status: cx.editor_style.status.clone(),
15595                                                inlay_hints_style: HighlightStyle {
15596                                                    font_weight: Some(FontWeight::BOLD),
15597                                                    ..make_inlay_hints_style(cx.app)
15598                                                },
15599                                                inline_completion_styles: make_suggestion_styles(
15600                                                    cx.app,
15601                                                ),
15602                                                ..EditorStyle::default()
15603                                            },
15604                                        ))
15605                                        .into_any_element()
15606                                }
15607                            }),
15608                            priority: 0,
15609                            render_in_minimap: true,
15610                        }],
15611                        Some(Autoscroll::fit()),
15612                        cx,
15613                    )[0];
15614                    this.pending_rename = Some(RenameState {
15615                        range,
15616                        old_name,
15617                        editor: rename_editor,
15618                        block_id,
15619                    });
15620                })?;
15621            }
15622
15623            Ok(())
15624        }))
15625    }
15626
15627    pub fn confirm_rename(
15628        &mut self,
15629        _: &ConfirmRename,
15630        window: &mut Window,
15631        cx: &mut Context<Self>,
15632    ) -> Option<Task<Result<()>>> {
15633        let rename = self.take_rename(false, window, cx)?;
15634        let workspace = self.workspace()?.downgrade();
15635        let (buffer, start) = self
15636            .buffer
15637            .read(cx)
15638            .text_anchor_for_position(rename.range.start, cx)?;
15639        let (end_buffer, _) = self
15640            .buffer
15641            .read(cx)
15642            .text_anchor_for_position(rename.range.end, cx)?;
15643        if buffer != end_buffer {
15644            return None;
15645        }
15646
15647        let old_name = rename.old_name;
15648        let new_name = rename.editor.read(cx).text(cx);
15649
15650        let rename = self.semantics_provider.as_ref()?.perform_rename(
15651            &buffer,
15652            start,
15653            new_name.clone(),
15654            cx,
15655        )?;
15656
15657        Some(cx.spawn_in(window, async move |editor, cx| {
15658            let project_transaction = rename.await?;
15659            Self::open_project_transaction(
15660                &editor,
15661                workspace,
15662                project_transaction,
15663                format!("Rename: {}{}", old_name, new_name),
15664                cx,
15665            )
15666            .await?;
15667
15668            editor.update(cx, |editor, cx| {
15669                editor.refresh_document_highlights(cx);
15670            })?;
15671            Ok(())
15672        }))
15673    }
15674
15675    fn take_rename(
15676        &mut self,
15677        moving_cursor: bool,
15678        window: &mut Window,
15679        cx: &mut Context<Self>,
15680    ) -> Option<RenameState> {
15681        let rename = self.pending_rename.take()?;
15682        if rename.editor.focus_handle(cx).is_focused(window) {
15683            window.focus(&self.focus_handle);
15684        }
15685
15686        self.remove_blocks(
15687            [rename.block_id].into_iter().collect(),
15688            Some(Autoscroll::fit()),
15689            cx,
15690        );
15691        self.clear_highlights::<Rename>(cx);
15692        self.show_local_selections = true;
15693
15694        if moving_cursor {
15695            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15696                editor.selections.newest::<usize>(cx).head()
15697            });
15698
15699            // Update the selection to match the position of the selection inside
15700            // the rename editor.
15701            let snapshot = self.buffer.read(cx).read(cx);
15702            let rename_range = rename.range.to_offset(&snapshot);
15703            let cursor_in_editor = snapshot
15704                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15705                .min(rename_range.end);
15706            drop(snapshot);
15707
15708            self.change_selections(None, window, cx, |s| {
15709                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15710            });
15711        } else {
15712            self.refresh_document_highlights(cx);
15713        }
15714
15715        Some(rename)
15716    }
15717
15718    pub fn pending_rename(&self) -> Option<&RenameState> {
15719        self.pending_rename.as_ref()
15720    }
15721
15722    fn format(
15723        &mut self,
15724        _: &Format,
15725        window: &mut Window,
15726        cx: &mut Context<Self>,
15727    ) -> Option<Task<Result<()>>> {
15728        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15729
15730        let project = match &self.project {
15731            Some(project) => project.clone(),
15732            None => return None,
15733        };
15734
15735        Some(self.perform_format(
15736            project,
15737            FormatTrigger::Manual,
15738            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15739            window,
15740            cx,
15741        ))
15742    }
15743
15744    fn format_selections(
15745        &mut self,
15746        _: &FormatSelections,
15747        window: &mut Window,
15748        cx: &mut Context<Self>,
15749    ) -> Option<Task<Result<()>>> {
15750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15751
15752        let project = match &self.project {
15753            Some(project) => project.clone(),
15754            None => return None,
15755        };
15756
15757        let ranges = self
15758            .selections
15759            .all_adjusted(cx)
15760            .into_iter()
15761            .map(|selection| selection.range())
15762            .collect_vec();
15763
15764        Some(self.perform_format(
15765            project,
15766            FormatTrigger::Manual,
15767            FormatTarget::Ranges(ranges),
15768            window,
15769            cx,
15770        ))
15771    }
15772
15773    fn perform_format(
15774        &mut self,
15775        project: Entity<Project>,
15776        trigger: FormatTrigger,
15777        target: FormatTarget,
15778        window: &mut Window,
15779        cx: &mut Context<Self>,
15780    ) -> Task<Result<()>> {
15781        let buffer = self.buffer.clone();
15782        let (buffers, target) = match target {
15783            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
15784            FormatTarget::Ranges(selection_ranges) => {
15785                let multi_buffer = buffer.read(cx);
15786                let snapshot = multi_buffer.read(cx);
15787                let mut buffers = HashSet::default();
15788                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15789                    BTreeMap::new();
15790                for selection_range in selection_ranges {
15791                    for (buffer, buffer_range, _) in
15792                        snapshot.range_to_buffer_ranges(selection_range)
15793                    {
15794                        let buffer_id = buffer.remote_id();
15795                        let start = buffer.anchor_before(buffer_range.start);
15796                        let end = buffer.anchor_after(buffer_range.end);
15797                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15798                        buffer_id_to_ranges
15799                            .entry(buffer_id)
15800                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15801                            .or_insert_with(|| vec![start..end]);
15802                    }
15803                }
15804                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15805            }
15806        };
15807
15808        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15809        let selections_prev = transaction_id_prev
15810            .and_then(|transaction_id_prev| {
15811                // default to selections as they were after the last edit, if we have them,
15812                // instead of how they are now.
15813                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15814                // will take you back to where you made the last edit, instead of staying where you scrolled
15815                self.selection_history
15816                    .transaction(transaction_id_prev)
15817                    .map(|t| t.0.clone())
15818            })
15819            .unwrap_or_else(|| {
15820                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15821                self.selections.disjoint_anchors()
15822            });
15823
15824        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15825        let format = project.update(cx, |project, cx| {
15826            project.format(buffers, target, true, trigger, cx)
15827        });
15828
15829        cx.spawn_in(window, async move |editor, cx| {
15830            let transaction = futures::select_biased! {
15831                transaction = format.log_err().fuse() => transaction,
15832                () = timeout => {
15833                    log::warn!("timed out waiting for formatting");
15834                    None
15835                }
15836            };
15837
15838            buffer
15839                .update(cx, |buffer, cx| {
15840                    if let Some(transaction) = transaction {
15841                        if !buffer.is_singleton() {
15842                            buffer.push_transaction(&transaction.0, cx);
15843                        }
15844                    }
15845                    cx.notify();
15846                })
15847                .ok();
15848
15849            if let Some(transaction_id_now) =
15850                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15851            {
15852                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15853                if has_new_transaction {
15854                    _ = editor.update(cx, |editor, _| {
15855                        editor
15856                            .selection_history
15857                            .insert_transaction(transaction_id_now, selections_prev);
15858                    });
15859                }
15860            }
15861
15862            Ok(())
15863        })
15864    }
15865
15866    fn organize_imports(
15867        &mut self,
15868        _: &OrganizeImports,
15869        window: &mut Window,
15870        cx: &mut Context<Self>,
15871    ) -> Option<Task<Result<()>>> {
15872        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15873        let project = match &self.project {
15874            Some(project) => project.clone(),
15875            None => return None,
15876        };
15877        Some(self.perform_code_action_kind(
15878            project,
15879            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15880            window,
15881            cx,
15882        ))
15883    }
15884
15885    fn perform_code_action_kind(
15886        &mut self,
15887        project: Entity<Project>,
15888        kind: CodeActionKind,
15889        window: &mut Window,
15890        cx: &mut Context<Self>,
15891    ) -> Task<Result<()>> {
15892        let buffer = self.buffer.clone();
15893        let buffers = buffer.read(cx).all_buffers();
15894        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15895        let apply_action = project.update(cx, |project, cx| {
15896            project.apply_code_action_kind(buffers, kind, true, cx)
15897        });
15898        cx.spawn_in(window, async move |_, cx| {
15899            let transaction = futures::select_biased! {
15900                () = timeout => {
15901                    log::warn!("timed out waiting for executing code action");
15902                    None
15903                }
15904                transaction = apply_action.log_err().fuse() => transaction,
15905            };
15906            buffer
15907                .update(cx, |buffer, cx| {
15908                    // check if we need this
15909                    if let Some(transaction) = transaction {
15910                        if !buffer.is_singleton() {
15911                            buffer.push_transaction(&transaction.0, cx);
15912                        }
15913                    }
15914                    cx.notify();
15915                })
15916                .ok();
15917            Ok(())
15918        })
15919    }
15920
15921    fn restart_language_server(
15922        &mut self,
15923        _: &RestartLanguageServer,
15924        _: &mut Window,
15925        cx: &mut Context<Self>,
15926    ) {
15927        if let Some(project) = self.project.clone() {
15928            self.buffer.update(cx, |multi_buffer, cx| {
15929                project.update(cx, |project, cx| {
15930                    project.restart_language_servers_for_buffers(
15931                        multi_buffer.all_buffers().into_iter().collect(),
15932                        cx,
15933                    );
15934                });
15935            })
15936        }
15937    }
15938
15939    fn stop_language_server(
15940        &mut self,
15941        _: &StopLanguageServer,
15942        _: &mut Window,
15943        cx: &mut Context<Self>,
15944    ) {
15945        if let Some(project) = self.project.clone() {
15946            self.buffer.update(cx, |multi_buffer, cx| {
15947                project.update(cx, |project, cx| {
15948                    project.stop_language_servers_for_buffers(
15949                        multi_buffer.all_buffers().into_iter().collect(),
15950                        cx,
15951                    );
15952                    cx.emit(project::Event::RefreshInlayHints);
15953                });
15954            });
15955        }
15956    }
15957
15958    fn cancel_language_server_work(
15959        workspace: &mut Workspace,
15960        _: &actions::CancelLanguageServerWork,
15961        _: &mut Window,
15962        cx: &mut Context<Workspace>,
15963    ) {
15964        let project = workspace.project();
15965        let buffers = workspace
15966            .active_item(cx)
15967            .and_then(|item| item.act_as::<Editor>(cx))
15968            .map_or(HashSet::default(), |editor| {
15969                editor.read(cx).buffer.read(cx).all_buffers()
15970            });
15971        project.update(cx, |project, cx| {
15972            project.cancel_language_server_work_for_buffers(buffers, cx);
15973        });
15974    }
15975
15976    fn show_character_palette(
15977        &mut self,
15978        _: &ShowCharacterPalette,
15979        window: &mut Window,
15980        _: &mut Context<Self>,
15981    ) {
15982        window.show_character_palette();
15983    }
15984
15985    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15986        if self.mode.is_minimap() {
15987            return;
15988        }
15989
15990        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15991            let buffer = self.buffer.read(cx).snapshot(cx);
15992            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15993            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15994            let is_valid = buffer
15995                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15996                .any(|entry| {
15997                    entry.diagnostic.is_primary
15998                        && !entry.range.is_empty()
15999                        && entry.range.start == primary_range_start
16000                        && entry.diagnostic.message == active_diagnostics.active_message
16001                });
16002
16003            if !is_valid {
16004                self.dismiss_diagnostics(cx);
16005            }
16006        }
16007    }
16008
16009    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16010        match &self.active_diagnostics {
16011            ActiveDiagnostic::Group(group) => Some(group),
16012            _ => None,
16013        }
16014    }
16015
16016    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16017        self.dismiss_diagnostics(cx);
16018        self.active_diagnostics = ActiveDiagnostic::All;
16019    }
16020
16021    fn activate_diagnostics(
16022        &mut self,
16023        buffer_id: BufferId,
16024        diagnostic: DiagnosticEntry<usize>,
16025        window: &mut Window,
16026        cx: &mut Context<Self>,
16027    ) {
16028        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16029            return;
16030        }
16031        self.dismiss_diagnostics(cx);
16032        let snapshot = self.snapshot(window, cx);
16033        let buffer = self.buffer.read(cx).snapshot(cx);
16034        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16035            return;
16036        };
16037
16038        let diagnostic_group = buffer
16039            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16040            .collect::<Vec<_>>();
16041
16042        let blocks =
16043            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16044
16045        let blocks = self.display_map.update(cx, |display_map, cx| {
16046            display_map.insert_blocks(blocks, cx).into_iter().collect()
16047        });
16048        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16049            active_range: buffer.anchor_before(diagnostic.range.start)
16050                ..buffer.anchor_after(diagnostic.range.end),
16051            active_message: diagnostic.diagnostic.message.clone(),
16052            group_id: diagnostic.diagnostic.group_id,
16053            blocks,
16054        });
16055        cx.notify();
16056    }
16057
16058    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16059        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16060            return;
16061        };
16062
16063        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16064        if let ActiveDiagnostic::Group(group) = prev {
16065            self.display_map.update(cx, |display_map, cx| {
16066                display_map.remove_blocks(group.blocks, cx);
16067            });
16068            cx.notify();
16069        }
16070    }
16071
16072    /// Disable inline diagnostics rendering for this editor.
16073    pub fn disable_inline_diagnostics(&mut self) {
16074        self.inline_diagnostics_enabled = false;
16075        self.inline_diagnostics_update = Task::ready(());
16076        self.inline_diagnostics.clear();
16077    }
16078
16079    pub fn diagnostics_enabled(&self) -> bool {
16080        self.mode.is_full()
16081    }
16082
16083    pub fn inline_diagnostics_enabled(&self) -> bool {
16084        self.diagnostics_enabled() && self.inline_diagnostics_enabled
16085    }
16086
16087    pub fn show_inline_diagnostics(&self) -> bool {
16088        self.show_inline_diagnostics
16089    }
16090
16091    pub fn toggle_inline_diagnostics(
16092        &mut self,
16093        _: &ToggleInlineDiagnostics,
16094        window: &mut Window,
16095        cx: &mut Context<Editor>,
16096    ) {
16097        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16098        self.refresh_inline_diagnostics(false, window, cx);
16099    }
16100
16101    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16102        self.diagnostics_max_severity = severity;
16103        self.display_map.update(cx, |display_map, _| {
16104            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16105        });
16106    }
16107
16108    pub fn toggle_diagnostics(
16109        &mut self,
16110        _: &ToggleDiagnostics,
16111        window: &mut Window,
16112        cx: &mut Context<Editor>,
16113    ) {
16114        if !self.diagnostics_enabled() {
16115            return;
16116        }
16117
16118        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16119            EditorSettings::get_global(cx)
16120                .diagnostics_max_severity
16121                .filter(|severity| severity != &DiagnosticSeverity::Off)
16122                .unwrap_or(DiagnosticSeverity::Hint)
16123        } else {
16124            DiagnosticSeverity::Off
16125        };
16126        self.set_max_diagnostics_severity(new_severity, cx);
16127        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16128            self.active_diagnostics = ActiveDiagnostic::None;
16129            self.inline_diagnostics_update = Task::ready(());
16130            self.inline_diagnostics.clear();
16131        } else {
16132            self.refresh_inline_diagnostics(false, window, cx);
16133        }
16134
16135        cx.notify();
16136    }
16137
16138    pub fn toggle_minimap(
16139        &mut self,
16140        _: &ToggleMinimap,
16141        window: &mut Window,
16142        cx: &mut Context<Editor>,
16143    ) {
16144        if self.supports_minimap(cx) {
16145            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16146        }
16147    }
16148
16149    fn refresh_inline_diagnostics(
16150        &mut self,
16151        debounce: bool,
16152        window: &mut Window,
16153        cx: &mut Context<Self>,
16154    ) {
16155        let max_severity = ProjectSettings::get_global(cx)
16156            .diagnostics
16157            .inline
16158            .max_severity
16159            .unwrap_or(self.diagnostics_max_severity);
16160
16161        if !self.inline_diagnostics_enabled()
16162            || !self.show_inline_diagnostics
16163            || max_severity == DiagnosticSeverity::Off
16164        {
16165            self.inline_diagnostics_update = Task::ready(());
16166            self.inline_diagnostics.clear();
16167            return;
16168        }
16169
16170        let debounce_ms = ProjectSettings::get_global(cx)
16171            .diagnostics
16172            .inline
16173            .update_debounce_ms;
16174        let debounce = if debounce && debounce_ms > 0 {
16175            Some(Duration::from_millis(debounce_ms))
16176        } else {
16177            None
16178        };
16179        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16180            if let Some(debounce) = debounce {
16181                cx.background_executor().timer(debounce).await;
16182            }
16183            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16184                editor
16185                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16186                    .ok()
16187            }) else {
16188                return;
16189            };
16190
16191            let new_inline_diagnostics = cx
16192                .background_spawn(async move {
16193                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16194                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16195                        let message = diagnostic_entry
16196                            .diagnostic
16197                            .message
16198                            .split_once('\n')
16199                            .map(|(line, _)| line)
16200                            .map(SharedString::new)
16201                            .unwrap_or_else(|| {
16202                                SharedString::from(diagnostic_entry.diagnostic.message)
16203                            });
16204                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16205                        let (Ok(i) | Err(i)) = inline_diagnostics
16206                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16207                        inline_diagnostics.insert(
16208                            i,
16209                            (
16210                                start_anchor,
16211                                InlineDiagnostic {
16212                                    message,
16213                                    group_id: diagnostic_entry.diagnostic.group_id,
16214                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16215                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16216                                    severity: diagnostic_entry.diagnostic.severity,
16217                                },
16218                            ),
16219                        );
16220                    }
16221                    inline_diagnostics
16222                })
16223                .await;
16224
16225            editor
16226                .update(cx, |editor, cx| {
16227                    editor.inline_diagnostics = new_inline_diagnostics;
16228                    cx.notify();
16229                })
16230                .ok();
16231        });
16232    }
16233
16234    fn pull_diagnostics(
16235        &mut self,
16236        buffer_id: Option<BufferId>,
16237        window: &Window,
16238        cx: &mut Context<Self>,
16239    ) -> Option<()> {
16240        if !self.mode().is_full() {
16241            return None;
16242        }
16243        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16244            .diagnostics
16245            .lsp_pull_diagnostics;
16246        if !pull_diagnostics_settings.enabled {
16247            return None;
16248        }
16249        let project = self.project.as_ref()?.downgrade();
16250        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16251        let mut buffers = self.buffer.read(cx).all_buffers();
16252        if let Some(buffer_id) = buffer_id {
16253            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16254        }
16255
16256        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16257            cx.background_executor().timer(debounce).await;
16258
16259            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16260                buffers
16261                    .into_iter()
16262                    .filter_map(|buffer| {
16263                        project
16264                            .update(cx, |project, cx| {
16265                                project.lsp_store().update(cx, |lsp_store, cx| {
16266                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16267                                })
16268                            })
16269                            .ok()
16270                    })
16271                    .collect::<FuturesUnordered<_>>()
16272            }) else {
16273                return;
16274            };
16275
16276            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16277                match pull_task {
16278                    Ok(()) => {
16279                        if editor
16280                            .update_in(cx, |editor, window, cx| {
16281                                editor.update_diagnostics_state(window, cx);
16282                            })
16283                            .is_err()
16284                        {
16285                            return;
16286                        }
16287                    }
16288                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16289                }
16290            }
16291        });
16292
16293        Some(())
16294    }
16295
16296    pub fn set_selections_from_remote(
16297        &mut self,
16298        selections: Vec<Selection<Anchor>>,
16299        pending_selection: Option<Selection<Anchor>>,
16300        window: &mut Window,
16301        cx: &mut Context<Self>,
16302    ) {
16303        let old_cursor_position = self.selections.newest_anchor().head();
16304        self.selections.change_with(cx, |s| {
16305            s.select_anchors(selections);
16306            if let Some(pending_selection) = pending_selection {
16307                s.set_pending(pending_selection, SelectMode::Character);
16308            } else {
16309                s.clear_pending();
16310            }
16311        });
16312        self.selections_did_change(
16313            false,
16314            &old_cursor_position,
16315            SelectionEffects::default(),
16316            window,
16317            cx,
16318        );
16319    }
16320
16321    pub fn transact(
16322        &mut self,
16323        window: &mut Window,
16324        cx: &mut Context<Self>,
16325        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16326    ) -> Option<TransactionId> {
16327        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16328            this.start_transaction_at(Instant::now(), window, cx);
16329            update(this, window, cx);
16330            this.end_transaction_at(Instant::now(), cx)
16331        })
16332    }
16333
16334    pub fn start_transaction_at(
16335        &mut self,
16336        now: Instant,
16337        window: &mut Window,
16338        cx: &mut Context<Self>,
16339    ) {
16340        self.end_selection(window, cx);
16341        if let Some(tx_id) = self
16342            .buffer
16343            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16344        {
16345            self.selection_history
16346                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16347            cx.emit(EditorEvent::TransactionBegun {
16348                transaction_id: tx_id,
16349            })
16350        }
16351    }
16352
16353    pub fn end_transaction_at(
16354        &mut self,
16355        now: Instant,
16356        cx: &mut Context<Self>,
16357    ) -> Option<TransactionId> {
16358        if let Some(transaction_id) = self
16359            .buffer
16360            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16361        {
16362            if let Some((_, end_selections)) =
16363                self.selection_history.transaction_mut(transaction_id)
16364            {
16365                *end_selections = Some(self.selections.disjoint_anchors());
16366            } else {
16367                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16368            }
16369
16370            cx.emit(EditorEvent::Edited { transaction_id });
16371            Some(transaction_id)
16372        } else {
16373            None
16374        }
16375    }
16376
16377    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16378        if self.selection_mark_mode {
16379            self.change_selections(None, window, cx, |s| {
16380                s.move_with(|_, sel| {
16381                    sel.collapse_to(sel.head(), SelectionGoal::None);
16382                });
16383            })
16384        }
16385        self.selection_mark_mode = true;
16386        cx.notify();
16387    }
16388
16389    pub fn swap_selection_ends(
16390        &mut self,
16391        _: &actions::SwapSelectionEnds,
16392        window: &mut Window,
16393        cx: &mut Context<Self>,
16394    ) {
16395        self.change_selections(None, window, cx, |s| {
16396            s.move_with(|_, sel| {
16397                if sel.start != sel.end {
16398                    sel.reversed = !sel.reversed
16399                }
16400            });
16401        });
16402        self.request_autoscroll(Autoscroll::newest(), cx);
16403        cx.notify();
16404    }
16405
16406    pub fn toggle_fold(
16407        &mut self,
16408        _: &actions::ToggleFold,
16409        window: &mut Window,
16410        cx: &mut Context<Self>,
16411    ) {
16412        if self.is_singleton(cx) {
16413            let selection = self.selections.newest::<Point>(cx);
16414
16415            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16416            let range = if selection.is_empty() {
16417                let point = selection.head().to_display_point(&display_map);
16418                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16419                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16420                    .to_point(&display_map);
16421                start..end
16422            } else {
16423                selection.range()
16424            };
16425            if display_map.folds_in_range(range).next().is_some() {
16426                self.unfold_lines(&Default::default(), window, cx)
16427            } else {
16428                self.fold(&Default::default(), window, cx)
16429            }
16430        } else {
16431            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16432            let buffer_ids: HashSet<_> = self
16433                .selections
16434                .disjoint_anchor_ranges()
16435                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16436                .collect();
16437
16438            let should_unfold = buffer_ids
16439                .iter()
16440                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16441
16442            for buffer_id in buffer_ids {
16443                if should_unfold {
16444                    self.unfold_buffer(buffer_id, cx);
16445                } else {
16446                    self.fold_buffer(buffer_id, cx);
16447                }
16448            }
16449        }
16450    }
16451
16452    pub fn toggle_fold_recursive(
16453        &mut self,
16454        _: &actions::ToggleFoldRecursive,
16455        window: &mut Window,
16456        cx: &mut Context<Self>,
16457    ) {
16458        let selection = self.selections.newest::<Point>(cx);
16459
16460        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16461        let range = if selection.is_empty() {
16462            let point = selection.head().to_display_point(&display_map);
16463            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16464            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16465                .to_point(&display_map);
16466            start..end
16467        } else {
16468            selection.range()
16469        };
16470        if display_map.folds_in_range(range).next().is_some() {
16471            self.unfold_recursive(&Default::default(), window, cx)
16472        } else {
16473            self.fold_recursive(&Default::default(), window, cx)
16474        }
16475    }
16476
16477    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16478        if self.is_singleton(cx) {
16479            let mut to_fold = Vec::new();
16480            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16481            let selections = self.selections.all_adjusted(cx);
16482
16483            for selection in selections {
16484                let range = selection.range().sorted();
16485                let buffer_start_row = range.start.row;
16486
16487                if range.start.row != range.end.row {
16488                    let mut found = false;
16489                    let mut row = range.start.row;
16490                    while row <= range.end.row {
16491                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16492                        {
16493                            found = true;
16494                            row = crease.range().end.row + 1;
16495                            to_fold.push(crease);
16496                        } else {
16497                            row += 1
16498                        }
16499                    }
16500                    if found {
16501                        continue;
16502                    }
16503                }
16504
16505                for row in (0..=range.start.row).rev() {
16506                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16507                        if crease.range().end.row >= buffer_start_row {
16508                            to_fold.push(crease);
16509                            if row <= range.start.row {
16510                                break;
16511                            }
16512                        }
16513                    }
16514                }
16515            }
16516
16517            self.fold_creases(to_fold, true, window, cx);
16518        } else {
16519            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16520            let buffer_ids = self
16521                .selections
16522                .disjoint_anchor_ranges()
16523                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16524                .collect::<HashSet<_>>();
16525            for buffer_id in buffer_ids {
16526                self.fold_buffer(buffer_id, cx);
16527            }
16528        }
16529    }
16530
16531    fn fold_at_level(
16532        &mut self,
16533        fold_at: &FoldAtLevel,
16534        window: &mut Window,
16535        cx: &mut Context<Self>,
16536    ) {
16537        if !self.buffer.read(cx).is_singleton() {
16538            return;
16539        }
16540
16541        let fold_at_level = fold_at.0;
16542        let snapshot = self.buffer.read(cx).snapshot(cx);
16543        let mut to_fold = Vec::new();
16544        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16545
16546        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16547            while start_row < end_row {
16548                match self
16549                    .snapshot(window, cx)
16550                    .crease_for_buffer_row(MultiBufferRow(start_row))
16551                {
16552                    Some(crease) => {
16553                        let nested_start_row = crease.range().start.row + 1;
16554                        let nested_end_row = crease.range().end.row;
16555
16556                        if current_level < fold_at_level {
16557                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16558                        } else if current_level == fold_at_level {
16559                            to_fold.push(crease);
16560                        }
16561
16562                        start_row = nested_end_row + 1;
16563                    }
16564                    None => start_row += 1,
16565                }
16566            }
16567        }
16568
16569        self.fold_creases(to_fold, true, window, cx);
16570    }
16571
16572    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16573        if self.buffer.read(cx).is_singleton() {
16574            let mut fold_ranges = Vec::new();
16575            let snapshot = self.buffer.read(cx).snapshot(cx);
16576
16577            for row in 0..snapshot.max_row().0 {
16578                if let Some(foldable_range) = self
16579                    .snapshot(window, cx)
16580                    .crease_for_buffer_row(MultiBufferRow(row))
16581                {
16582                    fold_ranges.push(foldable_range);
16583                }
16584            }
16585
16586            self.fold_creases(fold_ranges, true, window, cx);
16587        } else {
16588            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16589                editor
16590                    .update_in(cx, |editor, _, cx| {
16591                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16592                            editor.fold_buffer(buffer_id, cx);
16593                        }
16594                    })
16595                    .ok();
16596            });
16597        }
16598    }
16599
16600    pub fn fold_function_bodies(
16601        &mut self,
16602        _: &actions::FoldFunctionBodies,
16603        window: &mut Window,
16604        cx: &mut Context<Self>,
16605    ) {
16606        let snapshot = self.buffer.read(cx).snapshot(cx);
16607
16608        let ranges = snapshot
16609            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16610            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16611            .collect::<Vec<_>>();
16612
16613        let creases = ranges
16614            .into_iter()
16615            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16616            .collect();
16617
16618        self.fold_creases(creases, true, window, cx);
16619    }
16620
16621    pub fn fold_recursive(
16622        &mut self,
16623        _: &actions::FoldRecursive,
16624        window: &mut Window,
16625        cx: &mut Context<Self>,
16626    ) {
16627        let mut to_fold = Vec::new();
16628        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16629        let selections = self.selections.all_adjusted(cx);
16630
16631        for selection in selections {
16632            let range = selection.range().sorted();
16633            let buffer_start_row = range.start.row;
16634
16635            if range.start.row != range.end.row {
16636                let mut found = false;
16637                for row in range.start.row..=range.end.row {
16638                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16639                        found = true;
16640                        to_fold.push(crease);
16641                    }
16642                }
16643                if found {
16644                    continue;
16645                }
16646            }
16647
16648            for row in (0..=range.start.row).rev() {
16649                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16650                    if crease.range().end.row >= buffer_start_row {
16651                        to_fold.push(crease);
16652                    } else {
16653                        break;
16654                    }
16655                }
16656            }
16657        }
16658
16659        self.fold_creases(to_fold, true, window, cx);
16660    }
16661
16662    pub fn fold_at(
16663        &mut self,
16664        buffer_row: MultiBufferRow,
16665        window: &mut Window,
16666        cx: &mut Context<Self>,
16667    ) {
16668        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16669
16670        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16671            let autoscroll = self
16672                .selections
16673                .all::<Point>(cx)
16674                .iter()
16675                .any(|selection| crease.range().overlaps(&selection.range()));
16676
16677            self.fold_creases(vec![crease], autoscroll, window, cx);
16678        }
16679    }
16680
16681    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16682        if self.is_singleton(cx) {
16683            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16684            let buffer = &display_map.buffer_snapshot;
16685            let selections = self.selections.all::<Point>(cx);
16686            let ranges = selections
16687                .iter()
16688                .map(|s| {
16689                    let range = s.display_range(&display_map).sorted();
16690                    let mut start = range.start.to_point(&display_map);
16691                    let mut end = range.end.to_point(&display_map);
16692                    start.column = 0;
16693                    end.column = buffer.line_len(MultiBufferRow(end.row));
16694                    start..end
16695                })
16696                .collect::<Vec<_>>();
16697
16698            self.unfold_ranges(&ranges, true, true, cx);
16699        } else {
16700            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16701            let buffer_ids = self
16702                .selections
16703                .disjoint_anchor_ranges()
16704                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16705                .collect::<HashSet<_>>();
16706            for buffer_id in buffer_ids {
16707                self.unfold_buffer(buffer_id, cx);
16708            }
16709        }
16710    }
16711
16712    pub fn unfold_recursive(
16713        &mut self,
16714        _: &UnfoldRecursive,
16715        _window: &mut Window,
16716        cx: &mut Context<Self>,
16717    ) {
16718        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16719        let selections = self.selections.all::<Point>(cx);
16720        let ranges = selections
16721            .iter()
16722            .map(|s| {
16723                let mut range = s.display_range(&display_map).sorted();
16724                *range.start.column_mut() = 0;
16725                *range.end.column_mut() = display_map.line_len(range.end.row());
16726                let start = range.start.to_point(&display_map);
16727                let end = range.end.to_point(&display_map);
16728                start..end
16729            })
16730            .collect::<Vec<_>>();
16731
16732        self.unfold_ranges(&ranges, true, true, cx);
16733    }
16734
16735    pub fn unfold_at(
16736        &mut self,
16737        buffer_row: MultiBufferRow,
16738        _window: &mut Window,
16739        cx: &mut Context<Self>,
16740    ) {
16741        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16742
16743        let intersection_range = Point::new(buffer_row.0, 0)
16744            ..Point::new(
16745                buffer_row.0,
16746                display_map.buffer_snapshot.line_len(buffer_row),
16747            );
16748
16749        let autoscroll = self
16750            .selections
16751            .all::<Point>(cx)
16752            .iter()
16753            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16754
16755        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16756    }
16757
16758    pub fn unfold_all(
16759        &mut self,
16760        _: &actions::UnfoldAll,
16761        _window: &mut Window,
16762        cx: &mut Context<Self>,
16763    ) {
16764        if self.buffer.read(cx).is_singleton() {
16765            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16766            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16767        } else {
16768            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16769                editor
16770                    .update(cx, |editor, cx| {
16771                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16772                            editor.unfold_buffer(buffer_id, cx);
16773                        }
16774                    })
16775                    .ok();
16776            });
16777        }
16778    }
16779
16780    pub fn fold_selected_ranges(
16781        &mut self,
16782        _: &FoldSelectedRanges,
16783        window: &mut Window,
16784        cx: &mut Context<Self>,
16785    ) {
16786        let selections = self.selections.all_adjusted(cx);
16787        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16788        let ranges = selections
16789            .into_iter()
16790            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16791            .collect::<Vec<_>>();
16792        self.fold_creases(ranges, true, window, cx);
16793    }
16794
16795    pub fn fold_ranges<T: ToOffset + Clone>(
16796        &mut self,
16797        ranges: Vec<Range<T>>,
16798        auto_scroll: bool,
16799        window: &mut Window,
16800        cx: &mut Context<Self>,
16801    ) {
16802        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16803        let ranges = ranges
16804            .into_iter()
16805            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16806            .collect::<Vec<_>>();
16807        self.fold_creases(ranges, auto_scroll, window, cx);
16808    }
16809
16810    pub fn fold_creases<T: ToOffset + Clone>(
16811        &mut self,
16812        creases: Vec<Crease<T>>,
16813        auto_scroll: bool,
16814        _window: &mut Window,
16815        cx: &mut Context<Self>,
16816    ) {
16817        if creases.is_empty() {
16818            return;
16819        }
16820
16821        let mut buffers_affected = HashSet::default();
16822        let multi_buffer = self.buffer().read(cx);
16823        for crease in &creases {
16824            if let Some((_, buffer, _)) =
16825                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16826            {
16827                buffers_affected.insert(buffer.read(cx).remote_id());
16828            };
16829        }
16830
16831        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16832
16833        if auto_scroll {
16834            self.request_autoscroll(Autoscroll::fit(), cx);
16835        }
16836
16837        cx.notify();
16838
16839        self.scrollbar_marker_state.dirty = true;
16840        self.folds_did_change(cx);
16841    }
16842
16843    /// Removes any folds whose ranges intersect any of the given ranges.
16844    pub fn unfold_ranges<T: ToOffset + Clone>(
16845        &mut self,
16846        ranges: &[Range<T>],
16847        inclusive: bool,
16848        auto_scroll: bool,
16849        cx: &mut Context<Self>,
16850    ) {
16851        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16852            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16853        });
16854        self.folds_did_change(cx);
16855    }
16856
16857    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16858        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16859            return;
16860        }
16861        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16862        self.display_map.update(cx, |display_map, cx| {
16863            display_map.fold_buffers([buffer_id], cx)
16864        });
16865        cx.emit(EditorEvent::BufferFoldToggled {
16866            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16867            folded: true,
16868        });
16869        cx.notify();
16870    }
16871
16872    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16873        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16874            return;
16875        }
16876        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16877        self.display_map.update(cx, |display_map, cx| {
16878            display_map.unfold_buffers([buffer_id], cx);
16879        });
16880        cx.emit(EditorEvent::BufferFoldToggled {
16881            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16882            folded: false,
16883        });
16884        cx.notify();
16885    }
16886
16887    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16888        self.display_map.read(cx).is_buffer_folded(buffer)
16889    }
16890
16891    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16892        self.display_map.read(cx).folded_buffers()
16893    }
16894
16895    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16896        self.display_map.update(cx, |display_map, cx| {
16897            display_map.disable_header_for_buffer(buffer_id, cx);
16898        });
16899        cx.notify();
16900    }
16901
16902    /// Removes any folds with the given ranges.
16903    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16904        &mut self,
16905        ranges: &[Range<T>],
16906        type_id: TypeId,
16907        auto_scroll: bool,
16908        cx: &mut Context<Self>,
16909    ) {
16910        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16911            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16912        });
16913        self.folds_did_change(cx);
16914    }
16915
16916    fn remove_folds_with<T: ToOffset + Clone>(
16917        &mut self,
16918        ranges: &[Range<T>],
16919        auto_scroll: bool,
16920        cx: &mut Context<Self>,
16921        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16922    ) {
16923        if ranges.is_empty() {
16924            return;
16925        }
16926
16927        let mut buffers_affected = HashSet::default();
16928        let multi_buffer = self.buffer().read(cx);
16929        for range in ranges {
16930            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16931                buffers_affected.insert(buffer.read(cx).remote_id());
16932            };
16933        }
16934
16935        self.display_map.update(cx, update);
16936
16937        if auto_scroll {
16938            self.request_autoscroll(Autoscroll::fit(), cx);
16939        }
16940
16941        cx.notify();
16942        self.scrollbar_marker_state.dirty = true;
16943        self.active_indent_guides_state.dirty = true;
16944    }
16945
16946    pub fn update_fold_widths(
16947        &mut self,
16948        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16949        cx: &mut Context<Self>,
16950    ) -> bool {
16951        self.display_map
16952            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16953    }
16954
16955    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16956        self.display_map.read(cx).fold_placeholder.clone()
16957    }
16958
16959    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16960        self.buffer.update(cx, |buffer, cx| {
16961            buffer.set_all_diff_hunks_expanded(cx);
16962        });
16963    }
16964
16965    pub fn expand_all_diff_hunks(
16966        &mut self,
16967        _: &ExpandAllDiffHunks,
16968        _window: &mut Window,
16969        cx: &mut Context<Self>,
16970    ) {
16971        self.buffer.update(cx, |buffer, cx| {
16972            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16973        });
16974    }
16975
16976    pub fn toggle_selected_diff_hunks(
16977        &mut self,
16978        _: &ToggleSelectedDiffHunks,
16979        _window: &mut Window,
16980        cx: &mut Context<Self>,
16981    ) {
16982        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16983        self.toggle_diff_hunks_in_ranges(ranges, cx);
16984    }
16985
16986    pub fn diff_hunks_in_ranges<'a>(
16987        &'a self,
16988        ranges: &'a [Range<Anchor>],
16989        buffer: &'a MultiBufferSnapshot,
16990    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16991        ranges.iter().flat_map(move |range| {
16992            let end_excerpt_id = range.end.excerpt_id;
16993            let range = range.to_point(buffer);
16994            let mut peek_end = range.end;
16995            if range.end.row < buffer.max_row().0 {
16996                peek_end = Point::new(range.end.row + 1, 0);
16997            }
16998            buffer
16999                .diff_hunks_in_range(range.start..peek_end)
17000                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17001        })
17002    }
17003
17004    pub fn has_stageable_diff_hunks_in_ranges(
17005        &self,
17006        ranges: &[Range<Anchor>],
17007        snapshot: &MultiBufferSnapshot,
17008    ) -> bool {
17009        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17010        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17011    }
17012
17013    pub fn toggle_staged_selected_diff_hunks(
17014        &mut self,
17015        _: &::git::ToggleStaged,
17016        _: &mut Window,
17017        cx: &mut Context<Self>,
17018    ) {
17019        let snapshot = self.buffer.read(cx).snapshot(cx);
17020        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17021        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17022        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17023    }
17024
17025    pub fn set_render_diff_hunk_controls(
17026        &mut self,
17027        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17028        cx: &mut Context<Self>,
17029    ) {
17030        self.render_diff_hunk_controls = render_diff_hunk_controls;
17031        cx.notify();
17032    }
17033
17034    pub fn stage_and_next(
17035        &mut self,
17036        _: &::git::StageAndNext,
17037        window: &mut Window,
17038        cx: &mut Context<Self>,
17039    ) {
17040        self.do_stage_or_unstage_and_next(true, window, cx);
17041    }
17042
17043    pub fn unstage_and_next(
17044        &mut self,
17045        _: &::git::UnstageAndNext,
17046        window: &mut Window,
17047        cx: &mut Context<Self>,
17048    ) {
17049        self.do_stage_or_unstage_and_next(false, window, cx);
17050    }
17051
17052    pub fn stage_or_unstage_diff_hunks(
17053        &mut self,
17054        stage: bool,
17055        ranges: Vec<Range<Anchor>>,
17056        cx: &mut Context<Self>,
17057    ) {
17058        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17059        cx.spawn(async move |this, cx| {
17060            task.await?;
17061            this.update(cx, |this, cx| {
17062                let snapshot = this.buffer.read(cx).snapshot(cx);
17063                let chunk_by = this
17064                    .diff_hunks_in_ranges(&ranges, &snapshot)
17065                    .chunk_by(|hunk| hunk.buffer_id);
17066                for (buffer_id, hunks) in &chunk_by {
17067                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17068                }
17069            })
17070        })
17071        .detach_and_log_err(cx);
17072    }
17073
17074    fn save_buffers_for_ranges_if_needed(
17075        &mut self,
17076        ranges: &[Range<Anchor>],
17077        cx: &mut Context<Editor>,
17078    ) -> Task<Result<()>> {
17079        let multibuffer = self.buffer.read(cx);
17080        let snapshot = multibuffer.read(cx);
17081        let buffer_ids: HashSet<_> = ranges
17082            .iter()
17083            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17084            .collect();
17085        drop(snapshot);
17086
17087        let mut buffers = HashSet::default();
17088        for buffer_id in buffer_ids {
17089            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17090                let buffer = buffer_entity.read(cx);
17091                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17092                {
17093                    buffers.insert(buffer_entity);
17094                }
17095            }
17096        }
17097
17098        if let Some(project) = &self.project {
17099            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17100        } else {
17101            Task::ready(Ok(()))
17102        }
17103    }
17104
17105    fn do_stage_or_unstage_and_next(
17106        &mut self,
17107        stage: bool,
17108        window: &mut Window,
17109        cx: &mut Context<Self>,
17110    ) {
17111        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17112
17113        if ranges.iter().any(|range| range.start != range.end) {
17114            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17115            return;
17116        }
17117
17118        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17119        let snapshot = self.snapshot(window, cx);
17120        let position = self.selections.newest::<Point>(cx).head();
17121        let mut row = snapshot
17122            .buffer_snapshot
17123            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17124            .find(|hunk| hunk.row_range.start.0 > position.row)
17125            .map(|hunk| hunk.row_range.start);
17126
17127        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17128        // Outside of the project diff editor, wrap around to the beginning.
17129        if !all_diff_hunks_expanded {
17130            row = row.or_else(|| {
17131                snapshot
17132                    .buffer_snapshot
17133                    .diff_hunks_in_range(Point::zero()..position)
17134                    .find(|hunk| hunk.row_range.end.0 < position.row)
17135                    .map(|hunk| hunk.row_range.start)
17136            });
17137        }
17138
17139        if let Some(row) = row {
17140            let destination = Point::new(row.0, 0);
17141            let autoscroll = Autoscroll::center();
17142
17143            self.unfold_ranges(&[destination..destination], false, false, cx);
17144            self.change_selections(Some(autoscroll), window, cx, |s| {
17145                s.select_ranges([destination..destination]);
17146            });
17147        }
17148    }
17149
17150    fn do_stage_or_unstage(
17151        &self,
17152        stage: bool,
17153        buffer_id: BufferId,
17154        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17155        cx: &mut App,
17156    ) -> Option<()> {
17157        let project = self.project.as_ref()?;
17158        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17159        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17160        let buffer_snapshot = buffer.read(cx).snapshot();
17161        let file_exists = buffer_snapshot
17162            .file()
17163            .is_some_and(|file| file.disk_state().exists());
17164        diff.update(cx, |diff, cx| {
17165            diff.stage_or_unstage_hunks(
17166                stage,
17167                &hunks
17168                    .map(|hunk| buffer_diff::DiffHunk {
17169                        buffer_range: hunk.buffer_range,
17170                        diff_base_byte_range: hunk.diff_base_byte_range,
17171                        secondary_status: hunk.secondary_status,
17172                        range: Point::zero()..Point::zero(), // unused
17173                    })
17174                    .collect::<Vec<_>>(),
17175                &buffer_snapshot,
17176                file_exists,
17177                cx,
17178            )
17179        });
17180        None
17181    }
17182
17183    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17184        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17185        self.buffer
17186            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17187    }
17188
17189    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17190        self.buffer.update(cx, |buffer, cx| {
17191            let ranges = vec![Anchor::min()..Anchor::max()];
17192            if !buffer.all_diff_hunks_expanded()
17193                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17194            {
17195                buffer.collapse_diff_hunks(ranges, cx);
17196                true
17197            } else {
17198                false
17199            }
17200        })
17201    }
17202
17203    fn toggle_diff_hunks_in_ranges(
17204        &mut self,
17205        ranges: Vec<Range<Anchor>>,
17206        cx: &mut Context<Editor>,
17207    ) {
17208        self.buffer.update(cx, |buffer, cx| {
17209            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17210            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17211        })
17212    }
17213
17214    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17215        self.buffer.update(cx, |buffer, cx| {
17216            let snapshot = buffer.snapshot(cx);
17217            let excerpt_id = range.end.excerpt_id;
17218            let point_range = range.to_point(&snapshot);
17219            let expand = !buffer.single_hunk_is_expanded(range, cx);
17220            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17221        })
17222    }
17223
17224    pub(crate) fn apply_all_diff_hunks(
17225        &mut self,
17226        _: &ApplyAllDiffHunks,
17227        window: &mut Window,
17228        cx: &mut Context<Self>,
17229    ) {
17230        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17231
17232        let buffers = self.buffer.read(cx).all_buffers();
17233        for branch_buffer in buffers {
17234            branch_buffer.update(cx, |branch_buffer, cx| {
17235                branch_buffer.merge_into_base(Vec::new(), cx);
17236            });
17237        }
17238
17239        if let Some(project) = self.project.clone() {
17240            self.save(
17241                SaveOptions {
17242                    format: true,
17243                    autosave: false,
17244                },
17245                project,
17246                window,
17247                cx,
17248            )
17249            .detach_and_log_err(cx);
17250        }
17251    }
17252
17253    pub(crate) fn apply_selected_diff_hunks(
17254        &mut self,
17255        _: &ApplyDiffHunk,
17256        window: &mut Window,
17257        cx: &mut Context<Self>,
17258    ) {
17259        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17260        let snapshot = self.snapshot(window, cx);
17261        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17262        let mut ranges_by_buffer = HashMap::default();
17263        self.transact(window, cx, |editor, _window, cx| {
17264            for hunk in hunks {
17265                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17266                    ranges_by_buffer
17267                        .entry(buffer.clone())
17268                        .or_insert_with(Vec::new)
17269                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17270                }
17271            }
17272
17273            for (buffer, ranges) in ranges_by_buffer {
17274                buffer.update(cx, |buffer, cx| {
17275                    buffer.merge_into_base(ranges, cx);
17276                });
17277            }
17278        });
17279
17280        if let Some(project) = self.project.clone() {
17281            self.save(
17282                SaveOptions {
17283                    format: true,
17284                    autosave: false,
17285                },
17286                project,
17287                window,
17288                cx,
17289            )
17290            .detach_and_log_err(cx);
17291        }
17292    }
17293
17294    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17295        if hovered != self.gutter_hovered {
17296            self.gutter_hovered = hovered;
17297            cx.notify();
17298        }
17299    }
17300
17301    pub fn insert_blocks(
17302        &mut self,
17303        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17304        autoscroll: Option<Autoscroll>,
17305        cx: &mut Context<Self>,
17306    ) -> Vec<CustomBlockId> {
17307        let blocks = self
17308            .display_map
17309            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17310        if let Some(autoscroll) = autoscroll {
17311            self.request_autoscroll(autoscroll, cx);
17312        }
17313        cx.notify();
17314        blocks
17315    }
17316
17317    pub fn resize_blocks(
17318        &mut self,
17319        heights: HashMap<CustomBlockId, u32>,
17320        autoscroll: Option<Autoscroll>,
17321        cx: &mut Context<Self>,
17322    ) {
17323        self.display_map
17324            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17325        if let Some(autoscroll) = autoscroll {
17326            self.request_autoscroll(autoscroll, cx);
17327        }
17328        cx.notify();
17329    }
17330
17331    pub fn replace_blocks(
17332        &mut self,
17333        renderers: HashMap<CustomBlockId, RenderBlock>,
17334        autoscroll: Option<Autoscroll>,
17335        cx: &mut Context<Self>,
17336    ) {
17337        self.display_map
17338            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17339        if let Some(autoscroll) = autoscroll {
17340            self.request_autoscroll(autoscroll, cx);
17341        }
17342        cx.notify();
17343    }
17344
17345    pub fn remove_blocks(
17346        &mut self,
17347        block_ids: HashSet<CustomBlockId>,
17348        autoscroll: Option<Autoscroll>,
17349        cx: &mut Context<Self>,
17350    ) {
17351        self.display_map.update(cx, |display_map, cx| {
17352            display_map.remove_blocks(block_ids, cx)
17353        });
17354        if let Some(autoscroll) = autoscroll {
17355            self.request_autoscroll(autoscroll, cx);
17356        }
17357        cx.notify();
17358    }
17359
17360    pub fn row_for_block(
17361        &self,
17362        block_id: CustomBlockId,
17363        cx: &mut Context<Self>,
17364    ) -> Option<DisplayRow> {
17365        self.display_map
17366            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17367    }
17368
17369    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17370        self.focused_block = Some(focused_block);
17371    }
17372
17373    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17374        self.focused_block.take()
17375    }
17376
17377    pub fn insert_creases(
17378        &mut self,
17379        creases: impl IntoIterator<Item = Crease<Anchor>>,
17380        cx: &mut Context<Self>,
17381    ) -> Vec<CreaseId> {
17382        self.display_map
17383            .update(cx, |map, cx| map.insert_creases(creases, cx))
17384    }
17385
17386    pub fn remove_creases(
17387        &mut self,
17388        ids: impl IntoIterator<Item = CreaseId>,
17389        cx: &mut Context<Self>,
17390    ) -> Vec<(CreaseId, Range<Anchor>)> {
17391        self.display_map
17392            .update(cx, |map, cx| map.remove_creases(ids, cx))
17393    }
17394
17395    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17396        self.display_map
17397            .update(cx, |map, cx| map.snapshot(cx))
17398            .longest_row()
17399    }
17400
17401    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17402        self.display_map
17403            .update(cx, |map, cx| map.snapshot(cx))
17404            .max_point()
17405    }
17406
17407    pub fn text(&self, cx: &App) -> String {
17408        self.buffer.read(cx).read(cx).text()
17409    }
17410
17411    pub fn is_empty(&self, cx: &App) -> bool {
17412        self.buffer.read(cx).read(cx).is_empty()
17413    }
17414
17415    pub fn text_option(&self, cx: &App) -> Option<String> {
17416        let text = self.text(cx);
17417        let text = text.trim();
17418
17419        if text.is_empty() {
17420            return None;
17421        }
17422
17423        Some(text.to_string())
17424    }
17425
17426    pub fn set_text(
17427        &mut self,
17428        text: impl Into<Arc<str>>,
17429        window: &mut Window,
17430        cx: &mut Context<Self>,
17431    ) {
17432        self.transact(window, cx, |this, _, cx| {
17433            this.buffer
17434                .read(cx)
17435                .as_singleton()
17436                .expect("you can only call set_text on editors for singleton buffers")
17437                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17438        });
17439    }
17440
17441    pub fn display_text(&self, cx: &mut App) -> String {
17442        self.display_map
17443            .update(cx, |map, cx| map.snapshot(cx))
17444            .text()
17445    }
17446
17447    fn create_minimap(
17448        &self,
17449        minimap_settings: MinimapSettings,
17450        window: &mut Window,
17451        cx: &mut Context<Self>,
17452    ) -> Option<Entity<Self>> {
17453        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17454            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17455    }
17456
17457    fn initialize_new_minimap(
17458        &self,
17459        minimap_settings: MinimapSettings,
17460        window: &mut Window,
17461        cx: &mut Context<Self>,
17462    ) -> Entity<Self> {
17463        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17464
17465        let mut minimap = Editor::new_internal(
17466            EditorMode::Minimap {
17467                parent: cx.weak_entity(),
17468            },
17469            self.buffer.clone(),
17470            self.project.clone(),
17471            Some(self.display_map.clone()),
17472            window,
17473            cx,
17474        );
17475        minimap.scroll_manager.clone_state(&self.scroll_manager);
17476        minimap.set_text_style_refinement(TextStyleRefinement {
17477            font_size: Some(MINIMAP_FONT_SIZE),
17478            font_weight: Some(MINIMAP_FONT_WEIGHT),
17479            ..Default::default()
17480        });
17481        minimap.update_minimap_configuration(minimap_settings, cx);
17482        cx.new(|_| minimap)
17483    }
17484
17485    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17486        let current_line_highlight = minimap_settings
17487            .current_line_highlight
17488            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17489        self.set_current_line_highlight(Some(current_line_highlight));
17490    }
17491
17492    pub fn minimap(&self) -> Option<&Entity<Self>> {
17493        self.minimap
17494            .as_ref()
17495            .filter(|_| self.minimap_visibility.visible())
17496    }
17497
17498    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17499        let mut wrap_guides = smallvec![];
17500
17501        if self.show_wrap_guides == Some(false) {
17502            return wrap_guides;
17503        }
17504
17505        let settings = self.buffer.read(cx).language_settings(cx);
17506        if settings.show_wrap_guides {
17507            match self.soft_wrap_mode(cx) {
17508                SoftWrap::Column(soft_wrap) => {
17509                    wrap_guides.push((soft_wrap as usize, true));
17510                }
17511                SoftWrap::Bounded(soft_wrap) => {
17512                    wrap_guides.push((soft_wrap as usize, true));
17513                }
17514                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17515            }
17516            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17517        }
17518
17519        wrap_guides
17520    }
17521
17522    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17523        let settings = self.buffer.read(cx).language_settings(cx);
17524        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17525        match mode {
17526            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17527                SoftWrap::None
17528            }
17529            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17530            language_settings::SoftWrap::PreferredLineLength => {
17531                SoftWrap::Column(settings.preferred_line_length)
17532            }
17533            language_settings::SoftWrap::Bounded => {
17534                SoftWrap::Bounded(settings.preferred_line_length)
17535            }
17536        }
17537    }
17538
17539    pub fn set_soft_wrap_mode(
17540        &mut self,
17541        mode: language_settings::SoftWrap,
17542
17543        cx: &mut Context<Self>,
17544    ) {
17545        self.soft_wrap_mode_override = Some(mode);
17546        cx.notify();
17547    }
17548
17549    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17550        self.hard_wrap = hard_wrap;
17551        cx.notify();
17552    }
17553
17554    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17555        self.text_style_refinement = Some(style);
17556    }
17557
17558    /// called by the Element so we know what style we were most recently rendered with.
17559    pub(crate) fn set_style(
17560        &mut self,
17561        style: EditorStyle,
17562        window: &mut Window,
17563        cx: &mut Context<Self>,
17564    ) {
17565        // We intentionally do not inform the display map about the minimap style
17566        // so that wrapping is not recalculated and stays consistent for the editor
17567        // and its linked minimap.
17568        if !self.mode.is_minimap() {
17569            let rem_size = window.rem_size();
17570            self.display_map.update(cx, |map, cx| {
17571                map.set_font(
17572                    style.text.font(),
17573                    style.text.font_size.to_pixels(rem_size),
17574                    cx,
17575                )
17576            });
17577        }
17578        self.style = Some(style);
17579    }
17580
17581    pub fn style(&self) -> Option<&EditorStyle> {
17582        self.style.as_ref()
17583    }
17584
17585    // Called by the element. This method is not designed to be called outside of the editor
17586    // element's layout code because it does not notify when rewrapping is computed synchronously.
17587    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17588        self.display_map
17589            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17590    }
17591
17592    pub fn set_soft_wrap(&mut self) {
17593        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17594    }
17595
17596    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17597        if self.soft_wrap_mode_override.is_some() {
17598            self.soft_wrap_mode_override.take();
17599        } else {
17600            let soft_wrap = match self.soft_wrap_mode(cx) {
17601                SoftWrap::GitDiff => return,
17602                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17603                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17604                    language_settings::SoftWrap::None
17605                }
17606            };
17607            self.soft_wrap_mode_override = Some(soft_wrap);
17608        }
17609        cx.notify();
17610    }
17611
17612    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17613        let Some(workspace) = self.workspace() else {
17614            return;
17615        };
17616        let fs = workspace.read(cx).app_state().fs.clone();
17617        let current_show = TabBarSettings::get_global(cx).show;
17618        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17619            setting.show = Some(!current_show);
17620        });
17621    }
17622
17623    pub fn toggle_indent_guides(
17624        &mut self,
17625        _: &ToggleIndentGuides,
17626        _: &mut Window,
17627        cx: &mut Context<Self>,
17628    ) {
17629        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17630            self.buffer
17631                .read(cx)
17632                .language_settings(cx)
17633                .indent_guides
17634                .enabled
17635        });
17636        self.show_indent_guides = Some(!currently_enabled);
17637        cx.notify();
17638    }
17639
17640    fn should_show_indent_guides(&self) -> Option<bool> {
17641        self.show_indent_guides
17642    }
17643
17644    pub fn toggle_line_numbers(
17645        &mut self,
17646        _: &ToggleLineNumbers,
17647        _: &mut Window,
17648        cx: &mut Context<Self>,
17649    ) {
17650        let mut editor_settings = EditorSettings::get_global(cx).clone();
17651        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17652        EditorSettings::override_global(editor_settings, cx);
17653    }
17654
17655    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17656        if let Some(show_line_numbers) = self.show_line_numbers {
17657            return show_line_numbers;
17658        }
17659        EditorSettings::get_global(cx).gutter.line_numbers
17660    }
17661
17662    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17663        self.use_relative_line_numbers
17664            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17665    }
17666
17667    pub fn toggle_relative_line_numbers(
17668        &mut self,
17669        _: &ToggleRelativeLineNumbers,
17670        _: &mut Window,
17671        cx: &mut Context<Self>,
17672    ) {
17673        let is_relative = self.should_use_relative_line_numbers(cx);
17674        self.set_relative_line_number(Some(!is_relative), cx)
17675    }
17676
17677    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17678        self.use_relative_line_numbers = is_relative;
17679        cx.notify();
17680    }
17681
17682    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17683        self.show_gutter = show_gutter;
17684        cx.notify();
17685    }
17686
17687    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17688        self.show_scrollbars = ScrollbarAxes {
17689            horizontal: show,
17690            vertical: show,
17691        };
17692        cx.notify();
17693    }
17694
17695    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17696        self.show_scrollbars.vertical = show;
17697        cx.notify();
17698    }
17699
17700    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17701        self.show_scrollbars.horizontal = show;
17702        cx.notify();
17703    }
17704
17705    pub fn set_minimap_visibility(
17706        &mut self,
17707        minimap_visibility: MinimapVisibility,
17708        window: &mut Window,
17709        cx: &mut Context<Self>,
17710    ) {
17711        if self.minimap_visibility != minimap_visibility {
17712            if minimap_visibility.visible() && self.minimap.is_none() {
17713                let minimap_settings = EditorSettings::get_global(cx).minimap;
17714                self.minimap =
17715                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17716            }
17717            self.minimap_visibility = minimap_visibility;
17718            cx.notify();
17719        }
17720    }
17721
17722    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17723        self.set_show_scrollbars(false, cx);
17724        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17725    }
17726
17727    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17728        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17729    }
17730
17731    /// Normally the text in full mode and auto height editors is padded on the
17732    /// left side by roughly half a character width for improved hit testing.
17733    ///
17734    /// Use this method to disable this for cases where this is not wanted (e.g.
17735    /// if you want to align the editor text with some other text above or below)
17736    /// or if you want to add this padding to single-line editors.
17737    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17738        self.offset_content = offset_content;
17739        cx.notify();
17740    }
17741
17742    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17743        self.show_line_numbers = Some(show_line_numbers);
17744        cx.notify();
17745    }
17746
17747    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17748        self.disable_expand_excerpt_buttons = true;
17749        cx.notify();
17750    }
17751
17752    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17753        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17754        cx.notify();
17755    }
17756
17757    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17758        self.show_code_actions = Some(show_code_actions);
17759        cx.notify();
17760    }
17761
17762    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17763        self.show_runnables = Some(show_runnables);
17764        cx.notify();
17765    }
17766
17767    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17768        self.show_breakpoints = Some(show_breakpoints);
17769        cx.notify();
17770    }
17771
17772    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17773        if self.display_map.read(cx).masked != masked {
17774            self.display_map.update(cx, |map, _| map.masked = masked);
17775        }
17776        cx.notify()
17777    }
17778
17779    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17780        self.show_wrap_guides = Some(show_wrap_guides);
17781        cx.notify();
17782    }
17783
17784    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17785        self.show_indent_guides = Some(show_indent_guides);
17786        cx.notify();
17787    }
17788
17789    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17790        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17791            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17792                if let Some(dir) = file.abs_path(cx).parent() {
17793                    return Some(dir.to_owned());
17794                }
17795            }
17796
17797            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17798                return Some(project_path.path.to_path_buf());
17799            }
17800        }
17801
17802        None
17803    }
17804
17805    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17806        self.active_excerpt(cx)?
17807            .1
17808            .read(cx)
17809            .file()
17810            .and_then(|f| f.as_local())
17811    }
17812
17813    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17814        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17815            let buffer = buffer.read(cx);
17816            if let Some(project_path) = buffer.project_path(cx) {
17817                let project = self.project.as_ref()?.read(cx);
17818                project.absolute_path(&project_path, cx)
17819            } else {
17820                buffer
17821                    .file()
17822                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17823            }
17824        })
17825    }
17826
17827    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17828        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17829            let project_path = buffer.read(cx).project_path(cx)?;
17830            let project = self.project.as_ref()?.read(cx);
17831            let entry = project.entry_for_path(&project_path, cx)?;
17832            let path = entry.path.to_path_buf();
17833            Some(path)
17834        })
17835    }
17836
17837    pub fn reveal_in_finder(
17838        &mut self,
17839        _: &RevealInFileManager,
17840        _window: &mut Window,
17841        cx: &mut Context<Self>,
17842    ) {
17843        if let Some(target) = self.target_file(cx) {
17844            cx.reveal_path(&target.abs_path(cx));
17845        }
17846    }
17847
17848    pub fn copy_path(
17849        &mut self,
17850        _: &zed_actions::workspace::CopyPath,
17851        _window: &mut Window,
17852        cx: &mut Context<Self>,
17853    ) {
17854        if let Some(path) = self.target_file_abs_path(cx) {
17855            if let Some(path) = path.to_str() {
17856                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17857            }
17858        }
17859    }
17860
17861    pub fn copy_relative_path(
17862        &mut self,
17863        _: &zed_actions::workspace::CopyRelativePath,
17864        _window: &mut Window,
17865        cx: &mut Context<Self>,
17866    ) {
17867        if let Some(path) = self.target_file_path(cx) {
17868            if let Some(path) = path.to_str() {
17869                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17870            }
17871        }
17872    }
17873
17874    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17875        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17876            buffer.read(cx).project_path(cx)
17877        } else {
17878            None
17879        }
17880    }
17881
17882    // Returns true if the editor handled a go-to-line request
17883    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17884        maybe!({
17885            let breakpoint_store = self.breakpoint_store.as_ref()?;
17886
17887            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17888            else {
17889                self.clear_row_highlights::<ActiveDebugLine>();
17890                return None;
17891            };
17892
17893            let position = active_stack_frame.position;
17894            let buffer_id = position.buffer_id?;
17895            let snapshot = self
17896                .project
17897                .as_ref()?
17898                .read(cx)
17899                .buffer_for_id(buffer_id, cx)?
17900                .read(cx)
17901                .snapshot();
17902
17903            let mut handled = false;
17904            for (id, ExcerptRange { context, .. }) in
17905                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17906            {
17907                if context.start.cmp(&position, &snapshot).is_ge()
17908                    || context.end.cmp(&position, &snapshot).is_lt()
17909                {
17910                    continue;
17911                }
17912                let snapshot = self.buffer.read(cx).snapshot(cx);
17913                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17914
17915                handled = true;
17916                self.clear_row_highlights::<ActiveDebugLine>();
17917
17918                self.go_to_line::<ActiveDebugLine>(
17919                    multibuffer_anchor,
17920                    Some(cx.theme().colors().editor_debugger_active_line_background),
17921                    window,
17922                    cx,
17923                );
17924
17925                cx.notify();
17926            }
17927
17928            handled.then_some(())
17929        })
17930        .is_some()
17931    }
17932
17933    pub fn copy_file_name_without_extension(
17934        &mut self,
17935        _: &CopyFileNameWithoutExtension,
17936        _: &mut Window,
17937        cx: &mut Context<Self>,
17938    ) {
17939        if let Some(file) = self.target_file(cx) {
17940            if let Some(file_stem) = file.path().file_stem() {
17941                if let Some(name) = file_stem.to_str() {
17942                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17943                }
17944            }
17945        }
17946    }
17947
17948    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17949        if let Some(file) = self.target_file(cx) {
17950            if let Some(file_name) = file.path().file_name() {
17951                if let Some(name) = file_name.to_str() {
17952                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17953                }
17954            }
17955        }
17956    }
17957
17958    pub fn toggle_git_blame(
17959        &mut self,
17960        _: &::git::Blame,
17961        window: &mut Window,
17962        cx: &mut Context<Self>,
17963    ) {
17964        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17965
17966        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17967            self.start_git_blame(true, window, cx);
17968        }
17969
17970        cx.notify();
17971    }
17972
17973    pub fn toggle_git_blame_inline(
17974        &mut self,
17975        _: &ToggleGitBlameInline,
17976        window: &mut Window,
17977        cx: &mut Context<Self>,
17978    ) {
17979        self.toggle_git_blame_inline_internal(true, window, cx);
17980        cx.notify();
17981    }
17982
17983    pub fn open_git_blame_commit(
17984        &mut self,
17985        _: &OpenGitBlameCommit,
17986        window: &mut Window,
17987        cx: &mut Context<Self>,
17988    ) {
17989        self.open_git_blame_commit_internal(window, cx);
17990    }
17991
17992    fn open_git_blame_commit_internal(
17993        &mut self,
17994        window: &mut Window,
17995        cx: &mut Context<Self>,
17996    ) -> Option<()> {
17997        let blame = self.blame.as_ref()?;
17998        let snapshot = self.snapshot(window, cx);
17999        let cursor = self.selections.newest::<Point>(cx).head();
18000        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18001        let blame_entry = blame
18002            .update(cx, |blame, cx| {
18003                blame
18004                    .blame_for_rows(
18005                        &[RowInfo {
18006                            buffer_id: Some(buffer.remote_id()),
18007                            buffer_row: Some(point.row),
18008                            ..Default::default()
18009                        }],
18010                        cx,
18011                    )
18012                    .next()
18013            })
18014            .flatten()?;
18015        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18016        let repo = blame.read(cx).repository(cx)?;
18017        let workspace = self.workspace()?.downgrade();
18018        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18019        None
18020    }
18021
18022    pub fn git_blame_inline_enabled(&self) -> bool {
18023        self.git_blame_inline_enabled
18024    }
18025
18026    pub fn toggle_selection_menu(
18027        &mut self,
18028        _: &ToggleSelectionMenu,
18029        _: &mut Window,
18030        cx: &mut Context<Self>,
18031    ) {
18032        self.show_selection_menu = self
18033            .show_selection_menu
18034            .map(|show_selections_menu| !show_selections_menu)
18035            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18036
18037        cx.notify();
18038    }
18039
18040    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18041        self.show_selection_menu
18042            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18043    }
18044
18045    fn start_git_blame(
18046        &mut self,
18047        user_triggered: bool,
18048        window: &mut Window,
18049        cx: &mut Context<Self>,
18050    ) {
18051        if let Some(project) = self.project.as_ref() {
18052            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18053                return;
18054            };
18055
18056            if buffer.read(cx).file().is_none() {
18057                return;
18058            }
18059
18060            let focused = self.focus_handle(cx).contains_focused(window, cx);
18061
18062            let project = project.clone();
18063            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18064            self.blame_subscription =
18065                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18066            self.blame = Some(blame);
18067        }
18068    }
18069
18070    fn toggle_git_blame_inline_internal(
18071        &mut self,
18072        user_triggered: bool,
18073        window: &mut Window,
18074        cx: &mut Context<Self>,
18075    ) {
18076        if self.git_blame_inline_enabled {
18077            self.git_blame_inline_enabled = false;
18078            self.show_git_blame_inline = false;
18079            self.show_git_blame_inline_delay_task.take();
18080        } else {
18081            self.git_blame_inline_enabled = true;
18082            self.start_git_blame_inline(user_triggered, window, cx);
18083        }
18084
18085        cx.notify();
18086    }
18087
18088    fn start_git_blame_inline(
18089        &mut self,
18090        user_triggered: bool,
18091        window: &mut Window,
18092        cx: &mut Context<Self>,
18093    ) {
18094        self.start_git_blame(user_triggered, window, cx);
18095
18096        if ProjectSettings::get_global(cx)
18097            .git
18098            .inline_blame_delay()
18099            .is_some()
18100        {
18101            self.start_inline_blame_timer(window, cx);
18102        } else {
18103            self.show_git_blame_inline = true
18104        }
18105    }
18106
18107    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18108        self.blame.as_ref()
18109    }
18110
18111    pub fn show_git_blame_gutter(&self) -> bool {
18112        self.show_git_blame_gutter
18113    }
18114
18115    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18116        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18117    }
18118
18119    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18120        self.show_git_blame_inline
18121            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18122            && !self.newest_selection_head_on_empty_line(cx)
18123            && self.has_blame_entries(cx)
18124    }
18125
18126    fn has_blame_entries(&self, cx: &App) -> bool {
18127        self.blame()
18128            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18129    }
18130
18131    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18132        let cursor_anchor = self.selections.newest_anchor().head();
18133
18134        let snapshot = self.buffer.read(cx).snapshot(cx);
18135        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18136
18137        snapshot.line_len(buffer_row) == 0
18138    }
18139
18140    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18141        let buffer_and_selection = maybe!({
18142            let selection = self.selections.newest::<Point>(cx);
18143            let selection_range = selection.range();
18144
18145            let multi_buffer = self.buffer().read(cx);
18146            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18147            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18148
18149            let (buffer, range, _) = if selection.reversed {
18150                buffer_ranges.first()
18151            } else {
18152                buffer_ranges.last()
18153            }?;
18154
18155            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18156                ..text::ToPoint::to_point(&range.end, &buffer).row;
18157            Some((
18158                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18159                selection,
18160            ))
18161        });
18162
18163        let Some((buffer, selection)) = buffer_and_selection else {
18164            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18165        };
18166
18167        let Some(project) = self.project.as_ref() else {
18168            return Task::ready(Err(anyhow!("editor does not have project")));
18169        };
18170
18171        project.update(cx, |project, cx| {
18172            project.get_permalink_to_line(&buffer, selection, cx)
18173        })
18174    }
18175
18176    pub fn copy_permalink_to_line(
18177        &mut self,
18178        _: &CopyPermalinkToLine,
18179        window: &mut Window,
18180        cx: &mut Context<Self>,
18181    ) {
18182        let permalink_task = self.get_permalink_to_line(cx);
18183        let workspace = self.workspace();
18184
18185        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18186            Ok(permalink) => {
18187                cx.update(|_, cx| {
18188                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18189                })
18190                .ok();
18191            }
18192            Err(err) => {
18193                let message = format!("Failed to copy permalink: {err}");
18194
18195                anyhow::Result::<()>::Err(err).log_err();
18196
18197                if let Some(workspace) = workspace {
18198                    workspace
18199                        .update_in(cx, |workspace, _, cx| {
18200                            struct CopyPermalinkToLine;
18201
18202                            workspace.show_toast(
18203                                Toast::new(
18204                                    NotificationId::unique::<CopyPermalinkToLine>(),
18205                                    message,
18206                                ),
18207                                cx,
18208                            )
18209                        })
18210                        .ok();
18211                }
18212            }
18213        })
18214        .detach();
18215    }
18216
18217    pub fn copy_file_location(
18218        &mut self,
18219        _: &CopyFileLocation,
18220        _: &mut Window,
18221        cx: &mut Context<Self>,
18222    ) {
18223        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18224        if let Some(file) = self.target_file(cx) {
18225            if let Some(path) = file.path().to_str() {
18226                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18227            }
18228        }
18229    }
18230
18231    pub fn open_permalink_to_line(
18232        &mut self,
18233        _: &OpenPermalinkToLine,
18234        window: &mut Window,
18235        cx: &mut Context<Self>,
18236    ) {
18237        let permalink_task = self.get_permalink_to_line(cx);
18238        let workspace = self.workspace();
18239
18240        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18241            Ok(permalink) => {
18242                cx.update(|_, cx| {
18243                    cx.open_url(permalink.as_ref());
18244                })
18245                .ok();
18246            }
18247            Err(err) => {
18248                let message = format!("Failed to open permalink: {err}");
18249
18250                anyhow::Result::<()>::Err(err).log_err();
18251
18252                if let Some(workspace) = workspace {
18253                    workspace
18254                        .update(cx, |workspace, cx| {
18255                            struct OpenPermalinkToLine;
18256
18257                            workspace.show_toast(
18258                                Toast::new(
18259                                    NotificationId::unique::<OpenPermalinkToLine>(),
18260                                    message,
18261                                ),
18262                                cx,
18263                            )
18264                        })
18265                        .ok();
18266                }
18267            }
18268        })
18269        .detach();
18270    }
18271
18272    pub fn insert_uuid_v4(
18273        &mut self,
18274        _: &InsertUuidV4,
18275        window: &mut Window,
18276        cx: &mut Context<Self>,
18277    ) {
18278        self.insert_uuid(UuidVersion::V4, window, cx);
18279    }
18280
18281    pub fn insert_uuid_v7(
18282        &mut self,
18283        _: &InsertUuidV7,
18284        window: &mut Window,
18285        cx: &mut Context<Self>,
18286    ) {
18287        self.insert_uuid(UuidVersion::V7, window, cx);
18288    }
18289
18290    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18291        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18292        self.transact(window, cx, |this, window, cx| {
18293            let edits = this
18294                .selections
18295                .all::<Point>(cx)
18296                .into_iter()
18297                .map(|selection| {
18298                    let uuid = match version {
18299                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18300                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18301                    };
18302
18303                    (selection.range(), uuid.to_string())
18304                });
18305            this.edit(edits, cx);
18306            this.refresh_inline_completion(true, false, window, cx);
18307        });
18308    }
18309
18310    pub fn open_selections_in_multibuffer(
18311        &mut self,
18312        _: &OpenSelectionsInMultibuffer,
18313        window: &mut Window,
18314        cx: &mut Context<Self>,
18315    ) {
18316        let multibuffer = self.buffer.read(cx);
18317
18318        let Some(buffer) = multibuffer.as_singleton() else {
18319            return;
18320        };
18321
18322        let Some(workspace) = self.workspace() else {
18323            return;
18324        };
18325
18326        let title = multibuffer.title(cx).to_string();
18327
18328        let locations = self
18329            .selections
18330            .all_anchors(cx)
18331            .into_iter()
18332            .map(|selection| Location {
18333                buffer: buffer.clone(),
18334                range: selection.start.text_anchor..selection.end.text_anchor,
18335            })
18336            .collect::<Vec<_>>();
18337
18338        cx.spawn_in(window, async move |_, cx| {
18339            workspace.update_in(cx, |workspace, window, cx| {
18340                Self::open_locations_in_multibuffer(
18341                    workspace,
18342                    locations,
18343                    format!("Selections for '{title}'"),
18344                    false,
18345                    MultibufferSelectionMode::All,
18346                    window,
18347                    cx,
18348                );
18349            })
18350        })
18351        .detach();
18352    }
18353
18354    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18355    /// last highlight added will be used.
18356    ///
18357    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18358    pub fn highlight_rows<T: 'static>(
18359        &mut self,
18360        range: Range<Anchor>,
18361        color: Hsla,
18362        options: RowHighlightOptions,
18363        cx: &mut Context<Self>,
18364    ) {
18365        let snapshot = self.buffer().read(cx).snapshot(cx);
18366        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18367        let ix = row_highlights.binary_search_by(|highlight| {
18368            Ordering::Equal
18369                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18370                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18371        });
18372
18373        if let Err(mut ix) = ix {
18374            let index = post_inc(&mut self.highlight_order);
18375
18376            // If this range intersects with the preceding highlight, then merge it with
18377            // the preceding highlight. Otherwise insert a new highlight.
18378            let mut merged = false;
18379            if ix > 0 {
18380                let prev_highlight = &mut row_highlights[ix - 1];
18381                if prev_highlight
18382                    .range
18383                    .end
18384                    .cmp(&range.start, &snapshot)
18385                    .is_ge()
18386                {
18387                    ix -= 1;
18388                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18389                        prev_highlight.range.end = range.end;
18390                    }
18391                    merged = true;
18392                    prev_highlight.index = index;
18393                    prev_highlight.color = color;
18394                    prev_highlight.options = options;
18395                }
18396            }
18397
18398            if !merged {
18399                row_highlights.insert(
18400                    ix,
18401                    RowHighlight {
18402                        range: range.clone(),
18403                        index,
18404                        color,
18405                        options,
18406                        type_id: TypeId::of::<T>(),
18407                    },
18408                );
18409            }
18410
18411            // If any of the following highlights intersect with this one, merge them.
18412            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18413                let highlight = &row_highlights[ix];
18414                if next_highlight
18415                    .range
18416                    .start
18417                    .cmp(&highlight.range.end, &snapshot)
18418                    .is_le()
18419                {
18420                    if next_highlight
18421                        .range
18422                        .end
18423                        .cmp(&highlight.range.end, &snapshot)
18424                        .is_gt()
18425                    {
18426                        row_highlights[ix].range.end = next_highlight.range.end;
18427                    }
18428                    row_highlights.remove(ix + 1);
18429                } else {
18430                    break;
18431                }
18432            }
18433        }
18434    }
18435
18436    /// Remove any highlighted row ranges of the given type that intersect the
18437    /// given ranges.
18438    pub fn remove_highlighted_rows<T: 'static>(
18439        &mut self,
18440        ranges_to_remove: Vec<Range<Anchor>>,
18441        cx: &mut Context<Self>,
18442    ) {
18443        let snapshot = self.buffer().read(cx).snapshot(cx);
18444        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18445        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18446        row_highlights.retain(|highlight| {
18447            while let Some(range_to_remove) = ranges_to_remove.peek() {
18448                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18449                    Ordering::Less | Ordering::Equal => {
18450                        ranges_to_remove.next();
18451                    }
18452                    Ordering::Greater => {
18453                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18454                            Ordering::Less | Ordering::Equal => {
18455                                return false;
18456                            }
18457                            Ordering::Greater => break,
18458                        }
18459                    }
18460                }
18461            }
18462
18463            true
18464        })
18465    }
18466
18467    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18468    pub fn clear_row_highlights<T: 'static>(&mut self) {
18469        self.highlighted_rows.remove(&TypeId::of::<T>());
18470    }
18471
18472    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18473    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18474        self.highlighted_rows
18475            .get(&TypeId::of::<T>())
18476            .map_or(&[] as &[_], |vec| vec.as_slice())
18477            .iter()
18478            .map(|highlight| (highlight.range.clone(), highlight.color))
18479    }
18480
18481    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18482    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18483    /// Allows to ignore certain kinds of highlights.
18484    pub fn highlighted_display_rows(
18485        &self,
18486        window: &mut Window,
18487        cx: &mut App,
18488    ) -> BTreeMap<DisplayRow, LineHighlight> {
18489        let snapshot = self.snapshot(window, cx);
18490        let mut used_highlight_orders = HashMap::default();
18491        self.highlighted_rows
18492            .iter()
18493            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18494            .fold(
18495                BTreeMap::<DisplayRow, LineHighlight>::new(),
18496                |mut unique_rows, highlight| {
18497                    let start = highlight.range.start.to_display_point(&snapshot);
18498                    let end = highlight.range.end.to_display_point(&snapshot);
18499                    let start_row = start.row().0;
18500                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18501                        && end.column() == 0
18502                    {
18503                        end.row().0.saturating_sub(1)
18504                    } else {
18505                        end.row().0
18506                    };
18507                    for row in start_row..=end_row {
18508                        let used_index =
18509                            used_highlight_orders.entry(row).or_insert(highlight.index);
18510                        if highlight.index >= *used_index {
18511                            *used_index = highlight.index;
18512                            unique_rows.insert(
18513                                DisplayRow(row),
18514                                LineHighlight {
18515                                    include_gutter: highlight.options.include_gutter,
18516                                    border: None,
18517                                    background: highlight.color.into(),
18518                                    type_id: Some(highlight.type_id),
18519                                },
18520                            );
18521                        }
18522                    }
18523                    unique_rows
18524                },
18525            )
18526    }
18527
18528    pub fn highlighted_display_row_for_autoscroll(
18529        &self,
18530        snapshot: &DisplaySnapshot,
18531    ) -> Option<DisplayRow> {
18532        self.highlighted_rows
18533            .values()
18534            .flat_map(|highlighted_rows| highlighted_rows.iter())
18535            .filter_map(|highlight| {
18536                if highlight.options.autoscroll {
18537                    Some(highlight.range.start.to_display_point(snapshot).row())
18538                } else {
18539                    None
18540                }
18541            })
18542            .min()
18543    }
18544
18545    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18546        self.highlight_background::<SearchWithinRange>(
18547            ranges,
18548            |theme| theme.colors().editor_document_highlight_read_background,
18549            cx,
18550        )
18551    }
18552
18553    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18554        self.breadcrumb_header = Some(new_header);
18555    }
18556
18557    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18558        self.clear_background_highlights::<SearchWithinRange>(cx);
18559    }
18560
18561    pub fn highlight_background<T: 'static>(
18562        &mut self,
18563        ranges: &[Range<Anchor>],
18564        color_fetcher: fn(&Theme) -> Hsla,
18565        cx: &mut Context<Self>,
18566    ) {
18567        let highlights = ranges
18568            .iter()
18569            .map(|range| BackgroundHighlight {
18570                range: range.clone(),
18571                color_fetcher,
18572            })
18573            .collect();
18574        self.background_highlights
18575            .insert(TypeId::of::<T>(), highlights);
18576        self.scrollbar_marker_state.dirty = true;
18577        cx.notify();
18578    }
18579
18580    pub fn highlight_background_ranges<T: 'static>(
18581        &mut self,
18582        background_highlights: Vec<BackgroundHighlight>,
18583        cx: &mut Context<'_, Editor>,
18584    ) {
18585        self.background_highlights
18586            .insert(TypeId::of::<T>(), background_highlights);
18587        self.scrollbar_marker_state.dirty = true;
18588        cx.notify();
18589    }
18590
18591    pub fn clear_background_highlights<T: 'static>(
18592        &mut self,
18593        cx: &mut Context<Self>,
18594    ) -> Option<Vec<BackgroundHighlight>> {
18595        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18596        if !text_highlights.is_empty() {
18597            self.scrollbar_marker_state.dirty = true;
18598            cx.notify();
18599        }
18600        Some(text_highlights)
18601    }
18602
18603    pub fn highlight_gutter<T: 'static>(
18604        &mut self,
18605        ranges: impl Into<Vec<Range<Anchor>>>,
18606        color_fetcher: fn(&App) -> Hsla,
18607        cx: &mut Context<Self>,
18608    ) {
18609        self.gutter_highlights
18610            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18611        cx.notify();
18612    }
18613
18614    pub fn clear_gutter_highlights<T: 'static>(
18615        &mut self,
18616        cx: &mut Context<Self>,
18617    ) -> Option<GutterHighlight> {
18618        cx.notify();
18619        self.gutter_highlights.remove(&TypeId::of::<T>())
18620    }
18621
18622    pub fn insert_gutter_highlight<T: 'static>(
18623        &mut self,
18624        range: Range<Anchor>,
18625        color_fetcher: fn(&App) -> Hsla,
18626        cx: &mut Context<Self>,
18627    ) {
18628        let snapshot = self.buffer().read(cx).snapshot(cx);
18629        let mut highlights = self
18630            .gutter_highlights
18631            .remove(&TypeId::of::<T>())
18632            .map(|(_, highlights)| highlights)
18633            .unwrap_or_default();
18634        let ix = highlights.binary_search_by(|highlight| {
18635            Ordering::Equal
18636                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18637                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18638        });
18639        if let Err(ix) = ix {
18640            highlights.insert(ix, range);
18641        }
18642        self.gutter_highlights
18643            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18644    }
18645
18646    pub fn remove_gutter_highlights<T: 'static>(
18647        &mut self,
18648        ranges_to_remove: Vec<Range<Anchor>>,
18649        cx: &mut Context<Self>,
18650    ) {
18651        let snapshot = self.buffer().read(cx).snapshot(cx);
18652        let Some((color_fetcher, mut gutter_highlights)) =
18653            self.gutter_highlights.remove(&TypeId::of::<T>())
18654        else {
18655            return;
18656        };
18657        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18658        gutter_highlights.retain(|highlight| {
18659            while let Some(range_to_remove) = ranges_to_remove.peek() {
18660                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18661                    Ordering::Less | Ordering::Equal => {
18662                        ranges_to_remove.next();
18663                    }
18664                    Ordering::Greater => {
18665                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18666                            Ordering::Less | Ordering::Equal => {
18667                                return false;
18668                            }
18669                            Ordering::Greater => break,
18670                        }
18671                    }
18672                }
18673            }
18674
18675            true
18676        });
18677        self.gutter_highlights
18678            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18679    }
18680
18681    #[cfg(feature = "test-support")]
18682    pub fn all_text_background_highlights(
18683        &self,
18684        window: &mut Window,
18685        cx: &mut Context<Self>,
18686    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18687        let snapshot = self.snapshot(window, cx);
18688        let buffer = &snapshot.buffer_snapshot;
18689        let start = buffer.anchor_before(0);
18690        let end = buffer.anchor_after(buffer.len());
18691        let theme = cx.theme();
18692        self.background_highlights_in_range(start..end, &snapshot, theme)
18693    }
18694
18695    #[cfg(feature = "test-support")]
18696    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18697        let snapshot = self.buffer().read(cx).snapshot(cx);
18698
18699        let highlights = self
18700            .background_highlights
18701            .get(&TypeId::of::<items::BufferSearchHighlights>());
18702
18703        if let Some(highlights) = highlights {
18704            highlights
18705                .iter()
18706                .map(|highlight| {
18707                    highlight.range.start.to_point(&snapshot)
18708                        ..highlight.range.end.to_point(&snapshot)
18709                })
18710                .collect_vec()
18711        } else {
18712            vec![]
18713        }
18714    }
18715
18716    fn document_highlights_for_position<'a>(
18717        &'a self,
18718        position: Anchor,
18719        buffer: &'a MultiBufferSnapshot,
18720    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18721        let read_highlights = self
18722            .background_highlights
18723            .get(&TypeId::of::<DocumentHighlightRead>());
18724        let write_highlights = self
18725            .background_highlights
18726            .get(&TypeId::of::<DocumentHighlightWrite>());
18727        let left_position = position.bias_left(buffer);
18728        let right_position = position.bias_right(buffer);
18729        read_highlights
18730            .into_iter()
18731            .chain(write_highlights)
18732            .flat_map(move |highlights| {
18733                let start_ix = match highlights.binary_search_by(|probe| {
18734                    let cmp = probe.range.end.cmp(&left_position, buffer);
18735                    if cmp.is_ge() {
18736                        Ordering::Greater
18737                    } else {
18738                        Ordering::Less
18739                    }
18740                }) {
18741                    Ok(i) | Err(i) => i,
18742                };
18743
18744                highlights[start_ix..]
18745                    .iter()
18746                    .take_while(move |highlight| {
18747                        highlight.range.start.cmp(&right_position, buffer).is_le()
18748                    })
18749                    .map(|highlight| &highlight.range)
18750            })
18751    }
18752
18753    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18754        self.background_highlights
18755            .get(&TypeId::of::<T>())
18756            .map_or(false, |highlights| !highlights.is_empty())
18757    }
18758
18759    pub fn background_highlights_in_range(
18760        &self,
18761        search_range: Range<Anchor>,
18762        display_snapshot: &DisplaySnapshot,
18763        theme: &Theme,
18764    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18765        let mut results = Vec::new();
18766        for highlights in self.background_highlights.values() {
18767            let start_ix = match highlights.binary_search_by(|probe| {
18768                let cmp = probe
18769                    .range
18770                    .end
18771                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18772                if cmp.is_gt() {
18773                    Ordering::Greater
18774                } else {
18775                    Ordering::Less
18776                }
18777            }) {
18778                Ok(i) | Err(i) => i,
18779            };
18780            for highlight in &highlights[start_ix..] {
18781                if highlight
18782                    .range
18783                    .start
18784                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18785                    .is_ge()
18786                {
18787                    break;
18788                }
18789
18790                let start = highlight.range.start.to_display_point(display_snapshot);
18791                let end = highlight.range.end.to_display_point(display_snapshot);
18792                let color = (highlight.color_fetcher)(theme);
18793                results.push((start..end, color))
18794            }
18795        }
18796        results
18797    }
18798
18799    pub fn background_highlight_row_ranges<T: 'static>(
18800        &self,
18801        search_range: Range<Anchor>,
18802        display_snapshot: &DisplaySnapshot,
18803        count: usize,
18804    ) -> Vec<RangeInclusive<DisplayPoint>> {
18805        let mut results = Vec::new();
18806        let Some(highlights) = self.background_highlights.get(&TypeId::of::<T>()) else {
18807            return vec![];
18808        };
18809
18810        let start_ix = match highlights.binary_search_by(|probe| {
18811            let cmp = probe
18812                .range
18813                .end
18814                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18815            if cmp.is_gt() {
18816                Ordering::Greater
18817            } else {
18818                Ordering::Less
18819            }
18820        }) {
18821            Ok(i) | Err(i) => i,
18822        };
18823        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18824            if let (Some(start_display), Some(end_display)) = (start, end) {
18825                results.push(
18826                    start_display.to_display_point(display_snapshot)
18827                        ..=end_display.to_display_point(display_snapshot),
18828                );
18829            }
18830        };
18831        let mut start_row: Option<Point> = None;
18832        let mut end_row: Option<Point> = None;
18833        if highlights.len() > count {
18834            return Vec::new();
18835        }
18836        for highlight in &highlights[start_ix..] {
18837            if highlight
18838                .range
18839                .start
18840                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18841                .is_ge()
18842            {
18843                break;
18844            }
18845            let end = highlight
18846                .range
18847                .end
18848                .to_point(&display_snapshot.buffer_snapshot);
18849            if let Some(current_row) = &end_row {
18850                if end.row == current_row.row {
18851                    continue;
18852                }
18853            }
18854            let start = highlight
18855                .range
18856                .start
18857                .to_point(&display_snapshot.buffer_snapshot);
18858            if start_row.is_none() {
18859                assert_eq!(end_row, None);
18860                start_row = Some(start);
18861                end_row = Some(end);
18862                continue;
18863            }
18864            if let Some(current_end) = end_row.as_mut() {
18865                if start.row > current_end.row + 1 {
18866                    push_region(start_row, end_row);
18867                    start_row = Some(start);
18868                    end_row = Some(end);
18869                } else {
18870                    // Merge two hunks.
18871                    *current_end = end;
18872                }
18873            } else {
18874                unreachable!();
18875            }
18876        }
18877        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18878        push_region(start_row, end_row);
18879        results
18880    }
18881
18882    pub fn gutter_highlights_in_range(
18883        &self,
18884        search_range: Range<Anchor>,
18885        display_snapshot: &DisplaySnapshot,
18886        cx: &App,
18887    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18888        let mut results = Vec::new();
18889        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18890            let color = color_fetcher(cx);
18891            let start_ix = match ranges.binary_search_by(|probe| {
18892                let cmp = probe
18893                    .end
18894                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18895                if cmp.is_gt() {
18896                    Ordering::Greater
18897                } else {
18898                    Ordering::Less
18899                }
18900            }) {
18901                Ok(i) | Err(i) => i,
18902            };
18903            for range in &ranges[start_ix..] {
18904                if range
18905                    .start
18906                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18907                    .is_ge()
18908                {
18909                    break;
18910                }
18911
18912                let start = range.start.to_display_point(display_snapshot);
18913                let end = range.end.to_display_point(display_snapshot);
18914                results.push((start..end, color))
18915            }
18916        }
18917        results
18918    }
18919
18920    /// Get the text ranges corresponding to the redaction query
18921    pub fn redacted_ranges(
18922        &self,
18923        search_range: Range<Anchor>,
18924        display_snapshot: &DisplaySnapshot,
18925        cx: &App,
18926    ) -> Vec<Range<DisplayPoint>> {
18927        display_snapshot
18928            .buffer_snapshot
18929            .redacted_ranges(search_range, |file| {
18930                if let Some(file) = file {
18931                    file.is_private()
18932                        && EditorSettings::get(
18933                            Some(SettingsLocation {
18934                                worktree_id: file.worktree_id(cx),
18935                                path: file.path().as_ref(),
18936                            }),
18937                            cx,
18938                        )
18939                        .redact_private_values
18940                } else {
18941                    false
18942                }
18943            })
18944            .map(|range| {
18945                range.start.to_display_point(display_snapshot)
18946                    ..range.end.to_display_point(display_snapshot)
18947            })
18948            .collect()
18949    }
18950
18951    pub fn highlight_text<T: 'static>(
18952        &mut self,
18953        ranges: Vec<(Range<Anchor>, HighlightStyle)>,
18954        cx: &mut Context<Self>,
18955    ) {
18956        self.display_map
18957            .update(cx, |map, _| map.highlight_text(TypeId::of::<T>(), ranges));
18958        cx.notify();
18959    }
18960
18961    pub(crate) fn highlight_inlays<T: 'static>(
18962        &mut self,
18963        highlights: Vec<InlayHighlight>,
18964        style: HighlightStyle,
18965        cx: &mut Context<Self>,
18966    ) {
18967        self.display_map.update(cx, |map, _| {
18968            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18969        });
18970        cx.notify();
18971    }
18972
18973    pub fn text_highlights<'a, T: 'static>(
18974        &'a self,
18975        cx: &'a App,
18976    ) -> Option<&'a [(Range<Anchor>, HighlightStyle)]> {
18977        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18978    }
18979
18980    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18981        let cleared = self
18982            .display_map
18983            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18984        if cleared {
18985            cx.notify();
18986        }
18987    }
18988
18989    pub fn remove_text_highlights<T: 'static>(
18990        &mut self,
18991        cx: &mut Context<Self>,
18992    ) -> Option<Vec<(Range<Anchor>, HighlightStyle)>> {
18993        self.display_map
18994            .update(cx, |map, _| map.remove_text_highlights(TypeId::of::<T>()))
18995    }
18996
18997    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18998        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18999            && self.focus_handle.is_focused(window)
19000    }
19001
19002    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19003        self.show_cursor_when_unfocused = is_enabled;
19004        cx.notify();
19005    }
19006
19007    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19008        cx.notify();
19009    }
19010
19011    fn on_debug_session_event(
19012        &mut self,
19013        _session: Entity<Session>,
19014        event: &SessionEvent,
19015        cx: &mut Context<Self>,
19016    ) {
19017        match event {
19018            SessionEvent::InvalidateInlineValue => {
19019                self.refresh_inline_values(cx);
19020            }
19021            _ => {}
19022        }
19023    }
19024
19025    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19026        let Some(project) = self.project.clone() else {
19027            return;
19028        };
19029
19030        if !self.inline_value_cache.enabled {
19031            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19032            self.splice_inlays(&inlays, Vec::new(), cx);
19033            return;
19034        }
19035
19036        let current_execution_position = self
19037            .highlighted_rows
19038            .get(&TypeId::of::<ActiveDebugLine>())
19039            .and_then(|lines| lines.last().map(|line| line.range.start));
19040
19041        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19042            let inline_values = editor
19043                .update(cx, |editor, cx| {
19044                    let Some(current_execution_position) = current_execution_position else {
19045                        return Some(Task::ready(Ok(Vec::new())));
19046                    };
19047
19048                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19049                        let snapshot = buffer.snapshot(cx);
19050
19051                        let excerpt = snapshot.excerpt_containing(
19052                            current_execution_position..current_execution_position,
19053                        )?;
19054
19055                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19056                    })?;
19057
19058                    let range =
19059                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19060
19061                    project.inline_values(buffer, range, cx)
19062                })
19063                .ok()
19064                .flatten()?
19065                .await
19066                .context("refreshing debugger inlays")
19067                .log_err()?;
19068
19069            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19070
19071            for (buffer_id, inline_value) in inline_values
19072                .into_iter()
19073                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19074            {
19075                buffer_inline_values
19076                    .entry(buffer_id)
19077                    .or_default()
19078                    .push(inline_value);
19079            }
19080
19081            editor
19082                .update(cx, |editor, cx| {
19083                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19084                    let mut new_inlays = Vec::default();
19085
19086                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19087                        let buffer_id = buffer_snapshot.remote_id();
19088                        buffer_inline_values
19089                            .get(&buffer_id)
19090                            .into_iter()
19091                            .flatten()
19092                            .for_each(|hint| {
19093                                let inlay = Inlay::debugger(
19094                                    post_inc(&mut editor.next_inlay_id),
19095                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19096                                    hint.text(),
19097                                );
19098
19099                                new_inlays.push(inlay);
19100                            });
19101                    }
19102
19103                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19104                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19105
19106                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19107                })
19108                .ok()?;
19109            Some(())
19110        });
19111    }
19112
19113    fn on_buffer_event(
19114        &mut self,
19115        multibuffer: &Entity<MultiBuffer>,
19116        event: &multi_buffer::Event,
19117        window: &mut Window,
19118        cx: &mut Context<Self>,
19119    ) {
19120        match event {
19121            multi_buffer::Event::Edited {
19122                singleton_buffer_edited,
19123                edited_buffer,
19124            } => {
19125                self.scrollbar_marker_state.dirty = true;
19126                self.active_indent_guides_state.dirty = true;
19127                self.refresh_active_diagnostics(cx);
19128                self.refresh_code_actions(window, cx);
19129                self.refresh_selected_text_highlights(true, window, cx);
19130                refresh_matching_bracket_highlights(self, window, cx);
19131                if self.has_active_inline_completion() {
19132                    self.update_visible_inline_completion(window, cx);
19133                }
19134                if let Some(project) = self.project.as_ref() {
19135                    if let Some(edited_buffer) = edited_buffer {
19136                        project.update(cx, |project, cx| {
19137                            self.registered_buffers
19138                                .entry(edited_buffer.read(cx).remote_id())
19139                                .or_insert_with(|| {
19140                                    project
19141                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19142                                });
19143                        });
19144                    }
19145                }
19146                cx.emit(EditorEvent::BufferEdited);
19147                cx.emit(SearchEvent::MatchesInvalidated);
19148
19149                if let Some(buffer) = edited_buffer {
19150                    self.update_lsp_data(true, None, Some(buffer.read(cx).remote_id()), window, cx);
19151                }
19152
19153                if *singleton_buffer_edited {
19154                    if let Some(buffer) = edited_buffer {
19155                        if buffer.read(cx).file().is_none() {
19156                            cx.emit(EditorEvent::TitleChanged);
19157                        }
19158                    }
19159                    if let Some(project) = &self.project {
19160                        #[allow(clippy::mutable_key_type)]
19161                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19162                            multibuffer
19163                                .all_buffers()
19164                                .into_iter()
19165                                .filter_map(|buffer| {
19166                                    buffer.update(cx, |buffer, cx| {
19167                                        let language = buffer.language()?;
19168                                        let should_discard = project.update(cx, |project, cx| {
19169                                            project.is_local()
19170                                                && !project.has_language_servers_for(buffer, cx)
19171                                        });
19172                                        should_discard.not().then_some(language.clone())
19173                                    })
19174                                })
19175                                .collect::<HashSet<_>>()
19176                        });
19177                        if !languages_affected.is_empty() {
19178                            self.refresh_inlay_hints(
19179                                InlayHintRefreshReason::BufferEdited(languages_affected),
19180                                cx,
19181                            );
19182                        }
19183                    }
19184                }
19185
19186                let Some(project) = &self.project else { return };
19187                let (telemetry, is_via_ssh) = {
19188                    let project = project.read(cx);
19189                    let telemetry = project.client().telemetry().clone();
19190                    let is_via_ssh = project.is_via_ssh();
19191                    (telemetry, is_via_ssh)
19192                };
19193                refresh_linked_ranges(self, window, cx);
19194                telemetry.log_edit_event("editor", is_via_ssh);
19195            }
19196            multi_buffer::Event::ExcerptsAdded {
19197                buffer,
19198                predecessor,
19199                excerpts,
19200            } => {
19201                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19202                let buffer_id = buffer.read(cx).remote_id();
19203                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19204                    if let Some(project) = &self.project {
19205                        update_uncommitted_diff_for_buffer(
19206                            cx.entity(),
19207                            project,
19208                            [buffer.clone()],
19209                            self.buffer.clone(),
19210                            cx,
19211                        )
19212                        .detach();
19213                    }
19214                }
19215                self.update_lsp_data(false, None, Some(buffer_id), window, cx);
19216                cx.emit(EditorEvent::ExcerptsAdded {
19217                    buffer: buffer.clone(),
19218                    predecessor: *predecessor,
19219                    excerpts: excerpts.clone(),
19220                });
19221                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19222            }
19223            multi_buffer::Event::ExcerptsRemoved {
19224                ids,
19225                removed_buffer_ids,
19226            } => {
19227                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19228                let buffer = self.buffer.read(cx);
19229                self.registered_buffers
19230                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19231                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19232                cx.emit(EditorEvent::ExcerptsRemoved {
19233                    ids: ids.clone(),
19234                    removed_buffer_ids: removed_buffer_ids.clone(),
19235                });
19236            }
19237            multi_buffer::Event::ExcerptsEdited {
19238                excerpt_ids,
19239                buffer_ids,
19240            } => {
19241                self.display_map.update(cx, |map, cx| {
19242                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19243                });
19244                cx.emit(EditorEvent::ExcerptsEdited {
19245                    ids: excerpt_ids.clone(),
19246                });
19247            }
19248            multi_buffer::Event::ExcerptsExpanded { ids } => {
19249                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19250                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19251            }
19252            multi_buffer::Event::Reparsed(buffer_id) => {
19253                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19254                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19255
19256                cx.emit(EditorEvent::Reparsed(*buffer_id));
19257            }
19258            multi_buffer::Event::DiffHunksToggled => {
19259                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19260            }
19261            multi_buffer::Event::LanguageChanged(buffer_id) => {
19262                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19263                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19264                cx.emit(EditorEvent::Reparsed(*buffer_id));
19265                cx.notify();
19266            }
19267            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19268            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19269            multi_buffer::Event::FileHandleChanged
19270            | multi_buffer::Event::Reloaded
19271            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19272            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19273            multi_buffer::Event::DiagnosticsUpdated => {
19274                self.update_diagnostics_state(window, cx);
19275            }
19276            _ => {}
19277        };
19278    }
19279
19280    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19281        self.refresh_active_diagnostics(cx);
19282        self.refresh_inline_diagnostics(true, window, cx);
19283        self.scrollbar_marker_state.dirty = true;
19284        cx.notify();
19285    }
19286
19287    pub fn start_temporary_diff_override(&mut self) {
19288        self.load_diff_task.take();
19289        self.temporary_diff_override = true;
19290    }
19291
19292    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19293        self.temporary_diff_override = false;
19294        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19295        self.buffer.update(cx, |buffer, cx| {
19296            buffer.set_all_diff_hunks_collapsed(cx);
19297        });
19298
19299        if let Some(project) = self.project.clone() {
19300            self.load_diff_task = Some(
19301                update_uncommitted_diff_for_buffer(
19302                    cx.entity(),
19303                    &project,
19304                    self.buffer.read(cx).all_buffers(),
19305                    self.buffer.clone(),
19306                    cx,
19307                )
19308                .shared(),
19309            );
19310        }
19311    }
19312
19313    fn on_display_map_changed(
19314        &mut self,
19315        _: Entity<DisplayMap>,
19316        _: &mut Window,
19317        cx: &mut Context<Self>,
19318    ) {
19319        cx.notify();
19320    }
19321
19322    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19323        let new_severity = if self.diagnostics_enabled() {
19324            EditorSettings::get_global(cx)
19325                .diagnostics_max_severity
19326                .unwrap_or(DiagnosticSeverity::Hint)
19327        } else {
19328            DiagnosticSeverity::Off
19329        };
19330        self.set_max_diagnostics_severity(new_severity, cx);
19331        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19332        self.update_edit_prediction_settings(cx);
19333        self.refresh_inline_completion(true, false, window, cx);
19334        self.refresh_inlay_hints(
19335            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19336                self.selections.newest_anchor().head(),
19337                &self.buffer.read(cx).snapshot(cx),
19338                cx,
19339            )),
19340            cx,
19341        );
19342
19343        let old_cursor_shape = self.cursor_shape;
19344
19345        {
19346            let editor_settings = EditorSettings::get_global(cx);
19347            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19348            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19349            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19350            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19351            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19352        }
19353
19354        if old_cursor_shape != self.cursor_shape {
19355            cx.emit(EditorEvent::CursorShapeChanged);
19356        }
19357
19358        let project_settings = ProjectSettings::get_global(cx);
19359        self.serialize_dirty_buffers =
19360            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19361
19362        if self.mode.is_full() {
19363            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19364            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19365            if self.show_inline_diagnostics != show_inline_diagnostics {
19366                self.show_inline_diagnostics = show_inline_diagnostics;
19367                self.refresh_inline_diagnostics(false, window, cx);
19368            }
19369
19370            if self.git_blame_inline_enabled != inline_blame_enabled {
19371                self.toggle_git_blame_inline_internal(false, window, cx);
19372            }
19373
19374            let minimap_settings = EditorSettings::get_global(cx).minimap;
19375            if self.minimap_visibility != MinimapVisibility::Disabled {
19376                if self.minimap_visibility.settings_visibility()
19377                    != minimap_settings.minimap_enabled()
19378                {
19379                    self.set_minimap_visibility(
19380                        MinimapVisibility::for_mode(self.mode(), cx),
19381                        window,
19382                        cx,
19383                    );
19384                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19385                    minimap_entity.update(cx, |minimap_editor, cx| {
19386                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19387                    })
19388                }
19389            }
19390        }
19391
19392        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19393            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19394        }) {
19395            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19396                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19397            }
19398            self.refresh_colors(true, None, None, window, cx);
19399        }
19400
19401        cx.notify();
19402    }
19403
19404    pub fn set_searchable(&mut self, searchable: bool) {
19405        self.searchable = searchable;
19406    }
19407
19408    pub fn searchable(&self) -> bool {
19409        self.searchable
19410    }
19411
19412    fn open_proposed_changes_editor(
19413        &mut self,
19414        _: &OpenProposedChangesEditor,
19415        window: &mut Window,
19416        cx: &mut Context<Self>,
19417    ) {
19418        let Some(workspace) = self.workspace() else {
19419            cx.propagate();
19420            return;
19421        };
19422
19423        let selections = self.selections.all::<usize>(cx);
19424        let multi_buffer = self.buffer.read(cx);
19425        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19426        let mut new_selections_by_buffer = HashMap::default();
19427        for selection in selections {
19428            for (buffer, range, _) in
19429                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19430            {
19431                let mut range = range.to_point(buffer);
19432                range.start.column = 0;
19433                range.end.column = buffer.line_len(range.end.row);
19434                new_selections_by_buffer
19435                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19436                    .or_insert(Vec::new())
19437                    .push(range)
19438            }
19439        }
19440
19441        let proposed_changes_buffers = new_selections_by_buffer
19442            .into_iter()
19443            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19444            .collect::<Vec<_>>();
19445        let proposed_changes_editor = cx.new(|cx| {
19446            ProposedChangesEditor::new(
19447                "Proposed changes",
19448                proposed_changes_buffers,
19449                self.project.clone(),
19450                window,
19451                cx,
19452            )
19453        });
19454
19455        window.defer(cx, move |window, cx| {
19456            workspace.update(cx, |workspace, cx| {
19457                workspace.active_pane().update(cx, |pane, cx| {
19458                    pane.add_item(
19459                        Box::new(proposed_changes_editor),
19460                        true,
19461                        true,
19462                        None,
19463                        window,
19464                        cx,
19465                    );
19466                });
19467            });
19468        });
19469    }
19470
19471    pub fn open_excerpts_in_split(
19472        &mut self,
19473        _: &OpenExcerptsSplit,
19474        window: &mut Window,
19475        cx: &mut Context<Self>,
19476    ) {
19477        self.open_excerpts_common(None, true, window, cx)
19478    }
19479
19480    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19481        self.open_excerpts_common(None, false, window, cx)
19482    }
19483
19484    fn open_excerpts_common(
19485        &mut self,
19486        jump_data: Option<JumpData>,
19487        split: bool,
19488        window: &mut Window,
19489        cx: &mut Context<Self>,
19490    ) {
19491        let Some(workspace) = self.workspace() else {
19492            cx.propagate();
19493            return;
19494        };
19495
19496        if self.buffer.read(cx).is_singleton() {
19497            cx.propagate();
19498            return;
19499        }
19500
19501        let mut new_selections_by_buffer = HashMap::default();
19502        match &jump_data {
19503            Some(JumpData::MultiBufferPoint {
19504                excerpt_id,
19505                position,
19506                anchor,
19507                line_offset_from_top,
19508            }) => {
19509                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19510                if let Some(buffer) = multi_buffer_snapshot
19511                    .buffer_id_for_excerpt(*excerpt_id)
19512                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19513                {
19514                    let buffer_snapshot = buffer.read(cx).snapshot();
19515                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19516                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19517                    } else {
19518                        buffer_snapshot.clip_point(*position, Bias::Left)
19519                    };
19520                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19521                    new_selections_by_buffer.insert(
19522                        buffer,
19523                        (
19524                            vec![jump_to_offset..jump_to_offset],
19525                            Some(*line_offset_from_top),
19526                        ),
19527                    );
19528                }
19529            }
19530            Some(JumpData::MultiBufferRow {
19531                row,
19532                line_offset_from_top,
19533            }) => {
19534                let point = MultiBufferPoint::new(row.0, 0);
19535                if let Some((buffer, buffer_point, _)) =
19536                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19537                {
19538                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19539                    new_selections_by_buffer
19540                        .entry(buffer)
19541                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19542                        .0
19543                        .push(buffer_offset..buffer_offset)
19544                }
19545            }
19546            None => {
19547                let selections = self.selections.all::<usize>(cx);
19548                let multi_buffer = self.buffer.read(cx);
19549                for selection in selections {
19550                    for (snapshot, range, _, anchor) in multi_buffer
19551                        .snapshot(cx)
19552                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19553                    {
19554                        if let Some(anchor) = anchor {
19555                            // selection is in a deleted hunk
19556                            let Some(buffer_id) = anchor.buffer_id else {
19557                                continue;
19558                            };
19559                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19560                                continue;
19561                            };
19562                            let offset = text::ToOffset::to_offset(
19563                                &anchor.text_anchor,
19564                                &buffer_handle.read(cx).snapshot(),
19565                            );
19566                            let range = offset..offset;
19567                            new_selections_by_buffer
19568                                .entry(buffer_handle)
19569                                .or_insert((Vec::new(), None))
19570                                .0
19571                                .push(range)
19572                        } else {
19573                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19574                            else {
19575                                continue;
19576                            };
19577                            new_selections_by_buffer
19578                                .entry(buffer_handle)
19579                                .or_insert((Vec::new(), None))
19580                                .0
19581                                .push(range)
19582                        }
19583                    }
19584                }
19585            }
19586        }
19587
19588        new_selections_by_buffer
19589            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19590
19591        if new_selections_by_buffer.is_empty() {
19592            return;
19593        }
19594
19595        // We defer the pane interaction because we ourselves are a workspace item
19596        // and activating a new item causes the pane to call a method on us reentrantly,
19597        // which panics if we're on the stack.
19598        window.defer(cx, move |window, cx| {
19599            workspace.update(cx, |workspace, cx| {
19600                let pane = if split {
19601                    workspace.adjacent_pane(window, cx)
19602                } else {
19603                    workspace.active_pane().clone()
19604                };
19605
19606                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19607                    let editor = buffer
19608                        .read(cx)
19609                        .file()
19610                        .is_none()
19611                        .then(|| {
19612                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19613                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19614                            // Instead, we try to activate the existing editor in the pane first.
19615                            let (editor, pane_item_index) =
19616                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19617                                    let editor = item.downcast::<Editor>()?;
19618                                    let singleton_buffer =
19619                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19620                                    if singleton_buffer == buffer {
19621                                        Some((editor, i))
19622                                    } else {
19623                                        None
19624                                    }
19625                                })?;
19626                            pane.update(cx, |pane, cx| {
19627                                pane.activate_item(pane_item_index, true, true, window, cx)
19628                            });
19629                            Some(editor)
19630                        })
19631                        .flatten()
19632                        .unwrap_or_else(|| {
19633                            workspace.open_project_item::<Self>(
19634                                pane.clone(),
19635                                buffer,
19636                                true,
19637                                true,
19638                                window,
19639                                cx,
19640                            )
19641                        });
19642
19643                    editor.update(cx, |editor, cx| {
19644                        let autoscroll = match scroll_offset {
19645                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19646                            None => Autoscroll::newest(),
19647                        };
19648                        let nav_history = editor.nav_history.take();
19649                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19650                            s.select_ranges(ranges);
19651                        });
19652                        editor.nav_history = nav_history;
19653                    });
19654                }
19655            })
19656        });
19657    }
19658
19659    // For now, don't allow opening excerpts in buffers that aren't backed by
19660    // regular project files.
19661    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19662        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19663    }
19664
19665    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19666        let snapshot = self.buffer.read(cx).read(cx);
19667        let ranges = self.text_highlights::<InputComposition>(cx)?;
19668        Some(
19669            ranges
19670                .iter()
19671                .map(move |(range, _)| {
19672                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19673                })
19674                .collect(),
19675        )
19676    }
19677
19678    fn selection_replacement_ranges(
19679        &self,
19680        range: Range<OffsetUtf16>,
19681        cx: &mut App,
19682    ) -> Vec<Range<OffsetUtf16>> {
19683        let selections = self.selections.all::<OffsetUtf16>(cx);
19684        let newest_selection = selections
19685            .iter()
19686            .max_by_key(|selection| selection.id)
19687            .unwrap();
19688        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19689        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19690        let snapshot = self.buffer.read(cx).read(cx);
19691        selections
19692            .into_iter()
19693            .map(|mut selection| {
19694                selection.start.0 =
19695                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19696                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19697                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19698                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19699            })
19700            .collect()
19701    }
19702
19703    fn report_editor_event(
19704        &self,
19705        event_type: &'static str,
19706        file_extension: Option<String>,
19707        cx: &App,
19708    ) {
19709        if cfg!(any(test, feature = "test-support")) {
19710            return;
19711        }
19712
19713        let Some(project) = &self.project else { return };
19714
19715        // If None, we are in a file without an extension
19716        let file = self
19717            .buffer
19718            .read(cx)
19719            .as_singleton()
19720            .and_then(|b| b.read(cx).file());
19721        let file_extension = file_extension.or(file
19722            .as_ref()
19723            .and_then(|file| Path::new(file.file_name(cx)).extension())
19724            .and_then(|e| e.to_str())
19725            .map(|a| a.to_string()));
19726
19727        let vim_mode = vim_enabled(cx);
19728
19729        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19730        let copilot_enabled = edit_predictions_provider
19731            == language::language_settings::EditPredictionProvider::Copilot;
19732        let copilot_enabled_for_language = self
19733            .buffer
19734            .read(cx)
19735            .language_settings(cx)
19736            .show_edit_predictions;
19737
19738        let project = project.read(cx);
19739        telemetry::event!(
19740            event_type,
19741            file_extension,
19742            vim_mode,
19743            copilot_enabled,
19744            copilot_enabled_for_language,
19745            edit_predictions_provider,
19746            is_via_ssh = project.is_via_ssh(),
19747        );
19748    }
19749
19750    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19751    /// with each line being an array of {text, highlight} objects.
19752    fn copy_highlight_json(
19753        &mut self,
19754        _: &CopyHighlightJson,
19755        window: &mut Window,
19756        cx: &mut Context<Self>,
19757    ) {
19758        #[derive(Serialize)]
19759        struct Chunk<'a> {
19760            text: String,
19761            highlight: Option<&'a str>,
19762        }
19763
19764        let snapshot = self.buffer.read(cx).snapshot(cx);
19765        let range = self
19766            .selected_text_range(false, window, cx)
19767            .and_then(|selection| {
19768                if selection.range.is_empty() {
19769                    None
19770                } else {
19771                    Some(selection.range)
19772                }
19773            })
19774            .unwrap_or_else(|| 0..snapshot.len());
19775
19776        let chunks = snapshot.chunks(range, true);
19777        let mut lines = Vec::new();
19778        let mut line: VecDeque<Chunk> = VecDeque::new();
19779
19780        let Some(style) = self.style.as_ref() else {
19781            return;
19782        };
19783
19784        for chunk in chunks {
19785            let highlight = chunk
19786                .syntax_highlight_id
19787                .and_then(|id| id.name(&style.syntax));
19788            let mut chunk_lines = chunk.text.split('\n').peekable();
19789            while let Some(text) = chunk_lines.next() {
19790                let mut merged_with_last_token = false;
19791                if let Some(last_token) = line.back_mut() {
19792                    if last_token.highlight == highlight {
19793                        last_token.text.push_str(text);
19794                        merged_with_last_token = true;
19795                    }
19796                }
19797
19798                if !merged_with_last_token {
19799                    line.push_back(Chunk {
19800                        text: text.into(),
19801                        highlight,
19802                    });
19803                }
19804
19805                if chunk_lines.peek().is_some() {
19806                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19807                        line.pop_front();
19808                    }
19809                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19810                        line.pop_back();
19811                    }
19812
19813                    lines.push(mem::take(&mut line));
19814                }
19815            }
19816        }
19817
19818        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19819            return;
19820        };
19821        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19822    }
19823
19824    pub fn open_context_menu(
19825        &mut self,
19826        _: &OpenContextMenu,
19827        window: &mut Window,
19828        cx: &mut Context<Self>,
19829    ) {
19830        self.request_autoscroll(Autoscroll::newest(), cx);
19831        let position = self.selections.newest_display(cx).start;
19832        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19833    }
19834
19835    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19836        &self.inlay_hint_cache
19837    }
19838
19839    pub fn replay_insert_event(
19840        &mut self,
19841        text: &str,
19842        relative_utf16_range: Option<Range<isize>>,
19843        window: &mut Window,
19844        cx: &mut Context<Self>,
19845    ) {
19846        if !self.input_enabled {
19847            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19848            return;
19849        }
19850        if let Some(relative_utf16_range) = relative_utf16_range {
19851            let selections = self.selections.all::<OffsetUtf16>(cx);
19852            self.change_selections(None, window, cx, |s| {
19853                let new_ranges = selections.into_iter().map(|range| {
19854                    let start = OffsetUtf16(
19855                        range
19856                            .head()
19857                            .0
19858                            .saturating_add_signed(relative_utf16_range.start),
19859                    );
19860                    let end = OffsetUtf16(
19861                        range
19862                            .head()
19863                            .0
19864                            .saturating_add_signed(relative_utf16_range.end),
19865                    );
19866                    start..end
19867                });
19868                s.select_ranges(new_ranges);
19869            });
19870        }
19871
19872        self.handle_input(text, window, cx);
19873    }
19874
19875    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19876        let Some(provider) = self.semantics_provider.as_ref() else {
19877            return false;
19878        };
19879
19880        let mut supports = false;
19881        self.buffer().update(cx, |this, cx| {
19882            this.for_each_buffer(|buffer| {
19883                supports |= provider.supports_inlay_hints(buffer, cx);
19884            });
19885        });
19886
19887        supports
19888    }
19889
19890    pub fn is_focused(&self, window: &Window) -> bool {
19891        self.focus_handle.is_focused(window)
19892    }
19893
19894    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19895        cx.emit(EditorEvent::Focused);
19896
19897        if let Some(descendant) = self
19898            .last_focused_descendant
19899            .take()
19900            .and_then(|descendant| descendant.upgrade())
19901        {
19902            window.focus(&descendant);
19903        } else {
19904            if let Some(blame) = self.blame.as_ref() {
19905                blame.update(cx, GitBlame::focus)
19906            }
19907
19908            self.blink_manager.update(cx, BlinkManager::enable);
19909            self.show_cursor_names(window, cx);
19910            self.buffer.update(cx, |buffer, cx| {
19911                buffer.finalize_last_transaction(cx);
19912                if self.leader_id.is_none() {
19913                    buffer.set_active_selections(
19914                        &self.selections.disjoint_anchors(),
19915                        self.selections.line_mode,
19916                        self.cursor_shape,
19917                        cx,
19918                    );
19919                }
19920            });
19921        }
19922    }
19923
19924    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19925        cx.emit(EditorEvent::FocusedIn)
19926    }
19927
19928    fn handle_focus_out(
19929        &mut self,
19930        event: FocusOutEvent,
19931        _window: &mut Window,
19932        cx: &mut Context<Self>,
19933    ) {
19934        if event.blurred != self.focus_handle {
19935            self.last_focused_descendant = Some(event.blurred);
19936        }
19937        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19938    }
19939
19940    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19941        self.blink_manager.update(cx, BlinkManager::disable);
19942        self.buffer
19943            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19944
19945        if let Some(blame) = self.blame.as_ref() {
19946            blame.update(cx, GitBlame::blur)
19947        }
19948        if !self.hover_state.focused(window, cx) {
19949            hide_hover(self, cx);
19950        }
19951        if !self
19952            .context_menu
19953            .borrow()
19954            .as_ref()
19955            .is_some_and(|context_menu| context_menu.focused(window, cx))
19956        {
19957            self.hide_context_menu(window, cx);
19958        }
19959        self.discard_inline_completion(false, cx);
19960        cx.emit(EditorEvent::Blurred);
19961        cx.notify();
19962    }
19963
19964    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19965        let mut pending: String = window
19966            .pending_input_keystrokes()
19967            .into_iter()
19968            .flatten()
19969            .filter_map(|keystroke| {
19970                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19971                    keystroke.key_char.clone()
19972                } else {
19973                    None
19974                }
19975            })
19976            .collect();
19977
19978        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19979            pending = "".to_string();
19980        }
19981
19982        let existing_pending = self.text_highlights::<PendingInput>(cx).map(|ranges| {
19983            ranges
19984                .iter()
19985                .map(|(range, _)| range.clone())
19986                .collect::<Vec<_>>()
19987        });
19988        if existing_pending.is_none() && pending.is_empty() {
19989            return;
19990        }
19991        let transaction =
19992            self.transact(window, cx, |this, window, cx| {
19993                let selections = this.selections.all::<usize>(cx);
19994                let edits = selections
19995                    .iter()
19996                    .map(|selection| (selection.end..selection.end, pending.clone()));
19997                this.edit(edits, cx);
19998                this.change_selections(None, window, cx, |s| {
19999                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20000                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20001                    }));
20002                });
20003                if let Some(existing_ranges) = existing_pending {
20004                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20005                    this.edit(edits, cx);
20006                }
20007            });
20008
20009        let snapshot = self.snapshot(window, cx);
20010        let ranges = self
20011            .selections
20012            .all::<usize>(cx)
20013            .into_iter()
20014            .map(|selection| {
20015                (
20016                    snapshot.buffer_snapshot.anchor_after(selection.end)
20017                        ..snapshot
20018                            .buffer_snapshot
20019                            .anchor_before(selection.end + pending.len()),
20020                    HighlightStyle {
20021                        underline: Some(UnderlineStyle {
20022                            thickness: px(1.),
20023                            color: None,
20024                            wavy: false,
20025                        }),
20026                        ..Default::default()
20027                    },
20028                )
20029            })
20030            .collect();
20031
20032        if pending.is_empty() {
20033            self.clear_highlights::<PendingInput>(cx);
20034        } else {
20035            self.highlight_text::<PendingInput>(ranges, cx);
20036        }
20037
20038        self.ime_transaction = self.ime_transaction.or(transaction);
20039        if let Some(transaction) = self.ime_transaction {
20040            self.buffer.update(cx, |buffer, cx| {
20041                buffer.group_until_transaction(transaction, cx);
20042            });
20043        }
20044
20045        if self.text_highlights::<PendingInput>(cx).is_none() {
20046            self.ime_transaction.take();
20047        }
20048    }
20049
20050    pub fn register_action_renderer(
20051        &mut self,
20052        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20053    ) -> Subscription {
20054        let id = self.next_editor_action_id.post_inc();
20055        self.editor_actions
20056            .borrow_mut()
20057            .insert(id, Box::new(listener));
20058
20059        let editor_actions = self.editor_actions.clone();
20060        Subscription::new(move || {
20061            editor_actions.borrow_mut().remove(&id);
20062        })
20063    }
20064
20065    pub fn register_action<A: Action>(
20066        &mut self,
20067        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20068    ) -> Subscription {
20069        let id = self.next_editor_action_id.post_inc();
20070        let listener = Arc::new(listener);
20071        self.editor_actions.borrow_mut().insert(
20072            id,
20073            Box::new(move |_, window, _| {
20074                let listener = listener.clone();
20075                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20076                    let action = action.downcast_ref().unwrap();
20077                    if phase == DispatchPhase::Bubble {
20078                        listener(action, window, cx)
20079                    }
20080                })
20081            }),
20082        );
20083
20084        let editor_actions = self.editor_actions.clone();
20085        Subscription::new(move || {
20086            editor_actions.borrow_mut().remove(&id);
20087        })
20088    }
20089
20090    pub fn file_header_size(&self) -> u32 {
20091        FILE_HEADER_HEIGHT
20092    }
20093
20094    pub fn restore(
20095        &mut self,
20096        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20097        window: &mut Window,
20098        cx: &mut Context<Self>,
20099    ) {
20100        let workspace = self.workspace();
20101        let project = self.project.as_ref();
20102        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20103            let mut tasks = Vec::new();
20104            for (buffer_id, changes) in revert_changes {
20105                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20106                    buffer.update(cx, |buffer, cx| {
20107                        buffer.edit(
20108                            changes
20109                                .into_iter()
20110                                .map(|(range, text)| (range, text.to_string())),
20111                            None,
20112                            cx,
20113                        );
20114                    });
20115
20116                    if let Some(project) =
20117                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20118                    {
20119                        project.update(cx, |project, cx| {
20120                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20121                        })
20122                    }
20123                }
20124            }
20125            tasks
20126        });
20127        cx.spawn_in(window, async move |_, cx| {
20128            for (buffer, task) in save_tasks {
20129                let result = task.await;
20130                if result.is_err() {
20131                    let Some(path) = buffer
20132                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20133                        .ok()
20134                    else {
20135                        continue;
20136                    };
20137                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20138                        let Some(task) = cx
20139                            .update_window_entity(&workspace, |workspace, window, cx| {
20140                                workspace
20141                                    .open_path_preview(path, None, false, false, false, window, cx)
20142                            })
20143                            .ok()
20144                        else {
20145                            continue;
20146                        };
20147                        task.await.log_err();
20148                    }
20149                }
20150            }
20151        })
20152        .detach();
20153        self.change_selections(None, window, cx, |selections| selections.refresh());
20154    }
20155
20156    pub fn to_pixel_point(
20157        &self,
20158        source: multi_buffer::Anchor,
20159        editor_snapshot: &EditorSnapshot,
20160        window: &mut Window,
20161    ) -> Option<gpui::Point<Pixels>> {
20162        let source_point = source.to_display_point(editor_snapshot);
20163        self.display_to_pixel_point(source_point, editor_snapshot, window)
20164    }
20165
20166    pub fn display_to_pixel_point(
20167        &self,
20168        source: DisplayPoint,
20169        editor_snapshot: &EditorSnapshot,
20170        window: &mut Window,
20171    ) -> Option<gpui::Point<Pixels>> {
20172        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20173        let text_layout_details = self.text_layout_details(window);
20174        let scroll_top = text_layout_details
20175            .scroll_anchor
20176            .scroll_position(editor_snapshot)
20177            .y;
20178
20179        if source.row().as_f32() < scroll_top.floor() {
20180            return None;
20181        }
20182        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20183        let source_y = line_height * (source.row().as_f32() - scroll_top);
20184        Some(gpui::Point::new(source_x, source_y))
20185    }
20186
20187    pub fn has_visible_completions_menu(&self) -> bool {
20188        !self.edit_prediction_preview_is_active()
20189            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20190                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20191            })
20192    }
20193
20194    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20195        if self.mode.is_minimap() {
20196            return;
20197        }
20198        self.addons
20199            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20200    }
20201
20202    pub fn unregister_addon<T: Addon>(&mut self) {
20203        self.addons.remove(&std::any::TypeId::of::<T>());
20204    }
20205
20206    pub fn addon<T: Addon>(&self) -> Option<&T> {
20207        let type_id = std::any::TypeId::of::<T>();
20208        self.addons
20209            .get(&type_id)
20210            .and_then(|item| item.to_any().downcast_ref::<T>())
20211    }
20212
20213    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20214        let type_id = std::any::TypeId::of::<T>();
20215        self.addons
20216            .get_mut(&type_id)
20217            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20218    }
20219
20220    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20221        let text_layout_details = self.text_layout_details(window);
20222        let style = &text_layout_details.editor_style;
20223        let font_id = window.text_system().resolve_font(&style.text.font());
20224        let font_size = style.text.font_size.to_pixels(window.rem_size());
20225        let line_height = style.text.line_height_in_pixels(window.rem_size());
20226        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20227
20228        gpui::Size::new(em_width, line_height)
20229    }
20230
20231    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20232        self.load_diff_task.clone()
20233    }
20234
20235    fn read_metadata_from_db(
20236        &mut self,
20237        item_id: u64,
20238        workspace_id: WorkspaceId,
20239        window: &mut Window,
20240        cx: &mut Context<Editor>,
20241    ) {
20242        if self.is_singleton(cx)
20243            && !self.mode.is_minimap()
20244            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20245        {
20246            let buffer_snapshot = OnceCell::new();
20247
20248            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20249                if !folds.is_empty() {
20250                    let snapshot =
20251                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20252                    self.fold_ranges(
20253                        folds
20254                            .into_iter()
20255                            .map(|(start, end)| {
20256                                snapshot.clip_offset(start, Bias::Left)
20257                                    ..snapshot.clip_offset(end, Bias::Right)
20258                            })
20259                            .collect(),
20260                        false,
20261                        window,
20262                        cx,
20263                    );
20264                }
20265            }
20266
20267            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20268                if !selections.is_empty() {
20269                    let snapshot =
20270                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20271                    // skip adding the initial selection to selection history
20272                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20273                    self.change_selections(None, window, cx, |s| {
20274                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20275                            snapshot.clip_offset(start, Bias::Left)
20276                                ..snapshot.clip_offset(end, Bias::Right)
20277                        }));
20278                    });
20279                    self.selection_history.mode = SelectionHistoryMode::Normal;
20280                }
20281            };
20282        }
20283
20284        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20285    }
20286
20287    fn update_lsp_data(
20288        &mut self,
20289        update_on_edit: bool,
20290        for_server_id: Option<LanguageServerId>,
20291        for_buffer: Option<BufferId>,
20292        window: &mut Window,
20293        cx: &mut Context<'_, Self>,
20294    ) {
20295        self.pull_diagnostics(for_buffer, window, cx);
20296        self.refresh_colors(update_on_edit, for_server_id, for_buffer, window, cx);
20297    }
20298}
20299
20300fn vim_enabled(cx: &App) -> bool {
20301    cx.global::<SettingsStore>()
20302        .raw_user_settings()
20303        .get("vim_mode")
20304        == Some(&serde_json::Value::Bool(true))
20305}
20306
20307fn process_completion_for_edit(
20308    completion: &Completion,
20309    intent: CompletionIntent,
20310    buffer: &Entity<Buffer>,
20311    cursor_position: &text::Anchor,
20312    cx: &mut Context<Editor>,
20313) -> CompletionEdit {
20314    let buffer = buffer.read(cx);
20315    let buffer_snapshot = buffer.snapshot();
20316    let (snippet, new_text) = if completion.is_snippet() {
20317        // Workaround for typescript language server issues so that methods don't expand within
20318        // strings and functions with type expressions. The previous point is used because the query
20319        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20320        let mut snippet_source = completion.new_text.clone();
20321        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20322        previous_point.column = previous_point.column.saturating_sub(1);
20323        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20324            if scope.prefers_label_for_snippet_in_completion() {
20325                if let Some(label) = completion.label() {
20326                    if matches!(
20327                        completion.kind(),
20328                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20329                    ) {
20330                        snippet_source = label;
20331                    }
20332                }
20333            }
20334        }
20335        match Snippet::parse(&snippet_source).log_err() {
20336            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20337            None => (None, completion.new_text.clone()),
20338        }
20339    } else {
20340        (None, completion.new_text.clone())
20341    };
20342
20343    let mut range_to_replace = {
20344        let replace_range = &completion.replace_range;
20345        if let CompletionSource::Lsp {
20346            insert_range: Some(insert_range),
20347            ..
20348        } = &completion.source
20349        {
20350            debug_assert_eq!(
20351                insert_range.start, replace_range.start,
20352                "insert_range and replace_range should start at the same position"
20353            );
20354            debug_assert!(
20355                insert_range
20356                    .start
20357                    .cmp(&cursor_position, &buffer_snapshot)
20358                    .is_le(),
20359                "insert_range should start before or at cursor position"
20360            );
20361            debug_assert!(
20362                replace_range
20363                    .start
20364                    .cmp(&cursor_position, &buffer_snapshot)
20365                    .is_le(),
20366                "replace_range should start before or at cursor position"
20367            );
20368            debug_assert!(
20369                insert_range
20370                    .end
20371                    .cmp(&cursor_position, &buffer_snapshot)
20372                    .is_le(),
20373                "insert_range should end before or at cursor position"
20374            );
20375
20376            let should_replace = match intent {
20377                CompletionIntent::CompleteWithInsert => false,
20378                CompletionIntent::CompleteWithReplace => true,
20379                CompletionIntent::Complete | CompletionIntent::Compose => {
20380                    let insert_mode =
20381                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20382                            .completions
20383                            .lsp_insert_mode;
20384                    match insert_mode {
20385                        LspInsertMode::Insert => false,
20386                        LspInsertMode::Replace => true,
20387                        LspInsertMode::ReplaceSubsequence => {
20388                            let mut text_to_replace = buffer.chars_for_range(
20389                                buffer.anchor_before(replace_range.start)
20390                                    ..buffer.anchor_after(replace_range.end),
20391                            );
20392                            let mut current_needle = text_to_replace.next();
20393                            for haystack_ch in completion.label.text.chars() {
20394                                if let Some(needle_ch) = current_needle {
20395                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20396                                        current_needle = text_to_replace.next();
20397                                    }
20398                                }
20399                            }
20400                            current_needle.is_none()
20401                        }
20402                        LspInsertMode::ReplaceSuffix => {
20403                            if replace_range
20404                                .end
20405                                .cmp(&cursor_position, &buffer_snapshot)
20406                                .is_gt()
20407                            {
20408                                let range_after_cursor = *cursor_position..replace_range.end;
20409                                let text_after_cursor = buffer
20410                                    .text_for_range(
20411                                        buffer.anchor_before(range_after_cursor.start)
20412                                            ..buffer.anchor_after(range_after_cursor.end),
20413                                    )
20414                                    .collect::<String>()
20415                                    .to_ascii_lowercase();
20416                                completion
20417                                    .label
20418                                    .text
20419                                    .to_ascii_lowercase()
20420                                    .ends_with(&text_after_cursor)
20421                            } else {
20422                                true
20423                            }
20424                        }
20425                    }
20426                }
20427            };
20428
20429            if should_replace {
20430                replace_range.clone()
20431            } else {
20432                insert_range.clone()
20433            }
20434        } else {
20435            replace_range.clone()
20436        }
20437    };
20438
20439    if range_to_replace
20440        .end
20441        .cmp(&cursor_position, &buffer_snapshot)
20442        .is_lt()
20443    {
20444        range_to_replace.end = *cursor_position;
20445    }
20446
20447    CompletionEdit {
20448        new_text,
20449        replace_range: range_to_replace.to_offset(&buffer),
20450        snippet,
20451    }
20452}
20453
20454struct CompletionEdit {
20455    new_text: String,
20456    replace_range: Range<usize>,
20457    snippet: Option<Snippet>,
20458}
20459
20460fn insert_extra_newline_brackets(
20461    buffer: &MultiBufferSnapshot,
20462    range: Range<usize>,
20463    language: &language::LanguageScope,
20464) -> bool {
20465    let leading_whitespace_len = buffer
20466        .reversed_chars_at(range.start)
20467        .take_while(|c| c.is_whitespace() && *c != '\n')
20468        .map(|c| c.len_utf8())
20469        .sum::<usize>();
20470    let trailing_whitespace_len = buffer
20471        .chars_at(range.end)
20472        .take_while(|c| c.is_whitespace() && *c != '\n')
20473        .map(|c| c.len_utf8())
20474        .sum::<usize>();
20475    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20476
20477    language.brackets().any(|(pair, enabled)| {
20478        let pair_start = pair.start.trim_end();
20479        let pair_end = pair.end.trim_start();
20480
20481        enabled
20482            && pair.newline
20483            && buffer.contains_str_at(range.end, pair_end)
20484            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20485    })
20486}
20487
20488fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20489    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20490        [(buffer, range, _)] => (*buffer, range.clone()),
20491        _ => return false,
20492    };
20493    let pair = {
20494        let mut result: Option<BracketMatch> = None;
20495
20496        for pair in buffer
20497            .all_bracket_ranges(range.clone())
20498            .filter(move |pair| {
20499                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20500            })
20501        {
20502            let len = pair.close_range.end - pair.open_range.start;
20503
20504            if let Some(existing) = &result {
20505                let existing_len = existing.close_range.end - existing.open_range.start;
20506                if len > existing_len {
20507                    continue;
20508                }
20509            }
20510
20511            result = Some(pair);
20512        }
20513
20514        result
20515    };
20516    let Some(pair) = pair else {
20517        return false;
20518    };
20519    pair.newline_only
20520        && buffer
20521            .chars_for_range(pair.open_range.end..range.start)
20522            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20523            .all(|c| c.is_whitespace() && c != '\n')
20524}
20525
20526fn update_uncommitted_diff_for_buffer(
20527    editor: Entity<Editor>,
20528    project: &Entity<Project>,
20529    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20530    buffer: Entity<MultiBuffer>,
20531    cx: &mut App,
20532) -> Task<()> {
20533    let mut tasks = Vec::new();
20534    project.update(cx, |project, cx| {
20535        for buffer in buffers {
20536            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20537                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20538            }
20539        }
20540    });
20541    cx.spawn(async move |cx| {
20542        let diffs = future::join_all(tasks).await;
20543        if editor
20544            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20545            .unwrap_or(false)
20546        {
20547            return;
20548        }
20549
20550        buffer
20551            .update(cx, |buffer, cx| {
20552                for diff in diffs.into_iter().flatten() {
20553                    buffer.add_diff(diff, cx);
20554                }
20555            })
20556            .ok();
20557    })
20558}
20559
20560fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20561    let tab_size = tab_size.get() as usize;
20562    let mut width = offset;
20563
20564    for ch in text.chars() {
20565        width += if ch == '\t' {
20566            tab_size - (width % tab_size)
20567        } else {
20568            1
20569        };
20570    }
20571
20572    width - offset
20573}
20574
20575#[cfg(test)]
20576mod tests {
20577    use super::*;
20578
20579    #[test]
20580    fn test_string_size_with_expanded_tabs() {
20581        let nz = |val| NonZeroU32::new(val).unwrap();
20582        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20583        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20584        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20585        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20586        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20587        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20588        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20589        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20590    }
20591}
20592
20593/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20594struct WordBreakingTokenizer<'a> {
20595    input: &'a str,
20596}
20597
20598impl<'a> WordBreakingTokenizer<'a> {
20599    fn new(input: &'a str) -> Self {
20600        Self { input }
20601    }
20602}
20603
20604fn is_char_ideographic(ch: char) -> bool {
20605    use unicode_script::Script::*;
20606    use unicode_script::UnicodeScript;
20607    matches!(ch.script(), Han | Tangut | Yi)
20608}
20609
20610fn is_grapheme_ideographic(text: &str) -> bool {
20611    text.chars().any(is_char_ideographic)
20612}
20613
20614fn is_grapheme_whitespace(text: &str) -> bool {
20615    text.chars().any(|x| x.is_whitespace())
20616}
20617
20618fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20619    text.chars().next().map_or(false, |ch| {
20620        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20621    })
20622}
20623
20624#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20625enum WordBreakToken<'a> {
20626    Word { token: &'a str, grapheme_len: usize },
20627    InlineWhitespace { token: &'a str, grapheme_len: usize },
20628    Newline,
20629}
20630
20631impl<'a> Iterator for WordBreakingTokenizer<'a> {
20632    /// Yields a span, the count of graphemes in the token, and whether it was
20633    /// whitespace. Note that it also breaks at word boundaries.
20634    type Item = WordBreakToken<'a>;
20635
20636    fn next(&mut self) -> Option<Self::Item> {
20637        use unicode_segmentation::UnicodeSegmentation;
20638        if self.input.is_empty() {
20639            return None;
20640        }
20641
20642        let mut iter = self.input.graphemes(true).peekable();
20643        let mut offset = 0;
20644        let mut grapheme_len = 0;
20645        if let Some(first_grapheme) = iter.next() {
20646            let is_newline = first_grapheme == "\n";
20647            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20648            offset += first_grapheme.len();
20649            grapheme_len += 1;
20650            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20651                if let Some(grapheme) = iter.peek().copied() {
20652                    if should_stay_with_preceding_ideograph(grapheme) {
20653                        offset += grapheme.len();
20654                        grapheme_len += 1;
20655                    }
20656                }
20657            } else {
20658                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20659                let mut next_word_bound = words.peek().copied();
20660                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20661                    next_word_bound = words.next();
20662                }
20663                while let Some(grapheme) = iter.peek().copied() {
20664                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20665                        break;
20666                    };
20667                    if is_grapheme_whitespace(grapheme) != is_whitespace
20668                        || (grapheme == "\n") != is_newline
20669                    {
20670                        break;
20671                    };
20672                    offset += grapheme.len();
20673                    grapheme_len += 1;
20674                    iter.next();
20675                }
20676            }
20677            let token = &self.input[..offset];
20678            self.input = &self.input[offset..];
20679            if token == "\n" {
20680                Some(WordBreakToken::Newline)
20681            } else if is_whitespace {
20682                Some(WordBreakToken::InlineWhitespace {
20683                    token,
20684                    grapheme_len,
20685                })
20686            } else {
20687                Some(WordBreakToken::Word {
20688                    token,
20689                    grapheme_len,
20690                })
20691            }
20692        } else {
20693            None
20694        }
20695    }
20696}
20697
20698#[test]
20699fn test_word_breaking_tokenizer() {
20700    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20701        ("", &[]),
20702        ("  ", &[whitespace("  ", 2)]),
20703        ("Ʒ", &[word("Ʒ", 1)]),
20704        ("Ǽ", &[word("Ǽ", 1)]),
20705        ("", &[word("", 1)]),
20706        ("⋑⋑", &[word("⋑⋑", 2)]),
20707        (
20708            "原理,进而",
20709            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20710        ),
20711        (
20712            "hello world",
20713            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20714        ),
20715        (
20716            "hello, world",
20717            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20718        ),
20719        (
20720            "  hello world",
20721            &[
20722                whitespace("  ", 2),
20723                word("hello", 5),
20724                whitespace(" ", 1),
20725                word("world", 5),
20726            ],
20727        ),
20728        (
20729            "这是什么 \n 钢笔",
20730            &[
20731                word("", 1),
20732                word("", 1),
20733                word("", 1),
20734                word("", 1),
20735                whitespace(" ", 1),
20736                newline(),
20737                whitespace(" ", 1),
20738                word("", 1),
20739                word("", 1),
20740            ],
20741        ),
20742        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20743    ];
20744
20745    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20746        WordBreakToken::Word {
20747            token,
20748            grapheme_len,
20749        }
20750    }
20751
20752    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20753        WordBreakToken::InlineWhitespace {
20754            token,
20755            grapheme_len,
20756        }
20757    }
20758
20759    fn newline() -> WordBreakToken<'static> {
20760        WordBreakToken::Newline
20761    }
20762
20763    for (input, result) in tests {
20764        assert_eq!(
20765            WordBreakingTokenizer::new(input)
20766                .collect::<Vec<_>>()
20767                .as_slice(),
20768            *result,
20769        );
20770    }
20771}
20772
20773fn wrap_with_prefix(
20774    line_prefix: String,
20775    unwrapped_text: String,
20776    wrap_column: usize,
20777    tab_size: NonZeroU32,
20778    preserve_existing_whitespace: bool,
20779) -> String {
20780    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20781    let mut wrapped_text = String::new();
20782    let mut current_line = line_prefix.clone();
20783
20784    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20785    let mut current_line_len = line_prefix_len;
20786    let mut in_whitespace = false;
20787    for token in tokenizer {
20788        let have_preceding_whitespace = in_whitespace;
20789        match token {
20790            WordBreakToken::Word {
20791                token,
20792                grapheme_len,
20793            } => {
20794                in_whitespace = false;
20795                if current_line_len + grapheme_len > wrap_column
20796                    && current_line_len != line_prefix_len
20797                {
20798                    wrapped_text.push_str(current_line.trim_end());
20799                    wrapped_text.push('\n');
20800                    current_line.truncate(line_prefix.len());
20801                    current_line_len = line_prefix_len;
20802                }
20803                current_line.push_str(token);
20804                current_line_len += grapheme_len;
20805            }
20806            WordBreakToken::InlineWhitespace {
20807                mut token,
20808                mut grapheme_len,
20809            } => {
20810                in_whitespace = true;
20811                if have_preceding_whitespace && !preserve_existing_whitespace {
20812                    continue;
20813                }
20814                if !preserve_existing_whitespace {
20815                    token = " ";
20816                    grapheme_len = 1;
20817                }
20818                if current_line_len + grapheme_len > wrap_column {
20819                    wrapped_text.push_str(current_line.trim_end());
20820                    wrapped_text.push('\n');
20821                    current_line.truncate(line_prefix.len());
20822                    current_line_len = line_prefix_len;
20823                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20824                    current_line.push_str(token);
20825                    current_line_len += grapheme_len;
20826                }
20827            }
20828            WordBreakToken::Newline => {
20829                in_whitespace = true;
20830                if preserve_existing_whitespace {
20831                    wrapped_text.push_str(current_line.trim_end());
20832                    wrapped_text.push('\n');
20833                    current_line.truncate(line_prefix.len());
20834                    current_line_len = line_prefix_len;
20835                } else if have_preceding_whitespace {
20836                    continue;
20837                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20838                {
20839                    wrapped_text.push_str(current_line.trim_end());
20840                    wrapped_text.push('\n');
20841                    current_line.truncate(line_prefix.len());
20842                    current_line_len = line_prefix_len;
20843                } else if current_line_len != line_prefix_len {
20844                    current_line.push(' ');
20845                    current_line_len += 1;
20846                }
20847            }
20848        }
20849    }
20850
20851    if !current_line.is_empty() {
20852        wrapped_text.push_str(&current_line);
20853    }
20854    wrapped_text
20855}
20856
20857#[test]
20858fn test_wrap_with_prefix() {
20859    assert_eq!(
20860        wrap_with_prefix(
20861            "# ".to_string(),
20862            "abcdefg".to_string(),
20863            4,
20864            NonZeroU32::new(4).unwrap(),
20865            false,
20866        ),
20867        "# abcdefg"
20868    );
20869    assert_eq!(
20870        wrap_with_prefix(
20871            "".to_string(),
20872            "\thello world".to_string(),
20873            8,
20874            NonZeroU32::new(4).unwrap(),
20875            false,
20876        ),
20877        "hello\nworld"
20878    );
20879    assert_eq!(
20880        wrap_with_prefix(
20881            "// ".to_string(),
20882            "xx \nyy zz aa bb cc".to_string(),
20883            12,
20884            NonZeroU32::new(4).unwrap(),
20885            false,
20886        ),
20887        "// xx yy zz\n// aa bb cc"
20888    );
20889    assert_eq!(
20890        wrap_with_prefix(
20891            String::new(),
20892            "这是什么 \n 钢笔".to_string(),
20893            3,
20894            NonZeroU32::new(4).unwrap(),
20895            false,
20896        ),
20897        "这是什\n么 钢\n"
20898    );
20899}
20900
20901pub trait CollaborationHub {
20902    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20903    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20904    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20905}
20906
20907impl CollaborationHub for Entity<Project> {
20908    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20909        self.read(cx).collaborators()
20910    }
20911
20912    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20913        self.read(cx).user_store().read(cx).participant_indices()
20914    }
20915
20916    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20917        let this = self.read(cx);
20918        let user_ids = this.collaborators().values().map(|c| c.user_id);
20919        this.user_store().read(cx).participant_names(user_ids, cx)
20920    }
20921}
20922
20923pub trait SemanticsProvider {
20924    fn hover(
20925        &self,
20926        buffer: &Entity<Buffer>,
20927        position: text::Anchor,
20928        cx: &mut App,
20929    ) -> Option<Task<Vec<project::Hover>>>;
20930
20931    fn inline_values(
20932        &self,
20933        buffer_handle: Entity<Buffer>,
20934        range: Range<text::Anchor>,
20935        cx: &mut App,
20936    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20937
20938    fn inlay_hints(
20939        &self,
20940        buffer_handle: Entity<Buffer>,
20941        range: Range<text::Anchor>,
20942        cx: &mut App,
20943    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20944
20945    fn resolve_inlay_hint(
20946        &self,
20947        hint: InlayHint,
20948        buffer_handle: Entity<Buffer>,
20949        server_id: LanguageServerId,
20950        cx: &mut App,
20951    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20952
20953    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20954
20955    fn document_highlights(
20956        &self,
20957        buffer: &Entity<Buffer>,
20958        position: text::Anchor,
20959        cx: &mut App,
20960    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20961
20962    fn definitions(
20963        &self,
20964        buffer: &Entity<Buffer>,
20965        position: text::Anchor,
20966        kind: GotoDefinitionKind,
20967        cx: &mut App,
20968    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20969
20970    fn range_for_rename(
20971        &self,
20972        buffer: &Entity<Buffer>,
20973        position: text::Anchor,
20974        cx: &mut App,
20975    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20976
20977    fn perform_rename(
20978        &self,
20979        buffer: &Entity<Buffer>,
20980        position: text::Anchor,
20981        new_name: String,
20982        cx: &mut App,
20983    ) -> Option<Task<Result<ProjectTransaction>>>;
20984}
20985
20986pub trait CompletionProvider {
20987    fn completions(
20988        &self,
20989        excerpt_id: ExcerptId,
20990        buffer: &Entity<Buffer>,
20991        buffer_position: text::Anchor,
20992        trigger: CompletionContext,
20993        window: &mut Window,
20994        cx: &mut Context<Editor>,
20995    ) -> Task<Result<Vec<CompletionResponse>>>;
20996
20997    fn resolve_completions(
20998        &self,
20999        _buffer: Entity<Buffer>,
21000        _completion_indices: Vec<usize>,
21001        _completions: Rc<RefCell<Box<[Completion]>>>,
21002        _cx: &mut Context<Editor>,
21003    ) -> Task<Result<bool>> {
21004        Task::ready(Ok(false))
21005    }
21006
21007    fn apply_additional_edits_for_completion(
21008        &self,
21009        _buffer: Entity<Buffer>,
21010        _completions: Rc<RefCell<Box<[Completion]>>>,
21011        _completion_index: usize,
21012        _push_to_history: bool,
21013        _cx: &mut Context<Editor>,
21014    ) -> Task<Result<Option<language::Transaction>>> {
21015        Task::ready(Ok(None))
21016    }
21017
21018    fn is_completion_trigger(
21019        &self,
21020        buffer: &Entity<Buffer>,
21021        position: language::Anchor,
21022        text: &str,
21023        trigger_in_words: bool,
21024        menu_is_open: bool,
21025        cx: &mut Context<Editor>,
21026    ) -> bool;
21027
21028    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21029
21030    fn sort_completions(&self) -> bool {
21031        true
21032    }
21033
21034    fn filter_completions(&self) -> bool {
21035        true
21036    }
21037}
21038
21039pub trait CodeActionProvider {
21040    fn id(&self) -> Arc<str>;
21041
21042    fn code_actions(
21043        &self,
21044        buffer: &Entity<Buffer>,
21045        range: Range<text::Anchor>,
21046        window: &mut Window,
21047        cx: &mut App,
21048    ) -> Task<Result<Vec<CodeAction>>>;
21049
21050    fn apply_code_action(
21051        &self,
21052        buffer_handle: Entity<Buffer>,
21053        action: CodeAction,
21054        excerpt_id: ExcerptId,
21055        push_to_history: bool,
21056        window: &mut Window,
21057        cx: &mut App,
21058    ) -> Task<Result<ProjectTransaction>>;
21059}
21060
21061impl CodeActionProvider for Entity<Project> {
21062    fn id(&self) -> Arc<str> {
21063        "project".into()
21064    }
21065
21066    fn code_actions(
21067        &self,
21068        buffer: &Entity<Buffer>,
21069        range: Range<text::Anchor>,
21070        _window: &mut Window,
21071        cx: &mut App,
21072    ) -> Task<Result<Vec<CodeAction>>> {
21073        self.update(cx, |project, cx| {
21074            let code_lens = project.code_lens(buffer, range.clone(), cx);
21075            let code_actions = project.code_actions(buffer, range, None, cx);
21076            cx.background_spawn(async move {
21077                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21078                Ok(code_lens
21079                    .context("code lens fetch")?
21080                    .into_iter()
21081                    .chain(code_actions.context("code action fetch")?)
21082                    .collect())
21083            })
21084        })
21085    }
21086
21087    fn apply_code_action(
21088        &self,
21089        buffer_handle: Entity<Buffer>,
21090        action: CodeAction,
21091        _excerpt_id: ExcerptId,
21092        push_to_history: bool,
21093        _window: &mut Window,
21094        cx: &mut App,
21095    ) -> Task<Result<ProjectTransaction>> {
21096        self.update(cx, |project, cx| {
21097            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21098        })
21099    }
21100}
21101
21102fn snippet_completions(
21103    project: &Project,
21104    buffer: &Entity<Buffer>,
21105    buffer_position: text::Anchor,
21106    cx: &mut App,
21107) -> Task<Result<CompletionResponse>> {
21108    let languages = buffer.read(cx).languages_at(buffer_position);
21109    let snippet_store = project.snippets().read(cx);
21110
21111    let scopes: Vec<_> = languages
21112        .iter()
21113        .filter_map(|language| {
21114            let language_name = language.lsp_id();
21115            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21116
21117            if snippets.is_empty() {
21118                None
21119            } else {
21120                Some((language.default_scope(), snippets))
21121            }
21122        })
21123        .collect();
21124
21125    if scopes.is_empty() {
21126        return Task::ready(Ok(CompletionResponse {
21127            completions: vec![],
21128            is_incomplete: false,
21129        }));
21130    }
21131
21132    let snapshot = buffer.read(cx).text_snapshot();
21133    let chars: String = snapshot
21134        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21135        .collect();
21136    let executor = cx.background_executor().clone();
21137
21138    cx.background_spawn(async move {
21139        let mut is_incomplete = false;
21140        let mut completions: Vec<Completion> = Vec::new();
21141        for (scope, snippets) in scopes.into_iter() {
21142            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21143            let mut last_word = chars
21144                .chars()
21145                .take_while(|c| classifier.is_word(*c))
21146                .collect::<String>();
21147            last_word = last_word.chars().rev().collect();
21148
21149            if last_word.is_empty() {
21150                return Ok(CompletionResponse {
21151                    completions: vec![],
21152                    is_incomplete: true,
21153                });
21154            }
21155
21156            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21157            let to_lsp = |point: &text::Anchor| {
21158                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21159                point_to_lsp(end)
21160            };
21161            let lsp_end = to_lsp(&buffer_position);
21162
21163            let candidates = snippets
21164                .iter()
21165                .enumerate()
21166                .flat_map(|(ix, snippet)| {
21167                    snippet
21168                        .prefix
21169                        .iter()
21170                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21171                })
21172                .collect::<Vec<StringMatchCandidate>>();
21173
21174            const MAX_RESULTS: usize = 100;
21175            let mut matches = fuzzy::match_strings(
21176                &candidates,
21177                &last_word,
21178                last_word.chars().any(|c| c.is_uppercase()),
21179                MAX_RESULTS,
21180                &Default::default(),
21181                executor.clone(),
21182            )
21183            .await;
21184
21185            if matches.len() >= MAX_RESULTS {
21186                is_incomplete = true;
21187            }
21188
21189            // Remove all candidates where the query's start does not match the start of any word in the candidate
21190            if let Some(query_start) = last_word.chars().next() {
21191                matches.retain(|string_match| {
21192                    split_words(&string_match.string).any(|word| {
21193                        // Check that the first codepoint of the word as lowercase matches the first
21194                        // codepoint of the query as lowercase
21195                        word.chars()
21196                            .flat_map(|codepoint| codepoint.to_lowercase())
21197                            .zip(query_start.to_lowercase())
21198                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21199                    })
21200                });
21201            }
21202
21203            let matched_strings = matches
21204                .into_iter()
21205                .map(|m| m.string)
21206                .collect::<HashSet<_>>();
21207
21208            completions.extend(snippets.iter().filter_map(|snippet| {
21209                let matching_prefix = snippet
21210                    .prefix
21211                    .iter()
21212                    .find(|prefix| matched_strings.contains(*prefix))?;
21213                let start = as_offset - last_word.len();
21214                let start = snapshot.anchor_before(start);
21215                let range = start..buffer_position;
21216                let lsp_start = to_lsp(&start);
21217                let lsp_range = lsp::Range {
21218                    start: lsp_start,
21219                    end: lsp_end,
21220                };
21221                Some(Completion {
21222                    replace_range: range,
21223                    new_text: snippet.body.clone(),
21224                    source: CompletionSource::Lsp {
21225                        insert_range: None,
21226                        server_id: LanguageServerId(usize::MAX),
21227                        resolved: true,
21228                        lsp_completion: Box::new(lsp::CompletionItem {
21229                            label: snippet.prefix.first().unwrap().clone(),
21230                            kind: Some(CompletionItemKind::SNIPPET),
21231                            label_details: snippet.description.as_ref().map(|description| {
21232                                lsp::CompletionItemLabelDetails {
21233                                    detail: Some(description.clone()),
21234                                    description: None,
21235                                }
21236                            }),
21237                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21238                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21239                                lsp::InsertReplaceEdit {
21240                                    new_text: snippet.body.clone(),
21241                                    insert: lsp_range,
21242                                    replace: lsp_range,
21243                                },
21244                            )),
21245                            filter_text: Some(snippet.body.clone()),
21246                            sort_text: Some(char::MAX.to_string()),
21247                            ..lsp::CompletionItem::default()
21248                        }),
21249                        lsp_defaults: None,
21250                    },
21251                    label: CodeLabel {
21252                        text: matching_prefix.clone(),
21253                        runs: Vec::new(),
21254                        filter_range: 0..matching_prefix.len(),
21255                    },
21256                    icon_path: None,
21257                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21258                        single_line: snippet.name.clone().into(),
21259                        plain_text: snippet
21260                            .description
21261                            .clone()
21262                            .map(|description| description.into()),
21263                    }),
21264                    insert_text_mode: None,
21265                    confirm: None,
21266                })
21267            }))
21268        }
21269
21270        Ok(CompletionResponse {
21271            completions,
21272            is_incomplete,
21273        })
21274    })
21275}
21276
21277impl CompletionProvider for Entity<Project> {
21278    fn completions(
21279        &self,
21280        _excerpt_id: ExcerptId,
21281        buffer: &Entity<Buffer>,
21282        buffer_position: text::Anchor,
21283        options: CompletionContext,
21284        _window: &mut Window,
21285        cx: &mut Context<Editor>,
21286    ) -> Task<Result<Vec<CompletionResponse>>> {
21287        self.update(cx, |project, cx| {
21288            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21289            let project_completions = project.completions(buffer, buffer_position, options, cx);
21290            cx.background_spawn(async move {
21291                let mut responses = project_completions.await?;
21292                let snippets = snippets.await?;
21293                if !snippets.completions.is_empty() {
21294                    responses.push(snippets);
21295                }
21296                Ok(responses)
21297            })
21298        })
21299    }
21300
21301    fn resolve_completions(
21302        &self,
21303        buffer: Entity<Buffer>,
21304        completion_indices: Vec<usize>,
21305        completions: Rc<RefCell<Box<[Completion]>>>,
21306        cx: &mut Context<Editor>,
21307    ) -> Task<Result<bool>> {
21308        self.update(cx, |project, cx| {
21309            project.lsp_store().update(cx, |lsp_store, cx| {
21310                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21311            })
21312        })
21313    }
21314
21315    fn apply_additional_edits_for_completion(
21316        &self,
21317        buffer: Entity<Buffer>,
21318        completions: Rc<RefCell<Box<[Completion]>>>,
21319        completion_index: usize,
21320        push_to_history: bool,
21321        cx: &mut Context<Editor>,
21322    ) -> Task<Result<Option<language::Transaction>>> {
21323        self.update(cx, |project, cx| {
21324            project.lsp_store().update(cx, |lsp_store, cx| {
21325                lsp_store.apply_additional_edits_for_completion(
21326                    buffer,
21327                    completions,
21328                    completion_index,
21329                    push_to_history,
21330                    cx,
21331                )
21332            })
21333        })
21334    }
21335
21336    fn is_completion_trigger(
21337        &self,
21338        buffer: &Entity<Buffer>,
21339        position: language::Anchor,
21340        text: &str,
21341        trigger_in_words: bool,
21342        menu_is_open: bool,
21343        cx: &mut Context<Editor>,
21344    ) -> bool {
21345        let mut chars = text.chars();
21346        let char = if let Some(char) = chars.next() {
21347            char
21348        } else {
21349            return false;
21350        };
21351        if chars.next().is_some() {
21352            return false;
21353        }
21354
21355        let buffer = buffer.read(cx);
21356        let snapshot = buffer.snapshot();
21357        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21358            return false;
21359        }
21360        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21361        if trigger_in_words && classifier.is_word(char) {
21362            return true;
21363        }
21364
21365        buffer.completion_triggers().contains(text)
21366    }
21367}
21368
21369impl SemanticsProvider for Entity<Project> {
21370    fn hover(
21371        &self,
21372        buffer: &Entity<Buffer>,
21373        position: text::Anchor,
21374        cx: &mut App,
21375    ) -> Option<Task<Vec<project::Hover>>> {
21376        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21377    }
21378
21379    fn document_highlights(
21380        &self,
21381        buffer: &Entity<Buffer>,
21382        position: text::Anchor,
21383        cx: &mut App,
21384    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21385        Some(self.update(cx, |project, cx| {
21386            project.document_highlights(buffer, position, cx)
21387        }))
21388    }
21389
21390    fn definitions(
21391        &self,
21392        buffer: &Entity<Buffer>,
21393        position: text::Anchor,
21394        kind: GotoDefinitionKind,
21395        cx: &mut App,
21396    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21397        Some(self.update(cx, |project, cx| match kind {
21398            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21399            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21400            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21401            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21402        }))
21403    }
21404
21405    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21406        // TODO: make this work for remote projects
21407        self.update(cx, |project, cx| {
21408            if project
21409                .active_debug_session(cx)
21410                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21411            {
21412                return true;
21413            }
21414
21415            buffer.update(cx, |buffer, cx| {
21416                project.any_language_server_supports_inlay_hints(buffer, cx)
21417            })
21418        })
21419    }
21420
21421    fn inline_values(
21422        &self,
21423        buffer_handle: Entity<Buffer>,
21424
21425        range: Range<text::Anchor>,
21426        cx: &mut App,
21427    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21428        self.update(cx, |project, cx| {
21429            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21430
21431            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21432        })
21433    }
21434
21435    fn inlay_hints(
21436        &self,
21437        buffer_handle: Entity<Buffer>,
21438        range: Range<text::Anchor>,
21439        cx: &mut App,
21440    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21441        Some(self.update(cx, |project, cx| {
21442            project.inlay_hints(buffer_handle, range, cx)
21443        }))
21444    }
21445
21446    fn resolve_inlay_hint(
21447        &self,
21448        hint: InlayHint,
21449        buffer_handle: Entity<Buffer>,
21450        server_id: LanguageServerId,
21451        cx: &mut App,
21452    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21453        Some(self.update(cx, |project, cx| {
21454            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21455        }))
21456    }
21457
21458    fn range_for_rename(
21459        &self,
21460        buffer: &Entity<Buffer>,
21461        position: text::Anchor,
21462        cx: &mut App,
21463    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21464        Some(self.update(cx, |project, cx| {
21465            let buffer = buffer.clone();
21466            let task = project.prepare_rename(buffer.clone(), position, cx);
21467            cx.spawn(async move |_, cx| {
21468                Ok(match task.await? {
21469                    PrepareRenameResponse::Success(range) => Some(range),
21470                    PrepareRenameResponse::InvalidPosition => None,
21471                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21472                        // Fallback on using TreeSitter info to determine identifier range
21473                        buffer.read_with(cx, |buffer, _| {
21474                            let snapshot = buffer.snapshot();
21475                            let (range, kind) = snapshot.surrounding_word(position);
21476                            if kind != Some(CharKind::Word) {
21477                                return None;
21478                            }
21479                            Some(
21480                                snapshot.anchor_before(range.start)
21481                                    ..snapshot.anchor_after(range.end),
21482                            )
21483                        })?
21484                    }
21485                })
21486            })
21487        }))
21488    }
21489
21490    fn perform_rename(
21491        &self,
21492        buffer: &Entity<Buffer>,
21493        position: text::Anchor,
21494        new_name: String,
21495        cx: &mut App,
21496    ) -> Option<Task<Result<ProjectTransaction>>> {
21497        Some(self.update(cx, |project, cx| {
21498            project.perform_rename(buffer.clone(), position, new_name, cx)
21499        }))
21500    }
21501}
21502
21503fn inlay_hint_settings(
21504    location: Anchor,
21505    snapshot: &MultiBufferSnapshot,
21506    cx: &mut Context<Editor>,
21507) -> InlayHintSettings {
21508    let file = snapshot.file_at(location);
21509    let language = snapshot.language_at(location).map(|l| l.name());
21510    language_settings(language, file, cx).inlay_hints
21511}
21512
21513fn consume_contiguous_rows(
21514    contiguous_row_selections: &mut Vec<Selection<Point>>,
21515    selection: &Selection<Point>,
21516    display_map: &DisplaySnapshot,
21517    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21518) -> (MultiBufferRow, MultiBufferRow) {
21519    contiguous_row_selections.push(selection.clone());
21520    let start_row = MultiBufferRow(selection.start.row);
21521    let mut end_row = ending_row(selection, display_map);
21522
21523    while let Some(next_selection) = selections.peek() {
21524        if next_selection.start.row <= end_row.0 {
21525            end_row = ending_row(next_selection, display_map);
21526            contiguous_row_selections.push(selections.next().unwrap().clone());
21527        } else {
21528            break;
21529        }
21530    }
21531    (start_row, end_row)
21532}
21533
21534fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21535    if next_selection.end.column > 0 || next_selection.is_empty() {
21536        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21537    } else {
21538        MultiBufferRow(next_selection.end.row)
21539    }
21540}
21541
21542impl EditorSnapshot {
21543    pub fn remote_selections_in_range<'a>(
21544        &'a self,
21545        range: &'a Range<Anchor>,
21546        collaboration_hub: &dyn CollaborationHub,
21547        cx: &'a App,
21548    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21549        let participant_names = collaboration_hub.user_names(cx);
21550        let participant_indices = collaboration_hub.user_participant_indices(cx);
21551        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21552        let collaborators_by_replica_id = collaborators_by_peer_id
21553            .values()
21554            .map(|collaborator| (collaborator.replica_id, collaborator))
21555            .collect::<HashMap<_, _>>();
21556        self.buffer_snapshot
21557            .selections_in_range(range, false)
21558            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21559                if replica_id == AGENT_REPLICA_ID {
21560                    Some(RemoteSelection {
21561                        replica_id,
21562                        selection,
21563                        cursor_shape,
21564                        line_mode,
21565                        collaborator_id: CollaboratorId::Agent,
21566                        user_name: Some("Agent".into()),
21567                        color: cx.theme().players().agent(),
21568                    })
21569                } else {
21570                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21571                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21572                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21573                    Some(RemoteSelection {
21574                        replica_id,
21575                        selection,
21576                        cursor_shape,
21577                        line_mode,
21578                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21579                        user_name,
21580                        color: if let Some(index) = participant_index {
21581                            cx.theme().players().color_for_participant(index.0)
21582                        } else {
21583                            cx.theme().players().absent()
21584                        },
21585                    })
21586                }
21587            })
21588    }
21589
21590    pub fn hunks_for_ranges(
21591        &self,
21592        ranges: impl IntoIterator<Item = Range<Point>>,
21593    ) -> Vec<MultiBufferDiffHunk> {
21594        let mut hunks = Vec::new();
21595        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21596            HashMap::default();
21597        for query_range in ranges {
21598            let query_rows =
21599                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21600            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21601                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21602            ) {
21603                // Include deleted hunks that are adjacent to the query range, because
21604                // otherwise they would be missed.
21605                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21606                if hunk.status().is_deleted() {
21607                    intersects_range |= hunk.row_range.start == query_rows.end;
21608                    intersects_range |= hunk.row_range.end == query_rows.start;
21609                }
21610                if intersects_range {
21611                    if !processed_buffer_rows
21612                        .entry(hunk.buffer_id)
21613                        .or_default()
21614                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21615                    {
21616                        continue;
21617                    }
21618                    hunks.push(hunk);
21619                }
21620            }
21621        }
21622
21623        hunks
21624    }
21625
21626    fn display_diff_hunks_for_rows<'a>(
21627        &'a self,
21628        display_rows: Range<DisplayRow>,
21629        folded_buffers: &'a HashSet<BufferId>,
21630    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21631        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21632        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21633
21634        self.buffer_snapshot
21635            .diff_hunks_in_range(buffer_start..buffer_end)
21636            .filter_map(|hunk| {
21637                if folded_buffers.contains(&hunk.buffer_id) {
21638                    return None;
21639                }
21640
21641                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21642                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21643
21644                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21645                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21646
21647                let display_hunk = if hunk_display_start.column() != 0 {
21648                    DisplayDiffHunk::Folded {
21649                        display_row: hunk_display_start.row(),
21650                    }
21651                } else {
21652                    let mut end_row = hunk_display_end.row();
21653                    if hunk_display_end.column() > 0 {
21654                        end_row.0 += 1;
21655                    }
21656                    let is_created_file = hunk.is_created_file();
21657                    DisplayDiffHunk::Unfolded {
21658                        status: hunk.status(),
21659                        diff_base_byte_range: hunk.diff_base_byte_range,
21660                        display_row_range: hunk_display_start.row()..end_row,
21661                        multi_buffer_range: Anchor::range_in_buffer(
21662                            hunk.excerpt_id,
21663                            hunk.buffer_id,
21664                            hunk.buffer_range,
21665                        ),
21666                        is_created_file,
21667                    }
21668                };
21669
21670                Some(display_hunk)
21671            })
21672    }
21673
21674    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21675        self.display_snapshot.buffer_snapshot.language_at(position)
21676    }
21677
21678    pub fn is_focused(&self) -> bool {
21679        self.is_focused
21680    }
21681
21682    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21683        self.placeholder_text.as_ref()
21684    }
21685
21686    pub fn scroll_position(&self) -> gpui::Point<f32> {
21687        self.scroll_anchor.scroll_position(&self.display_snapshot)
21688    }
21689
21690    fn gutter_dimensions(
21691        &self,
21692        font_id: FontId,
21693        font_size: Pixels,
21694        max_line_number_width: Pixels,
21695        cx: &App,
21696    ) -> Option<GutterDimensions> {
21697        if !self.show_gutter {
21698            return None;
21699        }
21700
21701        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21702        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21703
21704        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21705            matches!(
21706                ProjectSettings::get_global(cx).git.git_gutter,
21707                Some(GitGutterSetting::TrackedFiles)
21708            )
21709        });
21710        let gutter_settings = EditorSettings::get_global(cx).gutter;
21711        let show_line_numbers = self
21712            .show_line_numbers
21713            .unwrap_or(gutter_settings.line_numbers);
21714        let line_gutter_width = if show_line_numbers {
21715            // Avoid flicker-like gutter resizes when the line number gains another digit by
21716            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21717            let min_width_for_number_on_gutter =
21718                ch_advance * gutter_settings.min_line_number_digits as f32;
21719            max_line_number_width.max(min_width_for_number_on_gutter)
21720        } else {
21721            0.0.into()
21722        };
21723
21724        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21725        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21726
21727        let git_blame_entries_width =
21728            self.git_blame_gutter_max_author_length
21729                .map(|max_author_length| {
21730                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21731                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21732
21733                    /// The number of characters to dedicate to gaps and margins.
21734                    const SPACING_WIDTH: usize = 4;
21735
21736                    let max_char_count = max_author_length.min(renderer.max_author_length())
21737                        + ::git::SHORT_SHA_LENGTH
21738                        + MAX_RELATIVE_TIMESTAMP.len()
21739                        + SPACING_WIDTH;
21740
21741                    ch_advance * max_char_count
21742                });
21743
21744        let is_singleton = self.buffer_snapshot.is_singleton();
21745
21746        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21747        left_padding += if !is_singleton {
21748            ch_width * 4.0
21749        } else if show_runnables || show_breakpoints {
21750            ch_width * 3.0
21751        } else if show_git_gutter && show_line_numbers {
21752            ch_width * 2.0
21753        } else if show_git_gutter || show_line_numbers {
21754            ch_width
21755        } else {
21756            px(0.)
21757        };
21758
21759        let shows_folds = is_singleton && gutter_settings.folds;
21760
21761        let right_padding = if shows_folds && show_line_numbers {
21762            ch_width * 4.0
21763        } else if shows_folds || (!is_singleton && show_line_numbers) {
21764            ch_width * 3.0
21765        } else if show_line_numbers {
21766            ch_width
21767        } else {
21768            px(0.)
21769        };
21770
21771        Some(GutterDimensions {
21772            left_padding,
21773            right_padding,
21774            width: line_gutter_width + left_padding + right_padding,
21775            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21776            git_blame_entries_width,
21777        })
21778    }
21779
21780    pub fn render_crease_toggle(
21781        &self,
21782        buffer_row: MultiBufferRow,
21783        row_contains_cursor: bool,
21784        editor: Entity<Editor>,
21785        window: &mut Window,
21786        cx: &mut App,
21787    ) -> Option<AnyElement> {
21788        let folded = self.is_line_folded(buffer_row);
21789        let mut is_foldable = false;
21790
21791        if let Some(crease) = self
21792            .crease_snapshot
21793            .query_row(buffer_row, &self.buffer_snapshot)
21794        {
21795            is_foldable = true;
21796            match crease {
21797                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21798                    if let Some(render_toggle) = render_toggle {
21799                        let toggle_callback =
21800                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21801                                if folded {
21802                                    editor.update(cx, |editor, cx| {
21803                                        editor.fold_at(buffer_row, window, cx)
21804                                    });
21805                                } else {
21806                                    editor.update(cx, |editor, cx| {
21807                                        editor.unfold_at(buffer_row, window, cx)
21808                                    });
21809                                }
21810                            });
21811                        return Some((render_toggle)(
21812                            buffer_row,
21813                            folded,
21814                            toggle_callback,
21815                            window,
21816                            cx,
21817                        ));
21818                    }
21819                }
21820            }
21821        }
21822
21823        is_foldable |= self.starts_indent(buffer_row);
21824
21825        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21826            Some(
21827                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21828                    .toggle_state(folded)
21829                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21830                        if folded {
21831                            this.unfold_at(buffer_row, window, cx);
21832                        } else {
21833                            this.fold_at(buffer_row, window, cx);
21834                        }
21835                    }))
21836                    .into_any_element(),
21837            )
21838        } else {
21839            None
21840        }
21841    }
21842
21843    pub fn render_crease_trailer(
21844        &self,
21845        buffer_row: MultiBufferRow,
21846        window: &mut Window,
21847        cx: &mut App,
21848    ) -> Option<AnyElement> {
21849        let folded = self.is_line_folded(buffer_row);
21850        if let Crease::Inline { render_trailer, .. } = self
21851            .crease_snapshot
21852            .query_row(buffer_row, &self.buffer_snapshot)?
21853        {
21854            let render_trailer = render_trailer.as_ref()?;
21855            Some(render_trailer(buffer_row, folded, window, cx))
21856        } else {
21857            None
21858        }
21859    }
21860}
21861
21862impl Deref for EditorSnapshot {
21863    type Target = DisplaySnapshot;
21864
21865    fn deref(&self) -> &Self::Target {
21866        &self.display_snapshot
21867    }
21868}
21869
21870#[derive(Clone, Debug, PartialEq, Eq)]
21871pub enum EditorEvent {
21872    InputIgnored {
21873        text: Arc<str>,
21874    },
21875    InputHandled {
21876        utf16_range_to_replace: Option<Range<isize>>,
21877        text: Arc<str>,
21878    },
21879    ExcerptsAdded {
21880        buffer: Entity<Buffer>,
21881        predecessor: ExcerptId,
21882        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21883    },
21884    ExcerptsRemoved {
21885        ids: Vec<ExcerptId>,
21886        removed_buffer_ids: Vec<BufferId>,
21887    },
21888    BufferFoldToggled {
21889        ids: Vec<ExcerptId>,
21890        folded: bool,
21891    },
21892    ExcerptsEdited {
21893        ids: Vec<ExcerptId>,
21894    },
21895    ExcerptsExpanded {
21896        ids: Vec<ExcerptId>,
21897    },
21898    BufferEdited,
21899    Edited {
21900        transaction_id: clock::Lamport,
21901    },
21902    Reparsed(BufferId),
21903    Focused,
21904    FocusedIn,
21905    Blurred,
21906    DirtyChanged,
21907    Saved,
21908    TitleChanged,
21909    DiffBaseChanged,
21910    SelectionsChanged {
21911        local: bool,
21912    },
21913    ScrollPositionChanged {
21914        local: bool,
21915        autoscroll: bool,
21916    },
21917    Closed,
21918    TransactionUndone {
21919        transaction_id: clock::Lamport,
21920    },
21921    TransactionBegun {
21922        transaction_id: clock::Lamport,
21923    },
21924    Reloaded,
21925    CursorShapeChanged,
21926    PushedToNavHistory {
21927        anchor: Anchor,
21928        is_deactivate: bool,
21929    },
21930}
21931
21932impl EventEmitter<EditorEvent> for Editor {}
21933
21934impl Focusable for Editor {
21935    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21936        self.focus_handle.clone()
21937    }
21938}
21939
21940impl Render for Editor {
21941    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21942        let settings = ThemeSettings::get_global(cx);
21943
21944        let mut text_style = match self.mode {
21945            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21946                color: cx.theme().colors().editor_foreground,
21947                font_family: settings.ui_font.family.clone(),
21948                font_features: settings.ui_font.features.clone(),
21949                font_fallbacks: settings.ui_font.fallbacks.clone(),
21950                font_size: rems(0.875).into(),
21951                font_weight: settings.ui_font.weight,
21952                line_height: relative(settings.buffer_line_height.value()),
21953                ..Default::default()
21954            },
21955            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21956                color: cx.theme().colors().editor_foreground,
21957                font_family: settings.buffer_font.family.clone(),
21958                font_features: settings.buffer_font.features.clone(),
21959                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21960                font_size: settings.buffer_font_size(cx).into(),
21961                font_weight: settings.buffer_font.weight,
21962                line_height: relative(settings.buffer_line_height.value()),
21963                ..Default::default()
21964            },
21965        };
21966        if let Some(text_style_refinement) = &self.text_style_refinement {
21967            text_style.refine(text_style_refinement)
21968        }
21969
21970        let background = match self.mode {
21971            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21972            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
21973            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21974            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21975        };
21976
21977        EditorElement::new(
21978            &cx.entity(),
21979            EditorStyle {
21980                background,
21981                local_player: cx.theme().players().local(),
21982                text: text_style,
21983                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21984                syntax: cx.theme().syntax().clone(),
21985                status: cx.theme().status().clone(),
21986                inlay_hints_style: make_inlay_hints_style(cx),
21987                inline_completion_styles: make_suggestion_styles(cx),
21988                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21989                show_underlines: !self.mode.is_minimap(),
21990            },
21991        )
21992    }
21993}
21994
21995impl EntityInputHandler for Editor {
21996    fn text_for_range(
21997        &mut self,
21998        range_utf16: Range<usize>,
21999        adjusted_range: &mut Option<Range<usize>>,
22000        _: &mut Window,
22001        cx: &mut Context<Self>,
22002    ) -> Option<String> {
22003        let snapshot = self.buffer.read(cx).read(cx);
22004        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22005        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22006        if (start.0..end.0) != range_utf16 {
22007            adjusted_range.replace(start.0..end.0);
22008        }
22009        Some(snapshot.text_for_range(start..end).collect())
22010    }
22011
22012    fn selected_text_range(
22013        &mut self,
22014        ignore_disabled_input: bool,
22015        _: &mut Window,
22016        cx: &mut Context<Self>,
22017    ) -> Option<UTF16Selection> {
22018        // Prevent the IME menu from appearing when holding down an alphabetic key
22019        // while input is disabled.
22020        if !ignore_disabled_input && !self.input_enabled {
22021            return None;
22022        }
22023
22024        let selection = self.selections.newest::<OffsetUtf16>(cx);
22025        let range = selection.range();
22026
22027        Some(UTF16Selection {
22028            range: range.start.0..range.end.0,
22029            reversed: selection.reversed,
22030        })
22031    }
22032
22033    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22034        let snapshot = self.buffer.read(cx).read(cx);
22035        let (range, _) = self.text_highlights::<InputComposition>(cx)?.first()?;
22036        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22037    }
22038
22039    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22040        self.clear_highlights::<InputComposition>(cx);
22041        self.ime_transaction.take();
22042    }
22043
22044    fn replace_text_in_range(
22045        &mut self,
22046        range_utf16: Option<Range<usize>>,
22047        text: &str,
22048        window: &mut Window,
22049        cx: &mut Context<Self>,
22050    ) {
22051        if !self.input_enabled {
22052            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22053            return;
22054        }
22055
22056        self.transact(window, cx, |this, window, cx| {
22057            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22058                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22059                Some(this.selection_replacement_ranges(range_utf16, cx))
22060            } else {
22061                this.marked_text_ranges(cx)
22062            };
22063
22064            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22065                let newest_selection_id = this.selections.newest_anchor().id;
22066                this.selections
22067                    .all::<OffsetUtf16>(cx)
22068                    .iter()
22069                    .zip(ranges_to_replace.iter())
22070                    .find_map(|(selection, range)| {
22071                        if selection.id == newest_selection_id {
22072                            Some(
22073                                (range.start.0 as isize - selection.head().0 as isize)
22074                                    ..(range.end.0 as isize - selection.head().0 as isize),
22075                            )
22076                        } else {
22077                            None
22078                        }
22079                    })
22080            });
22081
22082            cx.emit(EditorEvent::InputHandled {
22083                utf16_range_to_replace: range_to_replace,
22084                text: text.into(),
22085            });
22086
22087            if let Some(new_selected_ranges) = new_selected_ranges {
22088                this.change_selections(None, window, cx, |selections| {
22089                    selections.select_ranges(new_selected_ranges)
22090                });
22091                this.backspace(&Default::default(), window, cx);
22092            }
22093
22094            this.handle_input(text, window, cx);
22095        });
22096
22097        if let Some(transaction) = self.ime_transaction {
22098            self.buffer.update(cx, |buffer, cx| {
22099                buffer.group_until_transaction(transaction, cx);
22100            });
22101        }
22102
22103        self.unmark_text(window, cx);
22104    }
22105
22106    fn replace_and_mark_text_in_range(
22107        &mut self,
22108        range_utf16: Option<Range<usize>>,
22109        text: &str,
22110        new_selected_range_utf16: Option<Range<usize>>,
22111        window: &mut Window,
22112        cx: &mut Context<Self>,
22113    ) {
22114        if !self.input_enabled {
22115            return;
22116        }
22117
22118        let transaction = self.transact(window, cx, |this, window, cx| {
22119            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22120                let snapshot = this.buffer.read(cx).read(cx);
22121                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22122                    for marked_range in &mut marked_ranges {
22123                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22124                        marked_range.start.0 += relative_range_utf16.start;
22125                        marked_range.start =
22126                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22127                        marked_range.end =
22128                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22129                    }
22130                }
22131                Some(marked_ranges)
22132            } else if let Some(range_utf16) = range_utf16 {
22133                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22134                Some(this.selection_replacement_ranges(range_utf16, cx))
22135            } else {
22136                None
22137            };
22138
22139            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22140                let newest_selection_id = this.selections.newest_anchor().id;
22141                this.selections
22142                    .all::<OffsetUtf16>(cx)
22143                    .iter()
22144                    .zip(ranges_to_replace.iter())
22145                    .find_map(|(selection, range)| {
22146                        if selection.id == newest_selection_id {
22147                            Some(
22148                                (range.start.0 as isize - selection.head().0 as isize)
22149                                    ..(range.end.0 as isize - selection.head().0 as isize),
22150                            )
22151                        } else {
22152                            None
22153                        }
22154                    })
22155            });
22156
22157            cx.emit(EditorEvent::InputHandled {
22158                utf16_range_to_replace: range_to_replace,
22159                text: text.into(),
22160            });
22161
22162            if let Some(ranges) = ranges_to_replace {
22163                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22164            }
22165
22166            let marked_ranges = {
22167                let snapshot = this.buffer.read(cx).read(cx);
22168                this.selections
22169                    .disjoint_anchors()
22170                    .iter()
22171                    .map(|selection| {
22172                        (
22173                            selection.start.bias_left(&snapshot)
22174                                ..selection.end.bias_right(&snapshot),
22175                            HighlightStyle {
22176                                underline: Some(UnderlineStyle {
22177                                    thickness: px(1.),
22178                                    color: None,
22179                                    wavy: false,
22180                                }),
22181                                ..Default::default()
22182                            },
22183                        )
22184                    })
22185                    .collect::<Vec<_>>()
22186            };
22187
22188            if text.is_empty() {
22189                this.unmark_text(window, cx);
22190            } else {
22191                this.highlight_text::<InputComposition>(marked_ranges.clone(), cx);
22192            }
22193
22194            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22195            let use_autoclose = this.use_autoclose;
22196            let use_auto_surround = this.use_auto_surround;
22197            this.set_use_autoclose(false);
22198            this.set_use_auto_surround(false);
22199            this.handle_input(text, window, cx);
22200            this.set_use_autoclose(use_autoclose);
22201            this.set_use_auto_surround(use_auto_surround);
22202
22203            if let Some(new_selected_range) = new_selected_range_utf16 {
22204                let snapshot = this.buffer.read(cx).read(cx);
22205                let new_selected_ranges = marked_ranges
22206                    .into_iter()
22207                    .map(|(marked_range, _)| {
22208                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22209                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22210                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22211                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22212                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22213                    })
22214                    .collect::<Vec<_>>();
22215
22216                drop(snapshot);
22217                this.change_selections(None, window, cx, |selections| {
22218                    selections.select_ranges(new_selected_ranges)
22219                });
22220            }
22221        });
22222
22223        self.ime_transaction = self.ime_transaction.or(transaction);
22224        if let Some(transaction) = self.ime_transaction {
22225            self.buffer.update(cx, |buffer, cx| {
22226                buffer.group_until_transaction(transaction, cx);
22227            });
22228        }
22229
22230        if self.text_highlights::<InputComposition>(cx).is_none() {
22231            self.ime_transaction.take();
22232        }
22233    }
22234
22235    fn bounds_for_range(
22236        &mut self,
22237        range_utf16: Range<usize>,
22238        element_bounds: gpui::Bounds<Pixels>,
22239        window: &mut Window,
22240        cx: &mut Context<Self>,
22241    ) -> Option<gpui::Bounds<Pixels>> {
22242        let text_layout_details = self.text_layout_details(window);
22243        let gpui::Size {
22244            width: em_width,
22245            height: line_height,
22246        } = self.character_size(window);
22247
22248        let snapshot = self.snapshot(window, cx);
22249        let scroll_position = snapshot.scroll_position();
22250        let scroll_left = scroll_position.x * em_width;
22251
22252        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22253        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22254            + self.gutter_dimensions.width
22255            + self.gutter_dimensions.margin;
22256        let y = line_height * (start.row().as_f32() - scroll_position.y);
22257
22258        Some(Bounds {
22259            origin: element_bounds.origin + point(x, y),
22260            size: size(em_width, line_height),
22261        })
22262    }
22263
22264    fn character_index_for_point(
22265        &mut self,
22266        point: gpui::Point<Pixels>,
22267        _window: &mut Window,
22268        _cx: &mut Context<Self>,
22269    ) -> Option<usize> {
22270        let position_map = self.last_position_map.as_ref()?;
22271        if !position_map.text_hitbox.contains(&point) {
22272            return None;
22273        }
22274        let display_point = position_map.point_for_position(point).previous_valid;
22275        let anchor = position_map
22276            .snapshot
22277            .display_point_to_anchor(display_point, Bias::Left);
22278        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22279        Some(utf16_offset.0)
22280    }
22281}
22282
22283trait SelectionExt {
22284    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22285    fn spanned_rows(
22286        &self,
22287        include_end_if_at_line_start: bool,
22288        map: &DisplaySnapshot,
22289    ) -> Range<MultiBufferRow>;
22290}
22291
22292impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22293    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22294        let start = self
22295            .start
22296            .to_point(&map.buffer_snapshot)
22297            .to_display_point(map);
22298        let end = self
22299            .end
22300            .to_point(&map.buffer_snapshot)
22301            .to_display_point(map);
22302        if self.reversed {
22303            end..start
22304        } else {
22305            start..end
22306        }
22307    }
22308
22309    fn spanned_rows(
22310        &self,
22311        include_end_if_at_line_start: bool,
22312        map: &DisplaySnapshot,
22313    ) -> Range<MultiBufferRow> {
22314        let start = self.start.to_point(&map.buffer_snapshot);
22315        let mut end = self.end.to_point(&map.buffer_snapshot);
22316        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22317            end.row -= 1;
22318        }
22319
22320        let buffer_start = map.prev_line_boundary(start).0;
22321        let buffer_end = map.next_line_boundary(end).0;
22322        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22323    }
22324}
22325
22326impl<T: InvalidationRegion> InvalidationStack<T> {
22327    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22328    where
22329        S: Clone + ToOffset,
22330    {
22331        while let Some(region) = self.last() {
22332            let all_selections_inside_invalidation_ranges =
22333                if selections.len() == region.ranges().len() {
22334                    selections
22335                        .iter()
22336                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22337                        .all(|(selection, invalidation_range)| {
22338                            let head = selection.head().to_offset(buffer);
22339                            invalidation_range.start <= head && invalidation_range.end >= head
22340                        })
22341                } else {
22342                    false
22343                };
22344
22345            if all_selections_inside_invalidation_ranges {
22346                break;
22347            } else {
22348                self.pop();
22349            }
22350        }
22351    }
22352}
22353
22354impl<T> Default for InvalidationStack<T> {
22355    fn default() -> Self {
22356        Self(Default::default())
22357    }
22358}
22359
22360impl<T> Deref for InvalidationStack<T> {
22361    type Target = Vec<T>;
22362
22363    fn deref(&self) -> &Self::Target {
22364        &self.0
22365    }
22366}
22367
22368impl<T> DerefMut for InvalidationStack<T> {
22369    fn deref_mut(&mut self) -> &mut Self::Target {
22370        &mut self.0
22371    }
22372}
22373
22374impl InvalidationRegion for SnippetState {
22375    fn ranges(&self) -> &[Range<Anchor>] {
22376        &self.ranges[self.active_index]
22377    }
22378}
22379
22380fn inline_completion_edit_text(
22381    current_snapshot: &BufferSnapshot,
22382    edits: &[(Range<Anchor>, String)],
22383    edit_preview: &EditPreview,
22384    include_deletions: bool,
22385    cx: &App,
22386) -> HighlightedText {
22387    let edits = edits
22388        .iter()
22389        .map(|(anchor, text)| {
22390            (
22391                anchor.start.text_anchor..anchor.end.text_anchor,
22392                text.clone(),
22393            )
22394        })
22395        .collect::<Vec<_>>();
22396
22397    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22398}
22399
22400pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22401    match severity {
22402        lsp::DiagnosticSeverity::ERROR => colors.error,
22403        lsp::DiagnosticSeverity::WARNING => colors.warning,
22404        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22405        lsp::DiagnosticSeverity::HINT => colors.info,
22406        _ => colors.ignored,
22407    }
22408}
22409
22410pub fn styled_runs_for_code_label<'a>(
22411    label: &'a CodeLabel,
22412    syntax_theme: &'a theme::SyntaxTheme,
22413) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22414    let fade_out = HighlightStyle {
22415        fade_out: Some(0.35),
22416        ..Default::default()
22417    };
22418
22419    let mut prev_end = label.filter_range.end;
22420    label
22421        .runs
22422        .iter()
22423        .enumerate()
22424        .flat_map(move |(ix, (range, highlight_id))| {
22425            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22426                style
22427            } else {
22428                return Default::default();
22429            };
22430            let mut muted_style = style;
22431            muted_style.highlight(fade_out);
22432
22433            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22434            if range.start >= label.filter_range.end {
22435                if range.start > prev_end {
22436                    runs.push((prev_end..range.start, fade_out));
22437                }
22438                runs.push((range.clone(), muted_style));
22439            } else if range.end <= label.filter_range.end {
22440                runs.push((range.clone(), style));
22441            } else {
22442                runs.push((range.start..label.filter_range.end, style));
22443                runs.push((label.filter_range.end..range.end, muted_style));
22444            }
22445            prev_end = cmp::max(prev_end, range.end);
22446
22447            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22448                runs.push((prev_end..label.text.len(), fade_out));
22449            }
22450
22451            runs
22452        })
22453}
22454
22455pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22456    let mut prev_index = 0;
22457    let mut prev_codepoint: Option<char> = None;
22458    text.char_indices()
22459        .chain([(text.len(), '\0')])
22460        .filter_map(move |(index, codepoint)| {
22461            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22462            let is_boundary = index == text.len()
22463                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22464                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22465            if is_boundary {
22466                let chunk = &text[prev_index..index];
22467                prev_index = index;
22468                Some(chunk)
22469            } else {
22470                None
22471            }
22472        })
22473}
22474
22475pub trait RangeToAnchorExt: Sized {
22476    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22477
22478    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22479        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22480        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22481    }
22482}
22483
22484impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22485    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22486        let start_offset = self.start.to_offset(snapshot);
22487        let end_offset = self.end.to_offset(snapshot);
22488        if start_offset == end_offset {
22489            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22490        } else {
22491            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22492        }
22493    }
22494}
22495
22496pub trait RowExt {
22497    fn as_f32(&self) -> f32;
22498
22499    fn next_row(&self) -> Self;
22500
22501    fn previous_row(&self) -> Self;
22502
22503    fn minus(&self, other: Self) -> u32;
22504}
22505
22506impl RowExt for DisplayRow {
22507    fn as_f32(&self) -> f32 {
22508        self.0 as f32
22509    }
22510
22511    fn next_row(&self) -> Self {
22512        Self(self.0 + 1)
22513    }
22514
22515    fn previous_row(&self) -> Self {
22516        Self(self.0.saturating_sub(1))
22517    }
22518
22519    fn minus(&self, other: Self) -> u32 {
22520        self.0 - other.0
22521    }
22522}
22523
22524impl RowExt for MultiBufferRow {
22525    fn as_f32(&self) -> f32 {
22526        self.0 as f32
22527    }
22528
22529    fn next_row(&self) -> Self {
22530        Self(self.0 + 1)
22531    }
22532
22533    fn previous_row(&self) -> Self {
22534        Self(self.0.saturating_sub(1))
22535    }
22536
22537    fn minus(&self, other: Self) -> u32 {
22538        self.0 - other.0
22539    }
22540}
22541
22542trait RowRangeExt {
22543    type Row;
22544
22545    fn len(&self) -> usize;
22546
22547    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22548}
22549
22550impl RowRangeExt for Range<MultiBufferRow> {
22551    type Row = MultiBufferRow;
22552
22553    fn len(&self) -> usize {
22554        (self.end.0 - self.start.0) as usize
22555    }
22556
22557    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22558        (self.start.0..self.end.0).map(MultiBufferRow)
22559    }
22560}
22561
22562impl RowRangeExt for Range<DisplayRow> {
22563    type Row = DisplayRow;
22564
22565    fn len(&self) -> usize {
22566        (self.end.0 - self.start.0) as usize
22567    }
22568
22569    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22570        (self.start.0..self.end.0).map(DisplayRow)
22571    }
22572}
22573
22574/// If select range has more than one line, we
22575/// just point the cursor to range.start.
22576fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22577    if range.start.row == range.end.row {
22578        range
22579    } else {
22580        range.start..range.start
22581    }
22582}
22583pub struct KillRing(ClipboardItem);
22584impl Global for KillRing {}
22585
22586const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22587
22588enum BreakpointPromptEditAction {
22589    Log,
22590    Condition,
22591    HitCondition,
22592}
22593
22594struct BreakpointPromptEditor {
22595    pub(crate) prompt: Entity<Editor>,
22596    editor: WeakEntity<Editor>,
22597    breakpoint_anchor: Anchor,
22598    breakpoint: Breakpoint,
22599    edit_action: BreakpointPromptEditAction,
22600    block_ids: HashSet<CustomBlockId>,
22601    editor_margins: Arc<Mutex<EditorMargins>>,
22602    _subscriptions: Vec<Subscription>,
22603}
22604
22605impl BreakpointPromptEditor {
22606    const MAX_LINES: u8 = 4;
22607
22608    fn new(
22609        editor: WeakEntity<Editor>,
22610        breakpoint_anchor: Anchor,
22611        breakpoint: Breakpoint,
22612        edit_action: BreakpointPromptEditAction,
22613        window: &mut Window,
22614        cx: &mut Context<Self>,
22615    ) -> Self {
22616        let base_text = match edit_action {
22617            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22618            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22619            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22620        }
22621        .map(|msg| msg.to_string())
22622        .unwrap_or_default();
22623
22624        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22625        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22626
22627        let prompt = cx.new(|cx| {
22628            let mut prompt = Editor::new(
22629                EditorMode::AutoHeight {
22630                    min_lines: 1,
22631                    max_lines: Self::MAX_LINES as usize,
22632                },
22633                buffer,
22634                None,
22635                window,
22636                cx,
22637            );
22638            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22639            prompt.set_show_cursor_when_unfocused(false, cx);
22640            prompt.set_placeholder_text(
22641                match edit_action {
22642                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22643                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22644                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22645                },
22646                cx,
22647            );
22648
22649            prompt
22650        });
22651
22652        Self {
22653            prompt,
22654            editor,
22655            breakpoint_anchor,
22656            breakpoint,
22657            edit_action,
22658            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22659            block_ids: Default::default(),
22660            _subscriptions: vec![],
22661        }
22662    }
22663
22664    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22665        self.block_ids.extend(block_ids)
22666    }
22667
22668    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22669        if let Some(editor) = self.editor.upgrade() {
22670            let message = self
22671                .prompt
22672                .read(cx)
22673                .buffer
22674                .read(cx)
22675                .as_singleton()
22676                .expect("A multi buffer in breakpoint prompt isn't possible")
22677                .read(cx)
22678                .as_rope()
22679                .to_string();
22680
22681            editor.update(cx, |editor, cx| {
22682                editor.edit_breakpoint_at_anchor(
22683                    self.breakpoint_anchor,
22684                    self.breakpoint.clone(),
22685                    match self.edit_action {
22686                        BreakpointPromptEditAction::Log => {
22687                            BreakpointEditAction::EditLogMessage(message.into())
22688                        }
22689                        BreakpointPromptEditAction::Condition => {
22690                            BreakpointEditAction::EditCondition(message.into())
22691                        }
22692                        BreakpointPromptEditAction::HitCondition => {
22693                            BreakpointEditAction::EditHitCondition(message.into())
22694                        }
22695                    },
22696                    cx,
22697                );
22698
22699                editor.remove_blocks(self.block_ids.clone(), None, cx);
22700                cx.focus_self(window);
22701            });
22702        }
22703    }
22704
22705    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22706        self.editor
22707            .update(cx, |editor, cx| {
22708                editor.remove_blocks(self.block_ids.clone(), None, cx);
22709                window.focus(&editor.focus_handle);
22710            })
22711            .log_err();
22712    }
22713
22714    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22715        let settings = ThemeSettings::get_global(cx);
22716        let text_style = TextStyle {
22717            color: if self.prompt.read(cx).read_only(cx) {
22718                cx.theme().colors().text_disabled
22719            } else {
22720                cx.theme().colors().text
22721            },
22722            font_family: settings.buffer_font.family.clone(),
22723            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22724            font_size: settings.buffer_font_size(cx).into(),
22725            font_weight: settings.buffer_font.weight,
22726            line_height: relative(settings.buffer_line_height.value()),
22727            ..Default::default()
22728        };
22729        EditorElement::new(
22730            &self.prompt,
22731            EditorStyle {
22732                background: cx.theme().colors().editor_background,
22733                local_player: cx.theme().players().local(),
22734                text: text_style,
22735                ..Default::default()
22736            },
22737        )
22738    }
22739}
22740
22741impl Render for BreakpointPromptEditor {
22742    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22743        let editor_margins = *self.editor_margins.lock();
22744        let gutter_dimensions = editor_margins.gutter;
22745        h_flex()
22746            .key_context("Editor")
22747            .bg(cx.theme().colors().editor_background)
22748            .border_y_1()
22749            .border_color(cx.theme().status().info_border)
22750            .size_full()
22751            .py(window.line_height() / 2.5)
22752            .on_action(cx.listener(Self::confirm))
22753            .on_action(cx.listener(Self::cancel))
22754            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22755            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22756    }
22757}
22758
22759impl Focusable for BreakpointPromptEditor {
22760    fn focus_handle(&self, cx: &App) -> FocusHandle {
22761        self.prompt.focus_handle(cx)
22762    }
22763}
22764
22765fn all_edits_insertions_or_deletions(
22766    edits: &Vec<(Range<Anchor>, String)>,
22767    snapshot: &MultiBufferSnapshot,
22768) -> bool {
22769    let mut all_insertions = true;
22770    let mut all_deletions = true;
22771
22772    for (range, new_text) in edits.iter() {
22773        let range_is_empty = range.to_offset(&snapshot).is_empty();
22774        let text_is_empty = new_text.is_empty();
22775
22776        if range_is_empty != text_is_empty {
22777            if range_is_empty {
22778                all_deletions = false;
22779            } else {
22780                all_insertions = false;
22781            }
22782        } else {
22783            return false;
22784        }
22785
22786        if !all_insertions && !all_deletions {
22787            return false;
22788        }
22789    }
22790    all_insertions || all_deletions
22791}
22792
22793struct MissingEditPredictionKeybindingTooltip;
22794
22795impl Render for MissingEditPredictionKeybindingTooltip {
22796    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22797        ui::tooltip_container(window, cx, |container, _, cx| {
22798            container
22799                .flex_shrink_0()
22800                .max_w_80()
22801                .min_h(rems_from_px(124.))
22802                .justify_between()
22803                .child(
22804                    v_flex()
22805                        .flex_1()
22806                        .text_ui_sm(cx)
22807                        .child(Label::new("Conflict with Accept Keybinding"))
22808                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22809                )
22810                .child(
22811                    h_flex()
22812                        .pb_1()
22813                        .gap_1()
22814                        .items_end()
22815                        .w_full()
22816                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22817                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22818                        }))
22819                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22820                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22821                        })),
22822                )
22823        })
22824    }
22825}
22826
22827#[derive(Debug, Clone, Copy, PartialEq)]
22828pub struct LineHighlight {
22829    pub background: Background,
22830    pub border: Option<gpui::Hsla>,
22831    pub include_gutter: bool,
22832    pub type_id: Option<TypeId>,
22833}
22834
22835fn render_diff_hunk_controls(
22836    row: u32,
22837    status: &DiffHunkStatus,
22838    hunk_range: Range<Anchor>,
22839    is_created_file: bool,
22840    line_height: Pixels,
22841    editor: &Entity<Editor>,
22842    _window: &mut Window,
22843    cx: &mut App,
22844) -> AnyElement {
22845    h_flex()
22846        .h(line_height)
22847        .mr_1()
22848        .gap_1()
22849        .px_0p5()
22850        .pb_1()
22851        .border_x_1()
22852        .border_b_1()
22853        .border_color(cx.theme().colors().border_variant)
22854        .rounded_b_lg()
22855        .bg(cx.theme().colors().editor_background)
22856        .gap_1()
22857        .block_mouse_except_scroll()
22858        .shadow_md()
22859        .child(if status.has_secondary_hunk() {
22860            Button::new(("stage", row as u64), "Stage")
22861                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22862                .tooltip({
22863                    let focus_handle = editor.focus_handle(cx);
22864                    move |window, cx| {
22865                        Tooltip::for_action_in(
22866                            "Stage Hunk",
22867                            &::git::ToggleStaged,
22868                            &focus_handle,
22869                            window,
22870                            cx,
22871                        )
22872                    }
22873                })
22874                .on_click({
22875                    let editor = editor.clone();
22876                    move |_event, _window, cx| {
22877                        editor.update(cx, |editor, cx| {
22878                            editor.stage_or_unstage_diff_hunks(
22879                                true,
22880                                vec![hunk_range.start..hunk_range.start],
22881                                cx,
22882                            );
22883                        });
22884                    }
22885                })
22886        } else {
22887            Button::new(("unstage", row as u64), "Unstage")
22888                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22889                .tooltip({
22890                    let focus_handle = editor.focus_handle(cx);
22891                    move |window, cx| {
22892                        Tooltip::for_action_in(
22893                            "Unstage Hunk",
22894                            &::git::ToggleStaged,
22895                            &focus_handle,
22896                            window,
22897                            cx,
22898                        )
22899                    }
22900                })
22901                .on_click({
22902                    let editor = editor.clone();
22903                    move |_event, _window, cx| {
22904                        editor.update(cx, |editor, cx| {
22905                            editor.stage_or_unstage_diff_hunks(
22906                                false,
22907                                vec![hunk_range.start..hunk_range.start],
22908                                cx,
22909                            );
22910                        });
22911                    }
22912                })
22913        })
22914        .child(
22915            Button::new(("restore", row as u64), "Restore")
22916                .tooltip({
22917                    let focus_handle = editor.focus_handle(cx);
22918                    move |window, cx| {
22919                        Tooltip::for_action_in(
22920                            "Restore Hunk",
22921                            &::git::Restore,
22922                            &focus_handle,
22923                            window,
22924                            cx,
22925                        )
22926                    }
22927                })
22928                .on_click({
22929                    let editor = editor.clone();
22930                    move |_event, window, cx| {
22931                        editor.update(cx, |editor, cx| {
22932                            let snapshot = editor.snapshot(window, cx);
22933                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22934                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22935                        });
22936                    }
22937                })
22938                .disabled(is_created_file),
22939        )
22940        .when(
22941            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22942            |el| {
22943                el.child(
22944                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22945                        .shape(IconButtonShape::Square)
22946                        .icon_size(IconSize::Small)
22947                        // .disabled(!has_multiple_hunks)
22948                        .tooltip({
22949                            let focus_handle = editor.focus_handle(cx);
22950                            move |window, cx| {
22951                                Tooltip::for_action_in(
22952                                    "Next Hunk",
22953                                    &GoToHunk,
22954                                    &focus_handle,
22955                                    window,
22956                                    cx,
22957                                )
22958                            }
22959                        })
22960                        .on_click({
22961                            let editor = editor.clone();
22962                            move |_event, window, cx| {
22963                                editor.update(cx, |editor, cx| {
22964                                    let snapshot = editor.snapshot(window, cx);
22965                                    let position =
22966                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22967                                    editor.go_to_hunk_before_or_after_position(
22968                                        &snapshot,
22969                                        position,
22970                                        Direction::Next,
22971                                        window,
22972                                        cx,
22973                                    );
22974                                    editor.expand_selected_diff_hunks(cx);
22975                                });
22976                            }
22977                        }),
22978                )
22979                .child(
22980                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22981                        .shape(IconButtonShape::Square)
22982                        .icon_size(IconSize::Small)
22983                        // .disabled(!has_multiple_hunks)
22984                        .tooltip({
22985                            let focus_handle = editor.focus_handle(cx);
22986                            move |window, cx| {
22987                                Tooltip::for_action_in(
22988                                    "Previous Hunk",
22989                                    &GoToPreviousHunk,
22990                                    &focus_handle,
22991                                    window,
22992                                    cx,
22993                                )
22994                            }
22995                        })
22996                        .on_click({
22997                            let editor = editor.clone();
22998                            move |_event, window, cx| {
22999                                editor.update(cx, |editor, cx| {
23000                                    let snapshot = editor.snapshot(window, cx);
23001                                    let point =
23002                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23003                                    editor.go_to_hunk_before_or_after_position(
23004                                        &snapshot,
23005                                        point,
23006                                        Direction::Prev,
23007                                        window,
23008                                        cx,
23009                                    );
23010                                    editor.expand_selected_diff_hunks(cx);
23011                                });
23012                            }
23013                        }),
23014                )
23015            },
23016        )
23017        .into_any_element()
23018}